Mercurial > SDL_sound_CoreAudio
annotate mixer/tutorial.txt @ 562:7e08477b0fc1
MP3 decoder upgrade work.
Ripped out SMPEG and mpglib support, replaced it with "mpg123.c" and libmpg123.
libmpg123 is a much better version of mpglib, so it should solve all the
problems about MP3's not seeking, or most modern MP3's not playing at all,
etc. Since you no longer have to make a tradeoff with SMPEG for features, and
SMPEG is basically rotting, I removed it from the project.
There is still work to be done with libmpg123...there are MMX, 3DNow, SSE,
Altivec, etc decoders which we don't have enabled at the moment, and the
build system could use some work to make this compile more cleanly, etc.
Still: huge win.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 30 Jan 2009 02:44:47 -0500 |
parents | 3a3807dcf57f |
children |
rev | line source |
---|---|
478 | 1 |
2 SDL_sound version 2.0: Your Mixer, And Welcome To It. | |
3 | |
4 | |
5 SDL_sound v2's major addition is a software mixer. There are some other new | |
6 features, but this is the Big New Thing. | |
7 | |
8 | |
9 Some notable features of this mixer: | |
10 - No clamping at mix time. Most SDL-based mixing is done via SDL_MixAudio(), | |
11 which mixes two samples together, clamping to 16-bits, and then mixes the | |
12 next sample into this already-clamped buffer. This can lead to audio | |
13 distortion. SDL_sound mixes all samples into a 32-bit floating point buffer | |
14 before passing it to the audio device, which means no unnecessary clamping. | |
15 It also means it can be more optimized for MacOS X's CoreAudio and other | |
16 next-gen audio subsystems, which require you to feed it float32 data. | |
17 | |
18 - Optimized mixing: MMX, SSE, 3DNow!, and Altivec are used internally where | |
19 appropriate. (er...they WILL be, at least!) | |
20 | |
21 - Multiple "music" files. SDL_mixer is notorious for making a distinction | |
22 between "sound" and "music" files (that is, things that can be trivially | |
23 decoded to a waveform without bloating the memory footprint vs. things that | |
24 can't), and only allows mixing of one music file at a time. SDL_sound | |
25 doesn't bother with this distinction, which means you are free to mix any | |
26 combination of audio formats at the same time. | |
27 | |
28 - No "channels". If you want to mix 1,000 audio files and have the hardware | |
29 to cover it, you can. You don't have to manage playback channels. There | |
30 isn't a seperate "music" channel, since "music" isn't treated differently | |
31 from any other audio. | |
32 | |
33 - Lots of formats. SDL_sound already decodes a huge number of audio formats. | |
34 As the mixer is layered on top of this, all of the format support comes | |
35 for free. | |
36 | |
37 - Can handle non-power-of-two resampling. If your samples are at 8000Hz | |
38 and the audio hardware is at 11000Hz, this doesn't cause output problems. | |
39 | |
40 - Control over buffering and mixing. SDL_sound already lets you control how | |
41 much audio is prebuffered and predecoded; this carries over to the mixer, | |
42 so you can customize how your resources are being used on the fly. | |
43 | |
44 - Flexible enough for those that need to micromanage mixing, but dirt simple | |
45 to for those that just want to make some noise. | |
46 | |
47 - It can be compiled out if you just want the 1.0 API for decoding formats. | |
48 (initializing the mixer subsystem in this case will fail, but for binary | |
49 compatibility, the entry points will still exist). | |
50 | |
51 A brief tutorial follows. | |
52 | |
53 | |
54 Example #1: Play a sound and get the heck out of there. | |
55 | |
56 #include "SDL_sound.h" | |
57 | |
58 int main(int argc, char **argv) | |
59 { | |
60 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
61 Sound_Sample *hello = Sound_NewSampleFromFile("hello.wav", NULL, 10240); | |
62 Sound_MixPlay(hello); | |
63 while (Sound_MixPlaying(hello)) | |
64 SDL_Delay(100); // wait around; mixing is in a seperate thread! | |
65 Sound_FreeSample(hello); | |
66 Sound_MixDeinit(); | |
67 return(0); | |
68 } | |
69 | |
70 Every tutorial needs a "Hello World" example. | |
71 That will play hello.wav, wait for it to finish, and terminate the program. | |
72 But that's not really mixing! To qualify, you'd need to play two sounds at | |
73 once. So let's do that: | |
74 | |
75 | |
76 Example #2: Mixing two sounds. | |
77 | |
78 #include "SDL_sound.h" | |
79 | |
80 int main(int argc, char **argv) | |
81 { | |
82 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
83 Sound_Sample *hello = Sound_NewSampleFromFile("hello.wav", NULL, 10240); | |
84 Sound_Sample *music = Sound_NewSampleFromFile("icculus.ogg", NULL, 10240); | |
85 Sound_MixPlay(music); | |
86 while (Sound_MixPlaying(music)) | |
87 { | |
88 if (!Sound_MixPlaying(hello)) | |
89 { | |
90 Sound_Rewind(hello); | |
91 Sound_MixPlay(hello); | |
92 } | |
93 SDL_Delay(100); // wait around. | |
94 } | |
95 Sound_FreeSample(music); | |
96 Sound_FreeSample(hello); // will stop if it happens to still be playing. | |
97 Sound_MixDeinit(); | |
98 return(0); | |
99 } | |
100 | |
101 Same deal, but we play some music ("Icculus in San Jose" from the talented | |
102 Emmett Plant, in this case). We also load our "hello" sound from the previous | |
103 example. While the music is playing, we check if "hello" is playing, and if | |
104 not, we set it up to play again. Note that the two sounds are playing at the | |
105 same time, mixed together. Cool, huh? | |
106 | |
107 You might notice that we called Sound_Rewind() on the hello sample. This isn't | |
108 part of the mixer itself, and is a function from SDL_sound v1, before there | |
109 was a mixer at all. This illustrates that you can use the usual SDL_sound | |
110 methods to manipulate a sample in the mixer, including seeking and predecoding. | |
111 These are safe operations even while the sample is playing. | |
112 | |
113 That's about all you need to know to effectively use the mixer. Everything | |
114 after that is extra credit. | |
115 | |
116 | |
117 Extra credit #1: Mixer Attributes. | |
118 | |
119 An API's got to know its limitations. SDL_sound isn't meant to be a robust 3D | |
120 spatialization library. For that, one should look to the excellent OpenAL API | |
121 at http://www.openal.org/. Still, for many reasons, OpenAL might not be a good | |
122 fit: it doesn't support many audio formats (and all formats except uncompressed | |
123 integer PCM are optional extensions to the API), it is less likely to | |
124 support your platform and audio output target than SDL, and it is more | |
125 complicated to feed it streamed audio. While not as robust as AL's feature | |
126 set, SDL_sound v2 provides a handful of useful attributes you can set on a | |
127 sample to alter its playback. | |
128 | |
129 | |
130 Basic Attribute #1: Looping. | |
131 | |
132 Checking a sample's playing state in a loop just so you know when to restart | |
133 it has two problems: first, it's a pain in the butt, and second, there may | |
134 be a gap in the audio between when the sound starts and when you're able to | |
135 restart it. To remedy this, SDL_sound lets you flag a sample as "looping" so | |
136 you don't have to micromanage it. It will continue to rewind and play until | |
137 you explicitly stop it. Let's take our last example and do this right: | |
138 | |
139 | |
140 Example #3: Mixing two sounds with better looping. | |
141 | |
142 #include "SDL_sound.h" | |
143 | |
144 int main(int argc, char **argv) | |
145 { | |
146 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
147 Sound_Sample *hello = Sound_NewSampleFromFile("hello.wav", NULL, 10240); | |
148 Sound_Sample *music = Sound_NewSampleFromFile("icculus.ogg", NULL, 10240); | |
149 Sound_SetAttribute(hello, SOUND_ATTR_LOOPING, 1); // turn on looping. | |
150 Sound_MixPlay(music); | |
151 Sound_MixPlay(hello); | |
152 while (Sound_MixPlaying(music)) | |
153 SDL_Delay(100); // wait around. | |
154 Sound_FreeSample(music); | |
155 Sound_FreeSample(hello); // will stop now. | |
156 Sound_MixDeinit(); | |
157 return(0); | |
158 } | |
159 | |
160 ...it's that easy. | |
161 | |
162 | |
163 Basic attribute #2: Fire and forget | |
164 | |
165 You'll notice in previous examples that we are taking the pains to explicitly | |
166 free the resources associated with a sample via the Sound_FreeSample() call. | |
167 In a small program like this, it's easy to be tidy and sweep up after one | |
168 or two hardcoded sounds, but when you are managing a lot of different sounds, | |
169 or a lot of copies of the same sound, this can become tedious. Case in point: | |
170 laser beams. | |
171 | |
172 Let's say you've got a space fighter game, with a bunch of ships flying | |
173 around and shooting at each other. Every time they fire a laser, do you really | |
174 want to take the effort to decide when it is done and clean it up? You want | |
175 to, quite literally in this case, "fire and forget" the sound...that is, you | |
176 want the mixer to playback the audio and then clean it up without further | |
177 action or intervention from you. | |
178 | |
179 So let's take our previous example and adjust it to clean up after us. | |
180 | |
181 | |
182 Example #4: Fire and forget playback. | |
183 | |
184 #include "SDL_sound.h" | |
185 | |
186 int main(int argc, char **argv) | |
187 { | |
188 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
189 Sound_Sample *hello = Sound_NewSampleFromFile("hello.wav", NULL, 10240); | |
190 Sound_Sample *music = Sound_NewSampleFromFile("icculus.ogg", NULL, 10240); | |
191 Sound_SetAttribute(hello, SOUND_ATTR_FIREANDFORGET, 1); | |
192 Sound_SetAttribute(music, SOUND_ATTR_FIREANDFORGET, 1); | |
193 Sound_MixPlay(music); // play once, then call Sound_FreeSample() for you. | |
194 Sound_MixPlay(hello); // play once, then call Sound_FreeSample() for you. | |
195 while (Sound_MixPlayingCount() > 0) | |
196 SDL_Delay(100); // wait around. | |
197 | |
198 // Don't need Sound_FreeSample() here anymore! | |
199 | |
200 Sound_MixDeinit(); | |
201 return(0); | |
202 } | |
203 | |
204 So everything was deallocated automatically, and your mother didn't even have | |
205 to come along and tell you to clean up this pig sty! She is very proud of you | |
206 right now, I assure you. | |
207 | |
208 You'll note that we call Sound_MixPlayingCount() to see if the music finished. | |
209 You have to do this because the "music" sample is invalid once it gets pushed | |
210 through Sound_FreeSample(), which will happen as soon as the mixer is done | |
211 with it. To avoid touching deallocated memory, we just ask the mixer if | |
212 anything is still playing. | |
213 | |
214 Also, common sense dictates that looping sounds never get to the "forget" | |
215 part of "fire and forget", since they don't stop playing. You can either | |
216 manually halt them or turn off the looping, though, and then they'll clean | |
217 themselves up. | |
218 | |
219 | |
220 Basic attribute #3: Per-channel Gain. | |
221 | |
222 If you can tweak the volume of the left or right channel on a sample, you can | |
223 accomplish (or at least fake) a surprising number of simple sound effects. | |
224 Therefore the mixer allows you to do just this, and then builds a few features | |
225 on top of this magic. | |
226 | |
227 This is accomplished by tweaking the "gain" of a given channel. "Gain" is just | |
228 a fancy way of saying "volume". You specify it as a floating point number, | |
229 usually in the range of 0.0f to 2.0f. If you set the gain to 0.0f, it results | |
230 in silence, and 1.0f results in no change at all. 0.5f halves the volume and | |
231 2.0f doubles it. As you might have guessed, the sample gets multiplied by | |
232 this value. | |
233 | |
234 SDL_sound's mixer lets you tweak each channel in a sample individually. Right | |
235 now we're limited to mono (one channel) and stereo (two channel) sounds, but | |
236 this will probably be enhanced at some point. It's worth noting that this | |
237 refers not to the sample itself but to the speakers where they play. This | |
238 means you can set the left and right channels of a sample, even though the | |
239 sample itself only has one. Since a 2-speaker setup will promote a mono sound | |
240 to stereo (same waveform is fed to each speaker), you can tweak it to play at | |
241 different volumes in the left and right. | |
242 | |
243 | |
244 So to rehash our tired hello world example again... | |
245 | |
246 Example #5: Per-channel gain. | |
247 | |
248 #include "SDL_sound.h" | |
249 | |
250 int main(int argc, char **argv) | |
251 { | |
252 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
253 Sound_Sample *hello = Sound_NewSampleFromFile("hello.wav", NULL, 10240); | |
254 | |
255 // Every channel's gain defaults to 1.0f, or no adjustment. | |
256 | |
257 Sound_SetAttribute(hello, SOUND_ATTRGAIN0, 0.0f); // left chan==silence. | |
258 Sound_MixPlay(hello); // plays just right channel. | |
259 while (Sound_MixPlaying(hello)) | |
260 SDL_Delay(100); // wait around. | |
261 | |
262 Sound_SetAttribute(hello, SOUND_ATTRGAIN0, 1.0f); // left chan==normal | |
263 Sound_SetAttribute(hello, SOUND_ATTRGAIN1, 0.0f); // right chan==silence | |
264 Sound_MixPlay(hello); // plays just left channel. | |
265 while (Sound_MixPlaying(hello)) | |
266 SDL_Delay(100); // wait around. | |
267 | |
268 Sound_FreeSample(hello); | |
269 Sound_MixDeinit(); | |
270 return(0); | |
271 } | |
272 | |
273 | |
274 This played the hello sound twice, once in each speaker. Simple. | |
275 | |
276 Well, almost simple. If you only have mono output (one speaker), then this | |
277 will play silence the first time (channel 0 set to silence), then the sound | |
278 at normal volume the second time (channel 0, the only speaker, set to normal). | |
279 In a 1-speaker setup, screwing with the second channel is ignored. | |
280 | |
281 If this is going to be a pain for you to track yourself, you can use | |
282 Sound_MixInit() to set up a stereo environment and let it dither everything | |
283 down to one speaker behind the scenes if need be. Generally, this isn't a | |
284 huge concern, though. | |
285 | |
286 | |
287 Extra Credit #2: Fading | |
288 | |
289 Sometimes you want to fade out (or fade in) a sound over time...this is | |
290 handy when ending a game level. It's a nicer effect to silence everything | |
291 over some small amount of time than to abruptly kill all the noise. This is | |
292 more pleasant for the end-user. | |
293 | |
294 You could accomplish this by tweaking each channel of all your samples' gain | |
295 over time, but this is another one of those things that are annoying to | |
296 micromanage. The mixer has to constantly pay attention to these samples anyhow, | |
297 why should you do it, too? | |
298 | |
299 SDL_sound gives you a means to instruct the mixer to take care of this. | |
300 | |
301 | |
302 Example #6: Fading a sound. | |
303 | |
304 #include "SDL_sound.h" | |
305 | |
306 int main(int argc, char **argv) | |
307 { | |
308 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
309 Sound_Sample *music = Sound_NewSampleFromFile("icculus.ogg", NULL, 10240); | |
310 Sound_MixPlay(music); // Start music playing. | |
311 Sound_SetAttribute(music, SOUND_ATTR_FADEOUT, 10000); | |
312 SDL_Delay(10000); | |
313 Sound_SetAttribute(music, SOUND_ATTR_FADEIN, 10000); | |
314 SDL_Delay(10000); | |
315 Sound_FreeSample(music); | |
316 Sound_MixDeinit(); | |
317 return(0); | |
318 } | |
319 | |
320 | |
321 So this starts our favorite song playing, and tells it to fade to silence | |
322 smoothly over 10000 milliseconds (that is, 10 seconds). Since we know how | |
323 long we want this to take, we lazily call SDL_Delay() to wait that long; the | |
324 mixer works in another thread, so we have the luxury of doing nothing here. | |
325 Then we fade it back in over another 10 seconds before exiting. | |
326 | |
327 It's worth noting a few things here: | |
328 First, the FADEOUT attribute uses the same mechanism as SetGain() under the | |
329 hood when mixing, but the two attributes exist seperately: if you double the | |
330 gain (2.0f), the sound will drop in volume twice as much each time the fading | |
331 updates, but it's still going to go from twice-as-loud to silence in the | |
332 same amount of time (10000 milliseconds in this case). | |
333 | |
334 When a sample is totally silent, either because it faded out or you set its | |
335 gain to 0.0f, it is still playing! If you were to turn the volume back up | |
336 30 seconds after the fade completes, you'd hear the sound as it would be at | |
337 that 30 second moment as if you hadn't silenced it at all. This has a few | |
338 important ramifications: | |
339 1) It's still taking CPU time. Maybe not as much, since we can choose not | |
340 to mix when the gain is 0.0f, but in order to keep the sound "playing" | |
341 we might need to decode more of it, which means CPU time and memory | |
342 usage and such. Best to halt a silent sound if you aren't going to need | |
343 it. | |
344 2) Sound_MixPlayingCount() might be > 0 even though you don't hear noise. | |
345 3) A sound might not be where you left it. Keep better track of your things! | |
346 | |
347 You might also notice that we called Sound_FreeSample() on a playing sample. | |
348 This is legal. If a sample is playing when you free it, the mixer knows to | |
349 halt it first. | |
350 | |
351 | |
352 Extra Credit #3: Halting | |
353 | |
354 SDL_sound's mixer is a little different than most, in that there aren't | |
355 seperate playing states. "Halting" a mixing sample means you took it out of | |
356 the mixing list. "Playing" it means you put it back in, and it picks up the | |
357 mixing with the sample as it found it. | |
358 | |
359 If you want something anologous to that "stop" button in WinAmp, you would | |
360 halt the sample and then call Sound_Rewind() on it. Next time you start it | |
361 playing, it'll be playing from the start of the sample. If you didn't call | |
362 Sound_Rewind() first, it'll be playing from where you halted it. That's more | |
363 like clicking WinAmp's "pause" button. | |
364 | |
365 However, there are times when you want everything to stop at once. Just | |
366 looping over every sample and halting them isn't any good, since some might | |
367 play just a tiny bit longer...it's a lovely bug called a "race condition". | |
368 | |
369 And, as I'm sure you've heard me say before, why do a lot of work to manage | |
370 stuff that the mixer has to manage itself anyhow? You should learn to | |
371 delegate more, you control freak. | |
372 | |
373 | |
374 Example #7: Halting. | |
375 | |
376 #include "SDL_sound.h" | |
377 | |
378 int main(int argc, char **argv) | |
379 { | |
380 Sound_MixInit(NULL); // start the mixer; don't care what format. | |
381 Sound_Sample *hello = Sound_NewSampleFromFile("hello.wav", NULL, 10240); | |
382 Sound_Sample *chatter = Sound_NewSampleFromFile("chatter.wav", NULL, 10240); | |
383 Sound_Sample *music = Sound_NewSampleFromFile("icculus.ogg", NULL, 10240); | |
384 Sound_MixPlay(music); | |
385 | |
386 Sound_MixPlay(hello); | |
387 while (Sound_MixPlaying(hello)) SDL_Delay(100); // wait around. | |
388 Sound_MixPlay(hello); | |
389 while (Sound_MixPlaying(hello)) SDL_Delay(100); // wait around. | |
390 Sound_MixPlay(hello); | |
391 while (Sound_MixPlaying(hello)) SDL_Delay(100); // wait around. | |
392 | |
393 Sound_MixHalt(music); // halt the music. | |
394 | |
395 Sound_MixPlay(hello); | |
396 while (Sound_MixPlaying(hello)) SDL_Delay(100); // wait around. | |
397 Sound_MixPlay(hello); | |
398 while (Sound_MixPlaying(hello)) SDL_Delay(100); // wait around. | |
399 Sound_MixPlay(hello); | |
400 while (Sound_MixPlaying(hello)) SDL_Delay(100); // wait around. | |
401 | |
402 Sound_MixPlay(music); // start the music where it left off. | |
403 Sound_MixPlay(chatter); // start the chatter. | |
404 | |
405 SDL_Delay(3000); // let them play. | |
406 Sound_MixHalt(NULL); // halt _everything_ that's playing. | |
407 SDL_Delay(3000); // waste some time. | |
408 Sound_MixPlay(music); // start the music where it left off. | |
409 Sound_MixPlay(chatter); // start the chatter where it left off. | |
410 SDL_Delay(3000); // waste some more time. | |
411 | |
412 Sound_FreeSample(music); // clean up and quit. | |
413 Sound_FreeSample(chatter); | |
414 Sound_FreeSample(hello); | |
415 Sound_MixDeinit(); | |
416 return(0); | |
417 } | |
418 | |
419 | |
420 Ok, you following? That plays the music, plays "hello" three times while the | |
421 music is playing, halts the music and plays hello three times without anything | |
422 else, restarts the music where it left off mixed with "chatter" for three | |
423 seconds, stops everything (music and chatter in this case), waits three more | |
424 seconds of silence, restarts the music and chatter where it left off and | |
425 lets them play for three more seconds. Then it shuts it all down and goes | |
426 home. | |
427 | |
428 Fun, huh? | |
429 | |
430 There are some notable exceptions to this rule. When a sound gets to the end | |
431 of its mixing, it either halts or (if set looping) rewinds and starts playing | |
432 again without missing a beat. For these, you don't have to manually halt | |
433 (or manually restart, as it were). | |
434 | |
435 | |
436 You now have everything you need to make a game with robust audio. But for | |
437 some of you, that's not enough. You're never satisfied. You need the section | |
438 of this tutorial written for... | |
439 | |
440 | |
441 THE HARDCORE. | |
442 | |
443 (These sections are brief and lack full examples. If you're hardcore, you | |
444 probably don't read wussy tutorials anyhow.) | |
445 | |
446 | |
447 Hardcore #1: low-overhead copying of a sample. | |
448 | |
449 Let's say you've got a sound file that represents a laser blast. Everytime a | |
450 shot is fired in your game, you don't want to have the overhead of reloading | |
451 it from disk, decoding and mixing it on the fly! | |
452 | |
453 Here are some tips for your efficiency: | |
454 | |
455 - Opt for an uncompressed format, such as a standard .WAV file or even | |
456 raw PCM. For small, frequently used sounds, the bigger memory footprint | |
457 is usually an acceptable tradeoff to constant redecoding. In some cases, | |
458 we've found that compressing to, say, .ogg format actually makes the | |
459 file bigger if it's a very short sound. | |
460 | |
461 - Put your sound into a memory block and point multiple memory RWOPS at | |
462 it: one per playing sound. There are functions in SDL_sound 2 | |
463 for allocating these from a pool, which reduces allocation overhead | |
464 and memory fragmentation, and eliminates multiple trips to the disk | |
465 when you "read" the sound. | |
466 | |
467 - Sound_Sample structures are allocated in a pool, too, so throwaway | |
468 sounds (specifically, ones using pooled RWOPS) don't thrash system | |
469 resources. Good for those fire-and-forget effects. | |
470 | |
471 - It's trivial to roll a reference-counting RWOPS that lets you use the | |
472 same memory block for several playing sounds, and when the last one | |
473 closes it (all related Sound_Samples go through Sound_FreeSample()), it | |
474 deletes the original memory block. Handy if you only want to loosely | |
475 manage those buffers. | |
476 | |
477 - Cull samples if you're playing too many. The app can decide which sounds | |
478 are important and assign them a priority, and let only the first X | |
479 highest priority sounds actually mix. | |
480 | |
481 - Alternately, if you can swallow the memory: take a highly-compressed | |
482 file and put it into a Sound_Sample, call Sound_DecodeAll. Now, use | |
483 the sample's "decoded" field as raw PCM for other Sound_Samples using | |
484 above tricks. When you are done, clean up the other samples first, then | |
485 call Sound_FreeSample() on this one. This is extremely useful if you | |
486 want to reduce CPU usage for one sound that is otherwise compressed. | |
487 Memory usage doesn't grow exponentially with each simulataneous mixing | |
488 of this sound, because everyone is feeding from the same memory block, | |
489 so each new sample instance adds some bytes for the structures (which | |
490 might have been allocated in the pool already anyhow). | |
491 | |
492 | |
493 Hardcore #2: Predecoding and buffer sizes. | |
494 | |
495 Take advantage of the 1.0 API for predecoding and altering the decode buffer | |
496 size. This gives you control over the memory/CPU tradeoff at mix time, as the | |
497 mixer will call Sound_Decode() when it needs more data from a playing sample. | |
498 How much decoding is done at that point depends on how much buffering is | |
499 available. If you predecode the whole thing with Sound_DecodeAll(), then the | |
500 mixer can focus on mixing and not spend time decoding. | |
501 | |
502 | |
503 | |
504 Hardcore #3: Global gain, global fade. | |
505 | |
506 Most attributes that apply to one sample can be applied to all by passing a | |
507 NULL for the first argument to Sound_SetAttribute(). Gain and fade are | |
508 examples of this. If you want everything to fade out at once, this is the | |
509 best, race-condition free way to do it. | |
510 | |
511 Note that global attributes don't override (or overwrite) per-sample | |
512 attributes. If you set a sample's gain to 2.0 and the global gain to 0.5, the | |
513 sound plays at normal (1.0) gain...the sample's gain is still 2.0 when you | |
514 change the global gain thereafter. | |
515 | |
516 | |
517 Hardcore #4: Postmix callbacks. | |
518 | |
519 You can register a callback function per-sample that is called when the mixer | |
520 has finished its work and is about to send the data to the audio hardware. | |
521 These generally run in seperate threads on most platforms, and as such must be | |
522 protected from your main code with mutexes. | |
523 | |
524 These are useful if you are are writing a media player and want to show some | |
525 sort of visual feedback based on the playing audio data, or if you want to | |
526 tweak the sound with your own special effects. | |
527 | |
528 | |
529 Hardcore #5: Sample finished callback. | |
530 | |
531 You can register a callback function per-sample that is called when the mixer | |
532 has completely finished mixing a non-looping sample. This is largely a nod to | |
533 SDL_mixer, where this was the most convenient way to clean up fire-and-forget | |
534 sounds, but most people will want to let SDL_sound handle those. This has | |
535 other good uses: it lets you know when sound events are complete if you are | |
536 adding cinematics/cut-scenes to your program, or perhaps when it's safe for | |
537 characters to speak again (it's strange when one actor is speaking two | |
538 overlapping lines of dialogue, for example). | |
539 | |
540 | |
523
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
541 Hardcore #6: Procedural samples. |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
542 !!! WRITEME: Hook up a RAW Sound_Sample to a RWOPS that generates sound on |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
543 !!! WRITEME: read, so you can mix in a procedural sample instead of just |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
544 !!! WRITEME: pre/post mixing. |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
545 |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
546 |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
547 |
3a3807dcf57f
Minor tutorial.txt update.
Ryan C. Gordon <icculus@icculus.org>
parents:
478
diff
changeset
|
548 Hardcore #7: Your suggestion here! |
478 | 549 |
550 The goal is to try and make audio work fairly painless for the game developer, | |
551 which means that if there is a good way to generalize functionality into the | |
552 mixer layer, we probably should. Comments are welcome! | |
553 | |
554 It's worth noting that this tutorial covers common usage patterns and the Big | |
555 Important Things, so a lot of support API isn't covered here. For example, | |
556 important things like being able to query sample attributes weren't important | |
557 enough to mention here, but that doesn't mean you can't do it). | |
558 | |
559 // end of mixer.txt ... | |
560 |