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));
527 boolean isSoundPlaying(int nr)
531 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
532 if (mixer[i].active && mixer[i].nr == nr)
539 // THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
540 // ============================================================================
541 // THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS
543 #define CHUNK_ID_LEN 4 // IFF style chunk id length
544 #define WAV_HEADER_SIZE 16 // size of WAV file header
546 static void *Load_WAV(char *filename)
550 if (!audio.sound_available)
553 snd_info = checked_calloc(sizeof(SoundInfo));
555 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
557 Warn("cannot read sound file '%s': %s", filename, Mix_GetError());
564 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
566 snd_info->type = SND_TYPE_WAV;
567 snd_info->source_filename = getStringCopy(filename);
572 static void *Load_MOD(char *filename)
576 if (!audio.sound_available)
579 mod_info = checked_calloc(sizeof(MusicInfo));
581 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
583 Warn("cannot read music file '%s': %s", filename, Mix_GetError());
590 mod_info->type = MUS_TYPE_MOD;
591 mod_info->source_filename = getStringCopy(filename);
596 static void *Load_WAV_or_MOD(char *filename)
598 if (FileIsMusic(filename))
599 return Load_MOD(filename);
600 else if (FileIsSound(filename))
601 return Load_WAV(filename);
606 static int compareMusicInfo(const void *object1, const void *object2)
608 const MusicInfo *mi1 = *((MusicInfo **)object1);
609 const MusicInfo *mi2 = *((MusicInfo **)object2);
611 return strcmp(mi1->source_filename, mi2->source_filename);
614 static void LoadCustomMusic_NoConf(void)
616 static boolean draw_init_text = TRUE; // only draw at startup
617 static char *last_music_directory = NULL;
618 char *music_directory = getCustomMusicDirectory_NoConf();
620 DirectoryEntry *dir_entry;
621 int num_music = getMusicListSize();
623 if (!audio.sound_available)
626 if (last_music_directory != NULL &&
627 strEqual(last_music_directory, music_directory))
628 return; // old and new music directory are the same
630 if (last_music_directory != NULL)
631 free(last_music_directory);
632 last_music_directory = getStringCopy(music_directory);
634 FreeAllMusic_NoConf();
636 if (music_directory == NULL)
638 Warn("cannot find music directory with unconfigured music");
642 else if ((dir = openDirectory(music_directory)) == NULL)
644 Warn("cannot read music directory '%s'", music_directory);
650 DrawInitTextHead("Loading music");
652 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
654 char *basename = dir_entry->basename;
655 MusicInfo *mus_info = NULL;
656 boolean music_already_used = FALSE;
659 // skip all music files that are configured in music config file
660 for (i = 0; i < num_music; i++)
662 struct FileInfo *music = getMusicListEntry(i);
664 if (strEqual(basename, music->filename))
666 music_already_used = TRUE;
671 if (music_already_used)
675 DrawInitTextItem(basename);
677 if (FileIsMusic(dir_entry->filename))
678 mus_info = Load_WAV_or_MOD(dir_entry->filename);
683 Music_NoConf = checked_realloc(Music_NoConf,
684 num_music_noconf * sizeof(MusicInfo *));
685 Music_NoConf[num_music_noconf - 1] = mus_info;
691 // sort music files by filename
692 qsort(Music_NoConf, num_music_noconf, sizeof(MusicInfo *), compareMusicInfo);
694 draw_init_text = FALSE;
697 int getSoundListSize(void)
699 return (sound_info->num_file_list_entries +
700 sound_info->num_dynamic_file_list_entries);
703 int getMusicListSize(void)
705 return (music_info->num_file_list_entries +
706 music_info->num_dynamic_file_list_entries);
709 int getMusicListSize_NoConf(void)
711 return num_music_noconf;
714 struct FileInfo *getSoundListEntry(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);
720 if (pos < 0 || pos >= num_sounds) // invalid sound
723 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
724 &sound_info->dynamic_file_list[list_pos]);
727 struct FileInfo *getMusicListEntry(int pos)
729 int num_music = getMusicListSize();
730 int num_list_entries = music_info->num_file_list_entries;
731 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
733 if (pos < 0 || pos >= num_music) // invalid music
736 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
737 &music_info->dynamic_file_list[list_pos]);
740 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
742 int num_sounds = getSoundListSize();
743 int num_list_entries = sound_info->num_file_list_entries;
744 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
745 SoundInfo **snd_info =
746 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
747 sound_info->dynamic_artwork_list);
749 if (pos < 0 || pos >= num_sounds) // invalid sound
752 return snd_info[list_pos];
755 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
757 int num_music = getMusicListSize();
758 int num_list_entries = music_info->num_file_list_entries;
759 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
760 MusicInfo **mus_info =
761 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
762 music_info->dynamic_artwork_list);
764 if (pos >= num_music) // invalid music
767 if (pos < 0) // undefined music
769 if (num_music_noconf == 0) // no fallback music available
772 pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
774 return Music_NoConf[pos];
777 return mus_info[list_pos];
780 char *getSoundInfoEntryFilename(int pos)
782 SoundInfo *snd_info = getSoundInfoEntryFromSoundID(pos);
784 if (snd_info == NULL)
787 return getBaseNamePtr(snd_info->source_filename);
790 char *getMusicInfoEntryFilename(int pos)
792 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
794 if (mus_info == NULL)
797 return getBaseNamePtr(mus_info->source_filename);
800 char *getCurrentlyPlayingMusicFilename(void)
802 return currently_playing_music_filename;
805 int getSoundListPropertyMappingSize(void)
807 return sound_info->num_property_mapping_entries;
810 int getMusicListPropertyMappingSize(void)
812 return music_info->num_property_mapping_entries;
815 struct PropertyMapping *getSoundListPropertyMapping(void)
817 return sound_info->property_mapping;
820 struct PropertyMapping *getMusicListPropertyMapping(void)
822 return music_info->property_mapping;
825 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
826 struct ConfigTypeInfo *config_suffix_list,
827 char **base_prefixes, char **ext1_suffixes,
828 char **ext2_suffixes, char **ext3_suffixes,
829 char **ignore_tokens)
833 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
834 sound_info->type = ARTWORK_TYPE_SOUNDS;
836 // ---------- initialize file list and suffix lists ----------
838 sound_info->num_file_list_entries = num_file_list_entries;
839 sound_info->num_dynamic_file_list_entries = 0;
841 sound_info->file_list =
842 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
843 num_file_list_entries);
844 sound_info->dynamic_file_list = NULL;
846 sound_info->num_suffix_list_entries = 0;
847 for (i = 0; config_suffix_list[i].token != NULL; i++)
848 sound_info->num_suffix_list_entries++;
850 sound_info->suffix_list = config_suffix_list;
852 // ---------- initialize base prefix and suffixes lists ----------
854 sound_info->num_base_prefixes = 0;
855 for (i = 0; base_prefixes[i] != NULL; i++)
856 sound_info->num_base_prefixes++;
858 sound_info->num_ext1_suffixes = 0;
859 for (i = 0; ext1_suffixes[i] != NULL; i++)
860 sound_info->num_ext1_suffixes++;
862 sound_info->num_ext2_suffixes = 0;
863 for (i = 0; ext2_suffixes[i] != NULL; i++)
864 sound_info->num_ext2_suffixes++;
866 sound_info->num_ext3_suffixes = 0;
867 for (i = 0; ext3_suffixes[i] != NULL; i++)
868 sound_info->num_ext3_suffixes++;
870 sound_info->num_ignore_tokens = 0;
871 for (i = 0; ignore_tokens[i] != NULL; i++)
872 sound_info->num_ignore_tokens++;
874 sound_info->base_prefixes = base_prefixes;
875 sound_info->ext1_suffixes = ext1_suffixes;
876 sound_info->ext2_suffixes = ext2_suffixes;
877 sound_info->ext3_suffixes = ext3_suffixes;
878 sound_info->ignore_tokens = ignore_tokens;
880 sound_info->num_property_mapping_entries = 0;
882 sound_info->property_mapping = NULL;
884 // ---------- initialize artwork reference and content lists ----------
886 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
888 sound_info->artwork_list =
889 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
890 sound_info->dynamic_artwork_list = NULL;
892 sound_info->content_list = NULL;
894 // ---------- initialize artwork loading/freeing functions ----------
896 sound_info->load_artwork = Load_WAV;
897 sound_info->free_artwork = FreeSound;
900 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
901 struct ConfigTypeInfo *config_suffix_list,
902 char **base_prefixes, char **ext1_suffixes,
903 char **ext2_suffixes, char **ext3_suffixes,
904 char **ignore_tokens)
908 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
909 music_info->type = ARTWORK_TYPE_MUSIC;
911 // ---------- initialize file list and suffix lists ----------
913 music_info->num_file_list_entries = num_file_list_entries;
914 music_info->num_dynamic_file_list_entries = 0;
916 music_info->file_list =
917 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
918 num_file_list_entries);
919 music_info->dynamic_file_list = NULL;
921 music_info->num_suffix_list_entries = 0;
922 for (i = 0; config_suffix_list[i].token != NULL; i++)
923 music_info->num_suffix_list_entries++;
925 music_info->suffix_list = config_suffix_list;
927 // ---------- initialize base prefix and suffixes lists ----------
929 music_info->num_base_prefixes = 0;
930 for (i = 0; base_prefixes[i] != NULL; i++)
931 music_info->num_base_prefixes++;
933 music_info->num_ext1_suffixes = 0;
934 for (i = 0; ext1_suffixes[i] != NULL; i++)
935 music_info->num_ext1_suffixes++;
937 music_info->num_ext2_suffixes = 0;
938 for (i = 0; ext2_suffixes[i] != NULL; i++)
939 music_info->num_ext2_suffixes++;
941 music_info->num_ext3_suffixes = 0;
942 for (i = 0; ext3_suffixes[i] != NULL; i++)
943 music_info->num_ext3_suffixes++;
945 music_info->num_ignore_tokens = 0;
946 for (i = 0; ignore_tokens[i] != NULL; i++)
947 music_info->num_ignore_tokens++;
949 music_info->base_prefixes = base_prefixes;
950 music_info->ext1_suffixes = ext1_suffixes;
951 music_info->ext2_suffixes = ext2_suffixes;
952 music_info->ext3_suffixes = ext3_suffixes;
953 music_info->ignore_tokens = ignore_tokens;
955 music_info->num_property_mapping_entries = 0;
957 music_info->property_mapping = NULL;
959 // ---------- initialize artwork reference and content lists ----------
961 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
963 music_info->artwork_list =
964 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
965 music_info->dynamic_artwork_list = NULL;
967 music_info->content_list = NULL;
969 // ---------- initialize artwork loading/freeing functions ----------
971 music_info->load_artwork = Load_WAV_or_MOD;
972 music_info->free_artwork = FreeMusic;
975 void PlayMusic(int nr)
977 if (!audio.music_available)
983 void PlayMusicLoop(int nr)
985 if (!audio.music_available)
988 PlaySoundMusicLoop(nr);
991 void PlaySound(int nr)
993 if (!setup.sound_simple)
996 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
999 void PlaySoundStereo(int nr, int stereo_position)
1001 if (!setup.sound_simple)
1004 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
1007 void PlaySoundLoop(int nr)
1009 if (!setup.sound_loops)
1012 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
1015 void PlaySoundMusic(int nr)
1017 if (!setup.sound_music)
1020 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
1023 void PlaySoundMusicLoop(int nr)
1025 if (!setup.sound_music)
1028 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC_LOOP);
1031 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
1033 SoundControl snd_ctrl;
1035 if (!audio.sound_available ||
1036 !audio.sound_enabled ||
1037 audio.sound_deactivated)
1040 volume = SETUP_SOUND_VOLUME(volume, state);
1042 if (volume < SOUND_MIN_VOLUME)
1043 volume = SOUND_MIN_VOLUME;
1044 else if (volume > SOUND_MAX_VOLUME)
1045 volume = SOUND_MAX_VOLUME;
1047 if (stereo_position < SOUND_MAX_LEFT)
1048 stereo_position = SOUND_MAX_LEFT;
1049 else if (stereo_position > SOUND_MAX_RIGHT)
1050 stereo_position = SOUND_MAX_RIGHT;
1052 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1054 snd_ctrl.active = TRUE;
1056 snd_ctrl.volume = volume;
1057 snd_ctrl.stereo_position = stereo_position;
1058 snd_ctrl.state = state;
1060 HandleSoundRequest(snd_ctrl);
1063 void FadeMusic(void)
1065 if (!audio.music_available)
1068 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1071 void FadeSound(int nr)
1073 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1076 void FadeSounds(void)
1078 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1081 void FadeSoundsAndMusic(void)
1087 void StopMusic(void)
1089 if (!audio.music_available)
1092 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1095 void StopSound(int nr)
1097 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1100 void StopSounds(void)
1103 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1106 void StopSoundExt(int nr, int state)
1108 SoundControl snd_ctrl;
1110 if (!audio.sound_available)
1113 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1115 snd_ctrl.active = FALSE;
1117 snd_ctrl.state = state;
1119 HandleSoundRequest(snd_ctrl);
1122 void ExpireSoundLoops(boolean active)
1124 SoundControl snd_ctrl;
1126 if (!audio.sound_available)
1129 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1131 snd_ctrl.active = active;
1132 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1134 HandleSoundRequest(snd_ctrl);
1137 static void ReloadCustomSounds(void)
1139 LoadArtworkConfig(sound_info);
1140 ReloadCustomArtworkList(sound_info);
1143 static void ReloadCustomMusic(void)
1145 LoadArtworkConfig(music_info);
1146 ReloadCustomArtworkList(music_info);
1148 // load all music files from directory not defined in "musicinfo.conf"
1149 LoadCustomMusic_NoConf();
1152 void InitReloadCustomSounds(void)
1154 if (!audio.sound_available)
1157 ReloadCustomSounds();
1160 void InitReloadCustomMusic(void)
1162 if (!audio.music_available)
1165 ReloadCustomMusic();
1168 void FreeSound(void *ptr)
1170 SoundInfo *sound = (SoundInfo *)ptr;
1175 if (sound->data_ptr)
1177 Mix_FreeChunk(sound->data_ptr);
1180 checked_free(sound->source_filename);
1185 void FreeMusic(void *ptr)
1187 MusicInfo *music = (MusicInfo *)ptr;
1192 if (music->data_ptr)
1194 if (music->type == MUS_TYPE_MOD)
1195 Mix_FreeMusic(music->data_ptr);
1197 Mix_FreeChunk(music->data_ptr);
1203 static void FreeAllMusic_NoConf(void)
1207 if (Music_NoConf == NULL)
1210 for (i = 0; i < num_music_noconf; i++)
1211 FreeMusic(Music_NoConf[i]);
1215 Music_NoConf = NULL;
1216 num_music_noconf = 0;
1219 void FreeAllSounds(void)
1221 FreeCustomArtworkLists(sound_info);
1224 void FreeAllMusic(void)
1226 FreeCustomArtworkLists(music_info);
1227 FreeAllMusic_NoConf();
1230 // THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS
1231 // ============================================================================