Mercurial > fife-parpg
diff engine/python/fife/extensions/soundmanager.py @ 492:16ceb3228324
Moved the SoundManager and the 2D math function (helpers) from the shooter demo to the fife extensions.
Fixed fife_timer as it didn't work in the first place. Modified the SoundManager to use the now working fife_timer and removed the Timer class from the shooter demo entirely
author | prock@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Fri, 07 May 2010 21:07:27 +0000 |
parents | |
children | e29853880e87 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/python/fife/extensions/soundmanager.py Fri May 07 21:07:27 2010 +0000 @@ -0,0 +1,277 @@ +# -*- coding: utf-8 -*- + +# #################################################################### +# Copyright (C) 2005-2010 by the FIFE team +# http://www.fifengine.net +# This file is part of FIFE. +# +# FIFE is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# #################################################################### + +from fife import fife + +import fife.extensions.fife_timer as fife_timer +from fife.extensions.pychan.tools import callbackWithArguments as cbwa + +""" +Sound Manager +================================== + +This is a simple implementation of a sound manager that was originaly +intended for the shooter demo. It was functional enough that we decided +to include it in the FIFE extensions. This is by no means a fully featured +implementation for several reasons. It doesnt limit how many sounds can +play at once or allow the positioning of sounds. It does however provide +a good starting point for a more advanced version of a sound manager. + +""" + +class SoundEmitter(object): + """ + SoundEmitter + + This class wraps an instance of a L{fife.SoundEmitter} class along + with some information about a sound clip (like gain and if its + looping). All instances of SoundEmitter should be created by SoundManager. + + @todo At some point this class will store positional information + and also be responsible for updating the L{fife.SoundEmitter} position. + """ + def __init__(self, soundmanager, clipid, soundname, emitter): + """ + @param soundmanager A reference to the SoundManager + @param clipid The FIFE sound clip ID from the sound clip pool + @param soundname The filename of the sound + @param emitter A reference to the L{fife.SoundEmitter} associated with this clip + + """ + self._soundmanager = soundmanager + self._name = soundname + + #The FIFE SoundEmitter associated with this SoundEmitter. + #Note that we do NOT own the emitter. + self._fifeemitter = emitter + self._fifeemitter.thisown = 0 + self._fifeclipid = clipid + + #0 = mute, 255 = normal volume + self._gain = 255.0 + self._looping = False + + #if you set the callback it will be executed after the sound + #has finished playing. + self._callback = None + + #length of the sound + self._duration = 0 + + self._timer = None + + def play(self): + self._soundmanager.playClip(self) + + def stop(self): + self._soundmanager.stopClip(self) + + def _getClipID(self): + return self._fifeclipid + + def _getGain(self): + return self._gain + + def _setGain(self, gain): + self._gain = float(gain) + + def _getLooping(self): + return self._looping + + def _setLooping(self, looping): + self._looping = looping + + def _getFifeEmitter(self): + return self._fifeemitter + + def _setFifeEmitter(self, emitter): + self._fifeemitter = emitter + if self._fifeemitter: + self._fifeemitter.thisown = 0 + + def _getName(self): + return self._name + + def _getCallback(self): + return self._callback + + def _setCallback(self, cb): + self._callback = cb + + def _getDuration(self): + return self._duration + + def _setDuration(self, millliseconds): + self._duration = millliseconds + + def _getTimer(self): + return self._timer + + def _setTimer(self, timer): + self._timer = timer + + timer = property(_getTimer, _setTimer) + clipid = property(_getClipID) + gain = property(_getGain, _setGain) + looping = property(_getLooping, _setLooping) + fifeemitter = property(_getFifeEmitter, _setFifeEmitter) + name = property(_getName) + callback = property(_getCallback, _setCallback) + duration = property(_getDuration, _setDuration) + +class SoundManager(object): + """ + SoundManger + + This class manages and plays all the sounds of the game. + It creates SoundEmitters and ensures that there is only one + L{fife.SoundEmitter} per unique sound. + """ + def __init__(self, engine): + """ + @param engine A reference to the FIFE engine + """ + + self._engine = engine + + self._fifesoundmanager = self._engine.getSoundManager() + self._fifesoundmanager.init() + + #A dict of fife emitters + self._loadedclips = {} + + def createSoundEmitter(self, filename, forceUnique=False): + """ + Returns a valid SoundEmitter instance. + + @param filename The relative path and filename of the sound file + @parm forceUnique This forces a new L{fife.SoundEmitter} to be created. + This is useful if you want more than one instance of the same sound + to be played at the same time. + + @return Returns a new SoundEmitter instance. + """ + if not self._loadedclips.has_key(filename): + clipid = self._engine.getSoundClipPool().addResourceFromFile(filename) + fifeemitter = self._fifesoundmanager.createEmitter() + fifeemitter.thisown = 0 + fifeemitter.setSoundClip(clipid) + + self._loadedclips[filename] = [fifeemitter] + clip = SoundEmitter(self, clipid, filename, fifeemitter) + clip.duration = fifeemitter.getDuration() + else: + if forceUnique: + clipid = self._engine.getSoundClipPool().addResourceFromFile(filename) + fifeemitter = self._fifesoundmanager.createEmitter() + fifeemitter.thisown = 0 + fifeemitter.setSoundClip(clipid) + self._loadedclips[filename].append(fifeemitter) + else: + fifeemitter = self._loadedclips[filename][0] + + clip = SoundEmitter(self, fifeemitter.getID(), filename, fifeemitter) + clip.duration = fifeemitter.getDuration() + + return clip + + def playClip(self, clip): + """ + Plays a sound clip. + + This function does not use the L{fife.SoundEmitter} + "looping" property to loop a sound. Instead it registers + a new timer and uses the duration of the clip as the timer length. + + If the SoundEmitter is invalid (no fifeemitter) then it attempts + to load it before playing it. + + @note This will stop any clips that use the same L{fife.SoundEmitter}. + You cannot play the same sound more than once at a time unless you create + the SoundEmitter with the forceUnique paramater set to True. + + @param clip The SoundEmitter to be played + """ + + if clip.fifeemitter: + if clip.callback: + if clip.timer: + clip.timer.stop() + timer = None + + if clip.looping: + repeat = 0 + def real_callback(c, e, g): + c() + e.stop() + e.setGain(g) + e.play() + + clip.callback = cbwa(real_callback, clip.callback, clip.fifeemitter, clip.gain) + + else: + repeat = 1 + + clip.timer = fife_timer.delayCall(clip.duration, clip.callback) + #clip.timer.start() + + clip.fifeemitter.setGain(clip.gain) + clip.fifeemitter.play() + else: + clip = self.createSoundEmitter(clip.name) + self.playClip(clip) + + def stopClip(self, clip): + """ + Stops playing the sound clip. Note that this will stop all clips that + use the same FIFE emitter. + + @parm clip The SoundEmitter to stop. + """ + if clip.fifeemitter: + clip.fifeemitter.stop() + + if clip.timer: + clip.timer.stop() + clip.timer = None + + def stopAllSounds(self): + for emitterlist in self._loadedclips.values(): + for emitter in emitterlist: + emitter.stop() + + def destroy(self): + """ + Releases all instances of L{fife.SoundEmitter}. This does not free + the resources from the FIFE sound clip pool. + """ + self.stopAllSounds() + + for emitterlist in self._loadedclips.values(): + for emitter in emitterlist: + self._fifesoundmanager.releaseEmitter(emitter.getID()) + emitter = None + + self._loadedclips.clear() + +__all__ = ['SoundEmitter','SoundManager']