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);
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 DelayReached(&mixer[channel].playing_starttime,
170 SOUND_LOOP_EXPIRATION_TIME))
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_WIN32)
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_WIN32)
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 Error(ERR_INFO, "Mixer_InsertSound: Channel %d inactive", i);
413 Error(ERR_INFO, "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 Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError());
546 snd_info->data_len = ((Mix_Chunk *)snd_info->data_ptr)->alen;
548 snd_info->type = SND_TYPE_WAV;
549 snd_info->source_filename = getStringCopy(filename);
554 static void *Load_MOD(char *filename)
558 if (!audio.sound_available)
561 mod_info = checked_calloc(sizeof(MusicInfo));
563 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
565 Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError());
570 mod_info->type = MUS_TYPE_MOD;
571 mod_info->source_filename = getStringCopy(filename);
576 static void *Load_WAV_or_MOD(char *filename)
578 if (FileIsMusic(filename))
579 return Load_MOD(filename);
580 else if (FileIsSound(filename))
581 return Load_WAV(filename);
586 static void LoadCustomMusic_NoConf(void)
588 static boolean draw_init_text = TRUE; // only draw at startup
589 static char *last_music_directory = NULL;
590 char *music_directory = getCustomMusicDirectory();
592 DirectoryEntry *dir_entry;
593 int num_music = getMusicListSize();
595 if (!audio.sound_available)
598 if (last_music_directory != NULL &&
599 strEqual(last_music_directory, music_directory))
600 return; // old and new music directory are the same
602 if (last_music_directory != NULL)
603 free(last_music_directory);
604 last_music_directory = getStringCopy(music_directory);
606 FreeAllMusic_NoConf();
608 if ((dir = openDirectory(music_directory)) == NULL)
610 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
612 audio.music_available = FALSE;
618 DrawInitText("Loading music", 120, FC_GREEN);
620 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
622 char *basename = dir_entry->basename;
623 MusicInfo *mus_info = NULL;
624 boolean music_already_used = FALSE;
627 // skip all music files that are configured in music config file
628 for (i = 0; i < num_music; i++)
630 struct FileInfo *music = getMusicListEntry(i);
632 if (strEqual(basename, music->filename))
634 music_already_used = TRUE;
639 if (music_already_used)
643 DrawInitText(basename, 150, FC_YELLOW);
645 if (FileIsMusic(dir_entry->filename))
646 mus_info = Load_WAV_or_MOD(dir_entry->filename);
651 Music_NoConf = checked_realloc(Music_NoConf,
652 num_music_noconf * sizeof(MusicInfo *));
653 Music_NoConf[num_music_noconf - 1] = mus_info;
659 draw_init_text = FALSE;
662 int getSoundListSize(void)
664 return (sound_info->num_file_list_entries +
665 sound_info->num_dynamic_file_list_entries);
668 int getMusicListSize(void)
670 return (music_info->num_file_list_entries +
671 music_info->num_dynamic_file_list_entries);
674 struct FileInfo *getSoundListEntry(int pos)
676 int num_sounds = getSoundListSize();
677 int num_list_entries = sound_info->num_file_list_entries;
678 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
680 if (pos < 0 || pos >= num_sounds) // invalid sound
683 return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
684 &sound_info->dynamic_file_list[list_pos]);
687 struct FileInfo *getMusicListEntry(int pos)
689 int num_music = getMusicListSize();
690 int num_list_entries = music_info->num_file_list_entries;
691 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
693 if (pos < 0 || pos >= num_music) // invalid music
696 return (pos < num_list_entries ? &music_info->file_list[list_pos] :
697 &music_info->dynamic_file_list[list_pos]);
700 static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
702 int num_sounds = getSoundListSize();
703 int num_list_entries = sound_info->num_file_list_entries;
704 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
705 SoundInfo **snd_info =
706 (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
707 sound_info->dynamic_artwork_list);
709 if (pos < 0 || pos >= num_sounds) // invalid sound
712 return snd_info[list_pos];
715 static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
717 int num_music = getMusicListSize();
718 int num_list_entries = music_info->num_file_list_entries;
719 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
720 MusicInfo **mus_info =
721 (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list :
722 music_info->dynamic_artwork_list);
724 if (pos >= num_music) // invalid music
727 if (pos < 0) // undefined music
729 if (num_music_noconf == 0) // no fallback music available
732 pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf;
734 return Music_NoConf[pos];
737 return mus_info[list_pos];
740 char *getMusicInfoEntryFilename(int pos)
742 MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
744 if (mus_info == NULL)
747 return getBaseNamePtr(mus_info->source_filename);
750 char *getCurrentlyPlayingMusicFilename(void)
752 return currently_playing_music_filename;
755 int getSoundListPropertyMappingSize(void)
757 return sound_info->num_property_mapping_entries;
760 int getMusicListPropertyMappingSize(void)
762 return music_info->num_property_mapping_entries;
765 struct PropertyMapping *getSoundListPropertyMapping(void)
767 return sound_info->property_mapping;
770 struct PropertyMapping *getMusicListPropertyMapping(void)
772 return music_info->property_mapping;
775 void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
776 struct ConfigTypeInfo *config_suffix_list,
777 char **base_prefixes, char **ext1_suffixes,
778 char **ext2_suffixes, char **ext3_suffixes,
779 char **ignore_tokens)
783 sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
784 sound_info->type = ARTWORK_TYPE_SOUNDS;
786 // ---------- initialize file list and suffix lists ----------
788 sound_info->num_file_list_entries = num_file_list_entries;
789 sound_info->num_dynamic_file_list_entries = 0;
791 sound_info->file_list =
792 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
793 num_file_list_entries);
794 sound_info->dynamic_file_list = NULL;
796 sound_info->num_suffix_list_entries = 0;
797 for (i = 0; config_suffix_list[i].token != NULL; i++)
798 sound_info->num_suffix_list_entries++;
800 sound_info->suffix_list = config_suffix_list;
802 // ---------- initialize base prefix and suffixes lists ----------
804 sound_info->num_base_prefixes = 0;
805 for (i = 0; base_prefixes[i] != NULL; i++)
806 sound_info->num_base_prefixes++;
808 sound_info->num_ext1_suffixes = 0;
809 for (i = 0; ext1_suffixes[i] != NULL; i++)
810 sound_info->num_ext1_suffixes++;
812 sound_info->num_ext2_suffixes = 0;
813 for (i = 0; ext2_suffixes[i] != NULL; i++)
814 sound_info->num_ext2_suffixes++;
816 sound_info->num_ext3_suffixes = 0;
817 for (i = 0; ext3_suffixes[i] != NULL; i++)
818 sound_info->num_ext3_suffixes++;
820 sound_info->num_ignore_tokens = 0;
821 for (i = 0; ignore_tokens[i] != NULL; i++)
822 sound_info->num_ignore_tokens++;
824 sound_info->base_prefixes = base_prefixes;
825 sound_info->ext1_suffixes = ext1_suffixes;
826 sound_info->ext2_suffixes = ext2_suffixes;
827 sound_info->ext3_suffixes = ext3_suffixes;
828 sound_info->ignore_tokens = ignore_tokens;
830 sound_info->num_property_mapping_entries = 0;
832 sound_info->property_mapping = NULL;
834 // ---------- initialize artwork reference and content lists ----------
836 sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
838 sound_info->artwork_list =
839 checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
840 sound_info->dynamic_artwork_list = NULL;
842 sound_info->content_list = NULL;
844 // ---------- initialize artwork loading/freeing functions ----------
846 sound_info->load_artwork = Load_WAV;
847 sound_info->free_artwork = FreeSound;
850 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
851 struct ConfigTypeInfo *config_suffix_list,
852 char **base_prefixes, char **ext1_suffixes,
853 char **ext2_suffixes, char **ext3_suffixes,
854 char **ignore_tokens)
858 music_info = checked_calloc(sizeof(struct ArtworkListInfo));
859 music_info->type = ARTWORK_TYPE_MUSIC;
861 // ---------- initialize file list and suffix lists ----------
863 music_info->num_file_list_entries = num_file_list_entries;
864 music_info->num_dynamic_file_list_entries = 0;
866 music_info->file_list =
867 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
868 num_file_list_entries);
869 music_info->dynamic_file_list = NULL;
871 music_info->num_suffix_list_entries = 0;
872 for (i = 0; config_suffix_list[i].token != NULL; i++)
873 music_info->num_suffix_list_entries++;
875 music_info->suffix_list = config_suffix_list;
877 // ---------- initialize base prefix and suffixes lists ----------
879 music_info->num_base_prefixes = 0;
880 for (i = 0; base_prefixes[i] != NULL; i++)
881 music_info->num_base_prefixes++;
883 music_info->num_ext1_suffixes = 0;
884 for (i = 0; ext1_suffixes[i] != NULL; i++)
885 music_info->num_ext1_suffixes++;
887 music_info->num_ext2_suffixes = 0;
888 for (i = 0; ext2_suffixes[i] != NULL; i++)
889 music_info->num_ext2_suffixes++;
891 music_info->num_ext3_suffixes = 0;
892 for (i = 0; ext3_suffixes[i] != NULL; i++)
893 music_info->num_ext3_suffixes++;
895 music_info->num_ignore_tokens = 0;
896 for (i = 0; ignore_tokens[i] != NULL; i++)
897 music_info->num_ignore_tokens++;
899 music_info->base_prefixes = base_prefixes;
900 music_info->ext1_suffixes = ext1_suffixes;
901 music_info->ext2_suffixes = ext2_suffixes;
902 music_info->ext3_suffixes = ext3_suffixes;
903 music_info->ignore_tokens = ignore_tokens;
905 music_info->num_property_mapping_entries = 0;
907 music_info->property_mapping = NULL;
909 // ---------- initialize artwork reference and content lists ----------
911 music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *);
913 music_info->artwork_list =
914 checked_calloc(num_file_list_entries * sizeof(MusicInfo *));
915 music_info->dynamic_artwork_list = NULL;
917 music_info->content_list = NULL;
919 // ---------- initialize artwork loading/freeing functions ----------
921 music_info->load_artwork = Load_WAV_or_MOD;
922 music_info->free_artwork = FreeMusic;
925 void PlayMusic(int nr)
927 if (!audio.music_available)
933 void PlayMusicLoop(int nr)
935 if (!audio.music_available)
938 PlaySoundMusicLoop(nr);
941 void PlaySound(int nr)
943 if (!setup.sound_simple)
946 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_SOUND);
949 void PlaySoundStereo(int nr, int stereo_position)
951 if (!setup.sound_simple)
954 PlaySoundExt(nr, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_SOUND);
957 void PlaySoundLoop(int nr)
959 if (!setup.sound_loops)
962 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_LOOP);
965 void PlaySoundMusic(int nr)
967 if (!setup.sound_music)
970 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC);
973 void PlaySoundMusicLoop(int nr)
975 if (!setup.sound_music)
978 PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC_LOOP);
981 void PlaySoundExt(int nr, int volume, int stereo_position, int state)
983 SoundControl snd_ctrl;
985 if (!audio.sound_available ||
986 !audio.sound_enabled ||
987 audio.sound_deactivated)
990 volume = SETUP_SOUND_VOLUME(volume, state);
992 if (volume < SOUND_MIN_VOLUME)
993 volume = SOUND_MIN_VOLUME;
994 else if (volume > SOUND_MAX_VOLUME)
995 volume = SOUND_MAX_VOLUME;
997 if (stereo_position < SOUND_MAX_LEFT)
998 stereo_position = SOUND_MAX_LEFT;
999 else if (stereo_position > SOUND_MAX_RIGHT)
1000 stereo_position = SOUND_MAX_RIGHT;
1002 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1004 snd_ctrl.active = TRUE;
1006 snd_ctrl.volume = volume;
1007 snd_ctrl.stereo_position = stereo_position;
1008 snd_ctrl.state = state;
1010 HandleSoundRequest(snd_ctrl);
1013 void FadeMusic(void)
1015 if (!audio.music_available)
1018 StopSoundExt(-1, SND_CTRL_FADE_MUSIC);
1021 void FadeSound(int nr)
1023 StopSoundExt(nr, SND_CTRL_FADE_SOUND);
1026 void FadeSounds(void)
1028 StopSoundExt(-1, SND_CTRL_FADE_ALL);
1031 void FadeSoundsAndMusic(void)
1037 void StopMusic(void)
1039 if (!audio.music_available)
1042 StopSoundExt(-1, SND_CTRL_STOP_MUSIC);
1045 void StopSound(int nr)
1047 StopSoundExt(nr, SND_CTRL_STOP_SOUND);
1050 void StopSounds(void)
1053 StopSoundExt(-1, SND_CTRL_STOP_ALL);
1056 void StopSoundExt(int nr, int state)
1058 SoundControl snd_ctrl;
1060 if (!audio.sound_available)
1063 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1065 snd_ctrl.active = FALSE;
1067 snd_ctrl.state = state;
1069 HandleSoundRequest(snd_ctrl);
1072 void ExpireSoundLoops(boolean active)
1074 SoundControl snd_ctrl;
1076 if (!audio.sound_available)
1079 clear_mem(&snd_ctrl, sizeof(SoundControl)); // to make valgrind happy
1081 snd_ctrl.active = active;
1082 snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS;
1084 HandleSoundRequest(snd_ctrl);
1087 static void ReloadCustomSounds(void)
1089 LoadArtworkConfig(sound_info);
1090 ReloadCustomArtworkList(sound_info);
1093 static void ReloadCustomMusic(void)
1095 LoadArtworkConfig(music_info);
1096 ReloadCustomArtworkList(music_info);
1098 // load all music files from directory not defined in "musicinfo.conf"
1099 LoadCustomMusic_NoConf();
1102 void InitReloadCustomSounds(char *set_identifier)
1104 if (!audio.sound_available)
1107 ReloadCustomSounds();
1110 void InitReloadCustomMusic(char *set_identifier)
1112 if (!audio.music_available)
1115 ReloadCustomMusic();
1118 void FreeSound(void *ptr)
1120 SoundInfo *sound = (SoundInfo *)ptr;
1125 if (sound->data_ptr)
1127 Mix_FreeChunk(sound->data_ptr);
1130 checked_free(sound->source_filename);
1135 void FreeMusic(void *ptr)
1137 MusicInfo *music = (MusicInfo *)ptr;
1142 if (music->data_ptr)
1144 if (music->type == MUS_TYPE_MOD)
1145 Mix_FreeMusic(music->data_ptr);
1147 Mix_FreeChunk(music->data_ptr);
1153 static void FreeAllMusic_NoConf(void)
1157 if (Music_NoConf == NULL)
1160 for (i = 0; i < num_music_noconf; i++)
1161 FreeMusic(Music_NoConf[i]);
1165 Music_NoConf = NULL;
1166 num_music_noconf = 0;
1169 void FreeAllSounds(void)
1171 FreeCustomArtworkLists(sound_info);
1174 void FreeAllMusic(void)
1176 FreeCustomArtworkLists(music_info);
1177 FreeAllMusic_NoConf();
1180 // THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS
1181 // ============================================================================