improved error messages when loading artwork fails
[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': %s", filename, Mix_GetError());
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': %s", filename, Mix_GetError());
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     MusicInfo *mus_info = NULL;
602     boolean music_already_used = FALSE;
603     int i;
604
605     /* skip all music files that are configured in music config file */
606     for (i = 0; i < num_music; i++)
607     {
608       struct FileInfo *music = getMusicListEntry(i);
609
610       if (strEqual(basename, music->filename))
611       {
612         music_already_used = TRUE;
613         break;
614       }
615     }
616
617     if (music_already_used)
618       continue;
619
620     if (draw_init_text)
621       DrawInitText(basename, 150, FC_YELLOW);
622
623     if (FileIsMusic(dir_entry->filename))
624       mus_info = Load_WAV_or_MOD(dir_entry->filename);
625
626     if (mus_info)
627     {
628       num_music_noconf++;
629       Music_NoConf = checked_realloc(Music_NoConf,
630                                      num_music_noconf * sizeof(MusicInfo *));
631       Music_NoConf[num_music_noconf - 1] = mus_info;
632     }
633   }
634
635   closeDirectory(dir);
636
637   draw_init_text = FALSE;
638 }
639
640 int getSoundListSize()
641 {
642   return (sound_info->num_file_list_entries +
643           sound_info->num_dynamic_file_list_entries);
644 }
645
646 int getMusicListSize()
647 {
648   return (music_info->num_file_list_entries +
649           music_info->num_dynamic_file_list_entries);
650 }
651
652 struct FileInfo *getSoundListEntry(int pos)
653 {
654   int num_list_entries = sound_info->num_file_list_entries;
655   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
656
657   return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
658           &sound_info->dynamic_file_list[list_pos]);
659 }
660
661 struct FileInfo *getMusicListEntry(int pos)
662 {
663   int num_list_entries = music_info->num_file_list_entries;
664   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
665
666   return (pos < num_list_entries ? &music_info->file_list[list_pos] :
667           &music_info->dynamic_file_list[list_pos]);
668 }
669
670 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
671 {
672   int num_list_entries = sound_info->num_file_list_entries;
673   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
674   SoundInfo **snd_info =
675     (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
676                    sound_info->dynamic_artwork_list);
677
678   return snd_info[list_pos];
679 }
680
681 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
682 {
683   int num_list_entries = music_info->num_file_list_entries;
684   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
685   MusicInfo **mus_info =
686     (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
687                    music_info->dynamic_artwork_list);
688
689   return mus_info[list_pos];
690 }
691
692 int getSoundListPropertyMappingSize()
693 {
694   return sound_info->num_property_mapping_entries;
695 }
696
697 int getMusicListPropertyMappingSize()
698 {
699   return music_info->num_property_mapping_entries;
700 }
701
702 struct PropertyMapping *getSoundListPropertyMapping()
703 {
704   return sound_info->property_mapping;
705 }
706
707 struct PropertyMapping *getMusicListPropertyMapping()
708 {
709   return music_info->property_mapping;
710 }
711
712 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
713                    struct ConfigTypeInfo *config_suffix_list,
714                    char **base_prefixes, char **ext1_suffixes,
715                    char **ext2_suffixes, char **ext3_suffixes,
716                    char **ignore_tokens)
717 {
718   int i;
719
720   sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
721   sound_info->type = ARTWORK_TYPE_SOUNDS;
722
723   /* ---------- initialize file list and suffix lists ---------- */
724
725   sound_info->num_file_list_entries = num_file_list_entries;
726   sound_info->num_dynamic_file_list_entries = 0;
727
728   sound_info->file_list =
729     getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
730                               num_file_list_entries);
731   sound_info->dynamic_file_list = NULL;
732
733   sound_info->num_suffix_list_entries = 0;
734   for (i = 0; config_suffix_list[i].token != NULL; i++)
735     sound_info->num_suffix_list_entries++;
736
737   sound_info->suffix_list = config_suffix_list;
738
739   /* ---------- initialize base prefix and suffixes lists ---------- */
740
741   sound_info->num_base_prefixes = 0;
742   for (i = 0; base_prefixes[i] != NULL; i++)
743     sound_info->num_base_prefixes++;
744
745   sound_info->num_ext1_suffixes = 0;
746   for (i = 0; ext1_suffixes[i] != NULL; i++)
747     sound_info->num_ext1_suffixes++;
748
749   sound_info->num_ext2_suffixes = 0;
750   for (i = 0; ext2_suffixes[i] != NULL; i++)
751     sound_info->num_ext2_suffixes++;
752
753   sound_info->num_ext3_suffixes = 0;
754   for (i = 0; ext3_suffixes[i] != NULL; i++)
755     sound_info->num_ext3_suffixes++;
756
757   sound_info->num_ignore_tokens = 0;
758   for (i = 0; ignore_tokens[i] != NULL; i++)
759     sound_info->num_ignore_tokens++;
760
761   sound_info->base_prefixes = base_prefixes;
762   sound_info->ext1_suffixes = ext1_suffixes;
763   sound_info->ext2_suffixes = ext2_suffixes;
764   sound_info->ext3_suffixes = ext3_suffixes;
765   sound_info->ignore_tokens = ignore_tokens;
766
767   sound_info->num_property_mapping_entries = 0;
768
769   sound_info->property_mapping = NULL;
770
771   /* ---------- initialize artwork reference and content lists ---------- */
772
773   sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
774
775   sound_info->artwork_list =
776     checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
777   sound_info->dynamic_artwork_list = NULL;
778
779   sound_info->content_list = NULL;
780
781   /* ---------- initialize artwork loading/freeing functions ---------- */
782
783   sound_info->load_artwork = Load_WAV;
784   sound_info->free_artwork = FreeSound;
785 }
786
787 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
788                    struct ConfigTypeInfo *config_suffix_list,
789                    char **base_prefixes, char **ext1_suffixes,
790                    char **ext2_suffixes, char **ext3_suffixes,
791                    char **ignore_tokens)
792 {
793   int i;
794
795   music_info = checked_calloc(sizeof(struct ArtworkListInfo));
796   music_info->type = ARTWORK_TYPE_MUSIC;
797
798   /* ---------- initialize file list and suffix lists ---------- */
799
800   music_info->num_file_list_entries = num_file_list_entries;
801   music_info->num_dynamic_file_list_entries = 0;
802
803   music_info->file_list =
804     getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
805                               num_file_list_entries);
806   music_info->dynamic_file_list = NULL;
807
808   music_info->num_suffix_list_entries = 0;
809   for (i = 0; config_suffix_list[i].token != NULL; i++)
810     music_info->num_suffix_list_entries++;
811
812   music_info->suffix_list = config_suffix_list;
813
814   /* ---------- initialize base prefix and suffixes lists ---------- */
815
816   music_info->num_base_prefixes = 0;
817   for (i = 0; base_prefixes[i] != NULL; i++)
818     music_info->num_base_prefixes++;
819
820   music_info->num_ext1_suffixes = 0;
821   for (i = 0; ext1_suffixes[i] != NULL; i++)
822     music_info->num_ext1_suffixes++;
823
824   music_info->num_ext2_suffixes = 0;
825   for (i = 0; ext2_suffixes[i] != NULL; i++)
826     music_info->num_ext2_suffixes++;
827
828   music_info->num_ext3_suffixes = 0;
829   for (i = 0; ext3_suffixes[i] != NULL; i++)
830     music_info->num_ext3_suffixes++;
831
832   music_info->num_ignore_tokens = 0;
833   for (i = 0; ignore_tokens[i] != NULL; i++)
834     music_info->num_ignore_tokens++;
835
836   music_info->base_prefixes = base_prefixes;
837   music_info->ext1_suffixes = ext1_suffixes;
838   music_info->ext2_suffixes = ext2_suffixes;
839   music_info->ext3_suffixes = ext3_suffixes;
840   music_info->ignore_tokens = ignore_tokens;
841
842   music_info->num_property_mapping_entries = 0;
843
844   music_info->property_mapping = NULL;
845
846   /* ---------- initialize artwork reference and content lists ---------- */
847
848   music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
849
850   music_info->artwork_list =
851     checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
852   music_info->dynamic_artwork_list = NULL;
853
854   music_info->content_list = NULL;
855
856   /* ---------- initialize artwork loading/freeing functions ---------- */
857
858   music_info->load_artwork = Load_WAV_or_MOD;
859   music_info->free_artwork = FreeMusic;
860 }
861
862 void PlayMusic(int nr)
863 {
864   if (!audio.music_available)
865     return;
866
867   PlaySoundMusic(nr);
868 }
869
870 void PlaySound(int nr)
871 {
872   if (!setup.sound_simple)
873     return;
874
875   PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
876 }
877
878 void PlaySoundStereo(int nr, int stereo_position)
879 {
880   if (!setup.sound_simple)
881     return;
882
883   PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
884 }
885
886 void PlaySoundLoop(int nr)
887 {
888   if (!setup.sound_loops)
889     return;
890
891   PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
892 }
893
894 void PlaySoundMusic(int nr)
895 {
896   if (!setup.sound_music)
897     return;
898
899   PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
900 }
901
902 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
903 {
904   SoundControl snd_ctrl;
905
906   if (!audio.sound_available ||
907       !audio.sound_enabled ||
908       audio.sound_deactivated)
909     return;
910
911   volume = SETUP_SOUND_VOLUME(volume, state);
912
913   if (volume < SOUND_MIN_VOLUME)
914     volume = SOUND_MIN_VOLUME;
915   else if (volume > SOUND_MAX_VOLUME)
916     volume = SOUND_MAX_VOLUME;
917
918   if (stereo_position < SOUND_MAX_LEFT)
919     stereo_position = SOUND_MAX_LEFT;
920   else if (stereo_position > SOUND_MAX_RIGHT)
921     stereo_position = SOUND_MAX_RIGHT;
922
923   clear_mem(&snd_ctrl, sizeof(SoundControl));   /* to make valgrind happy */
924
925   snd_ctrl.active = TRUE;
926   snd_ctrl.nr = nr;
927   snd_ctrl.volume = volume;
928   snd_ctrl.stereo_position = stereo_position;
929   snd_ctrl.state = state;
930
931   HandleSoundRequest(snd_ctrl);
932 }
933
934 void FadeMusic(void)
935 {
936   if (!audio.music_available)
937     return;
938
939   StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
940 }
941
942 void FadeSound(int nr)
943 {
944   StopSoundExt(nr, SND_CTRL_FADE_SOUND);
945 }
946
947 void FadeSounds()
948 {
949   StopSoundExt(-1, SND_CTRL_FADE_ALL);
950 }
951
952 void FadeSoundsAndMusic()
953 {
954   FadeSounds();
955   FadeMusic();
956 }
957
958 void StopMusic(void)
959 {
960   if (!audio.music_available)
961     return;
962
963   StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
964 }
965
966 void StopSound(int nr)
967 {
968   StopSoundExt(nr, SND_CTRL_STOP_SOUND);
969 }
970
971 void StopSounds()
972 {
973   StopMusic();
974   StopSoundExt(-1, SND_CTRL_STOP_ALL);
975 }
976
977 void StopSoundExt(int nr, int state)
978 {
979   SoundControl snd_ctrl;
980
981   if (!audio.sound_available)
982     return;
983
984   clear_mem(&snd_ctrl, sizeof(SoundControl));   /* to make valgrind happy */
985
986   snd_ctrl.active = FALSE;
987   snd_ctrl.nr = nr;
988   snd_ctrl.state = state;
989
990   HandleSoundRequest(snd_ctrl);
991 }
992
993 static void ReloadCustomSounds()
994 {
995   LoadArtworkConfig(sound_info);
996   ReloadCustomArtworkList(sound_info);
997 }
998
999 static void ReloadCustomMusic()
1000 {
1001   LoadArtworkConfig(music_info);
1002   ReloadCustomArtworkList(music_info);
1003
1004   /* load all music files from directory not defined in "musicinfo.conf" */
1005   LoadCustomMusic_NoConf();
1006 }
1007
1008 void InitReloadCustomSounds(char *set_identifier)
1009 {
1010   if (!audio.sound_available)
1011     return;
1012
1013   ReloadCustomSounds();
1014 }
1015
1016 void InitReloadCustomMusic(char *set_identifier)
1017 {
1018   if (!audio.music_available)
1019     return;
1020
1021   ReloadCustomMusic();
1022 }
1023
1024 void FreeSound(void *ptr)
1025 {
1026   SoundInfo *sound = (SoundInfo *)ptr;
1027
1028   if (sound == NULL)
1029     return;
1030
1031   if (sound->data_ptr)
1032   {
1033     Mix_FreeChunk(sound->data_ptr);
1034   }
1035
1036   checked_free(sound->source_filename);
1037
1038   free(sound);
1039 }
1040
1041 void FreeMusic(void *ptr)
1042 {
1043   MusicInfo *music = (MusicInfo *)ptr;
1044
1045   if (music == NULL)
1046     return;
1047
1048   if (music->data_ptr)
1049   {
1050     if (music->type == MUS_TYPE_MOD)
1051       Mix_FreeMusic(music->data_ptr);
1052     else
1053       Mix_FreeChunk(music->data_ptr);
1054   }
1055
1056   free(music);
1057 }
1058
1059 static void FreeAllMusic_NoConf()
1060 {
1061   int i;
1062
1063   if (Music_NoConf == NULL)
1064     return;
1065
1066   for (i = 0; i < num_music_noconf; i++)
1067     FreeMusic(Music_NoConf[i]);
1068
1069   free(Music_NoConf);
1070
1071   Music_NoConf = NULL;
1072   num_music_noconf = 0;
1073 }
1074
1075 void FreeAllSounds()
1076 {
1077   FreeCustomArtworkLists(sound_info);
1078 }
1079
1080 void FreeAllMusic()
1081 {
1082   FreeCustomArtworkLists(music_info);
1083   FreeAllMusic_NoConf();
1084 }
1085
1086 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS                          */
1087 /* ========================================================================= */