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(&registered_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