comparison 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
comparison
equal deleted inserted replaced
491:c4168eb47a44 492:16ceb3228324
1 # -*- coding: utf-8 -*-
2
3 # ####################################################################
4 # Copyright (C) 2005-2010 by the FIFE team
5 # http://www.fifengine.net
6 # This file is part of FIFE.
7 #
8 # FIFE is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the
20 # Free Software Foundation, Inc.,
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 # ####################################################################
23
24 from fife import fife
25
26 import fife.extensions.fife_timer as fife_timer
27 from fife.extensions.pychan.tools import callbackWithArguments as cbwa
28
29 """
30 Sound Manager
31 ==================================
32
33 This is a simple implementation of a sound manager that was originaly
34 intended for the shooter demo. It was functional enough that we decided
35 to include it in the FIFE extensions. This is by no means a fully featured
36 implementation for several reasons. It doesnt limit how many sounds can
37 play at once or allow the positioning of sounds. It does however provide
38 a good starting point for a more advanced version of a sound manager.
39
40 """
41
42 class SoundEmitter(object):
43 """
44 SoundEmitter
45
46 This class wraps an instance of a L{fife.SoundEmitter} class along
47 with some information about a sound clip (like gain and if its
48 looping). All instances of SoundEmitter should be created by SoundManager.
49
50 @todo At some point this class will store positional information
51 and also be responsible for updating the L{fife.SoundEmitter} position.
52 """
53 def __init__(self, soundmanager, clipid, soundname, emitter):
54 """
55 @param soundmanager A reference to the SoundManager
56 @param clipid The FIFE sound clip ID from the sound clip pool
57 @param soundname The filename of the sound
58 @param emitter A reference to the L{fife.SoundEmitter} associated with this clip
59
60 """
61 self._soundmanager = soundmanager
62 self._name = soundname
63
64 #The FIFE SoundEmitter associated with this SoundEmitter.
65 #Note that we do NOT own the emitter.
66 self._fifeemitter = emitter
67 self._fifeemitter.thisown = 0
68 self._fifeclipid = clipid
69
70 #0 = mute, 255 = normal volume
71 self._gain = 255.0
72 self._looping = False
73
74 #if you set the callback it will be executed after the sound
75 #has finished playing.
76 self._callback = None
77
78 #length of the sound
79 self._duration = 0
80
81 self._timer = None
82
83 def play(self):
84 self._soundmanager.playClip(self)
85
86 def stop(self):
87 self._soundmanager.stopClip(self)
88
89 def _getClipID(self):
90 return self._fifeclipid
91
92 def _getGain(self):
93 return self._gain
94
95 def _setGain(self, gain):
96 self._gain = float(gain)
97
98 def _getLooping(self):
99 return self._looping
100
101 def _setLooping(self, looping):
102 self._looping = looping
103
104 def _getFifeEmitter(self):
105 return self._fifeemitter
106
107 def _setFifeEmitter(self, emitter):
108 self._fifeemitter = emitter
109 if self._fifeemitter:
110 self._fifeemitter.thisown = 0
111
112 def _getName(self):
113 return self._name
114
115 def _getCallback(self):
116 return self._callback
117
118 def _setCallback(self, cb):
119 self._callback = cb
120
121 def _getDuration(self):
122 return self._duration
123
124 def _setDuration(self, millliseconds):
125 self._duration = millliseconds
126
127 def _getTimer(self):
128 return self._timer
129
130 def _setTimer(self, timer):
131 self._timer = timer
132
133 timer = property(_getTimer, _setTimer)
134 clipid = property(_getClipID)
135 gain = property(_getGain, _setGain)
136 looping = property(_getLooping, _setLooping)
137 fifeemitter = property(_getFifeEmitter, _setFifeEmitter)
138 name = property(_getName)
139 callback = property(_getCallback, _setCallback)
140 duration = property(_getDuration, _setDuration)
141
142 class SoundManager(object):
143 """
144 SoundManger
145
146 This class manages and plays all the sounds of the game.
147 It creates SoundEmitters and ensures that there is only one
148 L{fife.SoundEmitter} per unique sound.
149 """
150 def __init__(self, engine):
151 """
152 @param engine A reference to the FIFE engine
153 """
154
155 self._engine = engine
156
157 self._fifesoundmanager = self._engine.getSoundManager()
158 self._fifesoundmanager.init()
159
160 #A dict of fife emitters
161 self._loadedclips = {}
162
163 def createSoundEmitter(self, filename, forceUnique=False):
164 """
165 Returns a valid SoundEmitter instance.
166
167 @param filename The relative path and filename of the sound file
168 @parm forceUnique This forces a new L{fife.SoundEmitter} to be created.
169 This is useful if you want more than one instance of the same sound
170 to be played at the same time.
171
172 @return Returns a new SoundEmitter instance.
173 """
174 if not self._loadedclips.has_key(filename):
175 clipid = self._engine.getSoundClipPool().addResourceFromFile(filename)
176 fifeemitter = self._fifesoundmanager.createEmitter()
177 fifeemitter.thisown = 0
178 fifeemitter.setSoundClip(clipid)
179
180 self._loadedclips[filename] = [fifeemitter]
181 clip = SoundEmitter(self, clipid, filename, fifeemitter)
182 clip.duration = fifeemitter.getDuration()
183 else:
184 if forceUnique:
185 clipid = self._engine.getSoundClipPool().addResourceFromFile(filename)
186 fifeemitter = self._fifesoundmanager.createEmitter()
187 fifeemitter.thisown = 0
188 fifeemitter.setSoundClip(clipid)
189 self._loadedclips[filename].append(fifeemitter)
190 else:
191 fifeemitter = self._loadedclips[filename][0]
192
193 clip = SoundEmitter(self, fifeemitter.getID(), filename, fifeemitter)
194 clip.duration = fifeemitter.getDuration()
195
196 return clip
197
198 def playClip(self, clip):
199 """
200 Plays a sound clip.
201
202 This function does not use the L{fife.SoundEmitter}
203 "looping" property to loop a sound. Instead it registers
204 a new timer and uses the duration of the clip as the timer length.
205
206 If the SoundEmitter is invalid (no fifeemitter) then it attempts
207 to load it before playing it.
208
209 @note This will stop any clips that use the same L{fife.SoundEmitter}.
210 You cannot play the same sound more than once at a time unless you create
211 the SoundEmitter with the forceUnique paramater set to True.
212
213 @param clip The SoundEmitter to be played
214 """
215
216 if clip.fifeemitter:
217 if clip.callback:
218 if clip.timer:
219 clip.timer.stop()
220 timer = None
221
222 if clip.looping:
223 repeat = 0
224 def real_callback(c, e, g):
225 c()
226 e.stop()
227 e.setGain(g)
228 e.play()
229
230 clip.callback = cbwa(real_callback, clip.callback, clip.fifeemitter, clip.gain)
231
232 else:
233 repeat = 1
234
235 clip.timer = fife_timer.delayCall(clip.duration, clip.callback)
236 #clip.timer.start()
237
238 clip.fifeemitter.setGain(clip.gain)
239 clip.fifeemitter.play()
240 else:
241 clip = self.createSoundEmitter(clip.name)
242 self.playClip(clip)
243
244 def stopClip(self, clip):
245 """
246 Stops playing the sound clip. Note that this will stop all clips that
247 use the same FIFE emitter.
248
249 @parm clip The SoundEmitter to stop.
250 """
251 if clip.fifeemitter:
252 clip.fifeemitter.stop()
253
254 if clip.timer:
255 clip.timer.stop()
256 clip.timer = None
257
258 def stopAllSounds(self):
259 for emitterlist in self._loadedclips.values():
260 for emitter in emitterlist:
261 emitter.stop()
262
263 def destroy(self):
264 """
265 Releases all instances of L{fife.SoundEmitter}. This does not free
266 the resources from the FIFE sound clip pool.
267 """
268 self.stopAllSounds()
269
270 for emitterlist in self._loadedclips.values():
271 for emitter in emitterlist:
272 self._fifesoundmanager.releaseEmitter(emitter.getID())
273 emitter = None
274
275 self._loadedclips.clear()
276
277 __all__ = ['SoundEmitter','SoundManager']