major cleanup of preprocessor hell
[rocksndiamonds.git] / src / libgame / sound.c
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // sound.c
10 // ============================================================================
11
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <dirent.h>
18 #include <signal.h>
19 #include <math.h>
20 #include <errno.h>
21
22 #include "platform.h"
23 #include "system.h"
24 #include "sound.h"
25 #include "misc.h"
26 #include "setup.h"
27 #include "text.h"
28
29
30 /* expiration time (in milliseconds) for sound loops */
31 #define SOUND_LOOP_EXPIRATION_TIME      200
32
33 /* one second fading interval == 1000 ticks (milliseconds) */
34 #define SOUND_FADING_INTERVAL           1000
35
36 #define SND_TYPE_NONE                   0
37 #define SND_TYPE_WAV                    1
38
39 #define MUS_TYPE_NONE                   0
40 #define MUS_TYPE_WAV                    1
41 #define MUS_TYPE_MOD                    2
42
43 #define DEVICENAME_DSP                  "/dev/dsp"
44 #define DEVICENAME_SOUND_DSP            "/dev/sound/dsp"
45 #define DEVICENAME_AUDIO                "/dev/audio"
46 #define DEVICENAME_AUDIOCTL             "/dev/audioCtl"
47
48 #define SOUND_VOLUME_LEFT(x)            (stereo_volume[x])
49 #define SOUND_VOLUME_RIGHT(x)           (stereo_volume[SOUND_MAX_LEFT2RIGHT-x])
50
51 #define SAME_SOUND_NR(x,y)              ((x).nr == (y).nr)
52 #define SAME_SOUND_DATA(x,y)            ((x).data_ptr == (y).data_ptr)
53
54 #define SOUND_VOLUME_FROM_PERCENT(v,p)  ((p) < 0   ? SOUND_MIN_VOLUME : \
55                                          (p) > 100 ? (v) :              \
56                                          (p) * (v) / 100)
57
58 #define SOUND_VOLUME_SIMPLE(v) SOUND_VOLUME_FROM_PERCENT(v, setup.volume_simple)
59 #define SOUND_VOLUME_LOOPS(v)  SOUND_VOLUME_FROM_PERCENT(v, setup.volume_loops)
60 #define SOUND_VOLUME_MUSIC(v)  SOUND_VOLUME_FROM_PERCENT(v, setup.volume_music)
61
62 #define SETUP_SOUND_VOLUME(v,s)         ((s) == SND_CTRL_PLAY_MUSIC ?   \
63                                          SOUND_VOLUME_MUSIC(v) :        \
64                                          (s) == SND_CTRL_PLAY_LOOP ?    \
65                                          SOUND_VOLUME_LOOPS(v) :        \
66                                          SOUND_VOLUME_SIMPLE(v))
67
68 struct AudioFormatInfo
69 {
70   boolean stereo;               /* availability of stereo sound */
71   int format;                   /* size and endianess of sample data */
72   int sample_rate;              /* sample frequency */
73   int fragment_size;            /* audio device fragment size in bytes */
74 };
75
76 struct SampleInfo
77 {
78   char *source_filename;
79   int num_references;
80
81   int type;
82   int format;
83   void *data_ptr;               /* pointer to first sample (8 or 16 bit) */
84   int data_len;                 /* number of samples, NOT number of bytes */
85   int num_channels;             /* mono: 1 channel, stereo: 2 channels */
86 };
87 typedef struct SampleInfo SoundInfo;
88 typedef struct SampleInfo MusicInfo;
89
90 struct SoundControl
91 {
92   boolean active;
93
94   int nr;
95   int volume;
96   int stereo_position;
97
98   int state;
99
100   unsigned int playing_starttime;
101   unsigned int playing_pos;
102
103   int type;
104   int format;
105   void *data_ptr;               /* pointer to first sample (8 or 16 bit) */
106   int data_len;         /* number of samples, NOT number of bytes */
107   int num_channels;             /* mono: 1 channel, stereo: 2 channels */
108 };
109 typedef struct SoundControl SoundControl;
110
111 static struct ArtworkListInfo *sound_info = NULL;
112 static struct ArtworkListInfo *music_info = NULL;
113
114 static MusicInfo **Music_NoConf = NULL;
115
116 static int num_music_noconf = 0;
117 static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1];
118
119
120 /* ========================================================================= */
121 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS            */
122
123 static struct SoundControl mixer[NUM_MIXER_CHANNELS];
124 static int mixer_active_channels = 0;
125
126 static void ReloadCustomSounds();
127 static void ReloadCustomMusic();
128 static void FreeSound(void *);
129 static void FreeMusic(void *);
130 static void FreeAllMusic_NoConf();
131
132 static SoundInfo *getSoundInfoEntryFromSoundID(int);
133 static MusicInfo *getMusicInfoEntryFromMusicID(int);
134
135
136 /* ------------------------------------------------------------------------- */
137 /* mixer functions                                                           */
138 /* ------------------------------------------------------------------------- */
139
140 void Mixer_InitChannels()
141 {
142   int i;
143
144   for (i = 0; i < audio.num_channels; i++)
145     mixer[i].active = FALSE;
146   mixer_active_channels = 0;
147 }
148
149 static void Mixer_ResetChannelExpiration(int channel)
150 {
151   mixer[channel].playing_starttime = Counter();
152
153   if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
154     Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME);
155 }
156
157 static boolean Mixer_ChannelExpired(int channel)
158 {
159   if (!mixer[channel].active)
160     return TRUE;
161
162   if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
163       DelayReached(&mixer[channel].playing_starttime,
164                    SOUND_LOOP_EXPIRATION_TIME))
165     return TRUE;
166
167   if (!Mix_Playing(channel))
168     return TRUE;
169
170   return FALSE;
171 }
172
173 static boolean Mixer_AllocateChannel(int channel)
174 {
175   return TRUE;
176 }
177
178 static void Mixer_SetChannelProperties(int channel)
179 {
180   Mix_Volume(channel, mixer[channel].volume);
181   Mix_SetPanning(channel,
182                  SOUND_VOLUME_LEFT(mixer[channel].stereo_position),
183                  SOUND_VOLUME_RIGHT(mixer[channel].stereo_position));
184 }
185
186 static void Mixer_StartChannel(int channel)
187 {
188   Mix_PlayChannel(channel, mixer[channel].data_ptr,
189                   IS_LOOP(mixer[channel]) ? -1 : 0);
190 }
191
192 static void Mixer_PlayChannel(int channel)
193 {
194   /* start with inactive channel in case something goes wrong */
195   mixer[channel].active = FALSE;
196
197   if (mixer[channel].type != MUS_TYPE_WAV)
198     return;
199
200   if (!Mixer_AllocateChannel(channel))
201     return;
202
203   Mixer_SetChannelProperties(channel);
204   Mixer_StartChannel(channel);
205
206   Mixer_ResetChannelExpiration(channel);
207
208   mixer[channel].playing_pos = 0;
209   mixer[channel].active = TRUE;
210   mixer_active_channels++;
211 }
212
213 static void Mixer_PlayMusicChannel()
214 {
215   Mixer_PlayChannel(audio.music_channel);
216
217   if (mixer[audio.music_channel].type != MUS_TYPE_WAV)
218   {
219     /* Mix_VolumeMusic() must be called _after_ Mix_PlayMusic() --
220        this looks like a bug in the SDL_mixer library */
221     Mix_PlayMusic(mixer[audio.music_channel].data_ptr, -1);
222     Mix_VolumeMusic(mixer[audio.music_channel].volume);
223   }
224 }
225
226 static void Mixer_StopChannel(int channel)
227 {
228   if (!mixer[channel].active)
229     return;
230
231   Mix_HaltChannel(channel);
232
233   mixer[channel].active = FALSE;
234   mixer_active_channels--;
235 }
236
237 static void Mixer_StopMusicChannel()
238 {
239   Mixer_StopChannel(audio.music_channel);
240
241   Mix_HaltMusic();
242 }
243
244 static void Mixer_FadeChannel(int channel)
245 {
246   if (!mixer[channel].active)
247     return;
248
249   mixer[channel].state |= SND_CTRL_FADE;
250
251   Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL);
252 }
253
254 static void Mixer_FadeMusicChannel()
255 {
256   Mixer_FadeChannel(audio.music_channel);
257
258   Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
259 }
260
261 static void Mixer_UnFadeChannel(int channel)
262 {
263   if (!mixer[channel].active || !IS_FADING(mixer[channel]))
264     return;
265
266   mixer[channel].state &= ~SND_CTRL_FADE;
267   mixer[channel].volume = SOUND_MAX_VOLUME;
268
269   Mix_ExpireChannel(channel, -1);
270   Mix_Volume(channel, mixer[channel].volume);
271 }
272
273 static void Mixer_InsertSound(SoundControl snd_ctrl)
274 {
275   SoundInfo *snd_info;
276   int i, k;
277   int num_sounds = getSoundListSize();
278   int num_music  = getMusicListSize();
279
280   if (IS_MUSIC(snd_ctrl))
281   {
282     if (snd_ctrl.nr >= num_music)       /* invalid music */
283       return;
284
285     if (snd_ctrl.nr < 0)                /* undefined music */
286     {
287       if (num_music_noconf == 0)        /* no fallback music available */
288         return;
289
290       snd_ctrl.nr = UNMAP_NOCONF_MUSIC(snd_ctrl.nr) % num_music_noconf;
291       snd_info = Music_NoConf[snd_ctrl.nr];
292     }
293     else
294       snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr);
295   }
296   else
297   {
298     if (snd_ctrl.nr < 0 || snd_ctrl.nr >= num_sounds)
299       return;
300
301     snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
302   }
303
304   if (snd_info == NULL)
305     return;
306
307   /* copy sound sample and format information */
308   snd_ctrl.type         = snd_info->type;
309   snd_ctrl.format       = snd_info->format;
310   snd_ctrl.data_ptr     = snd_info->data_ptr;
311   snd_ctrl.data_len     = snd_info->data_len;
312   snd_ctrl.num_channels = snd_info->num_channels;
313
314   /* play music samples on a dedicated music channel */
315   if (IS_MUSIC(snd_ctrl))
316   {
317     Mixer_StopMusicChannel();
318
319     mixer[audio.music_channel] = snd_ctrl;
320     Mixer_PlayMusicChannel();
321
322     return;
323   }
324
325   /* check if (and how often) this sound sample is already playing */
326   for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++)
327     if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
328       k++;
329
330   /* reset expiration delay for already playing loop sounds */
331   if (k > 0 && IS_LOOP(snd_ctrl))
332   {
333     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
334     {
335       if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
336       {
337         if (IS_FADING(mixer[i]))
338           Mixer_UnFadeChannel(i);
339
340         /* restore settings like volume and stereo position */
341         mixer[i].volume = snd_ctrl.volume;
342         mixer[i].stereo_position = snd_ctrl.stereo_position;
343
344         Mixer_SetChannelProperties(i);
345         Mixer_ResetChannelExpiration(i);
346       }
347     }
348
349     return;
350   }
351
352   /* don't play sound more than n times simultaneously (with n == 2 for now) */
353   if (k >= 2)
354   {
355     unsigned int playing_current = Counter();
356     int longest = 0, longest_nr = audio.first_sound_channel;
357
358     /* look for oldest equal sound */
359     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
360     {
361       int playing_time = playing_current - mixer[i].playing_starttime;
362       int actual;
363
364       if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
365         continue;
366
367       actual = 1000 * playing_time / mixer[i].data_len;
368
369       if (actual >= longest)
370       {
371         longest = actual;
372         longest_nr = i;
373       }
374     }
375
376     Mixer_StopChannel(longest_nr);
377   }
378
379   /* If all (non-music) channels are active, stop the channel that has
380      played its sound sample most completely (in percent of the sample
381      length). As we cannot currently get the actual playing position
382      of the channel's sound sample when compiling with the SDL mixer
383      library, we use the current playing time (in milliseconds) instead. */
384
385 #if DEBUG
386   /* channel allocation sanity check -- should not be needed */
387   if (mixer_active_channels ==
388       audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
389   {
390     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
391     {
392       if (!mixer[i].active)
393       {
394         Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i);
395         Error(ERR_INFO, "Mixer_InsertSound: This should never happen!");
396
397         mixer_active_channels--;
398       }
399     }
400   }
401 #endif
402
403   if (mixer_active_channels ==
404       audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
405   {
406     unsigned int playing_current = Counter();
407     int longest = 0, longest_nr = audio.first_sound_channel;
408
409     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
410     {
411       int playing_time = playing_current - mixer[i].playing_starttime;
412       int actual = 1000 * playing_time / mixer[i].data_len;
413
414       if (!IS_LOOP(mixer[i]) && actual > longest)
415       {
416         longest = actual;
417         longest_nr = i;
418       }
419     }
420
421     Mixer_StopChannel(longest_nr);
422   }
423
424   /* add the new sound to the mixer */
425   for (i = audio.first_sound_channel; i < audio.num_channels; i++)
426   {
427     if (!mixer[i].active)
428     {
429       mixer[i] = snd_ctrl;
430       Mixer_PlayChannel(i);
431
432       break;
433     }
434   }
435 }
436
437 static void HandleSoundRequest(SoundControl snd_ctrl)
438 {
439   int i;
440
441   /* deactivate channels that have expired since the last request */
442   for (i = 0; i < audio.num_channels; i++)
443     if (mixer[i].active && Mixer_ChannelExpired(i))
444       Mixer_StopChannel(i);
445
446   if (IS_RELOADING(snd_ctrl))           /* load new sound or music files */
447   {
448     Mixer_StopMusicChannel();
449     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
450       Mixer_StopChannel(i);
451
452     if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
453       ReloadCustomSounds();
454     else
455       ReloadCustomMusic();
456   }
457   else if (IS_FADING(snd_ctrl))         /* fade out existing sound or music */
458   {
459     if (IS_MUSIC(snd_ctrl))
460     {
461       Mixer_FadeMusicChannel();
462       return;
463     }
464
465     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
466       if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
467         Mixer_FadeChannel(i);
468   }
469   else if (IS_STOPPING(snd_ctrl))       /* stop existing sound or music */
470   {
471     if (IS_MUSIC(snd_ctrl))
472     {
473       Mixer_StopMusicChannel();
474       return;
475     }
476
477     for (i = audio.first_sound_channel; i < audio.num_channels; i++)
478       if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
479         Mixer_StopChannel(i);
480   }
481   else if (snd_ctrl.active)             /* add new sound to mixer */
482   {
483     Mixer_InsertSound(snd_ctrl);
484   }
485 }
486
487 void StartMixer(void)
488 {
489   int i;
490
491   if (!audio.sound_available)
492     return;
493
494   /* initialize stereo position conversion information */
495   for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
496     stereo_volume[i] =
497       (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
498 }
499
500
501 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS            */
502 /* ========================================================================= */
503 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS                          */
504
505 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
506 #define WAV_HEADER_SIZE         16      /* size of WAV file header */
507
508 static void *Load_WAV(char *filename)
509 {
510   SoundInfo *snd_info;
511
512   if (!audio.sound_available)
513     return NULL;
514
515   snd_info = checked_calloc(sizeof(SoundInfo));
516
517   if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
518   {
519     Error(ERR_WARN, "cannot read sound file '%s'", filename);
520     free(snd_info);
521     return NULL;
522   }
523
524   snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
525
526   snd_info->type = SND_TYPE_WAV;
527   snd_info->source_filename = getStringCopy(filename);
528
529   return snd_info;
530 }
531
532 static void *Load_MOD(char *filename)
533 {
534   MusicInfo *mod_info;
535
536   if (!audio.sound_available)
537     return NULL;
538
539   mod_info = checked_calloc(sizeof(MusicInfo));
540
541   if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
542   {
543     Error(ERR_WARN, "cannot read music file '%s'", filename);
544     free(mod_info);
545     return NULL;
546   }
547
548   mod_info->type = MUS_TYPE_MOD;
549   mod_info->source_filename = getStringCopy(filename);
550
551   return mod_info;
552 }
553
554 static void *Load_WAV_or_MOD(char *filename)
555 {
556   if (FileIsMusic(filename))
557     return Load_MOD(filename);
558   else if (FileIsSound(filename))
559     return Load_WAV(filename);
560   else
561     return NULL;
562 }
563
564 void LoadCustomMusic_NoConf(void)
565 {
566   static boolean draw_init_text = TRUE;         /* only draw at startup */
567   static char *last_music_directory = NULL;
568   char *music_directory = getCustomMusicDirectory();
569   Directory *dir;
570   DirectoryEntry *dir_entry;
571   int num_music = getMusicListSize();
572
573   if (!audio.sound_available)
574     return;
575
576   if (last_music_directory != NULL &&
577       strEqual(last_music_directory, music_directory))
578     return;     /* old and new music directory are the same */
579
580   if (last_music_directory != NULL)
581     free(last_music_directory);
582   last_music_directory = getStringCopy(music_directory);
583
584   FreeAllMusic_NoConf();
585
586   if ((dir = openDirectory(music_directory)) == NULL)
587   {
588     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
589
590     audio.music_available = FALSE;
591
592     return;
593   }
594
595   if (draw_init_text)
596     DrawInitText("Loading music", 120, FC_GREEN);
597
598   while ((dir_entry = readDirectory(dir)) != NULL)      /* loop all entries */
599   {
600     char *basename = dir_entry->basename;
601     char *filename = NULL;
602     MusicInfo *mus_info = NULL;
603     boolean music_already_used = FALSE;
604     int i;
605
606     /* skip all music files that are configured in music config file */
607     for (i = 0; i < num_music; i++)
608     {
609       struct FileInfo *music = getMusicListEntry(i);
610
611       if (strEqual(basename, music->filename))
612       {
613         music_already_used = TRUE;
614         break;
615       }
616     }
617
618     if (music_already_used)
619       continue;
620
621     if (draw_init_text)
622       DrawInitText(basename, 150, FC_YELLOW);
623
624     filename = getPath2(music_directory, basename);
625
626     if (FileIsMusic(basename))
627       mus_info = Load_WAV_or_MOD(filename);
628
629     free(filename);
630
631     if (mus_info)
632     {
633       num_music_noconf++;
634       Music_NoConf = checked_realloc(Music_NoConf,
635                                      num_music_noconf * sizeof(MusicInfo *));
636       Music_NoConf[num_music_noconf - 1] = mus_info;
637     }
638   }
639
640   closeDirectory(dir);
641
642   draw_init_text = FALSE;
643 }
644
645 int getSoundListSize()
646 {
647   return (sound_info->num_file_list_entries +
648           sound_info->num_dynamic_file_list_entries);
649 }
650
651 int getMusicListSize()
652 {
653   return (music_info->num_file_list_entries +
654           music_info->num_dynamic_file_list_entries);
655 }
656
657 struct FileInfo *getSoundListEntry(int pos)
658 {
659   int num_list_entries = sound_info->num_file_list_entries;
660   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
661
662   return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
663           &sound_info->dynamic_file_list[list_pos]);
664 }
665
666 struct FileInfo *getMusicListEntry(int pos)
667 {
668   int num_list_entries = music_info->num_file_list_entries;
669   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
670
671   return (pos < num_list_entries ? &music_info->file_list[list_pos] :
672           &music_info->dynamic_file_list[list_pos]);
673 }
674
675 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
676 {
677   int num_list_entries = sound_info->num_file_list_entries;
678   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
679   SoundInfo **snd_info =
680     (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
681                    sound_info->dynamic_artwork_list);
682
683   return snd_info[list_pos];
684 }
685
686 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
687 {
688   int num_list_entries = music_info->num_file_list_entries;
689   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
690   MusicInfo **mus_info =
691     (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
692                    music_info->dynamic_artwork_list);
693
694   return mus_info[list_pos];
695 }
696
697 int getSoundListPropertyMappingSize()
698 {
699   return sound_info->num_property_mapping_entries;
700 }
701
702 int getMusicListPropertyMappingSize()
703 {
704   return music_info->num_property_mapping_entries;
705 }
706
707 struct PropertyMapping *getSoundListPropertyMapping()
708 {
709   return sound_info->property_mapping;
710 }
711
712 struct PropertyMapping *getMusicListPropertyMapping()
713 {
714   return music_info->property_mapping;
715 }
716
717 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
718                    struct ConfigTypeInfo *config_suffix_list,
719                    char **base_prefixes, char **ext1_suffixes,
720                    char **ext2_suffixes, char **ext3_suffixes,
721                    char **ignore_tokens)
722 {
723   int i;
724
725   sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
726   sound_info->type = ARTWORK_TYPE_SOUNDS;
727
728   /* ---------- initialize file list and suffix lists ---------- */
729
730   sound_info->num_file_list_entries = num_file_list_entries;
731   sound_info->num_dynamic_file_list_entries = 0;
732
733   sound_info->file_list =
734     getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
735                               num_file_list_entries);
736   sound_info->dynamic_file_list = NULL;
737
738   sound_info->num_suffix_list_entries = 0;
739   for (i = 0; config_suffix_list[i].token != NULL; i++)
740     sound_info->num_suffix_list_entries++;
741
742   sound_info->suffix_list = config_suffix_list;
743
744   /* ---------- initialize base prefix and suffixes lists ---------- */
745
746   sound_info->num_base_prefixes = 0;
747   for (i = 0; base_prefixes[i] != NULL; i++)
748     sound_info->num_base_prefixes++;
749
750   sound_info->num_ext1_suffixes = 0;
751   for (i = 0; ext1_suffixes[i] != NULL; i++)
752     sound_info->num_ext1_suffixes++;
753
754   sound_info->num_ext2_suffixes = 0;
755   for (i = 0; ext2_suffixes[i] != NULL; i++)
756     sound_info->num_ext2_suffixes++;
757
758   sound_info->num_ext3_suffixes = 0;
759   for (i = 0; ext3_suffixes[i] != NULL; i++)
760     sound_info->num_ext3_suffixes++;
761
762   sound_info->num_ignore_tokens = 0;
763   for (i = 0; ignore_tokens[i] != NULL; i++)
764     sound_info->num_ignore_tokens++;
765
766   sound_info->base_prefixes = base_prefixes;
767   sound_info->ext1_suffixes = ext1_suffixes;
768   sound_info->ext2_suffixes = ext2_suffixes;
769   sound_info->ext3_suffixes = ext3_suffixes;
770   sound_info->ignore_tokens = ignore_tokens;
771
772   sound_info->num_property_mapping_entries = 0;
773
774   sound_info->property_mapping = NULL;
775
776   /* ---------- initialize artwork reference and content lists ---------- */
777
778   sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
779
780   sound_info->artwork_list =
781     checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
782   sound_info->dynamic_artwork_list = NULL;
783
784   sound_info->content_list = NULL;
785
786   /* ---------- initialize artwork loading/freeing functions ---------- */
787
788   sound_info->load_artwork = Load_WAV;
789   sound_info->free_artwork = FreeSound;
790 }
791
792 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
793                    struct ConfigTypeInfo *config_suffix_list,
794                    char **base_prefixes, char **ext1_suffixes,
795                    char **ext2_suffixes, char **ext3_suffixes,
796                    char **ignore_tokens)
797 {
798   int i;
799
800   music_info = checked_calloc(sizeof(struct ArtworkListInfo));
801   music_info->type = ARTWORK_TYPE_MUSIC;
802
803   /* ---------- initialize file list and suffix lists ---------- */
804
805   music_info->num_file_list_entries = num_file_list_entries;
806   music_info->num_dynamic_file_list_entries = 0;
807
808   music_info->file_list =
809     getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
810                               num_file_list_entries);
811   music_info->dynamic_file_list = NULL;
812
813   music_info->num_suffix_list_entries = 0;
814   for (i = 0; config_suffix_list[i].token != NULL; i++)
815     music_info->num_suffix_list_entries++;
816
817   music_info->suffix_list = config_suffix_list;
818
819   /* ---------- initialize base prefix and suffixes lists ---------- */
820
821   music_info->num_base_prefixes = 0;
822   for (i = 0; base_prefixes[i] != NULL; i++)
823     music_info->num_base_prefixes++;
824
825   music_info->num_ext1_suffixes = 0;
826   for (i = 0; ext1_suffixes[i] != NULL; i++)
827     music_info->num_ext1_suffixes++;
828
829   music_info->num_ext2_suffixes = 0;
830   for (i = 0; ext2_suffixes[i] != NULL; i++)
831     music_info->num_ext2_suffixes++;
832
833   music_info->num_ext3_suffixes = 0;
834   for (i = 0; ext3_suffixes[i] != NULL; i++)
835     music_info->num_ext3_suffixes++;
836
837   music_info->num_ignore_tokens = 0;
838   for (i = 0; ignore_tokens[i] != NULL; i++)
839     music_info->num_ignore_tokens++;
840
841   music_info->base_prefixes = base_prefixes;
842   music_info->ext1_suffixes = ext1_suffixes;
843   music_info->ext2_suffixes = ext2_suffixes;
844   music_info->ext3_suffixes = ext3_suffixes;
845   music_info->ignore_tokens = ignore_tokens;
846
847   music_info->num_property_mapping_entries = 0;
848
849   music_info->property_mapping = NULL;
850
851   /* ---------- initialize artwork reference and content lists ---------- */
852
853   music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
854
855   music_info->artwork_list =
856     checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
857   music_info->dynamic_artwork_list = NULL;
858
859   music_info->content_list = NULL;
860
861   /* ---------- initialize artwork loading/freeing functions ---------- */
862
863   music_info->load_artwork = Load_WAV_or_MOD;
864   music_info->free_artwork = FreeMusic;
865 }
866
867 void PlayMusic(int nr)
868 {
869   if (!audio.music_available)
870     return;
871
872   PlaySoundMusic(nr);
873 }
874
875 void PlaySound(int nr)
876 {
877   if (!setup.sound_simple)
878     return;
879
880   PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
881 }
882
883 void PlaySoundStereo(int nr, int stereo_position)
884 {
885   if (!setup.sound_simple)
886     return;
887
888   PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
889 }
890
891 void PlaySoundLoop(int nr)
892 {
893   if (!setup.sound_loops)
894     return;
895
896   PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
897 }
898
899 void PlaySoundMusic(int nr)
900 {
901   if (!setup.sound_music)
902     return;
903
904   PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
905 }
906
907 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
908 {
909   SoundControl snd_ctrl;
910
911   if (!audio.sound_available ||
912       !audio.sound_enabled ||
913       audio.sound_deactivated)
914     return;
915
916   volume = SETUP_SOUND_VOLUME(volume, state);
917
918   if (volume < SOUND_MIN_VOLUME)
919     volume = SOUND_MIN_VOLUME;
920   else if (volume > SOUND_MAX_VOLUME)
921     volume = SOUND_MAX_VOLUME;
922
923   if (stereo_position < SOUND_MAX_LEFT)
924     stereo_position = SOUND_MAX_LEFT;
925   else if (stereo_position > SOUND_MAX_RIGHT)
926     stereo_position = SOUND_MAX_RIGHT;
927
928   clear_mem(&snd_ctrl, sizeof(SoundControl));   /* to make valgrind happy */
929
930   snd_ctrl.active = TRUE;
931   snd_ctrl.nr = nr;
932   snd_ctrl.volume = volume;
933   snd_ctrl.stereo_position = stereo_position;
934   snd_ctrl.state = state;
935
936   HandleSoundRequest(snd_ctrl);
937 }
938
939 void FadeMusic(void)
940 {
941   if (!audio.music_available)
942     return;
943
944   StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
945 }
946
947 void FadeSound(int nr)
948 {
949   StopSoundExt(nr, SND_CTRL_FADE_SOUND);
950 }
951
952 void FadeSounds()
953 {
954   StopSoundExt(-1, SND_CTRL_FADE_ALL);
955 }
956
957 void FadeSoundsAndMusic()
958 {
959   FadeSounds();
960   FadeMusic();
961 }
962
963 void StopMusic(void)
964 {
965   if (!audio.music_available)
966     return;
967
968   StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
969 }
970
971 void StopSound(int nr)
972 {
973   StopSoundExt(nr, SND_CTRL_STOP_SOUND);
974 }
975
976 void StopSounds()
977 {
978   StopMusic();
979   StopSoundExt(-1, SND_CTRL_STOP_ALL);
980 }
981
982 void StopSoundExt(int nr, int state)
983 {
984   SoundControl snd_ctrl;
985
986   if (!audio.sound_available)
987     return;
988
989   clear_mem(&snd_ctrl, sizeof(SoundControl));   /* to make valgrind happy */
990
991   snd_ctrl.active = FALSE;
992   snd_ctrl.nr = nr;
993   snd_ctrl.state = state;
994
995   HandleSoundRequest(snd_ctrl);
996 }
997
998 static void ReloadCustomSounds()
999 {
1000   LoadArtworkConfig(sound_info);
1001   ReloadCustomArtworkList(sound_info);
1002 }
1003
1004 static void ReloadCustomMusic()
1005 {
1006   LoadArtworkConfig(music_info);
1007   ReloadCustomArtworkList(music_info);
1008
1009   /* load all music files from directory not defined in "musicinfo.conf" */
1010   LoadCustomMusic_NoConf();
1011 }
1012
1013 void InitReloadCustomSounds(char *set_identifier)
1014 {
1015   if (!audio.sound_available)
1016     return;
1017
1018   ReloadCustomSounds();
1019 }
1020
1021 void InitReloadCustomMusic(char *set_identifier)
1022 {
1023   if (!audio.music_available)
1024     return;
1025
1026   ReloadCustomMusic();
1027 }
1028
1029 void FreeSound(void *ptr)
1030 {
1031   SoundInfo *sound = (SoundInfo *)ptr;
1032
1033   if (sound == NULL)
1034     return;
1035
1036   if (sound->data_ptr)
1037   {
1038     Mix_FreeChunk(sound->data_ptr);
1039   }
1040
1041   checked_free(sound->source_filename);
1042
1043   free(sound);
1044 }
1045
1046 void FreeMusic(void *ptr)
1047 {
1048   MusicInfo *music = (MusicInfo *)ptr;
1049
1050   if (music == NULL)
1051     return;
1052
1053   if (music->data_ptr)
1054   {
1055     if (music->type == MUS_TYPE_MOD)
1056       Mix_FreeMusic(music->data_ptr);
1057     else
1058       Mix_FreeChunk(music->data_ptr);
1059   }
1060
1061   free(music);
1062 }
1063
1064 static void FreeAllMusic_NoConf()
1065 {
1066   int i;
1067
1068   if (Music_NoConf == NULL)
1069     return;
1070
1071   for (i = 0; i < num_music_noconf; i++)
1072     FreeMusic(Music_NoConf[i]);
1073
1074   free(Music_NoConf);
1075
1076   Music_NoConf = NULL;
1077   num_music_noconf = 0;
1078 }
1079
1080 void FreeAllSounds()
1081 {
1082   FreeCustomArtworkLists(sound_info);
1083 }
1084
1085 void FreeAllMusic()
1086 {
1087   FreeCustomArtworkLists(music_info);
1088   FreeAllMusic_NoConf();
1089 }
1090
1091 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS                          */
1092 /* ========================================================================= */