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)
306 int num_sounds = getSoundListSize();
307 int num_music = getMusicListSize();
309 if (IS_MUSIC(snd_ctrl))
311 if (snd_ctrl.nr >= num_music) /* invalid music */
314 if (snd_ctrl.nr < 0) /* undefined music */
316 if (num_music_noconf == 0) /* no fallback music available */
319 snd_ctrl.nr = UNMAP_NOCONF_MUSIC(snd_ctrl.nr) % num_music_noconf;
320 snd_info = Music_NoConf[snd_ctrl.nr];
323 snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr);
327 if (snd_ctrl.nr < 0 || snd_ctrl.nr >= num_sounds)
330 snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
333 if (snd_info == NULL)
336 /* copy sound sample and format information */
337 snd_ctrl.type = snd_info->type;
338 snd_ctrl.format = snd_info->format;
339 snd_ctrl.data_ptr = snd_info->data_ptr;
340 snd_ctrl.data_len = snd_info->data_len;
341 snd_ctrl.num_channels = snd_info->num_channels;
343 /* play music samples on a dedicated music channel */
344 if (IS_MUSIC(snd_ctrl))
346 Mixer_StopMusicChannel();
348 mixer[audio.music_channel] = snd_ctrl;
349 Mixer_PlayMusicChannel();
351 setString(¤tly_playing_music_filename,
352 getBaseNamePtr(snd_info->source_filename));
357 /* check if (and how often) this sound sample is already playing */
358 for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++)
359 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
362 /* reset expiration delay for already playing loop sounds */
363 if (k > 0 && IS_LOOP(snd_ctrl))
365 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
367 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
369 if (IS_FADING(mixer[i]))
370 Mixer_UnFadeChannel(i);
372 /* restore settings like volume and stereo position */
373 mixer[i].volume = snd_ctrl.volume;
374 mixer[i].stereo_position = snd_ctrl.stereo_position;
376 Mixer_SetChannelProperties(i);
377 Mixer_ResetChannelExpiration(i);
384 /* don't play sound more than n times simultaneously (with n == 2 for now) */
387 unsigned int playing_current = Counter();
388 int longest = 0, longest_nr = audio.first_sound_channel;
390 /* look for oldest equal sound */
391 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
393 int playing_time = playing_current - mixer[i].playing_starttime;
396 if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
399 actual = 1000 * playing_time / mixer[i].data_len;
401 if (actual >= longest)
408 Mixer_StopChannel(longest_nr);
411 /* If all (non-music) channels are active, stop the channel that has
412 played its sound sample most completely (in percent of the sample
413 length). As we cannot currently get the actual playing position
414 of the channel's sound sample when compiling with the SDL mixer
415 library, we use the current playing time (in milliseconds) instead. */
418 /* channel allocation sanity check -- should not be needed */
419 if (mixer_active_channels ==
420 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
422 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
424 if (!mixer[i].active)
426 Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i);
427 Error(ERR_INFO, "Mixer_InsertSound: This should never happen!");
429 mixer_active_channels--;
435 if (mixer_active_channels ==
436 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
438 unsigned int playing_current = Counter();
439 int longest = 0, longest_nr = audio.first_sound_channel;
441 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
443 int playing_time = playing_current - mixer[i].playing_starttime;
444 int actual = 1000 * playing_time / mixer[i].data_len;
446 if (!IS_LOOP(mixer[i]) && actual > longest)
453 Mixer_StopChannel(longest_nr);
456 /* add the new sound to the mixer */
457 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
459 if (!mixer[i].active)
462 Mixer_PlayChannel(i);
469 static void HandleSoundRequest(SoundControl snd_ctrl)
473 /* deactivate channels that have expired since the last request */
474 for (i = 0; i < audio.num_channels; i++)
475 if (mixer[i].active && Mixer_ChannelExpired(i))
476 Mixer_StopChannel(i);
478 if (IS_RELOADING(snd_ctrl)) /* load new sound or music files */
480 Mixer_StopMusicChannel();
481 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
482 Mixer_StopChannel(i);
484 if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
485 ReloadCustomSounds();
489 else if (IS_FADING(snd_ctrl)) /* fade out existing sound or music */
491 if (IS_MUSIC(snd_ctrl))
493 Mixer_FadeMusicChannel();
497 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
498 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
499 Mixer_FadeChannel(i);
501 else if (IS_STOPPING(snd_ctrl)) /* stop existing sound or music */
503 if (IS_MUSIC(snd_ctrl))
505 Mixer_StopMusicChannel();
509 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
510 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
511 Mixer_StopChannel(i);
513 else if (SET_EXPIRE_LOOPS(snd_ctrl)) /* set loop expiration on or off */
515 expire_loop_sounds = snd_ctrl.active;
517 else if (snd_ctrl.active) /* add new sound to mixer */
519 Mixer_InsertSound(snd_ctrl);
523 void StartMixer(void)
527 if (!audio.sound_available)
530 /* initialize stereo position conversion information */
531 for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
533 (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
537 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
538 /* ========================================================================= */
539 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
541 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
542 #define WAV_HEADER_SIZE 16 /* size of WAV file header */
544 static void *Load_WAV(char *filename)
548 if (!audio.sound_available)
551 snd_info = checked_calloc(sizeof(SoundInfo));
553 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
555 Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError());
560 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
562 snd_info->type = SND_TYPE_WAV;
563 snd_info->source_filename = getStringCopy(filename);
568 static void *Load_MOD(char *filename)
572 if (!audio.sound_available)
575 mod_info = checked_calloc(sizeof(MusicInfo));
577 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
579 Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError());
584 mod_info->type = MUS_TYPE_MOD;
585 mod_info->source_filename = getStringCopy(filename);
590 static void *Load_WAV_or_MOD(char *filename)
592 if (FileIsMusic(filename))
593 return Load_MOD(filename);
594 else if (FileIsSound(filename))
595 return Load_WAV(filename);
600 void LoadCustomMusic_NoConf(void)
602 static boolean draw_init_text = TRUE; /* only draw at startup */
603 static char *last_music_directory = NULL;
604 char *music_directory = getCustomMusicDirectory();
606 DirectoryEntry *dir_entry;
607 int num_music = getMusicListSize();
609 if (!audio.sound_available)
612 if (last_music_directory != NULL &&
613 strEqual(last_music_directory, music_directory))
614 return; /* old and new music directory are the same */
616 if (last_music_directory != NULL)
617 free(last_music_directory);
618 last_music_directory = getStringCopy(music_directory);
620 FreeAllMusic_NoConf();
622 if ((dir = openDirectory(music_directory)) == NULL)
624 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
626 audio.music_available = FALSE;
632 DrawInitText("Loading music", 120, FC_GREEN);
634 while ((dir_entry = readDirectory(dir)) != NULL) /* loop all entries */
636 char *basename = dir_entry->basename;
637 MusicInfo *mus_info = NULL;
638 boolean music_already_used = FALSE;
641 /* skip all music files that are configured in music config file */
642 for (i = 0; i < num_music; i++)
644 struct FileInfo *music = getMusicListEntry(i);
646 if (strEqual(basename, music->filename))
648 music_already_used = TRUE;
653 if (music_already_used)
657 DrawInitText(basename, 150, FC_YELLOW);
659 if (FileIsMusic(dir_entry->filename))
660 mus_info = Load_WAV_or_MOD(dir_entry->filename);
665 Music_NoConf = checked_realloc(Music_NoConf,
666 num_music_noconf * sizeof(MusicInfo *));
667 Music_NoConf[num_music_noconf - 1] = mus_info;
673 draw_init_text = FALSE;
676 int getSoundListSize()
678 return (sound_info->num_file_list_entries +
679 sound_info->num_dynamic_file_list_entries);
682 int getMusicListSize()
684 return (music_info->num_file_list_entries +
685 music_info->num_dynamic_file_list_entries);
688 struct FileInfo *getSoundListEntry(int pos)
690 int num_list_entries = sound_info->num_file_list_entries;
691 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
693 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
694 &sound_info->dynamic_file_list[list_pos]);
697 struct FileInfo *getMusicListEntry(int pos)
699 int num_list_entries = music_info->num_file_list_entries;
700 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
702 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
703 &music_info->dynamic_file_list[list_pos]);
706 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
708 int num_list_entries = sound_info->num_file_list_entries;
709 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
710 SoundInfo **snd_info =
711 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
712 sound_info->dynamic_artwork_list);
714 return snd_info[list_pos];
717 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
719 int num_list_entries = music_info->num_file_list_entries;
720 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
721 MusicInfo **mus_info =
722 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
723 music_info->dynamic_artwork_list);
725 return mus_info[list_pos];
728 char *getCurrentlyPlayingMusicFilename()
730 return currently_playing_music_filename;
733 int getSoundListPropertyMappingSize()
735 return sound_info->num_property_mapping_entries;
738 int getMusicListPropertyMappingSize()
740 return music_info->num_property_mapping_entries;
743 struct PropertyMapping *getSoundListPropertyMapping()
745 return sound_info->property_mapping;
748 struct PropertyMapping *getMusicListPropertyMapping()
750 return music_info->property_mapping;
753 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
754 struct ConfigTypeInfo *config_suffix_list,
755 char **base_prefixes, char **ext1_suffixes,
756 char **ext2_suffixes, char **ext3_suffixes,
757 char **ignore_tokens)
761 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
762 sound_info->type = ARTWORK_TYPE_SOUNDS;
764 /* ---------- initialize file list and suffix lists ---------- */
766 sound_info->num_file_list_entries = num_file_list_entries;
767 sound_info->num_dynamic_file_list_entries = 0;
769 sound_info->file_list =
770 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
771 num_file_list_entries);
772 sound_info->dynamic_file_list = NULL;
774 sound_info->num_suffix_list_entries = 0;
775 for (i = 0; config_suffix_list[i].token != NULL; i++)
776 sound_info->num_suffix_list_entries++;
778 sound_info->suffix_list = config_suffix_list;
780 /* ---------- initialize base prefix and suffixes lists ---------- */
782 sound_info->num_base_prefixes = 0;
783 for (i = 0; base_prefixes[i] != NULL; i++)
784 sound_info->num_base_prefixes++;
786 sound_info->num_ext1_suffixes = 0;
787 for (i = 0; ext1_suffixes[i] != NULL; i++)
788 sound_info->num_ext1_suffixes++;
790 sound_info->num_ext2_suffixes = 0;
791 for (i = 0; ext2_suffixes[i] != NULL; i++)
792 sound_info->num_ext2_suffixes++;
794 sound_info->num_ext3_suffixes = 0;
795 for (i = 0; ext3_suffixes[i] != NULL; i++)
796 sound_info->num_ext3_suffixes++;
798 sound_info->num_ignore_tokens = 0;
799 for (i = 0; ignore_tokens[i] != NULL; i++)
800 sound_info->num_ignore_tokens++;
802 sound_info->base_prefixes = base_prefixes;
803 sound_info->ext1_suffixes = ext1_suffixes;
804 sound_info->ext2_suffixes = ext2_suffixes;
805 sound_info->ext3_suffixes = ext3_suffixes;
806 sound_info->ignore_tokens = ignore_tokens;
808 sound_info->num_property_mapping_entries = 0;
810 sound_info->property_mapping = NULL;
812 /* ---------- initialize artwork reference and content lists ---------- */
814 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
816 sound_info->artwork_list =
817 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
818 sound_info->dynamic_artwork_list = NULL;
820 sound_info->content_list = NULL;
822 /* ---------- initialize artwork loading/freeing functions ---------- */
824 sound_info->load_artwork = Load_WAV;
825 sound_info->free_artwork = FreeSound;
828 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
829 struct ConfigTypeInfo *config_suffix_list,
830 char **base_prefixes, char **ext1_suffixes,
831 char **ext2_suffixes, char **ext3_suffixes,
832 char **ignore_tokens)
836 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
837 music_info->type = ARTWORK_TYPE_MUSIC;
839 /* ---------- initialize file list and suffix lists ---------- */
841 music_info->num_file_list_entries = num_file_list_entries;
842 music_info->num_dynamic_file_list_entries = 0;
844 music_info->file_list =
845 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
846 num_file_list_entries);
847 music_info->dynamic_file_list = NULL;
849 music_info->num_suffix_list_entries = 0;
850 for (i = 0; config_suffix_list[i].token != NULL; i++)
851 music_info->num_suffix_list_entries++;
853 music_info->suffix_list = config_suffix_list;
855 /* ---------- initialize base prefix and suffixes lists ---------- */
857 music_info->num_base_prefixes = 0;
858 for (i = 0; base_prefixes[i] != NULL; i++)
859 music_info->num_base_prefixes++;
861 music_info->num_ext1_suffixes = 0;
862 for (i = 0; ext1_suffixes[i] != NULL; i++)
863 music_info->num_ext1_suffixes++;
865 music_info->num_ext2_suffixes = 0;
866 for (i = 0; ext2_suffixes[i] != NULL; i++)
867 music_info->num_ext2_suffixes++;
869 music_info->num_ext3_suffixes = 0;
870 for (i = 0; ext3_suffixes[i] != NULL; i++)
871 music_info->num_ext3_suffixes++;
873 music_info->num_ignore_tokens = 0;
874 for (i = 0; ignore_tokens[i] != NULL; i++)
875 music_info->num_ignore_tokens++;
877 music_info->base_prefixes = base_prefixes;
878 music_info->ext1_suffixes = ext1_suffixes;
879 music_info->ext2_suffixes = ext2_suffixes;
880 music_info->ext3_suffixes = ext3_suffixes;
881 music_info->ignore_tokens = ignore_tokens;
883 music_info->num_property_mapping_entries = 0;
885 music_info->property_mapping = NULL;
887 /* ---------- initialize artwork reference and content lists ---------- */
889 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
891 music_info->artwork_list =
892 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
893 music_info->dynamic_artwork_list = NULL;
895 music_info->content_list = NULL;
897 /* ---------- initialize artwork loading/freeing functions ---------- */
899 music_info->load_artwork = Load_WAV_or_MOD;
900 music_info->free_artwork = FreeMusic;
903 void PlayMusic(int nr)
905 if (!audio.music_available)
911 void PlaySound(int nr)
913 if (!setup.sound_simple)
916 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
919 void PlaySoundStereo(int nr, int stereo_position)
921 if (!setup.sound_simple)
924 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
927 void PlaySoundLoop(int nr)
929 if (!setup.sound_loops)
932 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
935 void PlaySoundMusic(int nr)
937 if (!setup.sound_music)
940 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
943 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
945 SoundControl snd_ctrl;
947 if (!audio.sound_available ||
948 !audio.sound_enabled ||
949 audio.sound_deactivated)
952 volume = SETUP_SOUND_VOLUME(volume, state);
954 if (volume < SOUND_MIN_VOLUME)
955 volume = SOUND_MIN_VOLUME;
956 else if (volume > SOUND_MAX_VOLUME)
957 volume = SOUND_MAX_VOLUME;
959 if (stereo_position < SOUND_MAX_LEFT)
960 stereo_position = SOUND_MAX_LEFT;
961 else if (stereo_position > SOUND_MAX_RIGHT)
962 stereo_position = SOUND_MAX_RIGHT;
964 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
966 snd_ctrl.active = TRUE;
968 snd_ctrl.volume = volume;
969 snd_ctrl.stereo_position = stereo_position;
970 snd_ctrl.state = state;
972 HandleSoundRequest(snd_ctrl);
977 if (!audio.music_available)
980 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
983 void FadeSound(int nr)
985 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
990 StopSoundExt(-1, SND_CTRL_FADE_ALL);
993 void FadeSoundsAndMusic()
1001 if (!audio.music_available)
1004 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1007 void StopSound(int nr)
1009 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1015 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1018 void StopSoundExt(int nr, int state)
1020 SoundControl snd_ctrl;
1022 if (!audio.sound_available)
1025 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
1027 snd_ctrl.active = FALSE;
1029 snd_ctrl.state = state;
1031 HandleSoundRequest(snd_ctrl);
1034 void ExpireSoundLoops(boolean active)
1036 SoundControl snd_ctrl;
1038 if (!audio.sound_available)
1041 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
1043 snd_ctrl.active = active;
1044 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1046 HandleSoundRequest(snd_ctrl);
1049 static void ReloadCustomSounds()
1051 LoadArtworkConfig(sound_info);
1052 ReloadCustomArtworkList(sound_info);
1055 static void ReloadCustomMusic()
1057 LoadArtworkConfig(music_info);
1058 ReloadCustomArtworkList(music_info);
1060 /* load all music files from directory not defined in "musicinfo.conf" */
1061 LoadCustomMusic_NoConf();
1064 void InitReloadCustomSounds(char *set_identifier)
1066 if (!audio.sound_available)
1069 ReloadCustomSounds();
1072 void InitReloadCustomMusic(char *set_identifier)
1074 if (!audio.music_available)
1077 ReloadCustomMusic();
1080 void FreeSound(void *ptr)
1082 SoundInfo *sound = (SoundInfo *)ptr;
1087 if (sound->data_ptr)
1089 Mix_FreeChunk(sound->data_ptr);
1092 checked_free(sound->source_filename);
1097 void FreeMusic(void *ptr)
1099 MusicInfo *music = (MusicInfo *)ptr;
1104 if (music->data_ptr)
1106 if (music->type == MUS_TYPE_MOD)
1107 Mix_FreeMusic(music->data_ptr);
1109 Mix_FreeChunk(music->data_ptr);
1115 static void FreeAllMusic_NoConf()
1119 if (Music_NoConf == NULL)
1122 for (i = 0; i < num_music_noconf; i++)
1123 FreeMusic(Music_NoConf[i]);
1127 Music_NoConf = NULL;
1128 num_music_noconf = 0;
1131 void FreeAllSounds()
1133 FreeCustomArtworkLists(sound_info);
1138 FreeCustomArtworkLists(music_info);
1139 FreeAllMusic_NoConf();
1142 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1143 /* ========================================================================= */