1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import pygame
24 import Log
25 import time
26 from Task import Task
27
28 try:
29 import ogg.vorbis
30 except ImportError:
31 Log.warn("PyOGG not found. OGG files will be fully decoded prior to playing; expect absurd memory usage.")
32 ogg = None
33
35 - def pre_open(self, frequency = 22050, bits = 16, stereo = True, bufferSize = 1024):
36 pygame.mixer.pre_init(frequency, -bits, stereo and 2 or 1, bufferSize)
37 return True
38
39 - def open(self, frequency = 22050, bits = 16, stereo = True, bufferSize = 1024):
40 try:
41 pygame.mixer.quit()
42 except:
43 pass
44
45 try:
46 pygame.mixer.init(frequency, -bits, stereo and 2 or 1, bufferSize)
47 except:
48 Log.warn("Audio setup failed. Trying with default configuration.")
49 pygame.mixer.init()
50
51 Log.debug("Audio configuration: %s" % str(pygame.mixer.get_init()))
52
53 return True
54
56 return pygame.mixer.get_num_channels()
57
60
63
66
69
73
74 @staticmethod
76 pygame.mixer.music.set_endevent(event)
77
78 - def play(self, loops = -1, pos = 0.0):
79 pygame.mixer.music.play(loops, pos)
80
82 pygame.mixer.music.stop()
83
85 pygame.mixer.music.rewind()
86
88 pygame.mixer.music.pause()
89
92
94 pygame.mixer.music.set_volume(volume)
95
98
100 return pygame.mixer.music.get_busy()
101
103 return pygame.mixer.music.get_pos()
104
108
109 - def play(self, sound):
110 self.channel.play(sound.sound)
111
114
116 self.channel.set_volume(volume)
117
120
124
125 - def play(self, loops = 0):
126 self.sound.play(loops)
127
130
132 self.sound.set_volume(volume)
133
136
137 if ogg:
138 import struct
139
140 import Numeric
141
144 self.file = ogg.vorbis.VorbisFile(inputFileName)
145
146 - def read(self, bytes = 4096):
147 (data, bytes, bit) = self.file.read(bytes)
148 return data[:bytes]
149
151 - def __init__(self, engine, channel, fileName):
152 Task.__init__(self)
153 self.engine = engine
154 self.fileName = fileName
155 self.channel = channel.channel
156 self.playing = False
157 self.bufferSize = 1024 * 64
158 self.bufferCount = 8
159 self.volume = 1.0
160 self.buffer = Numeric.zeros((2 * self.bufferSize, 2), typecode = "s")
161 self.decodingRate = 4
162 self._reset()
163
165 self.stream = OggStream(self.fileName)
166 self.buffersIn = [pygame.sndarray.make_sound(Numeric.zeros((self.bufferSize, 2), typecode = "s")) for i in range(self.bufferCount + 1)]
167 self.buffersOut = []
168 self.buffersBusy = []
169 self.bufferPos = 0
170 self.done = False
171 self.lastQueueTime = time.time()
172
173 while len(self.buffersOut) < self.bufferCount and not self.done:
174 self._produceSoundBuffers()
175
178
180 if self.playing:
181 return
182
183 self.engine.addTask(self, synchronized = False)
184 self.playing = True
185
186 while len(self.buffersOut) < self.bufferCount and not self.done:
187 self._produceSoundBuffers()
188
189 self.channel.play(self.buffersOut.pop())
190
196
199
202
204
205 if not self.buffersIn or self.done:
206 return
207
208 data = self.stream.read()
209
210 if not data:
211 self.done = True
212 else:
213 data = struct.unpack("%dh" % (len(data) / 2), data)
214 samples = len(data) / 2
215 self.buffer[self.bufferPos:self.bufferPos + samples, 0] = data[0::2]
216 self.buffer[self.bufferPos:self.bufferPos + samples, 1] = data[1::2]
217 self.bufferPos += samples
218
219
220
221 if self.bufferPos >= self.bufferSize or (self.done and self.bufferPos):
222
223 if self.bufferPos < self.bufferSize:
224 self.buffer[self.bufferPos:] = 0
225 soundBuffer = self.buffersIn.pop()
226 pygame.sndarray.samples(soundBuffer)[:] = self.buffer[0:self.bufferSize]
227
228
229 n = max(0, self.bufferPos - self.bufferSize)
230 self.buffer[0:n] = self.buffer[self.bufferSize:self.bufferSize+n]
231 self.bufferPos = n
232
233 return soundBuffer
234
236
237
238 while not self.done:
239 for i in xrange(self.decodingRate):
240 soundBuffer = self._decodeStream()
241 if soundBuffer:
242 self.buffersOut.insert(0, soundBuffer)
243 if self.buffersOut:
244 break
245
246 - def run(self, ticks):
247 if not self.playing:
248 return
249
250 self.channel.set_volume(self.volume)
251
252 if len(self.buffersOut) < self.bufferCount:
253 self._produceSoundBuffers()
254
255 if not self.channel.get_queue() and self.buffersOut:
256
257 soundBuffer = self.buffersOut.pop()
258 self.buffersBusy.insert(0, soundBuffer)
259 self.lastQueueTime = time.time()
260 self.channel.queue(soundBuffer)
261 if len(self.buffersBusy) > 2:
262 self.buffersIn.insert(0, self.buffersBusy.pop())
263
264 if not self.buffersOut and self.done and time.time() - self.lastQueueTime > 4:
265 self.stop()
266
268 - def __init__(self, engine, channel, fileName):
272
273 - def __new__(cls, engine, channel, fileName):
274 frequency, format, stereo = pygame.mixer.get_init()
275 if fileName.lower().endswith(".ogg"):
276 if frequency == 44100 and format == -16 and stereo:
277 return StreamingOggSound(engine, channel, fileName)
278 else:
279 Log.warn("Audio settings must match stereo 16 bits at 44100 Hz in order to stream OGG files.")
280 return super(StreamingSound, cls).__new__(cls, engine, channel, fileName)
281
283 self.channel.play(self)
284
288
292
296