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_sounds = getSoundListSize();
691 int num_list_entries = sound_info->num_file_list_entries;
692 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
694 if (pos < 0 || pos >= num_sounds) /* invalid sound */
697 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
698 &sound_info->dynamic_file_list[list_pos]);
701 struct FileInfo *getMusicListEntry(int pos)
703 int num_music = getMusicListSize();
704 int num_list_entries = music_info->num_file_list_entries;
705 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
707 if (pos < 0 || pos >= num_music) /* invalid music */
710 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
711 &music_info->dynamic_file_list[list_pos]);
714 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
716 int num_sounds = getSoundListSize();
717 int num_list_entries = sound_info->num_file_list_entries;
718 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
719 SoundInfo **snd_info =
720 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
721 sound_info->dynamic_artwork_list);
723 if (pos < 0 || pos >= num_sounds) /* invalid sound */
726 return snd_info[list_pos];
729 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
731 int num_music = getMusicListSize();
732 int num_list_entries = music_info->num_file_list_entries;
733 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
734 MusicInfo **mus_info =
735 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
736 music_info->dynamic_artwork_list);
738 if (pos < 0 || pos >= num_music) /* invalid music */
741 return mus_info[list_pos];
744 char *getMusicInfoEntryFilename(int pos)
746 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
748 if (mus_info == NULL)
751 return getBaseNamePtr(mus_info->source_filename);
754 char *getCurrentlyPlayingMusicFilename()
756 return currently_playing_music_filename;
759 int getSoundListPropertyMappingSize()
761 return sound_info->num_property_mapping_entries;
764 int getMusicListPropertyMappingSize()
766 return music_info->num_property_mapping_entries;
769 struct PropertyMapping *getSoundListPropertyMapping()
771 return sound_info->property_mapping;
774 struct PropertyMapping *getMusicListPropertyMapping()
776 return music_info->property_mapping;
779 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
780 struct ConfigTypeInfo *config_suffix_list,
781 char **base_prefixes, char **ext1_suffixes,
782 char **ext2_suffixes, char **ext3_suffixes,
783 char **ignore_tokens)
787 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
788 sound_info->type = ARTWORK_TYPE_SOUNDS;
790 /* ---------- initialize file list and suffix lists ---------- */
792 sound_info->num_file_list_entries = num_file_list_entries;
793 sound_info->num_dynamic_file_list_entries = 0;
795 sound_info->file_list =
796 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
797 num_file_list_entries);
798 sound_info->dynamic_file_list = NULL;
800 sound_info->num_suffix_list_entries = 0;
801 for (i = 0; config_suffix_list[i].token != NULL; i++)
802 sound_info->num_suffix_list_entries++;
804 sound_info->suffix_list = config_suffix_list;
806 /* ---------- initialize base prefix and suffixes lists ---------- */
808 sound_info->num_base_prefixes = 0;
809 for (i = 0; base_prefixes[i] != NULL; i++)
810 sound_info->num_base_prefixes++;
812 sound_info->num_ext1_suffixes = 0;
813 for (i = 0; ext1_suffixes[i] != NULL; i++)
814 sound_info->num_ext1_suffixes++;
816 sound_info->num_ext2_suffixes = 0;
817 for (i = 0; ext2_suffixes[i] != NULL; i++)
818 sound_info->num_ext2_suffixes++;
820 sound_info->num_ext3_suffixes = 0;
821 for (i = 0; ext3_suffixes[i] != NULL; i++)
822 sound_info->num_ext3_suffixes++;
824 sound_info->num_ignore_tokens = 0;
825 for (i = 0; ignore_tokens[i] != NULL; i++)
826 sound_info->num_ignore_tokens++;
828 sound_info->base_prefixes = base_prefixes;
829 sound_info->ext1_suffixes = ext1_suffixes;
830 sound_info->ext2_suffixes = ext2_suffixes;
831 sound_info->ext3_suffixes = ext3_suffixes;
832 sound_info->ignore_tokens = ignore_tokens;
834 sound_info->num_property_mapping_entries = 0;
836 sound_info->property_mapping = NULL;
838 /* ---------- initialize artwork reference and content lists ---------- */
840 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
842 sound_info->artwork_list =
843 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
844 sound_info->dynamic_artwork_list = NULL;
846 sound_info->content_list = NULL;
848 /* ---------- initialize artwork loading/freeing functions ---------- */
850 sound_info->load_artwork = Load_WAV;
851 sound_info->free_artwork = FreeSound;
854 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
855 struct ConfigTypeInfo *config_suffix_list,
856 char **base_prefixes, char **ext1_suffixes,
857 char **ext2_suffixes, char **ext3_suffixes,
858 char **ignore_tokens)
862 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
863 music_info->type = ARTWORK_TYPE_MUSIC;
865 /* ---------- initialize file list and suffix lists ---------- */
867 music_info->num_file_list_entries = num_file_list_entries;
868 music_info->num_dynamic_file_list_entries = 0;
870 music_info->file_list =
871 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
872 num_file_list_entries);
873 music_info->dynamic_file_list = NULL;
875 music_info->num_suffix_list_entries = 0;
876 for (i = 0; config_suffix_list[i].token != NULL; i++)
877 music_info->num_suffix_list_entries++;
879 music_info->suffix_list = config_suffix_list;
881 /* ---------- initialize base prefix and suffixes lists ---------- */
883 music_info->num_base_prefixes = 0;
884 for (i = 0; base_prefixes[i] != NULL; i++)
885 music_info->num_base_prefixes++;
887 music_info->num_ext1_suffixes = 0;
888 for (i = 0; ext1_suffixes[i] != NULL; i++)
889 music_info->num_ext1_suffixes++;
891 music_info->num_ext2_suffixes = 0;
892 for (i = 0; ext2_suffixes[i] != NULL; i++)
893 music_info->num_ext2_suffixes++;
895 music_info->num_ext3_suffixes = 0;
896 for (i = 0; ext3_suffixes[i] != NULL; i++)
897 music_info->num_ext3_suffixes++;
899 music_info->num_ignore_tokens = 0;
900 for (i = 0; ignore_tokens[i] != NULL; i++)
901 music_info->num_ignore_tokens++;
903 music_info->base_prefixes = base_prefixes;
904 music_info->ext1_suffixes = ext1_suffixes;
905 music_info->ext2_suffixes = ext2_suffixes;
906 music_info->ext3_suffixes = ext3_suffixes;
907 music_info->ignore_tokens = ignore_tokens;
909 music_info->num_property_mapping_entries = 0;
911 music_info->property_mapping = NULL;
913 /* ---------- initialize artwork reference and content lists ---------- */
915 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
917 music_info->artwork_list =
918 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
919 music_info->dynamic_artwork_list = NULL;
921 music_info->content_list = NULL;
923 /* ---------- initialize artwork loading/freeing functions ---------- */
925 music_info->load_artwork = Load_WAV_or_MOD;
926 music_info->free_artwork = FreeMusic;
929 void PlayMusic(int nr)
931 if (!audio.music_available)
937 void PlaySound(int nr)
939 if (!setup.sound_simple)
942 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
945 void PlaySoundStereo(int nr, int stereo_position)
947 if (!setup.sound_simple)
950 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
953 void PlaySoundLoop(int nr)
955 if (!setup.sound_loops)
958 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
961 void PlaySoundMusic(int nr)
963 if (!setup.sound_music)
966 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
969 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
971 SoundControl snd_ctrl;
973 if (!audio.sound_available ||
974 !audio.sound_enabled ||
975 audio.sound_deactivated)
978 volume = SETUP_SOUND_VOLUME(volume, state);
980 if (volume < SOUND_MIN_VOLUME)
981 volume = SOUND_MIN_VOLUME;
982 else if (volume > SOUND_MAX_VOLUME)
983 volume = SOUND_MAX_VOLUME;
985 if (stereo_position < SOUND_MAX_LEFT)
986 stereo_position = SOUND_MAX_LEFT;
987 else if (stereo_position > SOUND_MAX_RIGHT)
988 stereo_position = SOUND_MAX_RIGHT;
990 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
992 snd_ctrl.active = TRUE;
994 snd_ctrl.volume = volume;
995 snd_ctrl.stereo_position = stereo_position;
996 snd_ctrl.state = state;
998 HandleSoundRequest(snd_ctrl);
1001 void FadeMusic(void)
1003 if (!audio.music_available)
1006 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1009 void FadeSound(int nr)
1011 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1016 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1019 void FadeSoundsAndMusic()
1025 void StopMusic(void)
1027 if (!audio.music_available)
1030 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1033 void StopSound(int nr)
1035 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1041 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1044 void StopSoundExt(int nr, int state)
1046 SoundControl snd_ctrl;
1048 if (!audio.sound_available)
1051 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
1053 snd_ctrl.active = FALSE;
1055 snd_ctrl.state = state;
1057 HandleSoundRequest(snd_ctrl);
1060 void ExpireSoundLoops(boolean active)
1062 SoundControl snd_ctrl;
1064 if (!audio.sound_available)
1067 clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */
1069 snd_ctrl.active = active;
1070 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1072 HandleSoundRequest(snd_ctrl);
1075 static void ReloadCustomSounds()
1077 LoadArtworkConfig(sound_info);
1078 ReloadCustomArtworkList(sound_info);
1081 static void ReloadCustomMusic()
1083 LoadArtworkConfig(music_info);
1084 ReloadCustomArtworkList(music_info);
1086 /* load all music files from directory not defined in "musicinfo.conf" */
1087 LoadCustomMusic_NoConf();
1090 void InitReloadCustomSounds(char *set_identifier)
1092 if (!audio.sound_available)
1095 ReloadCustomSounds();
1098 void InitReloadCustomMusic(char *set_identifier)
1100 if (!audio.music_available)
1103 ReloadCustomMusic();
1106 void FreeSound(void *ptr)
1108 SoundInfo *sound = (SoundInfo *)ptr;
1113 if (sound->data_ptr)
1115 Mix_FreeChunk(sound->data_ptr);
1118 checked_free(sound->source_filename);
1123 void FreeMusic(void *ptr)
1125 MusicInfo *music = (MusicInfo *)ptr;
1130 if (music->data_ptr)
1132 if (music->type == MUS_TYPE_MOD)
1133 Mix_FreeMusic(music->data_ptr);
1135 Mix_FreeChunk(music->data_ptr);
1141 static void FreeAllMusic_NoConf()
1145 if (Music_NoConf == NULL)
1148 for (i = 0; i < num_music_noconf; i++)
1149 FreeMusic(Music_NoConf[i]);
1153 Music_NoConf = NULL;
1154 num_music_noconf = 0;
1157 void FreeAllSounds()
1159 FreeCustomArtworkLists(sound_info);
1164 FreeCustomArtworkLists(music_info);
1165 FreeAllMusic_NoConf();
1168 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1169 /* ========================================================================= */