platypush/plugins/sound/__init__.py
def play(self, file=None, sound=None, device=None, blocksize=None,
             bufsize=None, samplerate=None, channels=None, stream_name=None,
             stream_index=None):
        """
        Plays a sound file (support formats: wav, raw) or a synthetic sound.

        :param file: Sound file path. Specify this if you want to play a file
        :type file: str

        :param sound: Sound to play. Specify this if you want to play
            synthetic sounds. You can also create polyphonic sounds by just
            calling play multiple times.
        :type sound: Sound. You can initialize it either from a list
            of `Sound` objects or from its JSON representation, e.g.::

                {
                    "midi_note": 69,  # 440 Hz A
                    "gain":      1.0, # Maximum volume
                    "duration":  1.0  # 1 second or until release/pause/stop
                }

        :param device: Output device (default: default configured device or
            system default audio output if not configured)
        :type device: int or str

        :param blocksize: Audio block size (default: configured
            `output_blocksize` or 2048)
        :type blocksize: int

        :param bufsize: Size of the audio buffer (default: 20 frames for audio
            files, 2 frames for synth sounds)
        :type bufsize: int

        :param samplerate: Audio samplerate. Default: audio file samplerate if
            in file mode, 44100 Hz if in synth mode
        :type samplerate: int

        :param channels: Number of audio channels. Default: number of channels
            in the audio file in file mode, 1 if in synth mode
        :type channels: int

        :param stream_index: If specified, play to an already active stream
            index (you can get them through
            :meth:`platypush.plugins.sound.query_streams`). Default:
            creates a new audio stream through PortAudio.
        :type stream_index: int

        :param stream_name: Name of the stream to play to. If set, the sound
            will be played to the specified stream name, or a stream with that
            name will be created. If not set, and ``stream_index`` is not set
            either, then a new stream will be created on the next available
            index and named ``platypush-stream-<index>``.
        :type stream_name: str
        """

        if not file and not sound:
            raise RuntimeError('Please specify either a file to play or a ' +
                               'list of sound objects')

        import sounddevice as sd

        if blocksize is None:
            blocksize = self.output_blocksize

        if bufsize is None:
            if file:
                bufsize = Sound._DEFAULT_FILE_BUFSIZE
            else:
                bufsize = Sound._DEFAULT_SYNTH_BUFSIZE

        q = queue.Queue(maxsize=bufsize)
        f = None
        t = 0.

        if file:
            file = os.path.abspath(os.path.expanduser(file))

        if device is None:
            device = self.output_device
        if device is None:
            device = self._get_default_device('output')

        if file:
            import soundfile as sf
            f = sf.SoundFile(file)
        if not samplerate:
            samplerate = f.samplerate if f else Sound._DEFAULT_SAMPLERATE
        if not channels:
            channels = f.channels if f else 1

        mix = None
        with self.playback_state_lock:
            stream_index, is_new_stream = self._get_or_allocate_stream_index(
                stream_index=stream_index, stream_name=stream_name)

            if sound and stream_index in self.stream_mixes:
                mix = self.stream_mixes[stream_index]
                mix.add(sound)

        if not mix:
            return None, "Unable to allocate the stream"

        self.logger.info(('Starting playback of {} to sound device [{}] ' +
                          'on stream [{}]').format(
            file or sound, device, stream_index))

        if not is_new_stream:
            return  # Let the existing callback handle the new mix
            # TODO Potential support also for mixed streams with
            # multiple sound files and synth sounds?

        try:
            # Audio queue pre-fill loop
            for _ in range(bufsize):
                if f:
                    data = f.buffer_read(blocksize, dtype='float32')
                    if not data:
                        break
                else:
                    duration = mix.duration()
                    blocktime = float(blocksize / samplerate)
                    next_t = min(t + blocktime, duration) \
                        if duration is not None else t + blocktime

                    data = mix.get_wave(t_start=t, t_end=next_t, samplerate=samplerate)
                    t = next_t

                    if duration is not None and t >= duration:
                        break

                q.put_nowait(data)  # Pre-fill the audio queue

            stream = self.active_streams[stream_index]
            completed_callback_event = self.completed_callback_events[stream_index]

            if stream is None:
                streamtype = sd.RawOutputStream if file else sd.OutputStream
                stream = streamtype(samplerate=samplerate, blocksize=blocksize,
                                    device=device, channels=channels,
                                    dtype='float32',
                                    callback=self._play_audio_callback(
                                        q=q, blocksize=blocksize,
                                        streamtype=streamtype,
                                        stream_index=stream_index),
                                    finished_callback=completed_callback_event.set)

                self._start_playback(stream_index=stream_index, stream=stream)

            with stream:
                # Timeout set until we expect all the buffered blocks to
                # be consumed
                timeout = blocksize * bufsize / samplerate

                while True:
                    while self._get_playback_state(stream_index) == \
                            PlaybackState.PAUSED:
                        self.playback_paused_changed[stream_index].wait()

                    if f:
                        data = f.buffer_read(blocksize, dtype='float32')
                        if not data:
                            break
                    else:
                        duration = mix.duration()
                        blocktime = float(blocksize / samplerate)
                        next_t = min(t + blocktime, duration) \
                            if duration is not None else t + blocktime

                        data = mix.get_wave(t_start=t, t_end=next_t,
                                            samplerate=samplerate)
                        t = next_t

                        if duration is not None and t >= duration:
                            break

                    if self._get_playback_state(stream_index) == \
                            PlaybackState.STOPPED:
                        break

                    try:
                        q.put(data, timeout=timeout)
                    except queue.Full as e:
                        if self._get_playback_state(stream_index) != \
                                PlaybackState.PAUSED:
                            raise e

                completed_callback_event.wait()
        except queue.Full:
            if stream_index is None or \
                    self._get_playback_state(stream_index) != PlaybackState.STOPPED:
                self.logger.warning('Playback timeout: audio callback failed?')
        finally:
            if f and not f.closed:
                f.close()

            self.stop_playback([stream_index])

        Plays a sound file (support formats: wav, raw) or a synthetic sound.

        :param file: Sound file path. Specify this if you want to play a file
        :type file: str

        :param sound: Sound to play. Specify this if you want to play
            synthetic sounds. You can also create polyphonic sounds by just
            calling play multiple times.
        :type sound: Sound. You can initialize it either from a list
            of `Sound` objects or from its JSON representation, e.g.::

                {
                    "midi_note": 69,  # 440 Hz A
                    "gain":      1.0, # Maximum volume
                    "duration":  1.0  # 1 second or until release/pause/stop
                }

        :param device: Output device (default: default configured device or
            system default audio output if not configured)
        :type device: int or str

        :param blocksize: Audio block size (default: configured
            `output_blocksize` or 2048)
        :type blocksize: int

        :param bufsize: Size of the audio buffer (default: 20 frames for audio
            files, 2 frames for synth sounds)
        :type bufsize: int

        :param samplerate: Audio samplerate. Default: audio file samplerate if
            in file mode, 44100 Hz if in synth mode
        :type samplerate: int

        :param channels: Number of audio channels. Default: number of channels
            in the audio file in file mode, 1 if in synth mode
        :type channels: int

        :param stream_index: If specified, play to an already active stream
            index (you can get them through
            :meth:`platypush.plugins.sound.query_streams`). Default:
            creates a new audio stream through PortAudio.
        :type stream_index: int

        :param stream_name: Name of the stream to play to. If set, the sound
            will be played to the specified stream name, or a stream with that
            name will be created. If not set, and ``stream_index`` is not set
            either, then a new stream will be created on the next available
            index and named ``platypush-stream-<index>``.
        :type stream_name: str
        
Plays a sound file (support formats: wav, raw) or a synthetic sound.
Plays a sound file ( support formats : wav raw ) or a synthetic sound .
def play(self, file=None, sound=None, device=None, blocksize=None,
             bufsize=None, samplerate=None, channels=None, stream_name=None,
             stream_index=None):
        if not file and not sound:
            raise RuntimeError('Please specify either a file to play or a ' +
                               'list of sound objects')
        import sounddevice as sd
        if blocksize is None:
            blocksize = self.output_blocksize
        if bufsize is None:
            if file:
                bufsize = Sound._DEFAULT_FILE_BUFSIZE
            else:
                bufsize = Sound._DEFAULT_SYNTH_BUFSIZE
        q = queue.Queue(maxsize=bufsize)
        f = None
        t = 0.
        if file:
            file = os.path.abspath(os.path.expanduser(file))
        if device is None:
            device = self.output_device
        if device is None:
            device = self._get_default_device('output')
        if file:
            import soundfile as sf
            f = sf.SoundFile(file)
        if not samplerate:
            samplerate = f.samplerate if f else Sound._DEFAULT_SAMPLERATE
        if not channels:
            channels = f.channels if f else 1
        mix = None
        with self.playback_state_lock:
            stream_index, is_new_stream = self._get_or_allocate_stream_index(
                stream_index=stream_index, stream_name=stream_name)
            if sound and stream_index in self.stream_mixes:
                mix = self.stream_mixes[stream_index]
                mix.add(sound)
        if not mix:
            return None, "Unable to allocate the stream"
        self.logger.info(('Starting playback of {} to sound device [{}] ' +
                          'on stream [{}]').format(
            file or sound, device, stream_index))
        if not is_new_stream:
            return  
        try:
            for _ in range(bufsize):
                if f:
                    data = f.buffer_read(blocksize, dtype='float32')
                    if not data:
                        break
                else:
                    duration = mix.duration()
                    blocktime = float(blocksize / samplerate)
                    next_t = min(t + blocktime, duration) \
                        if duration is not None else t + blocktime
                    data = mix.get_wave(t_start=t, t_end=next_t, samplerate=samplerate)
                    t = next_t
                    if duration is not None and t >= duration:
                        break
                q.put_nowait(data)  
            stream = self.active_streams[stream_index]
            completed_callback_event = self.completed_callback_events[stream_index]
            if stream is None:
                streamtype = sd.RawOutputStream if file else sd.OutputStream
                stream = streamtype(samplerate=samplerate, blocksize=blocksize,
                                    device=device, channels=channels,
                                    dtype='float32',
                                    callback=self._play_audio_callback(
                                        q=q, blocksize=blocksize,
                                        streamtype=streamtype,
                                        stream_index=stream_index),
                                    finished_callback=completed_callback_event.set)
                self._start_playback(stream_index=stream_index, stream=stream)
            with stream:
                timeout = blocksize * bufsize / samplerate
                while True:
                    while self._get_playback_state(stream_index) == \
                            PlaybackState.PAUSED:
                        self.playback_paused_changed[stream_index].wait()
                    if f:
                        data = f.buffer_read(blocksize, dtype='float32')
                        if not data:
                            break
                    else:
                        duration = mix.duration()
                        blocktime = float(blocksize / samplerate)
                        next_t = min(t + blocktime, duration) \
                            if duration is not None else t + blocktime
                        data = mix.get_wave(t_start=t, t_end=next_t,
                                            samplerate=samplerate)
                        t = next_t
                        if duration is not None and t >= duration:
                            break
                    if self._get_playback_state(stream_index) == \
                            PlaybackState.STOPPED:
                        break
                    try:
                        q.put(data, timeout=timeout)
                    except queue.Full as e:
                        if self._get_playback_state(stream_index) != \
                                PlaybackState.PAUSED:
                            raise e
                completed_callback_event.wait()
        except queue.Full:
            if stream_index is None or \
                    self._get_playback_state(stream_index) != PlaybackState.STOPPED:
                self.logger.warning('Playback timeout: audio callback failed?')
        finally:
            if f and not f.closed:
                f.close()
            self.stop_playback([stream_index])
def play ( self , file = None , sound = None , device = None , blocksize = None , bufsize = None , samplerate = None , channels = None , stream_name = None , stream_index = None ) : if not file and not sound : raise RuntimeError ( 'Please specify either a file to play or a ' + 'list of sound objects' ) import sounddevice as sd if blocksize is None : blocksize = self . output_blocksize if bufsize is None : if file : bufsize = Sound . _DEFAULT_FILE_BUFSIZE else : bufsize = Sound . _DEFAULT_SYNTH_BUFSIZE q = queue . Queue ( maxsize = bufsize ) f = None t = 0. if file : file = os . path . abspath ( os . path . expanduser ( file ) ) if device is None : device = self . output_device if device is None : device = self . _get_default_device ( 'output' ) if file : import soundfile as sf f = sf . SoundFile ( file ) if not samplerate : samplerate = f . samplerate if f else Sound . _DEFAULT_SAMPLERATE if not channels : channels = f . channels if f else 1 mix = None with self . playback_state_lock : stream_index , is_new_stream = self . _get_or_allocate_stream_index ( stream_index = stream_index , stream_name = stream_name ) if sound and stream_index in self . stream_mixes : mix = self . stream_mixes [ stream_index ] mix . add ( sound ) if not mix : return None , "Unable to allocate the stream" self . logger . info ( ( 'Starting playback of {} to sound device [{}] ' + 'on stream [{}]' ) . format ( file or sound , device , stream_index ) ) if not is_new_stream : return try : for _ in range ( bufsize ) : if f : data = f . buffer_read ( blocksize , dtype = 'float32' ) if not data : break else : duration = mix . duration ( ) blocktime = float ( blocksize / samplerate ) next_t = min ( t + blocktime , duration ) if duration is not None else t + blocktime data = mix . get_wave ( t_start = t , t_end = next_t , samplerate = samplerate ) t = next_t if duration is not None and t >= duration : break q . put_nowait ( data ) stream = self . active_streams [ stream_index ] completed_callback_event = self . completed_callback_events [ stream_index ] if stream is None : streamtype = sd . RawOutputStream if file else sd . OutputStream stream = streamtype ( samplerate = samplerate , blocksize = blocksize , device = device , channels = channels , dtype = 'float32' , callback = self . _play_audio_callback ( q = q , blocksize = blocksize , streamtype = streamtype , stream_index = stream_index ) , finished_callback = completed_callback_event . set ) self . _start_playback ( stream_index = stream_index , stream = stream ) with stream : timeout = blocksize * bufsize / samplerate while True : while self . _get_playback_state ( stream_index ) == PlaybackState . PAUSED : self . playback_paused_changed [ stream_index ] . wait ( ) if f : data = f . buffer_read ( blocksize , dtype = 'float32' ) if not data : break else : duration = mix . duration ( ) blocktime = float ( blocksize / samplerate ) next_t = min ( t + blocktime , duration ) if duration is not None else t + blocktime data = mix . get_wave ( t_start = t , t_end = next_t , samplerate = samplerate ) t = next_t if duration is not None and t >= duration : break if self . _get_playback_state ( stream_index ) == PlaybackState . STOPPED : break try : q . put ( data , timeout = timeout ) except queue . Full as e : if self . _get_playback_state ( stream_index ) != PlaybackState . PAUSED : raise e completed_callback_event . wait ( ) except queue . Full : if stream_index is None or self . _get_playback_state ( stream_index ) != PlaybackState . STOPPED : self . logger . warning ( 'Playback timeout: audio callback failed?' ) finally : if f and not f . closed : f . close ( ) self . stop_playback ( [ stream_index ] )
Plays a sound file (support formats: wav, raw) or a synthetic sound.
Plays a sound file ( support formats : wav raw ) or a synthetic sound .
"""
        Plays a sound file (support formats: wav, raw) or a synthetic sound.

        :param file: Sound file path. Specify this if you want to play a file
        :type file: str

        :param sound: Sound to play. Specify this if you want to play
            synthetic sounds. You can also create polyphonic sounds by just
            calling play multiple times.
        :type sound: Sound. You can initialize it either from a list
            of `Sound` objects or from its JSON representation, e.g.::

                {
                    "midi_note": 69,  # 440 Hz A
                    "gain":      1.0, # Maximum volume
                    "duration":  1.0  # 1 second or until release/pause/stop
                }

        :param device: Output device (default: default configured device or
            system default audio output if not configured)
        :type device: int or str

        :param blocksize: Audio block size (default: configured
            `output_blocksize` or 2048)
        :type blocksize: int

        :param bufsize: Size of the audio buffer (default: 20 frames for audio
            files, 2 frames for synth sounds)
        :type bufsize: int

        :param samplerate: Audio samplerate. Default: audio file samplerate if
            in file mode, 44100 Hz if in synth mode
        :type samplerate: int

        :param channels: Number of audio channels. Default: number of channels
            in the audio file in file mode, 1 if in synth mode
        :type channels: int

        :param stream_index: If specified, play to an already active stream
            index (you can get them through
            :meth:`platypush.plugins.sound.query_streams`). Default:
            creates a new audio stream through PortAudio.
        :type stream_index: int

        :param stream_name: Name of the stream to play to. If set, the sound
            will be played to the specified stream name, or a stream with that
            name will be created. If not set, and ``stream_index`` is not set
            either, then a new stream will be created on the next available
            index and named ``platypush-stream-<index>``.
        :type stream_name: str
        """ # Let the existing callback handle the new mix # TODO Potential support also for mixed streams with # multiple sound files and synth sounds? # Audio queue pre-fill loop # Pre-fill the audio queue # Timeout set until we expect all the buffered blocks to # be consumed
self
file
Sound file path. Specify this if you want to play a file
Sound file path . Specify this if you want to play a file
sound
Sound to play. Specify this if you want to play
synthetic sounds. You can also create polyphonic sounds by just
calling play multiple times.
Sound to play . Specify this if you want to play synthetic sounds . You can also create polyphonic sounds by just calling play multiple times .
device
Output device (default: default configured device or
system default audio output if not configured)
Output device ( default : default configured device or system default audio output if not configured )
blocksize
Audio block size (default: configured
`output_blocksize` or 2048)
Audio block size ( default : configured ` output_blocksize ` or 2048 )
bufsize
Size of the audio buffer (default: 20 frames for audio
files, 2 frames for synth sounds)
Size of the audio buffer ( default : 20 frames for audio files 2 frames for synth sounds )
samplerate
Audio samplerate. Default: audio file samplerate if
in file mode, 44100 Hz if in synth mode
Audio samplerate . Default : audio file samplerate if in file mode 44100 Hz if in synth mode
channels
Number of audio channels. Default: number of channels
in the audio file in file mode, 1 if in synth mode
Number of audio channels . Default : number of channels in the audio file in file mode 1 if in synth mode
stream_name
Name of the stream to play to. If set, the sound
will be played to the specified stream name, or a stream with that
name will be created. If not set, and ``stream_index`` is not set
either, then a new stream will be created on the next available
index and named ``platypush-stream-``.
Name of the stream to play to . If set the sound will be played to the specified stream name or a stream with that name will be created . If not set and ` ` stream_index ` ` is not set either then a new stream will be created on the next available index and named ` ` platypush - stream - ` ` .
stream_index
If specified, play to an already active stream
index (you can get them through
:meth:`platypush.plugins.sound.query_streams`). Default:
creates a new audio stream through PortAudio.
If specified play to an already active stream index ( you can get them through : meth : ` platypush . plugins . sound . query_streams ` ) . Default : creates a new audio stream through PortAudio .