1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include <sys/types.h>
30 /* expiration time (in milliseconds) for sound loops */
31 #define SOUND_LOOP_EXPIRATION_TIME 200
33 /* one second fading interval == 1000 ticks (milliseconds) */
34 #define SOUND_FADING_INTERVAL 1000
36 #define SND_TYPE_NONE 0
37 #define SND_TYPE_WAV 1
39 #define MUS_TYPE_NONE 0
40 #define MUS_TYPE_WAV 1
41 #define MUS_TYPE_MOD 2
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"
48 #define SOUND_VOLUME_LEFT(x) (stereo_volume[x])
49 #define SOUND_VOLUME_RIGHT(x) (stereo_volume[SOUND_MAX_LEFT2RIGHT-x])
51 #define SAME_SOUND_NR(x,y) ((x).nr == (y).nr)
52 #define SAME_SOUND_DATA(x,y) ((x).data_ptr == (y).data_ptr)
54 #define SOUND_VOLUME_FROM_PERCENT(v,p) ((p) < 0 ? SOUND_MIN_VOLUME : \
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)
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))
68 struct AudioFormatInfo
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 */
78 char *source_filename;
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 */
87 typedef struct SampleInfo SoundInfo;
88 typedef struct SampleInfo MusicInfo;
100 unsigned int playing_starttime;
101 unsigned int playing_pos;
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 */
109 typedef struct SoundControl SoundControl;
111 static struct ArtworkListInfo *sound_info = NULL;
112 static struct ArtworkListInfo *music_info = NULL;
114 static MusicInfo **Music_NoConf = NULL;
116 static int num_music_noconf = 0;
117 static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1];
119 static char *currently_playing_music_filename = NULL;
122 /* ========================================================================= */
123 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
125 static struct SoundControl mixer[NUM_MIXER_CHANNELS];
126 static int mixer_active_channels = 0;
127 static boolean expire_loop_sounds = FALSE;
129 static void ReloadCustomSounds();
130 static void ReloadCustomMusic();
131 static void FreeSound(void *);
132 static void FreeMusic(void *);
133 static void FreeAllMusic_NoConf();
135 static SoundInfo *getSoundInfoEntryFromSoundID(int);
136 static MusicInfo *getMusicInfoEntryFromMusicID(int);
139 /* ------------------------------------------------------------------------- */
140 /* mixer functions */
141 /* ------------------------------------------------------------------------- */
143 void Mixer_InitChannels()
147 for (i = 0; i < audio.num_channels; i++)
148 mixer[i].active = FALSE;
149 mixer_active_channels = 0;
152 static void Mixer_ResetChannelExpiration(int channel)
154 mixer[channel].playing_starttime = Counter();
156 if (expire_loop_sounds &&
157 IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
158 Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME);
161 static boolean Mixer_ChannelExpired(int channel)
163 if (!mixer[channel].active)
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))
172 if (!Mix_Playing(channel))
178 static boolean Mixer_AllocateChannel(int channel)
183 static void Mixer_SetChannelProperties(int channel)
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));
191 static void Mixer_StartChannel(int channel)
193 Mix_PlayChannel(channel, mixer[channel].data_ptr,
194 IS_LOOP(mixer[channel]) ? -1 : 0);
197 static void Mixer_PlayChannel(int channel)
199 /* start with inactive channel in case something goes wrong */
200 mixer[channel].active = FALSE;
202 if (mixer[channel].type != MUS_TYPE_WAV)
205 if (!Mixer_AllocateChannel(channel))
208 Mixer_SetChannelProperties(channel);
209 Mixer_StartChannel(channel);
211 Mixer_ResetChannelExpiration(channel);
213 mixer[channel].playing_pos = 0;
214 mixer[channel].active = TRUE;
215 mixer_active_channels++;
218 static void Mixer_PlayMusicChannel()
220 Mixer_PlayChannel(audio.music_channel);
222 if (mixer[audio.music_channel].type != MUS_TYPE_WAV)
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);
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);
241 static void Mixer_StopChannel(int channel)
243 if (!mixer[channel].active)
246 Mix_HaltChannel(channel);
248 mixer[channel].active = FALSE;
249 mixer_active_channels--;
252 static void Mixer_StopMusicChannel()
254 Mixer_StopChannel(audio.music_channel);
258 setString(¤tly_playing_music_filename, NULL);
261 static void Mixer_FadeChannel(int channel)
263 if (!mixer[channel].active)
266 mixer[channel].state |= SND_CTRL_FADE;
268 Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL);
271 static void Mixer_FadeMusicChannel()
273 Mixer_FadeChannel(audio.music_channel);
275 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
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();
287 setString(¤tly_playing_music_filename, NULL);
290 static void Mixer_UnFadeChannel(int channel)
292 if (!mixer[channel].active || !IS_FADING(mixer[channel]))
295 mixer[channel].state &= ~SND_CTRL_FADE;
296 mixer[channel].volume = SOUND_MAX_VOLUME;
298 Mix_ExpireChannel(channel, -1);
299 Mix_Volume(channel, mixer[channel].volume);
302 static void Mixer_InsertSound(SoundControl snd_ctrl)
307 if (IS_MUSIC(snd_ctrl))
308 snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr);
310 snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
312 if (snd_info == NULL)
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;
322 /* play music samples on a dedicated music channel */
323 if (IS_MUSIC(snd_ctrl))
325 Mixer_StopMusicChannel();
327 mixer[audio.music_channel] = snd_ctrl;
328 Mixer_PlayMusicChannel();
330 setString(¤tly_playing_music_filename,
331 getBaseNamePtr(snd_info->source_filename));
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))
341 /* reset expiration delay for already playing loop sounds */
342 if (k > 0 && IS_LOOP(snd_ctrl))
344 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
346 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
348 if (IS_FADING(mixer[i]))
349 Mixer_UnFadeChannel(i);
351 /* restore settings like volume and stereo position */
352 mixer[i].volume = snd_ctrl.volume;
353 mixer[i].stereo_position = snd_ctrl.stereo_position;
355 Mixer_SetChannelProperties(i);
356 Mixer_ResetChannelExpiration(i);
363 /* don't play sound more than n times simultaneously (with n == 2 for now) */
366 unsigned int playing_current = Counter();
367 int longest = 0, longest_nr = audio.first_sound_channel;
369 /* look for oldest equal sound */
370 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
372 int playing_time = playing_current - mixer[i].playing_starttime;
375 if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
378 actual = 1000 * playing_time / mixer[i].data_len;
380 if (actual >= longest)
387 Mixer_StopChannel(longest_nr);
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. */
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))
401 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
403 if (!mixer[i].active)
405 Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i);
406 Error(ERR_INFO, "Mixer_InsertSound: This should never happen!");
408 mixer_active_channels--;
414 if (mixer_active_channels ==
415 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
417 unsigned int playing_current = Counter();
418 int longest = 0, longest_nr = audio.first_sound_channel;
420 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
422 int playing_time = playing_current - mixer[i].playing_starttime;
423 int actual = 1000 * playing_time / mixer[i].data_len;
425 if (!IS_LOOP(mixer[i]) && actual > longest)
432 Mixer_StopChannel(longest_nr);
435 /* add the new sound to the mixer */
436 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
438 if (!mixer[i].active)
441 Mixer_PlayChannel(i);
448 static void HandleSoundRequest(SoundControl snd_ctrl)
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);
457 if (IS_RELOADING(snd_ctrl)) /* load new sound or music files */
459 Mixer_StopMusicChannel();
460 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
461 Mixer_StopChannel(i);
463 if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
464 ReloadCustomSounds();
468 else if (IS_FADING(snd_ctrl)) /* fade out existing sound or music */
470 if (IS_MUSIC(snd_ctrl))
472 Mixer_FadeMusicChannel();
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);
480 else if (IS_STOPPING(snd_ctrl)) /* stop existing sound or music */
482 if (IS_MUSIC(snd_ctrl))
484 Mixer_StopMusicChannel();
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);
492 else if (SET_EXPIRE_LOOPS(snd_ctrl)) /* set loop expiration on or off */
494 expire_loop_sounds = snd_ctrl.active;
496 else if (snd_ctrl.active) /* add new sound to mixer */
498 Mixer_InsertSound(snd_ctrl);
502 void StartMixer(void)
506 if (!audio.sound_available)
509 /* initialize stereo position conversion information */
510 for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
512 (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
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 */
520 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
521 #define WAV_HEADER_SIZE 16 /* size of WAV file header */
523 static void *Load_WAV(char *filename)
527 if (!audio.sound_available)
530 snd_info = checked_calloc(sizeof(SoundInfo));
532 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
534 Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError());
539 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
541 snd_info->type = SND_TYPE_WAV;
542 snd_info->source_filename = getStringCopy(filename);
547 static void *Load_MOD(char *filename)
551 if (!audio.sound_available)
554 mod_info = checked_calloc(sizeof(MusicInfo));
556 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
558 Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError());
563 mod_info->type = MUS_TYPE_MOD;
564 mod_info->source_filename = getStringCopy(filename);
569 static void *Load_WAV_or_MOD(char *filename)
571 if (FileIsMusic(filename))
572 return Load_MOD(filename);
573 else if (FileIsSound(filename))
574 return Load_WAV(filename);
579 void LoadCustomMusic_NoConf(void)
581 static boolean draw_init_text = TRUE; /* only draw at startup */
582 static char *last_music_directory = NULL;
583 char *music_directory = getCustomMusicDirectory();
585 DirectoryEntry *dir_entry;
586 int num_music = getMusicListSize();
588 if (!audio.sound_available)
591 if (last_music_directory != NULL &&
592 strEqual(last_music_directory, music_directory))
593 return; /* old and new music directory are the same */
595 if (last_music_directory != NULL)
596 free(last_music_directory);
597 last_music_directory = getStringCopy(music_directory);
599 FreeAllMusic_NoConf();
601 if ((dir = openDirectory(music_directory)) == NULL)
603 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
605 audio.music_available = FALSE;
611 DrawInitText("Loading music", 120, FC_GREEN);
613 while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */
615 char *basename = dir_entry->basename;
616 MusicInfo *mus_info = NULL;
617 boolean music_already_used = FALSE;
620 /* skip all music files that are configured in music config file */
621 for (i = 0; i < num_music; i++)
623 struct FileInfo *music = getMusicListEntry(i);
625 if (strEqual(basename, music->filename))
627 music_already_used = TRUE;
632 if (music_already_used)
636 DrawInitText(basename, 150, FC_YELLOW);
638 if (FileIsMusic(dir_entry->filename))
639 mus_info = Load_WAV_or_MOD(dir_entry->filename);
644 Music_NoConf = checked_realloc(Music_NoConf,
645 num_music_noconf * sizeof(MusicInfo *));
646 Music_NoConf[num_music_noconf - 1] = mus_info;
652 draw_init_text = FALSE;
655 int getSoundListSize()
657 return (sound_info->num_file_list_entries +
658 sound_info->num_dynamic_file_list_entries);
661 int getMusicListSize()
663 return (music_info->num_file_list_entries +
664 music_info->num_dynamic_file_list_entries);
667 struct FileInfo *getSoundListEntry(int pos)
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);
673 if (pos < 0 || pos >= num_sounds) /* invalid sound */
676 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
677 &sound_info->dynamic_file_list[list_pos]);
680 struct FileInfo *getMusicListEntry(int pos)
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);
686 if (pos < 0 || pos >= num_music) /* invalid music */
689 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
690 &music_info->dynamic_file_list[list_pos]);
693 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
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);
702 if (pos < 0 || pos >= num_sounds) /* invalid sound */
705 return snd_info[list_pos];
708 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
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);
717 if (pos >= num_music) /* invalid music */
720 if (pos < 0) /* undefined music */
722 if (num_music_noconf == 0) /* no fallback music available */
725 pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
727 return Music_NoConf[pos];
730 return mus_info[list_pos];
733 char *getMusicInfoEntryFilename(int pos)
735 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
737 if (mus_info == NULL)
740 return getBaseNamePtr(mus_info->source_filename);
743 char *getCurrentlyPlayingMusicFilename()
745 return currently_playing_music_filename;
748 int getSoundListPropertyMappingSize()
750 return sound_info->num_property_mapping_entries;
753 int getMusicListPropertyMappingSize()
755 return music_info->num_property_mapping_entries;
758 struct PropertyMapping *getSoundListPropertyMapping()
760 return sound_info->property_mapping;
763 struct PropertyMapping *getMusicListPropertyMapping()
765 return music_info->property_mapping;
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)
776 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
777 sound_info->type = ARTWORK_TYPE_SOUNDS;
779 /* ---------- initialize file list and suffix lists ---------- */
781 sound_info->num_file_list_entries = num_file_list_entries;
782 sound_info->num_dynamic_file_list_entries = 0;
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;
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++;
793 sound_info->suffix_list = config_suffix_list;
795 /* ---------- initialize base prefix and suffixes lists ---------- */
797 sound_info->num_base_prefixes = 0;
798 for (i = 0; base_prefixes[i] != NULL; i++)
799 sound_info->num_base_prefixes++;
801 sound_info->num_ext1_suffixes = 0;
802 for (i = 0; ext1_suffixes[i] != NULL; i++)
803 sound_info->num_ext1_suffixes++;
805 sound_info->num_ext2_suffixes = 0;
806 for (i = 0; ext2_suffixes[i] != NULL; i++)
807 sound_info->num_ext2_suffixes++;
809 sound_info->num_ext3_suffixes = 0;
810 for (i = 0; ext3_suffixes[i] != NULL; i++)
811 sound_info->num_ext3_suffixes++;
813 sound_info->num_ignore_tokens = 0;
814 for (i = 0; ignore_tokens[i] != NULL; i++)
815 sound_info->num_ignore_tokens++;
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;
823 sound_info->num_property_mapping_entries = 0;
825 sound_info->property_mapping = NULL;
827 /* ---------- initialize artwork reference and content lists ---------- */
829 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
831 sound_info->artwork_list =
832 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
833 sound_info->dynamic_artwork_list = NULL;
835 sound_info->content_list = NULL;
837 /* ---------- initialize artwork loading/freeing functions ---------- */
839 sound_info->load_artwork = Load_WAV;
840 sound_info->free_artwork = FreeSound;
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)
851 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
852 music_info->type = ARTWORK_TYPE_MUSIC;
854 /* ---------- initialize file list and suffix lists ---------- */
856 music_info->num_file_list_entries = num_file_list_entries;
857 music_info->num_dynamic_file_list_entries = 0;
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;
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++;
868 music_info->suffix_list = config_suffix_list;
870 /* ---------- initialize base prefix and suffixes lists ---------- */
872 music_info->num_base_prefixes = 0;
873 for (i = 0; base_prefixes[i] != NULL; i++)
874 music_info->num_base_prefixes++;
876 music_info->num_ext1_suffixes = 0;
877 for (i = 0; ext1_suffixes[i] != NULL; i++)
878 music_info->num_ext1_suffixes++;
880 music_info->num_ext2_suffixes = 0;
881 for (i = 0; ext2_suffixes[i] != NULL; i++)
882 music_info->num_ext2_suffixes++;
884 music_info->num_ext3_suffixes = 0;
885 for (i = 0; ext3_suffixes[i] != NULL; i++)
886 music_info->num_ext3_suffixes++;
888 music_info->num_ignore_tokens = 0;
889 for (i = 0; ignore_tokens[i] != NULL; i++)
890 music_info->num_ignore_tokens++;
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;
898 music_info->num_property_mapping_entries = 0;
900 music_info->property_mapping = NULL;
902 /* ---------- initialize artwork reference and content lists ---------- */
904 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
906 music_info->artwork_list =
907 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
908 music_info->dynamic_artwork_list = NULL;
910 music_info->content_list = NULL;
912 /* ---------- initialize artwork loading/freeing functions ---------- */
914 music_info->load_artwork = Load_WAV_or_MOD;
915 music_info->free_artwork = FreeMusic;
918 void PlayMusic(int nr)
920 if (!audio.music_available)
926 void PlaySound(int nr)
928 if (!setup.sound_simple)
931 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
934 void PlaySoundStereo(int nr, int stereo_position)
936 if (!setup.sound_simple)
939 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
942 void PlaySoundLoop(int nr)
944 if (!setup.sound_loops)
947 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
950 void PlaySoundMusic(int nr)
952 if (!setup.sound_music)
955 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
958 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
960 SoundControl snd_ctrl;
962 if (!audio.sound_available ||
963 !audio.sound_enabled ||
964 audio.sound_deactivated)
967 volume = SETUP_SOUND_VOLUME(volume, state);
969 if (volume < SOUND_MIN_VOLUME)
970 volume = SOUND_MIN_VOLUME;
971 else if (volume > SOUND_MAX_VOLUME)
972 volume = SOUND_MAX_VOLUME;
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;
979 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
981 snd_ctrl.active = TRUE;
983 snd_ctrl.volume = volume;
984 snd_ctrl.stereo_position = stereo_position;
985 snd_ctrl.state = state;
987 HandleSoundRequest(snd_ctrl);
992 if (!audio.music_available)
995 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
998 void FadeSound(int nr)
1000 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1005 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1008 void FadeSoundsAndMusic()
1014 void StopMusic(void)
1016 if (!audio.music_available)
1019 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1022 void StopSound(int nr)
1024 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1030 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1033 void StopSoundExt(int nr, int state)
1035 SoundControl snd_ctrl;
1037 if (!audio.sound_available)
1040 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
1042 snd_ctrl.active = FALSE;
1044 snd_ctrl.state = state;
1046 HandleSoundRequest(snd_ctrl);
1049 void ExpireSoundLoops(boolean active)
1051 SoundControl snd_ctrl;
1053 if (!audio.sound_available)
1056 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
1058 snd_ctrl.active = active;
1059 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1061 HandleSoundRequest(snd_ctrl);
1064 static void ReloadCustomSounds()
1066 LoadArtworkConfig(sound_info);
1067 ReloadCustomArtworkList(sound_info);
1070 static void ReloadCustomMusic()
1072 LoadArtworkConfig(music_info);
1073 ReloadCustomArtworkList(music_info);
1075 /* load all music files from directory not defined in "musicinfo.conf" */
1076 LoadCustomMusic_NoConf();
1079 void InitReloadCustomSounds(char *set_identifier)
1081 if (!audio.sound_available)
1084 ReloadCustomSounds();
1087 void InitReloadCustomMusic(char *set_identifier)
1089 if (!audio.music_available)
1092 ReloadCustomMusic();
1095 void FreeSound(void *ptr)
1097 SoundInfo *sound = (SoundInfo *)ptr;
1102 if (sound->data_ptr)
1104 Mix_FreeChunk(sound->data_ptr);
1107 checked_free(sound->source_filename);
1112 void FreeMusic(void *ptr)
1114 MusicInfo *music = (MusicInfo *)ptr;
1119 if (music->data_ptr)
1121 if (music->type == MUS_TYPE_MOD)
1122 Mix_FreeMusic(music->data_ptr);
1124 Mix_FreeChunk(music->data_ptr);
1130 static void FreeAllMusic_NoConf()
1134 if (Music_NoConf == NULL)
1137 for (i = 0; i < num_music_noconf; i++)
1138 FreeMusic(Music_NoConf[i]);
1142 Music_NoConf = NULL;
1143 num_music_noconf = 0;
1146 void FreeAllSounds()
1148 FreeCustomArtworkLists(sound_info);
1153 FreeCustomArtworkLists(music_info);
1154 FreeAllMusic_NoConf();
1157 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1158 /* ========================================================================= */