1 /**
2 * Sound effects (not music) management
3
4 * Copyright (C) 1997, 1998, 1999, 2002, 2003 Seth A. Robinson
5 * Copyright (C) 2003 Shawn Betts
6 * Copyright (C) 2005, 2007, 2008, 2009 Sylvain Beucler
7
8 * This file is part of GNU FreeDink
9
10 * GNU FreeDink is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 3 of the
13 * License, or (at your option) any later version.
14
15 * GNU FreeDink is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see
22 * <http://www.gnu.org/licenses/>.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdlib.h>
30 #include <string.h> /* memset, memcpy */
31 #include <errno.h>
32
33 #include "SDL.h"
34 #include "SDL_mixer.h"
35 #include "game_engine.h"
36 #include "io_util.h"
37 #include "paths.h"
38 #include "log.h"
39 #include "math.h"
40 #include "sfx.h"
41 #include "log.h"
42
43
44 /* Channel metadata */
45 #define NUM_CHANNELS 20
46 struct
47 {
48 /*bool*/int repeat;
49 int owner;
50 int survive;
51 int cur_sound; /* Sound currently played in that channel */
52 int looping;
53 int finished;
54 } channelinfo[NUM_CHANNELS];
55
56
57 /* Sound metadata */
58 #define MAX_SOUNDS 100
59 static struct
60 {
61 SDL_AudioSpec orig_spec;
62 Uint32 orig_len;
63 int pos_lastframe; /* index for the last frame */
64 int pos_end; /* upper bound (pre-calculated for efficiency&simplicity) */
65 SDL_AudioCVT cvt;
66 Uint32 cvt_buf_len;
67 } registered_sounds[MAX_SOUNDS];
68
69
70 /* Hardware soundcard information */
71 static int hw_freq, hw_channels;
72 static Uint16 hw_format;
73
74 /* Fake buffer */
75 static Uint8* fake_buf = NULL;
76 static Uint32 fake_buf_len = 0;
77
78 static int SetVolume(int channel, int dx_volume);
79 static int SetPan(int channel, int dx_panning);
80 static void CleanupChannel(int channel);
81 static void FreeRegisteredSound(int index);
82
83
84 /**
85 * Display a SDL audio-format in human-readable form
86 **/
format2string(Uint16 format)87 static const char *format2string(Uint16 format) {
88 char *format_str = "Unknown";
89 switch (format)
90 {
91 case AUDIO_U8: format_str = "U8"; break;
92 case AUDIO_S8: format_str = "S8"; break;
93 case AUDIO_U16LSB: format_str = "U16LSB"; break;
94 case AUDIO_S16LSB: format_str = "S16LSB"; break;
95 case AUDIO_U16MSB: format_str = "U16MSB"; break;
96 case AUDIO_S16MSB: format_str = "S16MSB"; break;
97 }
98 return format_str;
99 }
100
101
102
103 /**
104 * Frequency shift with linear interpolation
105 *
106 * Techniques from Allegro's mixer.c
107 *
108 * We'll assume 8bit is unsigned and 16bit is signed for simplicity
109 * (common case)
110 *
111 * We'll also assume that the converted buffer is in the system's
112 * endianness (there's no reason it shouldn't be) - still the code
113 * portably handles LSB and MSB endianness alike.
114 */
115 struct callback_data
116 {
117 int pos; /* which sample (not frame) we're playing now, in 1/256th */
118 int shift; /* position advance for 1 frame, in 1/256th */
119 int sound; /* sound index */
120 int channel; /* channel index */
121 };
callback_samplerate_cleanup(int chan,void * udata)122 static void callback_samplerate_cleanup(int chan, void *udata)
123 {
124 free(udata);
125 }
callback_samplerate(int chan,void * stream,int len,void * udata)126 static void callback_samplerate(int chan, void *stream, int len, void *udata)
127 {
128 struct callback_data* data = (struct callback_data*)udata;
129 if (channelinfo[data->channel].finished == 1)
130 return;
131
132 /* printf("%d - %d/%d\n", len, data->pos>>8, registered_sounds[data->sound].pos_end>>8); */
133 int pos_end = registered_sounds[data->sound].pos_end;
134 int pos_lastframe = registered_sounds[data->sound].pos_lastframe;
135
136 switch (registered_sounds[data->sound].cvt.dst_format)
137 {
138 case AUDIO_U8:
139 if (hw_channels == 1)
140 {
141 /* Unsigned 8bit mono */
142 Uint8 *buf = (Uint8*) registered_sounds[data->sound].cvt.buf;
143 Uint8 *pstream = (Uint8*)stream;
144 short silence = 128;
145 int bytesPerFrame = 1;
146 int i;
147 for (i = 0; i < len; i += bytesPerFrame)
148 {
149 int cur_index = data->pos >> 8;
150 Uint8 *pbuf = &buf[cur_index];
151 /* This frame (left and right channels)... */
152 Uint8 v1 = *(pbuf++);
153 /* and the next frame */
154 Uint8 v2;
155 if (data->pos < pos_lastframe)
156 v2 = *(pbuf++);
157 else
158 v2 = silence;
159
160 /* Compute interpolation based on progress (subpos) between v1
161 and v2 (measured between 0 and (1<<8)-1) */
162 int subpos = data->pos & ((1<<8) - 1); /* or: data->pos % 256 */
163 Uint8 v = (v1 * ((1<<8) - subpos) + v2 * subpos) >> 8;
164 *(pstream++) = v;
165
166 data->pos += data->shift;
167 if (data->pos >= pos_end)
168 {
169 if (!channelinfo[data->channel].looping)
170 {
171 channelinfo[data->channel].finished = 1;
172 break;
173 }
174 data->pos = 0;
175 }
176 }
177 }
178 else if (hw_channels == 2)
179 {
180 /* Unsigned 8bit stereo */
181 Uint8 *buf = (Uint8*) registered_sounds[data->sound].cvt.buf;
182 Uint8 *pstream = (Uint8*)stream;
183 short silence = 128;
184 int bytesPerFrame = 2;
185 int i;
186 for (i = 0; i < len; i += bytesPerFrame)
187 {
188 int cur_index = data->pos >> 8 << 1; /* x2 because stereo */
189 Uint8 *pbuf = &buf[cur_index];
190 /* This frame (left and right channels)... */
191 Uint8 v1l = *(pbuf++);
192 Uint8 v1r = *(pbuf++);
193 /* and the next frame */
194 Uint8 v2l, v2r;
195 if (data->pos < pos_lastframe)
196 {
197 v2l = *(pbuf++);
198 v2r = *(pbuf++);
199 }
200 else
201 {
202 v2l = v2r = silence;
203 }
204
205 /* Compute interpolation based on progress (subpos) between v1
206 and v2 (measured between 0 and (1<<8)-1) */
207 int subpos = data->pos & ((1<<8) - 1); /* or: data->pos % 256 */
208 Uint8 vl = (v1l * ((1<<8) - subpos) + v2l * subpos) >> 8;
209 Uint8 vr = (v1r * ((1<<8) - subpos) + v2r * subpos) >> 8;
210 *(pstream++) = vl;
211 *(pstream++) = vr;
212
213 data->pos += data->shift;
214 if (data->pos >= pos_end)
215 {
216 if (!channelinfo[data->channel].looping)
217 {
218 channelinfo[data->channel].finished = 1;
219 break;
220 }
221 data->pos = 0;
222 }
223 }
224 }
225 break;
226 case AUDIO_S16SYS:
227 if (hw_channels == 1)
228 {
229 /* Signed 16bit mono */
230 Sint16 *buf = (Sint16*) registered_sounds[data->sound].cvt.buf;
231 Sint16 *pstream = (Sint16*)stream;
232 short silence = 0;
233 int bytesPerFrame = 2;
234 int i;
235 for (i = 0; i < len; i += bytesPerFrame)
236 {
237 int cur_index = data->pos >> 8;
238 Sint16 *pbuf = &buf[cur_index];
239 /* This frame (left and right channels)... */
240 Sint16 v1 = *(pbuf++);
241 /* and the next frame */
242 Sint16 v2;
243 if (data->pos < pos_lastframe)
244 v2 = *(pbuf++);
245 else
246 v2 = silence;
247
248 /* Compute interpolation based on progress (subpos) between v1
249 and v2 (measured between 0 and (1<<8)-1) */
250 int subpos = data->pos & ((1<<8) - 1); /* or: data->pos % 256 */
251 Sint16 v = (v1 * ((1<<8) - subpos) + v2 * subpos) >> 8;
252 *(pstream++) = v;
253
254 data->pos += data->shift;
255 if (data->pos >= pos_end)
256 {
257 if (!channelinfo[data->channel].looping)
258 {
259 channelinfo[data->channel].finished = 1;
260 break;
261 }
262 data->pos = 0;
263 }
264 }
265 }
266 else if (hw_channels == 2)
267 {
268 /* Signed 16bit stereo */
269 Sint16 *buf = (Sint16*) registered_sounds[data->sound].cvt.buf;
270 Sint16 *pstream = (Sint16*)stream;
271 short silence = 0;
272 int bytesPerFrame = 4;
273 int i;
274 for (i = 0; i < len; i += bytesPerFrame)
275 {
276 int cur_index = (data->pos >> 8) << 1; /* x2 because stereo */
277 Sint16 *pbuf = &buf[cur_index];
278 /* This frame (left and right channels)... */
279 Sint16 v1l = *(pbuf++);
280 Sint16 v1r = *(pbuf++);
281 /* and the next frame */
282 Sint16 v2l, v2r;
283 if (data->pos < pos_lastframe)
284 {
285 v2l = *(pbuf++);
286 v2r = *(pbuf++);
287 }
288 else
289 {
290 v2l = v2r = silence;
291 }
292
293 /* Compute interpolation based on progress (subpos) between v1
294 and v2 (measured between 0 and (1<<8)-1) */
295 int subpos = data->pos & ((1<<8) - 1); /* or: data->pos % 256 */
296 Sint16 vl = (v1l * ((1<<8) - subpos) + v2l * subpos) >> 8;
297 Sint16 vr = (v1r * ((1<<8) - subpos) + v2r * subpos) >> 8;
298 *(pstream++) = vl;
299 *(pstream++) = vr;
300
301 data->pos += data->shift;
302 if (data->pos >= pos_end)
303 {
304 if (!channelinfo[data->channel].looping)
305 {
306 channelinfo[data->channel].finished = 1;
307 break;
308 }
309 data->pos = 0;
310 }
311 }
312 }
313 break;
314 }
315 }
316
317 /**
318 * Close channels that stopped playing
319 */
sfx_cleanup_finished_channels()320 void sfx_cleanup_finished_channels()
321 {
322 int i = 0;
323 for (i = 0; i < NUM_CHANNELS; i++)
324 {
325 if (channelinfo[i].finished == 1)
326 Mix_HaltChannel(i);
327 }
328 }
329
330
331
332 /**
333 * Load sounds from the standard paths. Sound is converted to the
334 * current hardware (soundcard) format so that sound rate can be
335 * altered with minimal overhead when playing the sound.
336 */
CreateBufferFromWaveFile(char * filename,int index)337 int CreateBufferFromWaveFile(char* filename, int index)
338 {
339 /* Open the wave file */
340 char path[150];
341 FILE* in = NULL;
342
343 sprintf(path, "sound/%s", filename);
344 in = paths_dmodfile_fopen(path, "rb");
345 if (in == NULL)
346 in = paths_fallbackfile_fopen(path, "rb");
347 if (in == NULL)
348 {
349 log_debug("CreateBufferFromWaveFile: %s", strerror(errno));
350 return 0;
351 }
352
353 SDL_RWops* rwops = SDL_RWFromFP(in, /*autoclose=*/1);
354 return CreateBufferFromWaveFile_RW(rwops, 1, index);
355 }
CreateBufferFromWaveFile_RW(SDL_RWops * rwops,int rwfreesrc,int index)356 int CreateBufferFromWaveFile_RW(SDL_RWops* rwops, int rwfreesrc, int index)
357 {
358 SDL_AudioSpec wav_spec;
359 Uint8 *wav_buf;
360 Uint32 wav_len;
361
362 // Safety check
363 if (index >= MAX_SOUNDS)
364 {
365 log_error("SCRIPTING ERROR: sound index %d is too big.", index);
366 return 0;
367 }
368
369 // Free previous sound if necessary
370 FreeRegisteredSound(index);
371
372
373 if (SDL_LoadWAV_RW(rwops, rwfreesrc, &wav_spec, &wav_buf, &wav_len) == NULL)
374 {
375 log_error("Could not open sound file: %s", SDL_GetError());
376 return 0;
377 }
378 log_info("frequency=%dHz\tformat=%s\tchannels=%d\tlength=%d bytes",
379 wav_spec.freq, format2string(wav_spec.format),
380 wav_spec.channels, wav_len);
381
382
383 /* Converting some WAV data to hardware format - except for sample
384 rate, which we will do better after that. */
385 /* TODO: testing with a sine.wav, I saw that stereo->mono (2->1
386 channels) conversion works quite bad - maybe we should it
387 ourselves too. AFAICS this case is not handled by
388 SDL_audiocvt.c. */
389 SDL_AudioCVT cvt;
390 int ret;
391
392 /* Build AudioCVT */
393 ret = SDL_BuildAudioCVT(&cvt,
394 wav_spec.format, wav_spec.channels, wav_spec.freq,
395 hw_format, hw_channels, wav_spec.freq);
396
397 /* Check that the convert was built */
398 if (ret == -1) {
399 log_error("Couldn't build converter: %s", SDL_GetError());
400 SDL_FreeWAV(wav_buf);
401 }
402
403 /* Setup for conversion */
404 Uint32 cvt_buf_len = wav_len*cvt.len_mult;
405 cvt.buf = (Uint8 *)malloc(cvt_buf_len);
406 cvt.len = wav_len;
407 memcpy(cvt.buf, wav_buf, wav_len);
408
409 /* We can delete to original WAV data now */
410 SDL_FreeWAV(wav_buf);
411
412
413 /* And now we're ready to convert */
414 ret = SDL_ConvertAudio(&cvt);
415 if (ret == -1) {
416 log_error("Couldn't convert audiox: %s", SDL_GetError());
417 SDL_FreeWAV(wav_buf);
418 }
419
420 /* Work-around: if no conversion is needed, format is not specified: */
421 if (cvt.needed == 0)
422 cvt.dst_format = wav_spec.format;
423
424 /* Converted audio is now in cvt.buf */
425 /*printf("CVT\t\tinfo: frequency=?Hz\tformat=%s\tchannels=??\tlength=%d bytes\n",
426 format2string(cvt.dst_format), cvt.len_cvt);*/
427
428 /* Precompute the sound bounds */
429 /* Last byte in hw_format is the number of bits per sample: */
430 int wav_bytesPerSample = (wav_spec.format & 0xFF) / 8;
431 int pos_end = ((wav_len / wav_bytesPerSample) / wav_spec.channels) << 8; /* number of frames */
432 int pos_lastframe = (((wav_len / wav_bytesPerSample) / wav_spec.channels) - 1) << 8;
433
434 registered_sounds[index].orig_spec = wav_spec;
435 registered_sounds[index].orig_len = wav_len;
436 registered_sounds[index].cvt = cvt;
437 registered_sounds[index].cvt_buf_len = cvt_buf_len;
438 registered_sounds[index].pos_end = pos_end;
439 registered_sounds[index].pos_lastframe = pos_lastframe;
440
441 return 1;
442 }
443
444 /**
445 * Return the channel that plays the specified sound, or -1 if not
446 * found
447 */
get_channel(int sound)448 int get_channel(int sound) {
449 int i;
450 /* Check all channels to see if it is playing the sound */
451 for (i = 0; i < NUM_CHANNELS; i++)
452 {
453 if (channelinfo[i].cur_sound == sound)
454 return i;
455 }
456 return -1;
457 }
458
459 /**
460 * Is the specified sound currently playing?
461 *
462 * Only used in pig_brain(), could be removed maybe.
463 */
playing(int sound)464 int playing(int sound)
465 {
466 if (sound >= MAX_SOUNDS)
467 {
468 log_error("Attempting to get the status of sound %d (> MAX_SOUNDS=%d)",
469 sound, MAX_SOUNDS);
470 return 0;
471 }
472
473 return (get_channel(sound) != -1);
474 }
475
476
477 /**
478 * Kill repeating sounds except the ones that survive
479 */
kill_repeat_sounds(void)480 void kill_repeat_sounds(void)
481 {
482 int i;
483 if (!sound_on)
484 return;
485
486 log_info("Killing repeating sound");
487
488 for (i = 0; i < NUM_CHANNELS; i++)
489 {
490 // Msg("Bank #%d: repeat=%d, owner=%d, survive=%d", i,
491 // soundinfo[i].repeat, soundinfo[i].owner, soundinfo[i].survive);
492 if (channelinfo[i].repeat && (channelinfo[i].owner == 0)
493 && (channelinfo[i].survive == 0))
494 {
495 Mix_HaltChannel(i);
496 log_info("Killed repeating sound %d", i);
497 channelinfo[i].repeat = 0;
498 }
499 }
500 }
501
502 /**
503 * Kill all repeating sounds, even the ones that survive (used from
504 * DinkC's restart_game() and load_game())
505 */
kill_repeat_sounds_all(void)506 void kill_repeat_sounds_all(void)
507 {
508 int i;
509 if (!sound_on)
510 return;
511
512 for (i = 0; i < NUM_CHANNELS; i++)
513 {
514 if (channelinfo[i].repeat && (channelinfo[i].owner == 0))
515 {
516 Mix_HaltChannel(i);
517 channelinfo[i].repeat = 0;
518 }
519 }
520 }
521
522 /**
523 * Kill one sound
524 */
kill_this_sound(int channel)525 void kill_this_sound(int channel)
526 {
527 Mix_HaltChannel(channel);
528 }
529
530 /**
531 * Called by update_frame()
532 *
533 * If sound is active, refreshed pan&vol for 3D effect.
534 *
535 * If repeating and sprite.sound==0 and sprite.owner!=0 -> stop sound
536 * If sprite.active==0 and sprite.owner!=0 -> stop sound
537 */
update_sound(void)538 void update_sound(void)
539 {
540 int i;
541
542 if (!sound_on)
543 return;
544
545 for (i = 0; i < NUM_CHANNELS; i++)
546 {
547 if (channelinfo[i].repeat && (channelinfo[i].owner != 0))
548 {
549 if ((spr[channelinfo[i].owner].sound == 0)
550 || (spr[channelinfo[i].owner].active == /*false*/0) )
551 {
552 Mix_HaltChannel(i);
553 channelinfo[i].owner = 0;
554 channelinfo[i].repeat = 0;
555 }
556 else
557 {
558 SetPan(i, get_pan(channelinfo[i].owner));
559 SetVolume(i, get_vol(channelinfo[i].owner));
560 }
561 }
562
563 if (Mix_Playing(i))
564 {
565 if (channelinfo[i].owner != 0)
566 {
567 if (spr[channelinfo[i].owner].active == /*false*/0)
568 {
569 Mix_HaltChannel(i);
570 }
571 else
572 {
573 SetPan(i, get_pan(channelinfo[i].owner));
574 SetVolume(i, get_vol(channelinfo[i].owner));
575 }
576 }
577 }
578 }
579 }
580
581
582 static int SoundPlayEffectChannel(int sound, int min, int plus, int sound3d, /*bool*/int repeat, int explicit_channel);
583
584 /**
585 * Just play a sound, do not try to update sprites info or apply
586 * effects
587 */
EditorSoundPlayEffect(int sound)588 void EditorSoundPlayEffect(int sound)
589 {
590 /* Don't print warning if the sound isn't present - as sounds are
591 played continuously when arrow keys are pressed */
592 if (registered_sounds[sound].cvt.buf != NULL)
593 SoundPlayEffectChannel(sound, registered_sounds[sound].orig_spec.freq, 0, 0, 0, 0);
594 }
595
596 /**
597 * Play a sound previously loaded to memory (in registered_sounds)
598 * - sound: sound index
599 * - min: frequency (Hz)
600 * - plus: max random frequency, to add to min
601 * - sound3d: if != 0, sprite number whose location will be used for
602 * pseudo-3d effects (volume, panning)
603 * - repeat: is sound looping?
604 **/
SoundPlayEffect(int sound,int min,int plus,int sound3d,int repeat)605 int SoundPlayEffect(int sound, int min, int plus, int sound3d, /*bool*/int repeat)
606 {
607 return SoundPlayEffectChannel(sound, min, plus, sound3d, repeat, -1);
608 }
609 /**
610 * SoundPlayEffect_Channel_ allows to specify an explicit audio
611 * channel, which in turns allows the editor to only use one channel
612 * for everything (when you move the mouse with the keyboard, you'll
613 * hear a series of close 'ticks', but they won't overlap each
614 * others). The rest of the time, the game will just pass '-1' for the
615 * channel, so the first available channel (among NUM_CHANNELS useable
616 * simultaneously) will be selected.
617 */
SoundPlayEffectChannel(int sound,int min,int plus,int sound3d,int repeat,int explicit_channel)618 static int SoundPlayEffectChannel(int sound, int min, int plus, int sound3d, /*bool*/int repeat, int explicit_channel)
619 {
620 int channel;
621
622 // Safety check
623 if (registered_sounds[sound].cvt.buf == NULL)
624 {
625 log_warn("Attempting to play empty sound %d.", sound);
626 return 0;
627 }
628
629 /* Sample rate / frequency */
630 {
631 /** Shift:
632 hw_adjust = wave_freq / hw_freq;
633 sample_rate_adjust = play_freq / wave_freq
634 shift = hw_adjust * sample_rate_adjust = wave_freq/hw_freq * play_freq/wave_freq
635 <<8 because we're using 1/256th units (poor man's double)
636 */
637 int play_freq;
638 if (plus == 0)
639 play_freq = min;
640 else
641 play_freq = (rand () % plus) + min;
642
643 /* Compute how much we should advance in the original sound when we
644 play one frame with hw_freq */
645 int shift = ((int)round((double)play_freq / hw_freq * (1<<8)));
646 /* printf("shift=%d (%d*64)\n", shift, shift>>8); */
647
648 /* Fake buffer: we give an empty buffer to SDL_mixer. We won't
649 actually play from that buffer though, as the audio buffer will
650 be generated in callback_samplerate(). That function will also
651 take care of updating the channelinfo when it's finished (and
652 should be cleaned from a non-callback function). */
653 Mix_Chunk *chunk = Mix_QuickLoad_RAW(fake_buf, fake_buf_len);
654
655 channel = Mix_PlayChannel(explicit_channel, chunk, -1);
656 if (channel < 0)
657 {
658 log_error("Mix_PlayChannel: Error playing sound %d - %s",
659 sound, Mix_GetError());
660 return 0;
661 }
662 Mix_Pause(channel);
663 channelinfo[channel].finished = 0;
664 channelinfo[channel].looping = repeat;
665
666 struct callback_data *data = calloc(1, sizeof(struct callback_data));
667 data->pos = 0;
668 data->shift = shift;
669 data->sound = sound;
670 data->channel = channel;
671
672 Mix_RegisterEffect(channel, callback_samplerate, callback_samplerate_cleanup, data);
673 Mix_ChannelFinished(CleanupChannel);
674 Mix_Resume(channel);
675 }
676
677
678 if (sound3d > 0)
679 {
680 SetPan(channel, get_pan(sound3d));
681 SetVolume(channel, get_vol(sound3d));
682 }
683
684
685 channelinfo[channel].owner = sound3d;
686 channelinfo[channel].repeat = repeat;
687 channelinfo[channel].survive = 0;
688 channelinfo[channel].cur_sound = sound;
689
690 /* Return a non-zero channel */
691 return channel+1;
692 }
693
694 /**
695 * SoundStopEffect
696 *
697 * Stops the sound effect specified.
698 * Returns TRUE if succeeded.
699 */
SoundStopEffect(int sound)700 int SoundStopEffect(int sound)
701 {
702 int channel;
703
704 if (sound >= MAX_SOUNDS)
705 {
706 log_error("Attempting to get stop sound %d (> MAX_SOUNDS=%d)",
707 sound, MAX_SOUNDS);
708 return 0;
709 }
710
711 channel = get_channel(sound);
712 if (channel < 0)
713 return 0;
714 else
715 return Mix_HaltChannel(channel); /* always returns 0 */
716 }
717
718
719 /**
720 * InitSound
721 *
722 * Sets up the DirectSound object and loads all sounds into secondary
723 * DirectSound buffers. Returns -1 on error, or 0 if successful
724 */
InitSound()725 int InitSound()
726 {
727 log_info("initting sound");
728
729 if (SDL_Init(SDL_INIT_AUDIO) == -1)
730 {
731 log_error("SDL_Init(SDL_INIT_AUDIO): %s", SDL_GetError());
732 return -1;
733 }
734
735 /* Work-around to disable fluidsynth and fallback to TiMidity++: */
736 /* TODO: allow user to set it at run-time */
737 /* SDL_putenv("SDL_SOUNDFONTS="); */
738 /* SDL_putenv("SDL_FORCE_SOUNDFONTS=1"); */
739
740 /* MIX_DEFAULT_FREQUENCY is ~22kHz are considered a good default,
741 44kHz is considered too CPU-intensive on older computers */
742 /* MIX_DEFAULT_FORMAT is 16bit adapted to current architecture
743 (little/big endian) */
744 /* MIX_DEFAULT_CHANNELS is 2 => stereo, allowing panning effects */
745 /* 1024 (chunk on which effects are applied) seems a good default,
746 4096 is considered too big for SFX */
747 int buf_samples = 1024;
748 if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, buf_samples) == -1)
749 {
750 log_error("Mix_OpenAudio: %s", Mix_GetError());
751 return -1;
752 }
753
754 /* Allocate channels (not mono/stereo, but the simultaneous sounds
755 to be mixed, possibly with effects) */
756 Mix_AllocateChannels(NUM_CHANNELS);
757
758 /* Done with initialization */
759 /* Avoid calling SDL_PauseAudio when using SDL_Mixer */
760 /* SDL_PauseAudio(0); */
761
762 /* Dump audio info */
763 {
764 char namebuf[128] = "";
765 SDL_AudioDriverName(namebuf, 128);
766 log_info("Audio driver: %s", namebuf);
767
768 int numtimesopened;
769 numtimesopened = Mix_QuerySpec(&hw_freq, &hw_format, &hw_channels);
770 if (!numtimesopened)
771 log_error("Mix_QuerySpec: %s", Mix_GetError());
772 else
773 log_info("Audio hardware info: frequency=%dHz\tformat=%s\tchannels=%d\topened=%d times",
774 hw_freq, format2string(hw_format), hw_channels, numtimesopened);
775 }
776
777 /* Test SDL_mixer capabilities */
778 {
779 int i, total;
780 total = Mix_GetNumChunkDecoders();
781 for (i = 0; i < total; i++)
782 log_info("Audio chunk decoder: %s", Mix_GetChunkDecoder(i));
783
784 total = Mix_GetNumMusicDecoders();
785 int ogg_available = 0;
786 for (i = 0; i < total; i++) {
787 if (strcmp(Mix_GetMusicDecoder(i), "OGG") == 0)
788 ogg_available = 1;
789 if (strcmp(Mix_GetMusicDecoder(i), "MP3") == 0)
790 log_info("Audio music decoder: MP3 (MP3 is patented, prefer Ogg Vorbis!)");
791 else
792 log_info("Audio music decoder: %s", Mix_GetMusicDecoder(i));
793 }
794 if (!ogg_available)
795 log_error("Audio music decoder: no Ogg support");
796
797 int available;
798 /* Don't mess with loading/unloading too much */
799 /*
800 available = Mix_Init(MIX_INIT_MOD); // libmikmod
801 log_info("Audio dynload: MOD %s", available ? "ok" : Mix_GetError());
802 available = Mix_Init(MIX_INIT_MODPLUG); // libmodplug
803 log_info("Audio dynload: MODPLUG %s", available ? "ok" : Mix_GetError());
804 available = Mix_Init(MIX_INIT_FLUIDSYNTH);
805 log_info("Audio dynload: FLUIDSYNTH %s", available ? "ok" : Mix_GetError());
806 available = Mix_Init(MIX_INIT_FLAC);
807 log_info("Audio dynload: FLAC %s", available ? "ok" : Mix_GetError());
808 available = Mix_Init(MIX_INIT_MP3);
809 log_info("Audio dynload: MP3 %s", available ? "ok" : Mix_GetError());
810 Mix_Quit();
811 */
812 available = Mix_Init(MIX_INIT_OGG);
813 log_info("Audio dynload: OGG: %s", available ? "ok" : Mix_GetError());
814 if (!available)
815 log_error("Audio dynload: no Ogg support");
816
817 // TODO: test MOD support (btw does mikmod and modplug conflict?)
818 }
819
820 /* Allocate fake buffer - use the same size as the audio buffer */
821 fake_buf_len = buf_samples;
822 fake_buf_len *= hw_channels;
823 if (hw_format != AUDIO_U8 && hw_format != AUDIO_S8)
824 /* 2 bytes per frame */
825 fake_buf_len *= 2;
826 fake_buf = calloc(1, fake_buf_len);
827
828 /* No sound playing yet - initialize the lookup table: */
829 memset(channelinfo, 0, sizeof(channelinfo));
830 int i;
831 for (i = 0; i < NUM_CHANNELS; i++)
832 {
833 channelinfo[i].cur_sound = -1;
834 channelinfo[i].finished = 0;
835 channelinfo[i].looping = 0;
836 }
837
838 /* No sound loaded yet - initialise the registered sounds: */
839 memset(registered_sounds, 0, sizeof(registered_sounds));
840 /* Make sure they won't be used: */
841 for (i = 0; i < MAX_SOUNDS; i++)
842 registered_sounds[i].cvt.buf = NULL;
843
844 return 0;
845 }
846
847 /**
848 * Undoes everything that was done in a InitSound call
849 */
QuitSound(void)850 void QuitSound(void)
851 {
852 if (SDL_WasInit(SDL_INIT_AUDIO) == 0)
853 return;
854
855 /* Stops all SFX channels */
856 Mix_HaltChannel(-1);
857
858 /**
859 * Frees up resources associated with a sound effect
860 */
861 int idxKill = 0;
862 for (; idxKill < MAX_SOUNDS; idxKill++)
863 FreeRegisteredSound(idxKill);
864
865 free(fake_buf);
866
867 Mix_CloseAudio();
868 SDL_QuitSubSystem(SDL_INIT_AUDIO);
869 }
870
871 /**
872 * Print SFX memory usage
873 */
sfx_log_meminfo()874 void sfx_log_meminfo()
875 {
876 int sum = 0;
877 int i = 0;
878
879 sum = 0;
880 for (i = 0; i < MAX_SOUNDS; i++)
881 {
882 if (registered_sounds[i].cvt.buf != NULL)
883 sum += registered_sounds[i].cvt_buf_len;
884 }
885 log_debug("Sounds = %8d", sum);
886 }
887
888
889 /**
890 * Free memory used by sound #'sound'
891 */
FreeRegisteredSound(int sound)892 static void FreeRegisteredSound(int sound)
893 {
894 if (registered_sounds[sound].cvt.buf != NULL)
895 /* cvt.buf was malloc'd by us before. It's used both as source and
896 destination by 'SDL_ConvertAudio', so it's not realloc'd in the
897 process, and we use 'free' (and not a SDL-specific func): */
898 free(registered_sounds[sound].cvt.buf);
899
900 memset(®istered_sounds[sound], 0, sizeof (registered_sounds[sound]));
901 /* Make sure it won't be reused: */
902 registered_sounds[sound].cvt.buf = NULL;
903 }
904
905 /**
906 * Free chunk once it's played (through Mix_ChannelFinished()
907 * callback)
908 */
CleanupChannel(int channel)909 static void CleanupChannel(int channel)
910 {
911 /* SDL_mixer won't try to free the actual audio buffer (fake_buf) if
912 the Chunk was loaded via Mix_QuickLoad_RAW() - which is a good
913 thing since fake_buf is shared by all Chunks. We still need to
914 free the Chunk when it's done playing. */
915 Mix_Chunk *chunk = Mix_GetChunk(channel);
916 if (chunk == NULL)
917 {
918 log_fatal("Internal error: cannot free channel %d's chunk (where did it disappear?)", channel);
919 exit(1);
920 }
921 Mix_FreeChunk(chunk);
922 channelinfo[channel].finished = 0;
923 channelinfo[channel].looping = 0;
924 channelinfo[channel].cur_sound = -1;
925
926 /* Revert SetVolume and SetPan effects */
927 Mix_UnregisterAllEffects(channel);
928 Mix_Volume(channel, MIX_MAX_VOLUME);
929 }
930
931
932 /**
933 * Set volume; dx_volume is [-10000;10000] in hundredth of dB
934 */
SetVolume(int channel,int dx_volume)935 static int SetVolume(int channel, int dx_volume)
936 {
937 // SFX
938 /* See doc/sound.txt for details */
939 return Mix_Volume(channel, MIX_MAX_VOLUME * pow(10, ((double)dx_volume / 100) / 20));
940 }
941
942
943 /**
944 * Set left/right balance; dx_panning is [-10000;10000] in hundredth
945 * of dB, -ive is right channel attenuation, +ive is left channel
946 * attenuation
947 */
SetPan(int channel,int dx_panning)948 static int SetPan(int channel, int dx_panning)
949 {
950 // SFX
951 /* See doc/sound.txt for details */
952 if (dx_panning > 0)
953 return Mix_SetPanning(channel, 255 * pow(10, ((double)-dx_panning / 100) / 20), 255);
954 else
955 return Mix_SetPanning(channel, 255, 255 * pow(10, ((double)dx_panning / 100) / 20));
956 }
957
958
959 /** DinkC procedures **/
960 /* BIG FAT WARNING: in DinkC, soundbank is channel+1
961 (a.k.a. non-zero), and 0 means failure. */
playsound(int sound,int min,int plus,int sound3d,int repeat)962 int playsound(int sound, int min, int plus, int sound3d, int repeat)
963 {
964 int channel = SoundPlayEffect(sound, min, plus, sound3d, repeat);
965 int soundbank = channel + 1;
966 return soundbank;
967 }
sound_set_kill(int soundbank)968 void sound_set_kill(int soundbank)
969 {
970 int channel = soundbank - 1;
971 Mix_HaltChannel(channel);
972 }
sound_set_survive(int soundbank,int survive)973 void sound_set_survive(int soundbank, int survive)
974 {
975 int channel = soundbank - 1;
976 channelinfo[channel].survive = survive;
977 }
sound_set_vol(int soundbank,int volume)978 void sound_set_vol(int soundbank, int volume)
979 {
980 int channel = soundbank - 1;
981 SetVolume(channel, volume);
982 }
983