1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://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_MUSIC ? \
63 SOUND_VOLUME_MUSIC(v) : \
64 (s) & SND_CTRL_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(void);
130 static void ReloadCustomMusic(void);
131 static void FreeSound(void *);
132 static void FreeMusic(void *);
133 static void FreeAllMusic_NoConf(void);
134 static void Mixer_StopMusicChannel(void);
136 static SoundInfo *getSoundInfoEntryFromSoundID(int);
137 static MusicInfo *getMusicInfoEntryFromMusicID(int);
140 // ----------------------------------------------------------------------------
142 // ----------------------------------------------------------------------------
144 static void Mixer_ChannelFinished(int channel)
146 if (!mixer[channel].active)
149 mixer[channel].active = FALSE;
150 mixer_active_channels--;
153 void Mixer_InitChannels(void)
157 for (i = 0; i < audio.num_channels; i++)
158 mixer[i].active = FALSE;
159 mixer_active_channels = 0;
161 Mix_ChannelFinished(Mixer_ChannelFinished);
164 static void Mixer_ResetChannelExpiration(int channel)
166 mixer[channel].playing_starttime = Counter();
168 if (expire_loop_sounds &&
169 IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
170 Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME);
173 static boolean Mixer_ChannelExpired(int channel)
175 if (!mixer[channel].active)
178 if (expire_loop_sounds &&
179 IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
180 DelayReachedExt2(&mixer[channel].playing_starttime,
181 SOUND_LOOP_EXPIRATION_TIME, Counter()))
184 if (!Mix_Playing(channel))
190 static boolean Mixer_AllocateChannel(int channel)
195 static void Mixer_SetChannelProperties(int channel)
197 Mix_Volume(channel, mixer[channel].volume);
198 Mix_SetPanning(channel,
199 SOUND_VOLUME_LEFT(mixer[channel].stereo_position),
200 SOUND_VOLUME_RIGHT(mixer[channel].stereo_position));
203 static void Mixer_StartChannel(int channel)
205 Mix_PlayChannel(channel, mixer[channel].data_ptr,
206 IS_LOOP(mixer[channel]) ? -1 : 0);
209 static void Mixer_PlayChannel(int channel)
211 // start with inactive channel in case something goes wrong
212 mixer[channel].active = FALSE;
214 if (mixer[channel].type != MUS_TYPE_WAV)
217 if (!Mixer_AllocateChannel(channel))
220 Mixer_SetChannelProperties(channel);
221 Mixer_StartChannel(channel);
223 Mixer_ResetChannelExpiration(channel);
225 mixer[channel].playing_pos = 0;
226 mixer[channel].active = TRUE;
227 mixer_active_channels++;
230 static void Mixer_PlayMusicChannel(void)
232 Mixer_PlayChannel(audio.music_channel);
234 if (mixer[audio.music_channel].type != MUS_TYPE_WAV)
236 int loops = (IS_LOOP(mixer[audio.music_channel]) ? -1 : 1);
238 // stopping music channel before playing next track seems to be needed to
239 // prevent audio problems that may occur when playing MP3 files on Windows
240 Mixer_StopMusicChannel();
242 // use short fade-in to prevent "plop" sound for certain music files
243 // (this may happen when switching on music while playing the game)
244 Mix_VolumeMusic(mixer[audio.music_channel].volume);
245 Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, loops, 100);
247 #if defined(PLATFORM_WINDOWS)
248 // playing MIDI music is broken since Windows Vista, as it sets the volume
249 // for MIDI music also for all other sounds and music, which cannot be set
250 // back to normal unless playing MIDI music again with that desired volume
251 // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253)
252 // => workaround: always play MIDI music with maximum volume
253 if (Mix_GetMusicType(NULL) == MUS_MID)
254 Mix_VolumeMusic(SOUND_MAX_VOLUME);
259 static void Mixer_StopChannel(int channel)
261 Mix_HaltChannel(channel);
264 static void Mixer_StopMusicChannel(void)
266 Mixer_StopChannel(audio.music_channel);
270 setString(¤tly_playing_music_filename, NULL);
273 static void Mixer_FadeChannel(int channel)
275 if (!mixer[channel].active)
278 mixer[channel].state |= SND_CTRL_FADE;
280 Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL);
283 static void Mixer_FadeMusicChannel(void)
285 Mixer_FadeChannel(audio.music_channel);
287 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
289 #if defined(PLATFORM_WINDOWS)
290 // playing MIDI music is broken since Windows Vista, as it sets the volume
291 // for MIDI music also for all other sounds and music, which cannot be set
292 // back to normal unless playing MIDI music again with that desired volume
293 // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253)
294 // => workaround: never fade MIDI music to lower volume, but just stop it
295 if (Mix_GetMusicType(NULL) == MUS_MID)
296 Mixer_StopMusicChannel();
299 setString(¤tly_playing_music_filename, NULL);
302 static void Mixer_UnFadeChannel(int channel)
304 if (!mixer[channel].active || !IS_FADING(mixer[channel]))
307 mixer[channel].state &= ~SND_CTRL_FADE;
308 mixer[channel].volume = SOUND_MAX_VOLUME;
310 Mix_ExpireChannel(channel, -1);
311 Mix_Volume(channel, mixer[channel].volume);
314 static void Mixer_InsertSound(SoundControl snd_ctrl)
319 if (IS_MUSIC(snd_ctrl))
320 snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr);
322 snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
324 if (snd_info == NULL)
327 // copy sound sample and format information
328 snd_ctrl.type = snd_info->type;
329 snd_ctrl.format = snd_info->format;
330 snd_ctrl.data_ptr = snd_info->data_ptr;
331 snd_ctrl.data_len = snd_info->data_len;
332 snd_ctrl.num_channels = snd_info->num_channels;
334 // play music samples on a dedicated music channel
335 if (IS_MUSIC(snd_ctrl))
337 Mixer_StopMusicChannel();
339 mixer[audio.music_channel] = snd_ctrl;
340 Mixer_PlayMusicChannel();
342 setString(¤tly_playing_music_filename,
343 getBaseNamePtr(snd_info->source_filename));
348 // check if (and how often) this sound sample is already playing
349 for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++)
350 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
353 // reset expiration delay for already playing loop sounds
354 if (k > 0 && IS_LOOP(snd_ctrl))
356 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
358 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
360 if (IS_FADING(mixer[i]))
361 Mixer_UnFadeChannel(i);
363 // restore settings like volume and stereo position
364 mixer[i].volume = snd_ctrl.volume;
365 mixer[i].stereo_position = snd_ctrl.stereo_position;
367 Mixer_SetChannelProperties(i);
368 Mixer_ResetChannelExpiration(i);
375 // don't play sound more than n times simultaneously (with n == 2 for now)
378 unsigned int playing_current = Counter();
379 int longest = 0, longest_nr = audio.first_sound_channel;
381 // look for oldest equal sound
382 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
384 int playing_time = playing_current - mixer[i].playing_starttime;
387 if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
390 actual = 1000 * playing_time / mixer[i].data_len;
392 if (actual >= longest)
399 Mixer_StopChannel(longest_nr);
402 /* If all (non-music) channels are active, stop the channel that has
403 played its sound sample most completely (in percent of the sample
404 length). As we cannot currently get the actual playing position
405 of the channel's sound sample when compiling with the SDL mixer
406 library, we use the current playing time (in milliseconds) instead. */
409 // channel allocation sanity check -- should not be needed
410 if (mixer_active_channels ==
411 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
413 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
415 if (!mixer[i].active)
417 Debug("audio", "Mixer_InsertSound: Channel %d inactive", i);
418 Debug("audio", "Mixer_InsertSound: This should never happen!");
420 mixer_active_channels--;
426 if (mixer_active_channels ==
427 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
429 unsigned int playing_current = Counter();
430 int longest = 0, longest_nr = audio.first_sound_channel;
432 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
434 int playing_time = playing_current - mixer[i].playing_starttime;
435 int actual = 1000 * playing_time / mixer[i].data_len;
437 if (!IS_LOOP(mixer[i]) && actual > longest)
444 Mixer_StopChannel(longest_nr);
447 // add the new sound to the mixer
448 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
450 if (!mixer[i].active)
453 Mixer_PlayChannel(i);
460 static void HandleSoundRequest(SoundControl snd_ctrl)
464 // deactivate channels that have expired since the last request
465 for (i = 0; i < audio.num_channels; i++)
466 if (mixer[i].active && Mixer_ChannelExpired(i))
467 Mixer_StopChannel(i);
469 if (IS_RELOADING(snd_ctrl)) // load new sound or music files
471 Mixer_StopMusicChannel();
472 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
473 Mixer_StopChannel(i);
475 if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
476 ReloadCustomSounds();
480 else if (IS_FADING(snd_ctrl)) // fade out existing sound or music
482 if (IS_MUSIC(snd_ctrl))
484 Mixer_FadeMusicChannel();
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_FadeChannel(i);
492 else if (IS_STOPPING(snd_ctrl)) // stop existing sound or music
494 if (IS_MUSIC(snd_ctrl))
496 Mixer_StopMusicChannel();
500 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
501 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
502 Mixer_StopChannel(i);
504 else if (SET_EXPIRE_LOOPS(snd_ctrl)) // set loop expiration on or off
506 expire_loop_sounds = snd_ctrl.active;
508 else if (snd_ctrl.active) // add new sound to mixer
510 Mixer_InsertSound(snd_ctrl);
514 void StartMixer(void)
518 if (!audio.sound_available)
521 // initialize stereo position conversion information
522 for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
524 (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
528 // THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
529 // ============================================================================
530 // THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS
532 #define CHUNK_ID_LEN 4 // IFF style chunk id length
533 #define WAV_HEADER_SIZE 16 // size of WAV file header
535 static void *Load_WAV(char *filename)
539 if (!audio.sound_available)
542 snd_info = checked_calloc(sizeof(SoundInfo));
544 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
546 Warn("cannot read sound file '%s': %s", filename, Mix_GetError());
553 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
555 snd_info->type = SND_TYPE_WAV;
556 snd_info->source_filename = getStringCopy(filename);
561 static void *Load_MOD(char *filename)
565 if (!audio.sound_available)
568 mod_info = checked_calloc(sizeof(MusicInfo));
570 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
572 Warn("cannot read music file '%s': %s", filename, Mix_GetError());
579 mod_info->type = MUS_TYPE_MOD;
580 mod_info->source_filename = getStringCopy(filename);
585 static void *Load_WAV_or_MOD(char *filename)
587 if (FileIsMusic(filename))
588 return Load_MOD(filename);
589 else if (FileIsSound(filename))
590 return Load_WAV(filename);
595 static int compareMusicInfo(const void *object1, const void *object2)
597 const MusicInfo *mi1 = *((MusicInfo **)object1);
598 const MusicInfo *mi2 = *((MusicInfo **)object2);
600 return strcmp(mi1->source_filename, mi2->source_filename);
603 static void LoadCustomMusic_NoConf(void)
605 static boolean draw_init_text = TRUE; // only draw at startup
606 static char *last_music_directory = NULL;
607 char *music_directory = getCustomMusicDirectory_NoConf();
609 DirectoryEntry *dir_entry;
610 int num_music = getMusicListSize();
612 if (!audio.sound_available)
615 if (last_music_directory != NULL &&
616 strEqual(last_music_directory, music_directory))
617 return; // old and new music directory are the same
619 if (last_music_directory != NULL)
620 free(last_music_directory);
621 last_music_directory = getStringCopy(music_directory);
623 FreeAllMusic_NoConf();
625 if (music_directory == NULL)
627 Warn("cannot find music directory with unconfigured music");
631 else if ((dir = openDirectory(music_directory)) == NULL)
633 Warn("cannot read music directory '%s'", music_directory);
639 DrawInitTextHead("Loading music");
641 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
643 char *basename = dir_entry->basename;
644 MusicInfo *mus_info = NULL;
645 boolean music_already_used = FALSE;
648 // skip all music files that are configured in music config file
649 for (i = 0; i < num_music; i++)
651 struct FileInfo *music = getMusicListEntry(i);
653 if (strEqual(basename, music->filename))
655 music_already_used = TRUE;
660 if (music_already_used)
664 DrawInitTextItem(basename);
666 if (FileIsMusic(dir_entry->filename))
667 mus_info = Load_WAV_or_MOD(dir_entry->filename);
672 Music_NoConf = checked_realloc(Music_NoConf,
673 num_music_noconf * sizeof(MusicInfo *));
674 Music_NoConf[num_music_noconf - 1] = mus_info;
680 // sort music files by filename
681 qsort(Music_NoConf, num_music_noconf, sizeof(MusicInfo *), compareMusicInfo);
683 draw_init_text = FALSE;
686 int getSoundListSize(void)
688 return (sound_info->num_file_list_entries +
689 sound_info->num_dynamic_file_list_entries);
692 int getMusicListSize(void)
694 return (music_info->num_file_list_entries +
695 music_info->num_dynamic_file_list_entries);
698 int getMusicListSize_NoConf(void)
700 return num_music_noconf;
703 struct FileInfo *getSoundListEntry(int pos)
705 int num_sounds = getSoundListSize();
706 int num_list_entries = sound_info->num_file_list_entries;
707 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
709 if (pos < 0 || pos >= num_sounds) // invalid sound
712 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
713 &sound_info->dynamic_file_list[list_pos]);
716 struct FileInfo *getMusicListEntry(int pos)
718 int num_music = getMusicListSize();
719 int num_list_entries = music_info->num_file_list_entries;
720 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
722 if (pos < 0 || pos >= num_music) // invalid music
725 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
726 &music_info->dynamic_file_list[list_pos]);
729 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
731 int num_sounds = getSoundListSize();
732 int num_list_entries = sound_info->num_file_list_entries;
733 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
734 SoundInfo **snd_info =
735 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
736 sound_info->dynamic_artwork_list);
738 if (pos < 0 || pos >= num_sounds) // invalid sound
741 return snd_info[list_pos];
744 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
746 int num_music = getMusicListSize();
747 int num_list_entries = music_info->num_file_list_entries;
748 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
749 MusicInfo **mus_info =
750 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
751 music_info->dynamic_artwork_list);
753 if (pos >= num_music) // invalid music
756 if (pos < 0) // undefined music
758 if (num_music_noconf == 0) // no fallback music available
761 pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
763 return Music_NoConf[pos];
766 return mus_info[list_pos];
769 char *getSoundInfoEntryFilename(int pos)
771 SoundInfo *snd_info = getSoundInfoEntryFromSoundID(pos);
773 if (snd_info == NULL)
776 return getBaseNamePtr(snd_info->source_filename);
779 char *getMusicInfoEntryFilename(int pos)
781 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
783 if (mus_info == NULL)
786 return getBaseNamePtr(mus_info->source_filename);
789 char *getCurrentlyPlayingMusicFilename(void)
791 return currently_playing_music_filename;
794 int getSoundListPropertyMappingSize(void)
796 return sound_info->num_property_mapping_entries;
799 int getMusicListPropertyMappingSize(void)
801 return music_info->num_property_mapping_entries;
804 struct PropertyMapping *getSoundListPropertyMapping(void)
806 return sound_info->property_mapping;
809 struct PropertyMapping *getMusicListPropertyMapping(void)
811 return music_info->property_mapping;
814 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
815 struct ConfigTypeInfo *config_suffix_list,
816 char **base_prefixes, char **ext1_suffixes,
817 char **ext2_suffixes, char **ext3_suffixes,
818 char **ignore_tokens)
822 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
823 sound_info->type = ARTWORK_TYPE_SOUNDS;
825 // ---------- initialize file list and suffix lists ----------
827 sound_info->num_file_list_entries = num_file_list_entries;
828 sound_info->num_dynamic_file_list_entries = 0;
830 sound_info->file_list =
831 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
832 num_file_list_entries);
833 sound_info->dynamic_file_list = NULL;
835 sound_info->num_suffix_list_entries = 0;
836 for (i = 0; config_suffix_list[i].token != NULL; i++)
837 sound_info->num_suffix_list_entries++;
839 sound_info->suffix_list = config_suffix_list;
841 // ---------- initialize base prefix and suffixes lists ----------
843 sound_info->num_base_prefixes = 0;
844 for (i = 0; base_prefixes[i] != NULL; i++)
845 sound_info->num_base_prefixes++;
847 sound_info->num_ext1_suffixes = 0;
848 for (i = 0; ext1_suffixes[i] != NULL; i++)
849 sound_info->num_ext1_suffixes++;
851 sound_info->num_ext2_suffixes = 0;
852 for (i = 0; ext2_suffixes[i] != NULL; i++)
853 sound_info->num_ext2_suffixes++;
855 sound_info->num_ext3_suffixes = 0;
856 for (i = 0; ext3_suffixes[i] != NULL; i++)
857 sound_info->num_ext3_suffixes++;
859 sound_info->num_ignore_tokens = 0;
860 for (i = 0; ignore_tokens[i] != NULL; i++)
861 sound_info->num_ignore_tokens++;
863 sound_info->base_prefixes = base_prefixes;
864 sound_info->ext1_suffixes = ext1_suffixes;
865 sound_info->ext2_suffixes = ext2_suffixes;
866 sound_info->ext3_suffixes = ext3_suffixes;
867 sound_info->ignore_tokens = ignore_tokens;
869 sound_info->num_property_mapping_entries = 0;
871 sound_info->property_mapping = NULL;
873 // ---------- initialize artwork reference and content lists ----------
875 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
877 sound_info->artwork_list =
878 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
879 sound_info->dynamic_artwork_list = NULL;
881 sound_info->content_list = NULL;
883 // ---------- initialize artwork loading/freeing functions ----------
885 sound_info->load_artwork = Load_WAV;
886 sound_info->free_artwork = FreeSound;
889 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
890 struct ConfigTypeInfo *config_suffix_list,
891 char **base_prefixes, char **ext1_suffixes,
892 char **ext2_suffixes, char **ext3_suffixes,
893 char **ignore_tokens)
897 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
898 music_info->type = ARTWORK_TYPE_MUSIC;
900 // ---------- initialize file list and suffix lists ----------
902 music_info->num_file_list_entries = num_file_list_entries;
903 music_info->num_dynamic_file_list_entries = 0;
905 music_info->file_list =
906 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
907 num_file_list_entries);
908 music_info->dynamic_file_list = NULL;
910 music_info->num_suffix_list_entries = 0;
911 for (i = 0; config_suffix_list[i].token != NULL; i++)
912 music_info->num_suffix_list_entries++;
914 music_info->suffix_list = config_suffix_list;
916 // ---------- initialize base prefix and suffixes lists ----------
918 music_info->num_base_prefixes = 0;
919 for (i = 0; base_prefixes[i] != NULL; i++)
920 music_info->num_base_prefixes++;
922 music_info->num_ext1_suffixes = 0;
923 for (i = 0; ext1_suffixes[i] != NULL; i++)
924 music_info->num_ext1_suffixes++;
926 music_info->num_ext2_suffixes = 0;
927 for (i = 0; ext2_suffixes[i] != NULL; i++)
928 music_info->num_ext2_suffixes++;
930 music_info->num_ext3_suffixes = 0;
931 for (i = 0; ext3_suffixes[i] != NULL; i++)
932 music_info->num_ext3_suffixes++;
934 music_info->num_ignore_tokens = 0;
935 for (i = 0; ignore_tokens[i] != NULL; i++)
936 music_info->num_ignore_tokens++;
938 music_info->base_prefixes = base_prefixes;
939 music_info->ext1_suffixes = ext1_suffixes;
940 music_info->ext2_suffixes = ext2_suffixes;
941 music_info->ext3_suffixes = ext3_suffixes;
942 music_info->ignore_tokens = ignore_tokens;
944 music_info->num_property_mapping_entries = 0;
946 music_info->property_mapping = NULL;
948 // ---------- initialize artwork reference and content lists ----------
950 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
952 music_info->artwork_list =
953 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
954 music_info->dynamic_artwork_list = NULL;
956 music_info->content_list = NULL;
958 // ---------- initialize artwork loading/freeing functions ----------
960 music_info->load_artwork = Load_WAV_or_MOD;
961 music_info->free_artwork = FreeMusic;
964 void PlayMusic(int nr)
966 if (!audio.music_available)
972 void PlayMusicLoop(int nr)
974 if (!audio.music_available)
977 PlaySoundMusicLoop(nr);
980 void PlaySound(int nr)
982 if (!setup.sound_simple)
985 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
988 void PlaySoundStereo(int nr, int stereo_position)
990 if (!setup.sound_simple)
993 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
996 void PlaySoundLoop(int nr)
998 if (!setup.sound_loops)
1001 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
1004 void PlaySoundMusic(int nr)
1006 if (!setup.sound_music)
1009 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
1012 void PlaySoundMusicLoop(int nr)
1014 if (!setup.sound_music)
1017 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC_LOOP);
1020 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
1022 SoundControl snd_ctrl;
1024 if (!audio.sound_available ||
1025 !audio.sound_enabled ||
1026 audio.sound_deactivated)
1029 volume = SETUP_SOUND_VOLUME(volume, state);
1031 if (volume < SOUND_MIN_VOLUME)
1032 volume = SOUND_MIN_VOLUME;
1033 else if (volume > SOUND_MAX_VOLUME)
1034 volume = SOUND_MAX_VOLUME;
1036 if (stereo_position < SOUND_MAX_LEFT)
1037 stereo_position = SOUND_MAX_LEFT;
1038 else if (stereo_position > SOUND_MAX_RIGHT)
1039 stereo_position = SOUND_MAX_RIGHT;
1041 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1043 snd_ctrl.active = TRUE;
1045 snd_ctrl.volume = volume;
1046 snd_ctrl.stereo_position = stereo_position;
1047 snd_ctrl.state = state;
1049 HandleSoundRequest(snd_ctrl);
1052 void FadeMusic(void)
1054 if (!audio.music_available)
1057 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1060 void FadeSound(int nr)
1062 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1065 void FadeSounds(void)
1067 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1070 void FadeSoundsAndMusic(void)
1076 void StopMusic(void)
1078 if (!audio.music_available)
1081 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1084 void StopSound(int nr)
1086 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1089 void StopSounds(void)
1092 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1095 void StopSoundExt(int nr, int state)
1097 SoundControl snd_ctrl;
1099 if (!audio.sound_available)
1102 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1104 snd_ctrl.active = FALSE;
1106 snd_ctrl.state = state;
1108 HandleSoundRequest(snd_ctrl);
1111 void ExpireSoundLoops(boolean active)
1113 SoundControl snd_ctrl;
1115 if (!audio.sound_available)
1118 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1120 snd_ctrl.active = active;
1121 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1123 HandleSoundRequest(snd_ctrl);
1126 static void ReloadCustomSounds(void)
1128 LoadArtworkConfig(sound_info);
1129 ReloadCustomArtworkList(sound_info);
1132 static void ReloadCustomMusic(void)
1134 LoadArtworkConfig(music_info);
1135 ReloadCustomArtworkList(music_info);
1137 // load all music files from directory not defined in "musicinfo.conf"
1138 LoadCustomMusic_NoConf();
1141 void InitReloadCustomSounds(void)
1143 if (!audio.sound_available)
1146 ReloadCustomSounds();
1149 void InitReloadCustomMusic(void)
1151 if (!audio.music_available)
1154 ReloadCustomMusic();
1157 void FreeSound(void *ptr)
1159 SoundInfo *sound = (SoundInfo *)ptr;
1164 if (sound->data_ptr)
1166 Mix_FreeChunk(sound->data_ptr);
1169 checked_free(sound->source_filename);
1174 void FreeMusic(void *ptr)
1176 MusicInfo *music = (MusicInfo *)ptr;
1181 if (music->data_ptr)
1183 if (music->type == MUS_TYPE_MOD)
1184 Mix_FreeMusic(music->data_ptr);
1186 Mix_FreeChunk(music->data_ptr);
1192 static void FreeAllMusic_NoConf(void)
1196 if (Music_NoConf == NULL)
1199 for (i = 0; i < num_music_noconf; i++)
1200 FreeMusic(Music_NoConf[i]);
1204 Music_NoConf = NULL;
1205 num_music_noconf = 0;
1208 void FreeAllSounds(void)
1210 FreeCustomArtworkLists(sound_info);
1213 void FreeAllMusic(void)
1215 FreeCustomArtworkLists(music_info);
1216 FreeAllMusic_NoConf();
1219 // THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS
1220 // ============================================================================