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_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);
135 static SoundInfo *getSoundInfoEntryFromSoundID(int);
136 static MusicInfo *getMusicInfoEntryFromMusicID(int);
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 void Mixer_InitChannels(void)
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(void)
220 Mixer_PlayChannel(audio.music_channel);
222 if (mixer[audio.music_channel].type != MUS_TYPE_WAV)
224 int loops = (IS_LOOP(mixer[audio.music_channel]) ? -1 : 1);
226 // use short fade-in to prevent "plop" sound for certain music files
227 // (this may happen when switching on music while playing the game)
228 Mix_VolumeMusic(mixer[audio.music_channel].volume);
229 Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, loops, 100);
231 #if defined(PLATFORM_WIN32)
232 // playing MIDI music is broken since Windows Vista, as it sets the volume
233 // for MIDI music also for all other sounds and music, which cannot be set
234 // back to normal unless playing MIDI music again with that desired volume
235 // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253)
236 // => workaround: always play MIDI music with maximum volume
237 if (Mix_GetMusicType(NULL) == MUS_MID)
238 Mix_VolumeMusic(SOUND_MAX_VOLUME);
243 static void Mixer_StopChannel(int channel)
245 if (!mixer[channel].active)
248 Mix_HaltChannel(channel);
250 mixer[channel].active = FALSE;
251 mixer_active_channels--;
254 static void Mixer_StopMusicChannel(void)
256 Mixer_StopChannel(audio.music_channel);
260 setString(¤tly_playing_music_filename, NULL);
263 static void Mixer_FadeChannel(int channel)
265 if (!mixer[channel].active)
268 mixer[channel].state |= SND_CTRL_FADE;
270 Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL);
273 static void Mixer_FadeMusicChannel(void)
275 Mixer_FadeChannel(audio.music_channel);
277 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
279 #if defined(PLATFORM_WIN32)
280 // playing MIDI music is broken since Windows Vista, as it sets the volume
281 // for MIDI music also for all other sounds and music, which cannot be set
282 // back to normal unless playing MIDI music again with that desired volume
283 // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253)
284 // => workaround: never fade MIDI music to lower volume, but just stop it
285 if (Mix_GetMusicType(NULL) == MUS_MID)
286 Mixer_StopMusicChannel();
289 setString(¤tly_playing_music_filename, NULL);
292 static void Mixer_UnFadeChannel(int channel)
294 if (!mixer[channel].active || !IS_FADING(mixer[channel]))
297 mixer[channel].state &= ~SND_CTRL_FADE;
298 mixer[channel].volume = SOUND_MAX_VOLUME;
300 Mix_ExpireChannel(channel, -1);
301 Mix_Volume(channel, mixer[channel].volume);
304 static void Mixer_InsertSound(SoundControl snd_ctrl)
309 if (IS_MUSIC(snd_ctrl))
310 snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr);
312 snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
314 if (snd_info == NULL)
317 // copy sound sample and format information
318 snd_ctrl.type = snd_info->type;
319 snd_ctrl.format = snd_info->format;
320 snd_ctrl.data_ptr = snd_info->data_ptr;
321 snd_ctrl.data_len = snd_info->data_len;
322 snd_ctrl.num_channels = snd_info->num_channels;
324 // play music samples on a dedicated music channel
325 if (IS_MUSIC(snd_ctrl))
327 Mixer_StopMusicChannel();
329 mixer[audio.music_channel] = snd_ctrl;
330 Mixer_PlayMusicChannel();
332 setString(¤tly_playing_music_filename,
333 getBaseNamePtr(snd_info->source_filename));
338 // check if (and how often) this sound sample is already playing
339 for (k = 0, i = audio.first_sound_channel; i < audio.num_channels; i++)
340 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
343 // reset expiration delay for already playing loop sounds
344 if (k > 0 && IS_LOOP(snd_ctrl))
346 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
348 if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
350 if (IS_FADING(mixer[i]))
351 Mixer_UnFadeChannel(i);
353 // restore settings like volume and stereo position
354 mixer[i].volume = snd_ctrl.volume;
355 mixer[i].stereo_position = snd_ctrl.stereo_position;
357 Mixer_SetChannelProperties(i);
358 Mixer_ResetChannelExpiration(i);
365 // don't play sound more than n times simultaneously (with n == 2 for now)
368 unsigned int playing_current = Counter();
369 int longest = 0, longest_nr = audio.first_sound_channel;
371 // look for oldest equal sound
372 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
374 int playing_time = playing_current - mixer[i].playing_starttime;
377 if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
380 actual = 1000 * playing_time / mixer[i].data_len;
382 if (actual >= longest)
389 Mixer_StopChannel(longest_nr);
392 /* If all (non-music) channels are active, stop the channel that has
393 played its sound sample most completely (in percent of the sample
394 length). As we cannot currently get the actual playing position
395 of the channel's sound sample when compiling with the SDL mixer
396 library, we use the current playing time (in milliseconds) instead. */
399 // channel allocation sanity check -- should not be needed
400 if (mixer_active_channels ==
401 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
403 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
405 if (!mixer[i].active)
407 Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i);
408 Error(ERR_INFO, "Mixer_InsertSound: This should never happen!");
410 mixer_active_channels--;
416 if (mixer_active_channels ==
417 audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
419 unsigned int playing_current = Counter();
420 int longest = 0, longest_nr = audio.first_sound_channel;
422 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
424 int playing_time = playing_current - mixer[i].playing_starttime;
425 int actual = 1000 * playing_time / mixer[i].data_len;
427 if (!IS_LOOP(mixer[i]) && actual > longest)
434 Mixer_StopChannel(longest_nr);
437 // add the new sound to the mixer
438 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
440 if (!mixer[i].active)
443 Mixer_PlayChannel(i);
450 static void HandleSoundRequest(SoundControl snd_ctrl)
454 // deactivate channels that have expired since the last request
455 for (i = 0; i < audio.num_channels; i++)
456 if (mixer[i].active && Mixer_ChannelExpired(i))
457 Mixer_StopChannel(i);
459 if (IS_RELOADING(snd_ctrl)) // load new sound or music files
461 Mixer_StopMusicChannel();
462 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
463 Mixer_StopChannel(i);
465 if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
466 ReloadCustomSounds();
470 else if (IS_FADING(snd_ctrl)) // fade out existing sound or music
472 if (IS_MUSIC(snd_ctrl))
474 Mixer_FadeMusicChannel();
478 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
479 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
480 Mixer_FadeChannel(i);
482 else if (IS_STOPPING(snd_ctrl)) // stop existing sound or music
484 if (IS_MUSIC(snd_ctrl))
486 Mixer_StopMusicChannel();
490 for (i = audio.first_sound_channel; i < audio.num_channels; i++)
491 if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
492 Mixer_StopChannel(i);
494 else if (SET_EXPIRE_LOOPS(snd_ctrl)) // set loop expiration on or off
496 expire_loop_sounds = snd_ctrl.active;
498 else if (snd_ctrl.active) // add new sound to mixer
500 Mixer_InsertSound(snd_ctrl);
504 void StartMixer(void)
508 if (!audio.sound_available)
511 // initialize stereo position conversion information
512 for (i = 0; i <= SOUND_MAX_LEFT2RIGHT; i++)
514 (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
518 // THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
519 // ============================================================================
520 // THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS
522 #define CHUNK_ID_LEN 4 // IFF style chunk id length
523 #define WAV_HEADER_SIZE 16 // size of WAV file header
525 static void *Load_WAV(char *filename)
529 if (!audio.sound_available)
532 snd_info = checked_calloc(sizeof(SoundInfo));
534 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
536 Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError());
541 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
543 snd_info->type = SND_TYPE_WAV;
544 snd_info->source_filename = getStringCopy(filename);
549 static void *Load_MOD(char *filename)
553 if (!audio.sound_available)
556 mod_info = checked_calloc(sizeof(MusicInfo));
558 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
560 Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError());
565 mod_info->type = MUS_TYPE_MOD;
566 mod_info->source_filename = getStringCopy(filename);
571 static void *Load_WAV_or_MOD(char *filename)
573 if (FileIsMusic(filename))
574 return Load_MOD(filename);
575 else if (FileIsSound(filename))
576 return Load_WAV(filename);
581 static void LoadCustomMusic_NoConf(void)
583 static boolean draw_init_text = TRUE; // only draw at startup
584 static char *last_music_directory = NULL;
585 char *music_directory = getCustomMusicDirectory();
587 DirectoryEntry *dir_entry;
588 int num_music = getMusicListSize();
590 if (!audio.sound_available)
593 if (last_music_directory != NULL &&
594 strEqual(last_music_directory, music_directory))
595 return; // old and new music directory are the same
597 if (last_music_directory != NULL)
598 free(last_music_directory);
599 last_music_directory = getStringCopy(music_directory);
601 FreeAllMusic_NoConf();
603 if ((dir = openDirectory(music_directory)) == NULL)
605 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
607 audio.music_available = FALSE;
613 DrawInitText("Loading music", 120, FC_GREEN);
615 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
617 char *basename = dir_entry->basename;
618 MusicInfo *mus_info = NULL;
619 boolean music_already_used = FALSE;
622 // skip all music files that are configured in music config file
623 for (i = 0; i < num_music; i++)
625 struct FileInfo *music = getMusicListEntry(i);
627 if (strEqual(basename, music->filename))
629 music_already_used = TRUE;
634 if (music_already_used)
638 DrawInitText(basename, 150, FC_YELLOW);
640 if (FileIsMusic(dir_entry->filename))
641 mus_info = Load_WAV_or_MOD(dir_entry->filename);
646 Music_NoConf = checked_realloc(Music_NoConf,
647 num_music_noconf * sizeof(MusicInfo *));
648 Music_NoConf[num_music_noconf - 1] = mus_info;
654 draw_init_text = FALSE;
657 int getSoundListSize(void)
659 return (sound_info->num_file_list_entries +
660 sound_info->num_dynamic_file_list_entries);
663 int getMusicListSize(void)
665 return (music_info->num_file_list_entries +
666 music_info->num_dynamic_file_list_entries);
669 struct FileInfo *getSoundListEntry(int pos)
671 int num_sounds = getSoundListSize();
672 int num_list_entries = sound_info->num_file_list_entries;
673 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
675 if (pos < 0 || pos >= num_sounds) // invalid sound
678 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
679 &sound_info->dynamic_file_list[list_pos]);
682 struct FileInfo *getMusicListEntry(int pos)
684 int num_music = getMusicListSize();
685 int num_list_entries = music_info->num_file_list_entries;
686 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
688 if (pos < 0 || pos >= num_music) // invalid music
691 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
692 &music_info->dynamic_file_list[list_pos]);
695 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
697 int num_sounds = getSoundListSize();
698 int num_list_entries = sound_info->num_file_list_entries;
699 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
700 SoundInfo **snd_info =
701 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
702 sound_info->dynamic_artwork_list);
704 if (pos < 0 || pos >= num_sounds) // invalid sound
707 return snd_info[list_pos];
710 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
712 int num_music = getMusicListSize();
713 int num_list_entries = music_info->num_file_list_entries;
714 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
715 MusicInfo **mus_info =
716 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
717 music_info->dynamic_artwork_list);
719 if (pos >= num_music) // invalid music
722 if (pos < 0) // undefined music
724 if (num_music_noconf == 0) // no fallback music available
727 pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
729 return Music_NoConf[pos];
732 return mus_info[list_pos];
735 char *getMusicInfoEntryFilename(int pos)
737 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
739 if (mus_info == NULL)
742 return getBaseNamePtr(mus_info->source_filename);
745 char *getCurrentlyPlayingMusicFilename(void)
747 return currently_playing_music_filename;
750 int getSoundListPropertyMappingSize(void)
752 return sound_info->num_property_mapping_entries;
755 int getMusicListPropertyMappingSize(void)
757 return music_info->num_property_mapping_entries;
760 struct PropertyMapping *getSoundListPropertyMapping(void)
762 return sound_info->property_mapping;
765 struct PropertyMapping *getMusicListPropertyMapping(void)
767 return music_info->property_mapping;
770 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
771 struct ConfigTypeInfo *config_suffix_list,
772 char **base_prefixes, char **ext1_suffixes,
773 char **ext2_suffixes, char **ext3_suffixes,
774 char **ignore_tokens)
778 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
779 sound_info->type = ARTWORK_TYPE_SOUNDS;
781 // ---------- initialize file list and suffix lists ----------
783 sound_info->num_file_list_entries = num_file_list_entries;
784 sound_info->num_dynamic_file_list_entries = 0;
786 sound_info->file_list =
787 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
788 num_file_list_entries);
789 sound_info->dynamic_file_list = NULL;
791 sound_info->num_suffix_list_entries = 0;
792 for (i = 0; config_suffix_list[i].token != NULL; i++)
793 sound_info->num_suffix_list_entries++;
795 sound_info->suffix_list = config_suffix_list;
797 // ---------- initialize base prefix and suffixes lists ----------
799 sound_info->num_base_prefixes = 0;
800 for (i = 0; base_prefixes[i] != NULL; i++)
801 sound_info->num_base_prefixes++;
803 sound_info->num_ext1_suffixes = 0;
804 for (i = 0; ext1_suffixes[i] != NULL; i++)
805 sound_info->num_ext1_suffixes++;
807 sound_info->num_ext2_suffixes = 0;
808 for (i = 0; ext2_suffixes[i] != NULL; i++)
809 sound_info->num_ext2_suffixes++;
811 sound_info->num_ext3_suffixes = 0;
812 for (i = 0; ext3_suffixes[i] != NULL; i++)
813 sound_info->num_ext3_suffixes++;
815 sound_info->num_ignore_tokens = 0;
816 for (i = 0; ignore_tokens[i] != NULL; i++)
817 sound_info->num_ignore_tokens++;
819 sound_info->base_prefixes = base_prefixes;
820 sound_info->ext1_suffixes = ext1_suffixes;
821 sound_info->ext2_suffixes = ext2_suffixes;
822 sound_info->ext3_suffixes = ext3_suffixes;
823 sound_info->ignore_tokens = ignore_tokens;
825 sound_info->num_property_mapping_entries = 0;
827 sound_info->property_mapping = NULL;
829 // ---------- initialize artwork reference and content lists ----------
831 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
833 sound_info->artwork_list =
834 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
835 sound_info->dynamic_artwork_list = NULL;
837 sound_info->content_list = NULL;
839 // ---------- initialize artwork loading/freeing functions ----------
841 sound_info->load_artwork = Load_WAV;
842 sound_info->free_artwork = FreeSound;
845 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
846 struct ConfigTypeInfo *config_suffix_list,
847 char **base_prefixes, char **ext1_suffixes,
848 char **ext2_suffixes, char **ext3_suffixes,
849 char **ignore_tokens)
853 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
854 music_info->type = ARTWORK_TYPE_MUSIC;
856 // ---------- initialize file list and suffix lists ----------
858 music_info->num_file_list_entries = num_file_list_entries;
859 music_info->num_dynamic_file_list_entries = 0;
861 music_info->file_list =
862 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
863 num_file_list_entries);
864 music_info->dynamic_file_list = NULL;
866 music_info->num_suffix_list_entries = 0;
867 for (i = 0; config_suffix_list[i].token != NULL; i++)
868 music_info->num_suffix_list_entries++;
870 music_info->suffix_list = config_suffix_list;
872 // ---------- initialize base prefix and suffixes lists ----------
874 music_info->num_base_prefixes = 0;
875 for (i = 0; base_prefixes[i] != NULL; i++)
876 music_info->num_base_prefixes++;
878 music_info->num_ext1_suffixes = 0;
879 for (i = 0; ext1_suffixes[i] != NULL; i++)
880 music_info->num_ext1_suffixes++;
882 music_info->num_ext2_suffixes = 0;
883 for (i = 0; ext2_suffixes[i] != NULL; i++)
884 music_info->num_ext2_suffixes++;
886 music_info->num_ext3_suffixes = 0;
887 for (i = 0; ext3_suffixes[i] != NULL; i++)
888 music_info->num_ext3_suffixes++;
890 music_info->num_ignore_tokens = 0;
891 for (i = 0; ignore_tokens[i] != NULL; i++)
892 music_info->num_ignore_tokens++;
894 music_info->base_prefixes = base_prefixes;
895 music_info->ext1_suffixes = ext1_suffixes;
896 music_info->ext2_suffixes = ext2_suffixes;
897 music_info->ext3_suffixes = ext3_suffixes;
898 music_info->ignore_tokens = ignore_tokens;
900 music_info->num_property_mapping_entries = 0;
902 music_info->property_mapping = NULL;
904 // ---------- initialize artwork reference and content lists ----------
906 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
908 music_info->artwork_list =
909 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
910 music_info->dynamic_artwork_list = NULL;
912 music_info->content_list = NULL;
914 // ---------- initialize artwork loading/freeing functions ----------
916 music_info->load_artwork = Load_WAV_or_MOD;
917 music_info->free_artwork = FreeMusic;
920 void PlayMusic(int nr)
922 if (!audio.music_available)
928 void PlayMusicLoop(int nr)
930 if (!audio.music_available)
933 PlaySoundMusicLoop(nr);
936 void PlaySound(int nr)
938 if (!setup.sound_simple)
941 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
944 void PlaySoundStereo(int nr, int stereo_position)
946 if (!setup.sound_simple)
949 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
952 void PlaySoundLoop(int nr)
954 if (!setup.sound_loops)
957 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
960 void PlaySoundMusic(int nr)
962 if (!setup.sound_music)
965 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
968 void PlaySoundMusicLoop(int nr)
970 if (!setup.sound_music)
973 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC_LOOP);
976 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
978 SoundControl snd_ctrl;
980 if (!audio.sound_available ||
981 !audio.sound_enabled ||
982 audio.sound_deactivated)
985 volume = SETUP_SOUND_VOLUME(volume, state);
987 if (volume < SOUND_MIN_VOLUME)
988 volume = SOUND_MIN_VOLUME;
989 else if (volume > SOUND_MAX_VOLUME)
990 volume = SOUND_MAX_VOLUME;
992 if (stereo_position < SOUND_MAX_LEFT)
993 stereo_position = SOUND_MAX_LEFT;
994 else if (stereo_position > SOUND_MAX_RIGHT)
995 stereo_position = SOUND_MAX_RIGHT;
997 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
999 snd_ctrl.active = TRUE;
1001 snd_ctrl.volume = volume;
1002 snd_ctrl.stereo_position = stereo_position;
1003 snd_ctrl.state = state;
1005 HandleSoundRequest(snd_ctrl);
1008 void FadeMusic(void)
1010 if (!audio.music_available)
1013 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1016 void FadeSound(int nr)
1018 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1021 void FadeSounds(void)
1023 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1026 void FadeSoundsAndMusic(void)
1032 void StopMusic(void)
1034 if (!audio.music_available)
1037 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1040 void StopSound(int nr)
1042 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1045 void StopSounds(void)
1048 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1051 void StopSoundExt(int nr, int state)
1053 SoundControl snd_ctrl;
1055 if (!audio.sound_available)
1058 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1060 snd_ctrl.active = FALSE;
1062 snd_ctrl.state = state;
1064 HandleSoundRequest(snd_ctrl);
1067 void ExpireSoundLoops(boolean active)
1069 SoundControl snd_ctrl;
1071 if (!audio.sound_available)
1074 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1076 snd_ctrl.active = active;
1077 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1079 HandleSoundRequest(snd_ctrl);
1082 static void ReloadCustomSounds(void)
1084 LoadArtworkConfig(sound_info);
1085 ReloadCustomArtworkList(sound_info);
1088 static void ReloadCustomMusic(void)
1090 LoadArtworkConfig(music_info);
1091 ReloadCustomArtworkList(music_info);
1093 // load all music files from directory not defined in "musicinfo.conf"
1094 LoadCustomMusic_NoConf();
1097 void InitReloadCustomSounds(char *set_identifier)
1099 if (!audio.sound_available)
1102 ReloadCustomSounds();
1105 void InitReloadCustomMusic(char *set_identifier)
1107 if (!audio.music_available)
1110 ReloadCustomMusic();
1113 void FreeSound(void *ptr)
1115 SoundInfo *sound = (SoundInfo *)ptr;
1120 if (sound->data_ptr)
1122 Mix_FreeChunk(sound->data_ptr);
1125 checked_free(sound->source_filename);
1130 void FreeMusic(void *ptr)
1132 MusicInfo *music = (MusicInfo *)ptr;
1137 if (music->data_ptr)
1139 if (music->type == MUS_TYPE_MOD)
1140 Mix_FreeMusic(music->data_ptr);
1142 Mix_FreeChunk(music->data_ptr);
1148 static void FreeAllMusic_NoConf(void)
1152 if (Music_NoConf == NULL)
1155 for (i = 0; i < num_music_noconf; i++)
1156 FreeMusic(Music_NoConf[i]);
1160 Music_NoConf = NULL;
1161 num_music_noconf = 0;
1164 void FreeAllSounds(void)
1166 FreeCustomArtworkLists(sound_info);
1169 void FreeAllMusic(void)
1171 FreeCustomArtworkLists(music_info);
1172 FreeAllMusic_NoConf();
1175 // THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS
1176 // ============================================================================