Mercurial > fife-parpg
view engine/python/fife/extensions/soundmanager.py @ 500:5e6ff32a46fb
Added listener position to the soundmanager.
author | prock@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Fri, 14 May 2010 20:28:05 +0000 |
parents | 5ff83f209333 |
children | 6614a5446352 |
line wrap: on
line source
# -*- 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 # #################################################################### """ 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. Usage:: soundmanager = SoundManager(my_fife_engine) emitter = soundmanager.createSoundEmitter("path/filename.ogg") emitter.gain = 128 emitter.play() """ from fife import fife import fife.extensions.fife_timer as fife_timer from fife.extensions.pychan.tools import callbackWithArguments as cbwa class SoundEmitter(object): """ Wraps the L{fife.SoundEmitter} class. 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 @type soundmanager: L{SoundManager} @param clipid: The FIFE sound clip ID from the sound clip pool @type clipid: C{int} @param soundname: The filename of the sound @type soundname: C{string} @param emitter: A reference to the L{fife.SoundEmitter} associated with this clip @type emitter: L{fife.SoundEmitter} """ 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 self._position = None self._rolloff = 0 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): """ Sets the volume of the L{SoundEmitter}. @param gain: Value should be from 0-255. 0 being mute and 255 being the normal volume of the clip. @type gain: C{int} """ 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 def _setPosition(self, position): self._position = position def _getPosition(self): return self._position def _setRolloff(self, rolloff): self._rolloff = rolloff def _getRolloff(self): return self._rolloff rolloff = property(_getRolloff, _setRolloff) position = property(_getPosition, _setPosition) 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): """ A simple sound manager class. 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 @type engine: L{fife.Engine} """ self._engine = engine self._fifesoundmanager = self._engine.getSoundManager() self._fifesoundmanager.init() # basic rolloff used for positional sounds self._rolloff = 1 #A dict of fife emitters self._loadedclips = {} #A tuple representing the listener position (x,y) self._listenerposition = None def createSoundEmitter(self, filename, forceUnique=False, position=None): """ Returns a valid SoundEmitter instance. @param filename: The relative path and filename of the sound file @type clip: C{string} @param 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. @type forceUnique: C{boolean} @param position: The position on the map that the sound emitter is to be created at. @type position: L{tuple} @return: Returns a new L{SoundEmitter} instance. @rtype: L{SoundEmitter} """ 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() if position is not None: clip.position = position clip.rolloff = self.rolloff 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 L{SoundEmitter} to be played @type clip: L{SoundEmitter} """ 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(float(g)/255.0) e.play() clip.callback = cbwa(real_callback, clip.callback, clip.fifeemitter, clip.gain) else: repeat = 1 clip.timer = fife_timer.Timer(clip.duration, clip.callback, repeat) else: if clip.looping: def real_callback(e, g): e.stop() e.setGain(float(g)/255.0) e.play() clip.callback = cbwa(real_callback, clip.fifeemitter, clip.gain) clip.timer = fife_timer.Timer(clip.duration, clip.callback, 0) clip.fifeemitter.setGain(float(clip.gain)/255.0) if self.listenerposition and clip.position: # Use 1 as z coordinate, no need to specify it clip.fifeemitter.setPosition(clip.position[0], clip.position[1], 1) clip.fifeemitter.setRolloff(clip.rolloff) elif self.listenerposition and not clip.position: clip.fifeemitter.setPosition(self.listenerposition[0], self.listenerposition[1], 1) clip.fifeemitter.setRolloff(self.rolloff) clip.fifeemitter.play() if clip.timer: clip.timer.start() 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. @param clip: The SoundEmitter to stop. @type clip: L{SoundEmitter} """ 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}. @note: 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() def _getRolloff(self): return self._rolloff def _setRolloff(self, rolloff): self._rolloff = rolloff def _getListenerPosition(self): return self._listenerposition def _setListenerPosition(self, position): self._listenerposition = position self._fifesoundmanager.setListenerPosition(self._listenerposition[0], self._listenerposition[1], 1) rolloff = property(_getRolloff, _setRolloff) listenerposition = property(_getListenerPosition, _setListenerPosition) __all__ = ['SoundEmitter','SoundManager']