Beispiel #1
0
    def delete(self):
        try:
            self.player_group.remove(self)
        except:
            log.exception('ManagedSoundPlayer have already been removed from player group')

        Player.delete(self)
Beispiel #2
0
 def stop(self, player: media.Player) -> None:
     """
     Stop a currently playing sound.
     """
     player.pause()
     player.delete()
     media.Source._players.remove(player)
Beispiel #3
0
    def delete(self):
        try:
            self.player_group.remove(self)
        except:
            log.exception(
                'ManagedSoundPlayer have already been removed from player group'
            )

        Player.delete(self)
Beispiel #4
0
def stop_sound(player: media.Player):
    """
    Stop a sound that is currently playing.

    :param pyglet.media.Player player: Player returned from :func:`play_sound`.
    """
    player.pause()
    player.delete()
    media.Source._players.remove(player)
Beispiel #5
0
class Video(object):
    """Read video file and draw it to the screen

    Parameters
    ----------
    ec : instance of expyfun.ExperimentController
    file_name : str
        the video file path
    pos : array-like
        2-element array-like with X, Y elements.
    units : str
        Units to use for the position. See ``check_units`` for options.
    scale : float | str
        The scale factor. 1 is native size (pixel-to-pixel), 2 is twice as
        large, etc. If `scale` is a string, it must be either ``'fill'``
        (which ensures the entire ``ExperimentController`` window is
        covered by the video, at the expense of some parts of the video
        potentially being offscreen), or ``'fit'`` (which scales maximally
        while ensuring none of the video is offscreen, and may result in
        letterboxing or pillarboxing).
    center : bool
        If ``False``, the elements of ``pos`` specify the position of the lower
        left corner of the video frame; otherwise they position the center of
        the frame.
    visible : bool
        Whether to show the video when initialized. Can be toggled later using
        ``set_visible`` method.

    Returns
    -------
    None

    Notes
    -----
    This is a somewhat pared-down implementation of video playback. Looping is
    not available, and the audio stream from the video file is discarded.
    Timing of individual frames is relegated to the pyglet media player's
    internal clock. Recommended for use only in paradigms where the relative
    timing of audio and video are unimportant (e.g., if the video is merely
    entertainment for the participant during a passive auditory task).
    """
    def __init__(self,
                 ec,
                 file_name,
                 pos=(0, 0),
                 units='norm',
                 scale=1.,
                 center=True,
                 visible=True):
        from pyglet.media import load, Player
        self._ec = ec
        self._source = load(file_name)
        self._player = Player()
        with warnings.catch_warnings(record=True):  # deprecated eos_action
            self._player.queue(self._source)
        self._player._audio_player = None
        frame_rate = self.frame_rate
        if frame_rate is None:
            logger.warning('Frame rate could not be determined')
            frame_rate = 60.
        self._dt = 1. / frame_rate
        self._texture = None
        self._playing = False
        self._finished = False
        self._pos = pos
        self._units = units
        self._center = center
        self.set_scale(scale)  # also calls set_pos
        self._visible = visible

    def play(self):
        """Play video from current position.

        Returns
        -------
        time : float
            The timestamp (on the parent ``ExperimentController`` timeline) at
            which ``play()`` was called.
        """
        if not self._playing:
            self._ec.call_on_every_flip(self.draw)
            self._player.play()
            self._playing = True
        else:
            warnings.warn('ExperimentController.video.play() called when '
                          'already playing.')
        return self._ec.get_time()

    def pause(self):
        """Halt video playback.

        Returns
        -------
        time : float
            The timestamp (on the parent ``ExperimentController`` timeline) at
            which ``pause()`` was called.
        """
        if self._playing:
            idx = self._ec.on_every_flip_functions.index(self.draw)
            self._ec.on_every_flip_functions.pop(idx)
            self._player.pause()
            self._playing = False
        else:
            warnings.warn('ExperimentController.video.pause() called when '
                          'already paused.')
        return self._ec.get_time()

    def _delete(self):
        """Halt video playback and remove player."""
        if self._playing:
            self.pause()
        self._player.delete()

    def _scale_texture(self):
        if self._texture:
            self._texture.width = self.source_width * self._scale
            self._texture.height = self.source_height * self._scale

    def set_scale(self, scale=1.):
        """Set video scale.

        Parameters
        ----------
        scale : float | str
            The scale factor. 1 is native size (pixel-to-pixel), 2 is twice as
            large, etc. If `scale` is a string, it must be either ``'fill'``
            (which ensures the entire ``ExperimentController`` window is
            covered by the video, at the expense of some parts of the video
            potentially being offscreen), or ``'fit'`` (which scales maximally
            while ensuring none of the video is offscreen, which may result in
            letterboxing).
        """
        if isinstance(scale, string_types):
            _scale = self._ec.window_size_pix / np.array(
                (self.source_width, self.source_height), dtype=float)
            if scale == 'fit':
                scale = _scale.min()
            elif scale == 'fill':
                scale = _scale.max()
        self._scale = float(scale)  # allows [1, 1., '1']; others: ValueError
        if self._scale <= 0:
            raise ValueError('Video scale factor must be strictly positive.')
        self._scale_texture()
        self.set_pos(self._pos, self._units, self._center)

    def set_pos(self, pos, units='norm', center=True):
        """Set video position.

        Parameters
        ----------
        pos : array-like
            2-element array-like with X, Y elements.
        units : str
            Units to use for the position. See ``check_units`` for options.
        center : bool
            If ``False``, the elements of ``pos`` specify the position of the
            lower left corner of the video frame; otherwise they position the
            center of the frame.
        """
        pos = np.array(pos, float)
        if pos.size != 2:
            raise ValueError('pos must be a 2-element array')
        pos = np.reshape(pos, (2, 1))
        pix = self._ec._convert_units(pos, units, 'pix').ravel()
        offset = np.array((self.width, self.height)) // 2 if center else 0
        self._pos = pos
        self._actual_pos = pix - offset
        self._pos_unit = units
        self._pos_centered = center

    def _draw(self):
        self._texture = self._player.get_texture()
        self._scale_texture()
        self._texture.blit(*self._actual_pos)

    def draw(self):
        """Draw the video texture to the screen buffer."""
        self._player.update_texture()
        # detect end-of-stream to prevent pyglet from hanging:
        if not self._eos:
            if self._visible:
                self._draw()
        else:
            self._finished = True
            self.pause()
        self._ec.check_force_quit()

    def set_visible(self, show, flip=False):
        """Show/hide the video frame."""
        if show:
            self._visible = True
            self._draw()
        else:
            self._visible = False
            self._ec.flip()
        if flip:
            self._ec.flip()

    # PROPERTIES
    @property
    def _eos(self):
        return (self._player._last_video_timestamp is not None
                and self._player._last_video_timestamp
                == self._source.get_next_video_timestamp())

    @property
    def playing(self):
        return self._playing

    @property
    def finished(self):
        return self._finished

    @property
    def position(self):
        return np.squeeze(self._pos)

    @property
    def scale(self):
        return self._scale

    @property
    def duration(self):
        return self._source.duration

    @property
    def frame_rate(self):
        return self._source.video_format.frame_rate

    @property
    def dt(self):
        return self._dt

    @property
    def time(self):
        return self._player.time

    @property
    def width(self):
        return self.source_width * self._scale

    @property
    def height(self):
        return self.source_height * self._scale

    @property
    def source_width(self):
        return self._source.video_format.width

    @property
    def source_height(self):
        return self._source.video_format.height

    @property
    def time_offset(self):
        return self._ec.get_time() - self._player.time
Beispiel #6
0
class Video(object):
    """Read video file and draw it to the screen.

    Parameters
    ----------
    ec : instance of expyfun.ExperimentController
    file_name : str
        the video file path
    pos : array-like
        2-element array-like with X, Y elements.
    units : str
        Units to use for the position. See ``check_units`` for options.
    scale : float | str
        The scale factor. 1 is native size (pixel-to-pixel), 2 is twice as
        large, etc. If scale is a string, it must be either ``'fill'``
        (which ensures the entire ``ExperimentController`` window is
        covered by the video, at the expense of some parts of the video
        potentially being offscreen), or ``'fit'`` (which scales maximally
        while ensuring none of the video is offscreen, and may result in
        letterboxing or pillarboxing).
    center : bool
        If ``False``, the elements of ``pos`` specify the position of the lower
        left corner of the video frame; otherwise they position the center of
        the frame.
    visible : bool
        Whether to show the video when initialized. Can be toggled later using
        `Video.set_visible` method.

    Notes
    -----
    This is a somewhat pared-down implementation of video playback. Looping is
    not available, and the audio stream from the video file is discarded.
    Timing of individual frames is relegated to the pyglet media player's
    internal clock. Recommended for use only in paradigms where the relative
    timing of audio and video are unimportant (e.g., if the video is merely
    entertainment for the participant during a passive auditory task).
    """
    def __init__(self,
                 ec,
                 file_name,
                 pos=(0, 0),
                 units='norm',
                 scale=1.,
                 center=True,
                 visible=True):
        from pyglet.media import load, Player
        self._ec = ec
        # On Windows, the default is unaccelerated WMF, which is terribly slow.
        decoder = None
        if _new_pyglet():
            try:
                from pyglet.media.codecs.ffmpeg import FFmpegDecoder
                decoder = FFmpegDecoder()
            except Exception as exc:
                warnings.warn(
                    'FFmpeg decoder could not be instantiated, decoding '
                    f'performance could be compromised:\n{exc}')
        self._source = load(file_name, decoder=decoder)
        self._player = Player()
        with warnings.catch_warnings(record=True):  # deprecated eos_action
            self._player.queue(self._source)
        self._player._audio_player = None
        frame_rate = self.frame_rate
        if frame_rate is None:
            logger.warning('Frame rate could not be determined')
            frame_rate = 60.
        self._dt = 1. / frame_rate
        self._playing = False
        self._finished = False
        self._pos = pos
        self._units = units
        self._center = center
        self.set_scale(scale)  # also calls set_pos
        self._visible = visible
        self._eos_fun = self._eos_new if _new_pyglet() else self._eos_old

        self._program = _create_program(ec, tex_vert, tex_frag)
        gl.glUseProgram(self._program)
        self._buffers = dict()
        for key in ('position', 'texcoord'):
            self._buffers[key] = gl.GLuint(0)
            gl.glGenBuffers(1, pointer(self._buffers[key]))
        w, h = self.source_width, self.source_height
        tex = np.array([(0, h), (w, h), (w, 0), (0, 0)], np.float32)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._buffers['texcoord'])
        gl.glBufferData(gl.GL_ARRAY_BUFFER, tex.nbytes, tex.tobytes(),
                        gl.GL_DYNAMIC_DRAW)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        gl.glUseProgram(0)

    def play(self, auto_draw=True):
        """Play video from current position.

        Parameters
        ----------
        auto_draw : bool
            If True, add ``self.draw`` to ``ec.on_every_flip``.

        Returns
        -------
        time : float
            The timestamp (on the parent ``ExperimentController`` timeline) at
            which ``play()`` was called.
        """
        if not self._playing:
            if auto_draw:
                self._ec.call_on_every_flip(self.draw)
            self._player.play()
            self._playing = True
        else:
            warnings.warn('ExperimentController.video.play() called when '
                          'already playing.')
        return self._ec.get_time()

    def pause(self):
        """Halt video playback.

        Returns
        -------
        time : float
            The timestamp (on the parent ``ExperimentController`` timeline) at
            which ``pause()`` was called.
        """
        if self._playing:
            try:
                idx = self._ec.on_every_flip_functions.index(self.draw)
            except ValueError:  # not auto_draw
                pass
            else:
                self._ec.on_every_flip_functions.pop(idx)
            self._player.pause()
            self._playing = False
        else:
            warnings.warn('ExperimentController.video.pause() called when '
                          'already paused.')
        return self._ec.get_time()

    def _delete(self):
        """Halt video playback and remove player."""
        if self._playing:
            self.pause()
        self._player.delete()

    def set_scale(self, scale=1.):
        """Set video scale.

        Parameters
        ----------
        scale : float | str
            The scale factor. 1 is native size (pixel-to-pixel), 2 is twice as
            large, etc. If scale is a string, it must be either ``'fill'``
            (which ensures the entire ``ExperimentController`` window is
            covered by the video, at the expense of some parts of the video
            potentially being offscreen), or ``'fit'`` (which scales maximally
            while ensuring none of the video is offscreen, which may result in
            letterboxing).
        """
        if isinstance(scale, string_types):
            _scale = self._ec.window_size_pix / np.array(
                (self.source_width, self.source_height), dtype=float)
            if scale == 'fit':
                scale = _scale.min()
            elif scale == 'fill':
                scale = _scale.max()
        self._scale = float(scale)  # allows [1, 1., '1']; others: ValueError
        if self._scale <= 0:
            raise ValueError('Video scale factor must be strictly positive.')
        self.set_pos(self._pos, self._units, self._center)

    def set_pos(self, pos, units='norm', center=True):
        """Set video position.

        Parameters
        ----------
        pos : array-like
            2-element array-like with X, Y elements.
        units : str
            Units to use for the position. See ``check_units`` for options.
        center : bool
            If ``False``, the elements of ``pos`` specify the position of the
            lower left corner of the video frame; otherwise they position the
            center of the frame.
        """
        pos = np.array(pos, float)
        if pos.size != 2:
            raise ValueError('pos must be a 2-element array')
        pos = np.reshape(pos, (2, 1))
        pix = self._ec._convert_units(pos, units, 'pix').ravel()
        offset = np.array((self.width, self.height)) // 2 if center else 0
        self._pos = pos
        self._actual_pos = pix - offset
        self._pos_unit = units
        self._pos_centered = center

    def _draw(self):
        tex = self._player.get_texture()
        gl.glUseProgram(self._program)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(tex.target, tex.id)
        gl.glBindVertexArray(0)
        x, y = self._actual_pos
        w = self.source_width * self._scale
        h = self.source_height * self._scale
        pos = np.array([(x, y), (x + w, y), (x + w, y + h), (x, y + h)],
                       np.float32)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._buffers['position'])
        gl.glBufferData(gl.GL_ARRAY_BUFFER, pos.nbytes, pos.tobytes(),
                        gl.GL_DYNAMIC_DRAW)
        loc_pos = gl.glGetAttribLocation(self._program, b'a_position')
        gl.glEnableVertexAttribArray(loc_pos)
        gl.glVertexAttribPointer(loc_pos, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, 0)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._buffers['texcoord'])
        loc_tex = gl.glGetAttribLocation(self._program, b'a_texcoord')
        gl.glEnableVertexAttribArray(loc_tex)
        gl.glVertexAttribPointer(loc_tex, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, 0)
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        gl.glDrawArrays(gl.GL_QUADS, 0, 4)
        gl.glDisableVertexAttribArray(loc_pos)
        gl.glDisableVertexAttribArray(loc_tex)
        gl.glUseProgram(0)
        gl.glBindTexture(tex.target, 0)

    def draw(self):
        """Draw the video texture to the screen buffer."""
        self._player.update_texture()
        # detect end-of-stream to prevent pyglet from hanging:
        if not self._eos:
            if self._visible:
                self._draw()
        else:
            self._finished = True
            self.pause()
        self._ec.check_force_quit()

    def set_visible(self, show, flip=False):
        """Show/hide the video frame.

        Parameters
        ----------
        show : bool
            Show or hide.
        flip : bool
            If True, flip after showing or hiding.
        """
        if show:
            self._visible = True
            self._draw()
        else:
            self._visible = False
            self._ec.flip()
        if flip:
            self._ec.flip()

    # PROPERTIES
    @property
    def _eos(self):
        return self._eos_fun()

    def _eos_old(self):
        return (self._player._last_video_timestamp is not None
                and self._player._last_video_timestamp
                == self._source.get_next_video_timestamp())

    def _eos_new(self):
        ts = self._source.get_next_video_timestamp()
        dur = self._source._duration
        return ts is None or ts >= dur

    @property
    def playing(self):
        return self._playing

    @property
    def finished(self):
        return self._finished

    @property
    def position(self):
        return np.squeeze(self._pos)

    @property
    def scale(self):
        return self._scale

    @property
    def duration(self):
        return self._source.duration

    @property
    def frame_rate(self):
        return self._source.video_format.frame_rate

    @property
    def dt(self):
        return self._dt

    @property
    def time(self):
        return self._player.time

    @property
    def width(self):
        return self.source_width * self._scale

    @property
    def height(self):
        return self.source_height * self._scale

    @property
    def source_width(self):
        return self._source.video_format.width

    @property
    def source_height(self):
        return self._source.video_format.height

    @property
    def time_offset(self):
        return self._ec.get_time() - self._player.time
Beispiel #7
0
class Video(object):
    """Read video file and draw it to the screen

    Parameters
    ----------
    ec : instance of expyfun.ExperimentController
    file_name : str
        the video file path
    pos : array-like
        2-element array-like with X, Y elements.
    units : str
        Units to use for the position. See ``check_units`` for options.
    scale : float | str
        The scale factor. 1 is native size (pixel-to-pixel), 2 is twice as
        large, etc. If `scale` is a string, it must be either ``'fill'``
        (which ensures the entire ``ExperimentController`` window is
        covered by the video, at the expense of some parts of the video
        potentially being offscreen), or ``'fit'`` (which scales maximally
        while ensuring none of the video is offscreen, and may result in
        letterboxing or pillarboxing).
    center : bool
        If ``False``, the elements of ``pos`` specify the position of the lower
        left corner of the video frame; otherwise they position the center of
        the frame.
    visible : bool
        Whether to show the video when initialized. Can be toggled later using
        ``set_visible`` method.

    Returns
    -------
    None

    Notes
    -----
    This is a somewhat pared-down implementation of video playback. Looping is
    not available, and the audio stream from the video file is discarded.
    Timing of individual frames is relegated to the pyglet media player's
    internal clock. Recommended for use only in paradigms where the relative
    timing of audio and video are unimportant (e.g., if the video is merely
    entertainment for the participant during a passive auditory task).
    """
    def __init__(self, ec, file_name, pos=(0, 0), units='norm', scale=1.,
                 center=True, visible=True):
        from pyglet.media import load, Player
        self._ec = ec
        self._source = load(file_name)
        self._player = Player()
        self._player.queue(self._source)
        self._player._audio_player = None
        frame_rate = self.frame_rate
        if frame_rate is None:
            logger.warning('Frame rate could not be determined')
            frame_rate = 60.
        self._dt = 1. / frame_rate
        self._texture = None
        self._playing = False
        self._finished = False
        self._pos = pos
        self._units = units
        self._center = center
        self.set_scale(scale)  # also calls set_pos
        self._visible = visible

    def play(self):
        """Play video from current position.

        Returns
        -------
        time : float
            The timestamp (on the parent ``ExperimentController`` timeline) at
            which ``play()`` was called.
        """
        if not self._playing:
            self._ec.call_on_every_flip(self.draw)
            self._player.play()
            self._playing = True
        else:
            warnings.warn('ExperimentController.video.play() called when '
                          'already playing.')
        return self._ec.get_time()

    def pause(self):
        """Halt video playback.

        Returns
        -------
        time : float
            The timestamp (on the parent ``ExperimentController`` timeline) at
            which ``pause()`` was called.
        """
        if self._playing:
            idx = self._ec.on_every_flip_functions.index(self.draw)
            self._ec.on_every_flip_functions.pop(idx)
            self._player.pause()
            self._playing = False
        else:
            warnings.warn('ExperimentController.video.pause() called when '
                          'already paused.')
        return self._ec.get_time()

    def _delete(self):
        """Halt video playback and remove player."""
        if self._playing:
            self.pause()
        self._player.delete()

    def _scale_texture(self):
        if self._texture:
            self._texture.width = self.source_width * self._scale
            self._texture.height = self.source_height * self._scale

    def set_scale(self, scale=1.):
        """Set video scale.

        Parameters
        ----------
        scale : float | str
            The scale factor. 1 is native size (pixel-to-pixel), 2 is twice as
            large, etc. If `scale` is a string, it must be either ``'fill'``
            (which ensures the entire ``ExperimentController`` window is
            covered by the video, at the expense of some parts of the video
            potentially being offscreen), or ``'fit'`` (which scales maximally
            while ensuring none of the video is offscreen, which may result in
            letterboxing).
        """
        if isinstance(scale, string_types):
            _scale = self._ec.window_size_pix / np.array((self.source_width,
                                                          self.source_height),
                                                         dtype=float)
            if scale == 'fit':
                scale = _scale.min()
            elif scale == 'fill':
                scale = _scale.max()
        self._scale = float(scale)  # allows [1, 1., '1']; others: ValueError
        if self._scale <= 0:
            raise ValueError('Video scale factor must be strictly positive.')
        self._scale_texture()
        self.set_pos(self._pos, self._units, self._center)

    def set_pos(self, pos, units='norm', center=True):
        """Set video position.

        Parameters
        ----------
        pos : array-like
            2-element array-like with X, Y elements.
        units : str
            Units to use for the position. See ``check_units`` for options.
        center : bool
            If ``False``, the elements of ``pos`` specify the position of the
            lower left corner of the video frame; otherwise they position the
            center of the frame.
        """
        pos = np.array(pos, float)
        if pos.size != 2:
            raise ValueError('pos must be a 2-element array')
        pos = np.reshape(pos, (2, 1))
        pix = self._ec._convert_units(pos, units, 'pix').ravel()
        offset = np.array((self.width, self.height)) // 2 if center else 0
        self._pos = pos
        self._actual_pos = pix - offset
        self._pos_unit = units
        self._pos_centered = center

    def _draw(self):
        self._texture = self._player.get_texture()
        self._scale_texture()
        self._texture.blit(*self._actual_pos)

    def draw(self):
        """Draw the video texture to the screen buffer."""
        self._player.update_texture()
        # detect end-of-stream to prevent pyglet from hanging:
        if not self._eos:
            if self._visible:
                self._draw()
        else:
            self._finished = True
            self.pause()
        self._ec.check_force_quit()

    def set_visible(self, show, flip=False):
        """Show/hide the video frame."""
        if show:
            self._visible = True
            self._draw()
        else:
            self._visible = False
            self._ec.flip()
        if flip:
            self._ec.flip()

    # PROPERTIES
    @property
    def _eos(self):
        return (self._player._last_video_timestamp is not None and
                self._player._last_video_timestamp ==
                self._source.get_next_video_timestamp())

    @property
    def playing(self):
        return self._playing

    @property
    def finished(self):
        return self._finished

    @property
    def position(self):
        return np.squeeze(self._pos)

    @property
    def scale(self):
        return self._scale

    @property
    def duration(self):
        return self._source.duration

    @property
    def frame_rate(self):
        return self._source.video_format.frame_rate

    @property
    def dt(self):
        return self._dt

    @property
    def time(self):
        return self._player.time

    @property
    def width(self):
        return self.source_width * self._scale

    @property
    def height(self):
        return self.source_height * self._scale

    @property
    def source_width(self):
        return self._source.video_format.width

    @property
    def source_height(self):
        return self._source.video_format.height

    @property
    def time_offset(self):
        return self._ec.get_time() - self._player.time
Beispiel #8
0
class SoundPlayer(object):
    def __init__(self, soundDirPath):
        self.soundDirPath = soundDirPath
        self.loadSounds()
        self.musicPlayer = Player()
        self.queue = False
        self.queuePlayer = None
        self.enabled = True
        self.soundEffectVolume = 1.0  # between 0.0 and 1.0
        self._musicVolume = 1.0  # between 0.0 and 1.0

    '''
        loads sounds from gui config file into dict.
        maps name to pyglet sound object.
        if ',stream' exists after filename in config file,
         will stream file instead of loading the whole thing in once.
    '''

    def loadSounds(self):
        self.sounds = dict()
        soundTypes = dict(gui.config.items('sound_events'))
        for key in soundTypes:
            self._loadSoundResource(key)

    @staticmethod
    def _loadSoundEntry(key):
        entry = gui.config.get('sound_events', key)
        if ',' in entry:
            sp = entry.split(",")
            fileName = sp[0]
            if sp[1] == "stream":
                stream = True
        else:
            fileName = entry
            stream = False
        return fileName, stream

    def _loadSoundResource(self, key):
        fileName, stream = self._loadSoundEntry(key)
        if key in self.sounds:
            self.sounds[key].delete()
        self.sounds[key] = pyglet.resource.media(self.soundDirPath + fileName,
                                                 streaming=stream)

    def shutdown(self):
        from pyglet.media import avbin
        if self.musicPlayer.source is not None:
            avbin.av.avbin_close_file(
                self.musicPlayer.source._file
            )  # hack to ensure avbin closes properly.
        self.musicPlayer.delete()
        toDel = self.sounds.keys()
        for snd in toDel:
            del self.sounds[snd]

    @property
    def musicVolume(self):
        return self._soundEffectVolume

    @musicVolume.setter
    def musicVolume(self, value):
        self.musicPlayer.volume = value
        self._musicVolume = self.musicPlayer.volume

    def setMute(self, value):
        self.enabled = value

    def getSound(self, soundName):
        try:
            snd = self.sounds[soundName.lower()]
        except KeyError:
            print "Sound requsted to be played does not exist in config file."
            return None
        return snd

    def playMusic(self, soundName):
        if not self.enabled:
            return
        soundName = soundName.lower()
        snd = self.getSound(soundName)
        assert snd
        if self.musicPlayer.playing and self.musicPlayer.source == snd:
            self.musicPlayer.seek(0)
            return
        else:
            # reload sound and reset Player obj
            # (streaming sounds needs to be reloaded every time)
            if isinstance(snd, pyglet.media.StreamingSource):
                self._loadSoundResource(soundName)
            self.musicPlayer.delete()
            self.musicPlayer = Player()
            self.musicPlayer.volume = self._musicVolume
        looper = pyglet.media.SourceGroup(snd.audio_format, None)
        looper.loop = True
        looper.queue(snd)
        self.musicPlayer.queue(looper)
        self.musicPlayer.play()

    def playEffect(self, soundName):
        if not self.enabled:
            return
        soundName = soundName.lower()
        snd = self.getSound(soundName)
        assert snd
        p = Player()
        p.volume = self.soundEffectVolume
        p.queue(snd)
        p.play()

    def startEffectsQueue(self):
        self.queue = True
        self.queuePlayer = Player()

    def queueEffect(self, soundName):
        if not self.enabled:
            return
        soundName = soundName.lower()
        snd = self.getSound(soundName)
        assert snd
        self.queuePlayer.queue(snd)

    '''
        Plays the queue and resets queue state.
    '''

    def playEffectsQueue(self):
        self.queuePlayer.volume = self.soundEffectVolume
        self.queuePlayer.play()
        self.queue = False
        self.queuePlayer = None
Beispiel #9
0
class SoundPlayer(object):
    def __init__(self, soundDirPath):
        self.soundDirPath = soundDirPath
        self.loadSounds()
        self.musicPlayer = Player()
        self.queue = False
        self.queuePlayer = None
        self.enabled = True
        self.soundEffectVolume = 1.0  # between 0.0 and 1.0
        self._musicVolume = 1.0  # between 0.0 and 1.0

    """
        loads sounds from gui config file into dict.
        maps name to pyglet sound object.
        if ',stream' exists after filename in config file,
         will stream file instead of loading the whole thing in once.
    """

    def loadSounds(self):
        self.sounds = dict()
        soundTypes = dict(gui.config.items("sound_events"))
        for key in soundTypes:
            self._loadSoundResource(key)

    @staticmethod
    def _loadSoundEntry(key):
        entry = gui.config.get("sound_events", key)
        if "," in entry:
            sp = entry.split(",")
            fileName = sp[0]
            if sp[1] == "stream":
                stream = True
        else:
            fileName = entry
            stream = False
        return fileName, stream

    def _loadSoundResource(self, key):
        fileName, stream = self._loadSoundEntry(key)
        if key in self.sounds:
            self.sounds[key].delete()
        self.sounds[key] = pyglet.resource.media(self.soundDirPath + fileName, streaming=stream)

    def shutdown(self):
        from pyglet.media import avbin

        if self.musicPlayer.source is not None:
            avbin.av.avbin_close_file(self.musicPlayer.source._file)  # hack to ensure avbin closes properly.
        self.musicPlayer.delete()
        toDel = self.sounds.keys()
        for snd in toDel:
            del self.sounds[snd]

    @property
    def musicVolume(self):
        return self._soundEffectVolume

    @musicVolume.setter
    def musicVolume(self, value):
        self.musicPlayer.volume = value
        self._musicVolume = self.musicPlayer.volume

    def setMute(self, value):
        self.enabled = value

    def getSound(self, soundName):
        try:
            snd = self.sounds[soundName.lower()]
        except KeyError:
            print "Sound requsted to be played does not exist in config file."
            return None
        return snd

    def playMusic(self, soundName):
        if not self.enabled:
            return
        soundName = soundName.lower()
        snd = self.getSound(soundName)
        assert snd
        if self.musicPlayer.playing and self.musicPlayer.source == snd:
            self.musicPlayer.seek(0)
            return
        else:
            # reload sound and reset Player obj
            # (streaming sounds needs to be reloaded every time)
            if isinstance(snd, pyglet.media.StreamingSource):
                self._loadSoundResource(soundName)
            self.musicPlayer.delete()
            self.musicPlayer = Player()
            self.musicPlayer.volume = self._musicVolume
        looper = pyglet.media.SourceGroup(snd.audio_format, None)
        looper.loop = True
        looper.queue(snd)
        self.musicPlayer.queue(looper)
        self.musicPlayer.play()

    def playEffect(self, soundName):
        if not self.enabled:
            return
        soundName = soundName.lower()
        snd = self.getSound(soundName)
        assert snd
        p = Player()
        p.volume = self.soundEffectVolume
        p.queue(snd)
        p.play()

    def startEffectsQueue(self):
        self.queue = True
        self.queuePlayer = Player()

    def queueEffect(self, soundName):
        if not self.enabled:
            return
        soundName = soundName.lower()
        snd = self.getSound(soundName)
        assert snd
        self.queuePlayer.queue(snd)

    """
        Plays the queue and resets queue state.
    """

    def playEffectsQueue(self):
        self.queuePlayer.volume = self.soundEffectVolume
        self.queuePlayer.play()
        self.queue = False
        self.queuePlayer = None