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 void Mixer_InitChannels(void)
148 for (i = 0; i < audio.num_channels; i++)
149 mixer[i].active = FALSE;
150 mixer_active_channels = 0;
153 static void Mixer_ResetChannelExpiration(int channel)
155 mixer[channel].playing_starttime = Counter();
157 if (expire_loop_sounds &&
158 IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
159 Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME);
162 static boolean Mixer_ChannelExpired(int channel)
164 if (!mixer[channel].active)
167 if (expire_loop_sounds &&
168 IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
169 DelayReachedExt2(&mixer[channel].playing_starttime,
170 SOUND_LOOP_EXPIRATION_TIME, Counter()))
173 if (!Mix_Playing(channel))
179 static boolean Mixer_AllocateChannel(int channel)
184 static void Mixer_SetChannelProperties(int channel)
186 Mix_Volume(channel, mixer[channel].volume);
187 Mix_SetPanning(channel,
188 SOUND_VOLUME_LEFT(mixer[channel].stereo_position),
189 SOUND_VOLUME_RIGHT(mixer[channel].stereo_position));
192 static void Mixer_StartChannel(int channel)
194 Mix_PlayChannel(channel, mixer[channel].data_ptr,
195 IS_LOOP(mixer[channel]) ? -1 : 0);
198 static void Mixer_PlayChannel(int channel)
200 // start with inactive channel in case something goes wrong
201 mixer[channel].active = FALSE;
203 if (mixer[channel].type != MUS_TYPE_WAV)
206 if (!Mixer_AllocateChannel(channel))
209 Mixer_SetChannelProperties(channel);
210 Mixer_StartChannel(channel);
212 Mixer_ResetChannelExpiration(channel);
214 mixer[channel].playing_pos = 0;
215 mixer[channel].active = TRUE;
216 mixer_active_channels++;
219 static void Mixer_PlayMusicChannel(void)
221 Mixer_PlayChannel(audio.music_channel);
223 if (mixer[audio.music_channel].type != MUS_TYPE_WAV)
225 int loops = (IS_LOOP(mixer[audio.music_channel]) ? -1 : 1);
227 // stopping music channel before playing next track seems to be needed to
228 // prevent audio problems that may occur when playing MP3 files on Windows
229 Mixer_StopMusicChannel();
231 // use short fade-in to prevent "plop" sound for certain music files
232 // (this may happen when switching on music while playing the game)
233 Mix_VolumeMusic(mixer[audio.music_channel].volume);
234 Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, loops, 100);
236 #if defined(PLATFORM_WINDOWS)
237 // playing MIDI music is broken since Windows Vista, as it sets the volume
238 // for MIDI music also for all other sounds and music, which cannot be set
239 // back to normal unless playing MIDI music again with that desired volume
240 // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253)
241 // => workaround: always play MIDI music with maximum volume
242 if (Mix_GetMusicType(NULL) == MUS_MID)
243 Mix_VolumeMusic(SOUND_MAX_VOLUME);
248 static void Mixer_StopChannel(int channel)
250 if (!mixer[channel].active)
253 Mix_HaltChannel(channel);
255 mixer[channel].active = FALSE;
256 mixer_active_channels--;
259 static void Mixer_StopMusicChannel(void)
261 Mixer_StopChannel(audio.music_channel);
265 setString(¤tly_playing_music_filename, NULL);
268 static void Mixer_FadeChannel(int channel)
270 if (!mixer[channel].active)
273 mixer[channel].state |= SND_CTRL_FADE;
275 Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL);
278 static void Mixer_FadeMusicChannel(void)
280 Mixer_FadeChannel(audio.music_channel);
282 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
284 #if defined(PLATFORM_WINDOWS)
285 // playing MIDI music is broken since Windows Vista, as it sets the volume
286 // for MIDI music also for all other sounds and music, which cannot be set
287 // back to normal unless playing MIDI music again with that desired volume
288 // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253)
289 // => workaround: never fade MIDI music to lower volume, but just stop it
290 if (Mix_GetMusicType(NULL) == MUS_MID)
291 Mixer_StopMusicChannel();
294 setString(¤tly_playing_music_filename, NULL);
297 static void Mixer_UnFadeChannel(int channel)
299 if (!mixer[channel].active || !IS_FADING(mixer[channel]))
302 mixer[channel].state &= ~SND_CTRL_FADE;
303 mixer[channel].volume = SOUND_MAX_VOLUME;
305 Mix_ExpireChannel(channel, -1);
306 Mix_Volume(channel, mixer[channel].volume);
309 static void Mixer_InsertSound(SoundControl snd_ctrl)
314 if (IS_MUSIC(snd_ctrl))
315 snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr);
317 snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
319 if (snd_info == NULL)
322 // copy sound sample and format information
323 snd_ctrl.type = snd_info->type;
324 snd_ctrl.format = snd_info->format;
325 snd_ctrl.data_ptr = snd_info->data_ptr;
326 snd_ctrl.data_len = snd_info->data_len;
327 snd_ctrl.num_channels = snd_info->num_channels;
329 // play music samples on a dedicated music channel
330 if (IS_MUSIC(snd_ctrl))
332 Mixer_StopMusicChannel();
334 mixer[audio.music_channel] = snd_ctrl;
335 Mixer_PlayMusicChannel();
337 setString(¤tly_playing_music_filename,
338 getBaseNamePtr(snd_info->source_filename));
343 // check if (and how often) this sound sample is already playing
344 for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++)
345 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
348 // reset expiration delay for already playing loop sounds
349 if (k > 0 && IS_LOOP(snd_ctrl))
351 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
353 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
355 if (IS_FADING(mixer[i]))
356 Mixer_UnFadeChannel(i);
358 // restore settings like volume and stereo position
359 mixer[i].volume = snd_ctrl.volume;
360 mixer[i].stereo_position = snd_ctrl.stereo_position;
362 Mixer_SetChannelProperties(i);
363 Mixer_ResetChannelExpiration(i);
370 // don't play sound more than n times simultaneously (with n == 2 for now)
373 unsigned int playing_current = Counter();
374 int longest = 0, longest_nr = audio.first_sound_channel;
376 // look for oldest equal sound
377 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
379 int playing_time = playing_current - mixer[i].playing_starttime;
382 if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
385 actual = 1000 * playing_time / mixer[i].data_len;
387 if (actual >= longest)
394 Mixer_StopChannel(longest_nr);
397 /* If all (non-music) channels are active, stop the channel that has
398 played its sound sample most completely (in percent of the sample
399 length). As we cannot currently get the actual playing position
400 of the channel's sound sample when compiling with the SDL mixer
401 library, we use the current playing time (in milliseconds) instead. */
404 // channel allocation sanity check -- should not be needed
405 if (mixer_active_channels ==
406 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
408 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
410 if (!mixer[i].active)
412 Debug("audio", "Mixer_InsertSound: Channel %d inactive", i);
413 Debug("audio", "Mixer_InsertSound: This should never happen!");
415 mixer_active_channels--;
421 if (mixer_active_channels ==
422 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
424 unsigned int playing_current = Counter();
425 int longest = 0, longest_nr = audio.first_sound_channel;
427 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
429 int playing_time = playing_current - mixer[i].playing_starttime;
430 int actual = 1000 * playing_time / mixer[i].data_len;
432 if (!IS_LOOP(mixer[i]) && actual > longest)
439 Mixer_StopChannel(longest_nr);
442 // add the new sound to the mixer
443 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
445 if (!mixer[i].active)
448 Mixer_PlayChannel(i);
455 static void HandleSoundRequest(SoundControl snd_ctrl)
459 // deactivate channels that have expired since the last request
460 for (i = 0; i < audio.num_channels; i++)
461 if (mixer[i].active && Mixer_ChannelExpired(i))
462 Mixer_StopChannel(i);
464 if (IS_RELOADING(snd_ctrl)) // load new sound or music files
466 Mixer_StopMusicChannel();
467 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
468 Mixer_StopChannel(i);
470 if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
471 ReloadCustomSounds();
475 else if (IS_FADING(snd_ctrl)) // fade out existing sound or music
477 if (IS_MUSIC(snd_ctrl))
479 Mixer_FadeMusicChannel();
483 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
484 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
485 Mixer_FadeChannel(i);
487 else if (IS_STOPPING(snd_ctrl)) // stop existing sound or music
489 if (IS_MUSIC(snd_ctrl))
491 Mixer_StopMusicChannel();
495 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
496 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
497 Mixer_StopChannel(i);
499 else if (SET_EXPIRE_LOOPS(snd_ctrl)) // set loop expiration on or off
501 expire_loop_sounds = snd_ctrl.active;
503 else if (snd_ctrl.active) // add new sound to mixer
505 Mixer_InsertSound(snd_ctrl);
509 void StartMixer(void)
513 if (!audio.sound_available)
516 // initialize stereo position conversion information
517 for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
519 (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
523 // THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
524 // ============================================================================
525 // THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS
527 #define CHUNK_ID_LEN 4 // IFF style chunk id length
528 #define WAV_HEADER_SIZE 16 // size of WAV file header
530 static void *Load_WAV(char *filename)
534 if (!audio.sound_available)
537 snd_info = checked_calloc(sizeof(SoundInfo));
539 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
541 Warn("cannot read sound file '%s': %s", filename, Mix_GetError());
548 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
550 snd_info->type = SND_TYPE_WAV;
551 snd_info->source_filename = getStringCopy(filename);
556 static void *Load_MOD(char *filename)
560 if (!audio.sound_available)
563 mod_info = checked_calloc(sizeof(MusicInfo));
565 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
567 Warn("cannot read music file '%s': %s", filename, Mix_GetError());
574 mod_info->type = MUS_TYPE_MOD;
575 mod_info->source_filename = getStringCopy(filename);
580 static void *Load_WAV_or_MOD(char *filename)
582 if (FileIsMusic(filename))
583 return Load_MOD(filename);
584 else if (FileIsSound(filename))
585 return Load_WAV(filename);
590 static int compareMusicInfo(const void *object1, const void *object2)
592 const MusicInfo *mi1 = *((MusicInfo **)object1);
593 const MusicInfo *mi2 = *((MusicInfo **)object2);
595 return strcmp(mi1->source_filename, mi2->source_filename);
598 static void LoadCustomMusic_NoConf(void)
600 static boolean draw_init_text = TRUE; // only draw at startup
601 static char *last_music_directory = NULL;
602 char *music_directory = getCustomMusicDirectory_NoConf();
604 DirectoryEntry *dir_entry;
605 int num_music = getMusicListSize();
607 if (!audio.sound_available)
610 if (last_music_directory != NULL &&
611 strEqual(last_music_directory, music_directory))
612 return; // old and new music directory are the same
614 if (last_music_directory != NULL)
615 free(last_music_directory);
616 last_music_directory = getStringCopy(music_directory);
618 FreeAllMusic_NoConf();
620 if (music_directory == NULL)
622 Warn("cannot find music directory with unconfigured music");
626 else if ((dir = openDirectory(music_directory)) == NULL)
628 Warn("cannot read music directory '%s'", music_directory);
634 DrawInitTextHead("Loading music");
636 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
638 char *basename = dir_entry->basename;
639 MusicInfo *mus_info = NULL;
640 boolean music_already_used = FALSE;
643 // skip all music files that are configured in music config file
644 for (i = 0; i < num_music; i++)
646 struct FileInfo *music = getMusicListEntry(i);
648 if (strEqual(basename, music->filename))
650 music_already_used = TRUE;
655 if (music_already_used)
659 DrawInitTextItem(basename);
661 if (FileIsMusic(dir_entry->filename))
662 mus_info = Load_WAV_or_MOD(dir_entry->filename);
667 Music_NoConf = checked_realloc(Music_NoConf,
668 num_music_noconf * sizeof(MusicInfo *));
669 Music_NoConf[num_music_noconf - 1] = mus_info;
675 // sort music files by filename
676 qsort(Music_NoConf, num_music_noconf, sizeof(MusicInfo *), compareMusicInfo);
678 draw_init_text = FALSE;
681 int getSoundListSize(void)
683 return (sound_info->num_file_list_entries +
684 sound_info->num_dynamic_file_list_entries);
687 int getMusicListSize(void)
689 return (music_info->num_file_list_entries +
690 music_info->num_dynamic_file_list_entries);
693 int getMusicListSize_NoConf(void)
695 return num_music_noconf;
698 struct FileInfo *getSoundListEntry(int pos)
700 int num_sounds = getSoundListSize();
701 int num_list_entries = sound_info->num_file_list_entries;
702 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
704 if (pos < 0 || pos >= num_sounds) // invalid sound
707 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
708 &sound_info->dynamic_file_list[list_pos]);
711 struct FileInfo *getMusicListEntry(int pos)
713 int num_music = getMusicListSize();
714 int num_list_entries = music_info->num_file_list_entries;
715 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
717 if (pos < 0 || pos >= num_music) // invalid music
720 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
721 &music_info->dynamic_file_list[list_pos]);
724 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
726 int num_sounds = getSoundListSize();
727 int num_list_entries = sound_info->num_file_list_entries;
728 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
729 SoundInfo **snd_info =
730 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
731 sound_info->dynamic_artwork_list);
733 if (pos < 0 || pos >= num_sounds) // invalid sound
736 return snd_info[list_pos];
739 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
741 int num_music = getMusicListSize();
742 int num_list_entries = music_info->num_file_list_entries;
743 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
744 MusicInfo **mus_info =
745 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
746 music_info->dynamic_artwork_list);
748 if (pos >= num_music) // invalid music
751 if (pos < 0) // undefined music
753 if (num_music_noconf == 0) // no fallback music available
756 pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
758 return Music_NoConf[pos];
761 return mus_info[list_pos];
764 char *getSoundInfoEntryFilename(int pos)
766 SoundInfo *snd_info = getSoundInfoEntryFromSoundID(pos);
768 if (snd_info == NULL)
771 return getBaseNamePtr(snd_info->source_filename);
774 char *getMusicInfoEntryFilename(int pos)
776 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
778 if (mus_info == NULL)
781 return getBaseNamePtr(mus_info->source_filename);
784 char *getCurrentlyPlayingMusicFilename(void)
786 return currently_playing_music_filename;
789 int getSoundListPropertyMappingSize(void)
791 return sound_info->num_property_mapping_entries;
794 int getMusicListPropertyMappingSize(void)
796 return music_info->num_property_mapping_entries;
799 struct PropertyMapping *getSoundListPropertyMapping(void)
801 return sound_info->property_mapping;
804 struct PropertyMapping *getMusicListPropertyMapping(void)
806 return music_info->property_mapping;
809 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
810 struct ConfigTypeInfo *config_suffix_list,
811 char **base_prefixes, char **ext1_suffixes,
812 char **ext2_suffixes, char **ext3_suffixes,
813 char **ignore_tokens)
817 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
818 sound_info->type = ARTWORK_TYPE_SOUNDS;
820 // ---------- initialize file list and suffix lists ----------
822 sound_info->num_file_list_entries = num_file_list_entries;
823 sound_info->num_dynamic_file_list_entries = 0;
825 sound_info->file_list =
826 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
827 num_file_list_entries);
828 sound_info->dynamic_file_list = NULL;
830 sound_info->num_suffix_list_entries = 0;
831 for (i = 0; config_suffix_list[i].token != NULL; i++)
832 sound_info->num_suffix_list_entries++;
834 sound_info->suffix_list = config_suffix_list;
836 // ---------- initialize base prefix and suffixes lists ----------
838 sound_info->num_base_prefixes = 0;
839 for (i = 0; base_prefixes[i] != NULL; i++)
840 sound_info->num_base_prefixes++;
842 sound_info->num_ext1_suffixes = 0;
843 for (i = 0; ext1_suffixes[i] != NULL; i++)
844 sound_info->num_ext1_suffixes++;
846 sound_info->num_ext2_suffixes = 0;
847 for (i = 0; ext2_suffixes[i] != NULL; i++)
848 sound_info->num_ext2_suffixes++;
850 sound_info->num_ext3_suffixes = 0;
851 for (i = 0; ext3_suffixes[i] != NULL; i++)
852 sound_info->num_ext3_suffixes++;
854 sound_info->num_ignore_tokens = 0;
855 for (i = 0; ignore_tokens[i] != NULL; i++)
856 sound_info->num_ignore_tokens++;
858 sound_info->base_prefixes = base_prefixes;
859 sound_info->ext1_suffixes = ext1_suffixes;
860 sound_info->ext2_suffixes = ext2_suffixes;
861 sound_info->ext3_suffixes = ext3_suffixes;
862 sound_info->ignore_tokens = ignore_tokens;
864 sound_info->num_property_mapping_entries = 0;
866 sound_info->property_mapping = NULL;
868 // ---------- initialize artwork reference and content lists ----------
870 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
872 sound_info->artwork_list =
873 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
874 sound_info->dynamic_artwork_list = NULL;
876 sound_info->content_list = NULL;
878 // ---------- initialize artwork loading/freeing functions ----------
880 sound_info->load_artwork = Load_WAV;
881 sound_info->free_artwork = FreeSound;
884 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
885 struct ConfigTypeInfo *config_suffix_list,
886 char **base_prefixes, char **ext1_suffixes,
887 char **ext2_suffixes, char **ext3_suffixes,
888 char **ignore_tokens)
892 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
893 music_info->type = ARTWORK_TYPE_MUSIC;
895 // ---------- initialize file list and suffix lists ----------
897 music_info->num_file_list_entries = num_file_list_entries;
898 music_info->num_dynamic_file_list_entries = 0;
900 music_info->file_list =
901 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
902 num_file_list_entries);
903 music_info->dynamic_file_list = NULL;
905 music_info->num_suffix_list_entries = 0;
906 for (i = 0; config_suffix_list[i].token != NULL; i++)
907 music_info->num_suffix_list_entries++;
909 music_info->suffix_list = config_suffix_list;
911 // ---------- initialize base prefix and suffixes lists ----------
913 music_info->num_base_prefixes = 0;
914 for (i = 0; base_prefixes[i] != NULL; i++)
915 music_info->num_base_prefixes++;
917 music_info->num_ext1_suffixes = 0;
918 for (i = 0; ext1_suffixes[i] != NULL; i++)
919 music_info->num_ext1_suffixes++;
921 music_info->num_ext2_suffixes = 0;
922 for (i = 0; ext2_suffixes[i] != NULL; i++)
923 music_info->num_ext2_suffixes++;
925 music_info->num_ext3_suffixes = 0;
926 for (i = 0; ext3_suffixes[i] != NULL; i++)
927 music_info->num_ext3_suffixes++;
929 music_info->num_ignore_tokens = 0;
930 for (i = 0; ignore_tokens[i] != NULL; i++)
931 music_info->num_ignore_tokens++;
933 music_info->base_prefixes = base_prefixes;
934 music_info->ext1_suffixes = ext1_suffixes;
935 music_info->ext2_suffixes = ext2_suffixes;
936 music_info->ext3_suffixes = ext3_suffixes;
937 music_info->ignore_tokens = ignore_tokens;
939 music_info->num_property_mapping_entries = 0;
941 music_info->property_mapping = NULL;
943 // ---------- initialize artwork reference and content lists ----------
945 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
947 music_info->artwork_list =
948 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
949 music_info->dynamic_artwork_list = NULL;
951 music_info->content_list = NULL;
953 // ---------- initialize artwork loading/freeing functions ----------
955 music_info->load_artwork = Load_WAV_or_MOD;
956 music_info->free_artwork = FreeMusic;
959 void PlayMusic(int nr)
961 if (!audio.music_available)
967 void PlayMusicLoop(int nr)
969 if (!audio.music_available)
972 PlaySoundMusicLoop(nr);
975 void PlaySound(int nr)
977 if (!setup.sound_simple)
980 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
983 void PlaySoundStereo(int nr, int stereo_position)
985 if (!setup.sound_simple)
988 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
991 void PlaySoundLoop(int nr)
993 if (!setup.sound_loops)
996 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
999 void PlaySoundMusic(int nr)
1001 if (!setup.sound_music)
1004 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
1007 void PlaySoundMusicLoop(int nr)
1009 if (!setup.sound_music)
1012 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC_LOOP);
1015 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
1017 SoundControl snd_ctrl;
1019 if (!audio.sound_available ||
1020 !audio.sound_enabled ||
1021 audio.sound_deactivated)
1024 volume = SETUP_SOUND_VOLUME(volume, state);
1026 if (volume < SOUND_MIN_VOLUME)
1027 volume = SOUND_MIN_VOLUME;
1028 else if (volume > SOUND_MAX_VOLUME)
1029 volume = SOUND_MAX_VOLUME;
1031 if (stereo_position < SOUND_MAX_LEFT)
1032 stereo_position = SOUND_MAX_LEFT;
1033 else if (stereo_position > SOUND_MAX_RIGHT)
1034 stereo_position = SOUND_MAX_RIGHT;
1036 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1038 snd_ctrl.active = TRUE;
1040 snd_ctrl.volume = volume;
1041 snd_ctrl.stereo_position = stereo_position;
1042 snd_ctrl.state = state;
1044 HandleSoundRequest(snd_ctrl);
1047 void FadeMusic(void)
1049 if (!audio.music_available)
1052 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1055 void FadeSound(int nr)
1057 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1060 void FadeSounds(void)
1062 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1065 void FadeSoundsAndMusic(void)
1071 void StopMusic(void)
1073 if (!audio.music_available)
1076 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1079 void StopSound(int nr)
1081 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1084 void StopSounds(void)
1087 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1090 void StopSoundExt(int nr, int state)
1092 SoundControl snd_ctrl;
1094 if (!audio.sound_available)
1097 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1099 snd_ctrl.active = FALSE;
1101 snd_ctrl.state = state;
1103 HandleSoundRequest(snd_ctrl);
1106 void ExpireSoundLoops(boolean active)
1108 SoundControl snd_ctrl;
1110 if (!audio.sound_available)
1113 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1115 snd_ctrl.active = active;
1116 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1118 HandleSoundRequest(snd_ctrl);
1121 static void ReloadCustomSounds(void)
1123 LoadArtworkConfig(sound_info);
1124 ReloadCustomArtworkList(sound_info);
1127 static void ReloadCustomMusic(void)
1129 LoadArtworkConfig(music_info);
1130 ReloadCustomArtworkList(music_info);
1132 // load all music files from directory not defined in "musicinfo.conf"
1133 LoadCustomMusic_NoConf();
1136 void InitReloadCustomSounds(void)
1138 if (!audio.sound_available)
1141 ReloadCustomSounds();
1144 void InitReloadCustomMusic(void)
1146 if (!audio.music_available)
1149 ReloadCustomMusic();
1152 void FreeSound(void *ptr)
1154 SoundInfo *sound = (SoundInfo *)ptr;
1159 if (sound->data_ptr)
1161 Mix_FreeChunk(sound->data_ptr);
1164 checked_free(sound->source_filename);
1169 void FreeMusic(void *ptr)
1171 MusicInfo *music = (MusicInfo *)ptr;
1176 if (music->data_ptr)
1178 if (music->type == MUS_TYPE_MOD)
1179 Mix_FreeMusic(music->data_ptr);
1181 Mix_FreeChunk(music->data_ptr);
1187 static void FreeAllMusic_NoConf(void)
1191 if (Music_NoConf == NULL)
1194 for (i = 0; i < num_music_noconf; i++)
1195 FreeMusic(Music_NoConf[i]);
1199 Music_NoConf = NULL;
1200 num_music_noconf = 0;
1203 void FreeAllSounds(void)
1205 FreeCustomArtworkLists(sound_info);
1208 void FreeAllMusic(void)
1210 FreeCustomArtworkLists(music_info);
1211 FreeAllMusic_NoConf();
1214 // THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS
1215 // ============================================================================