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