X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fsound.c;h=9d894b3c283530171b1223ba1b4df2ad81a068f0;hp=5ace5922af201154ff5f96f9f0385a868365072a;hb=30eb586d06bc4d1ee7388dced1c20e530292aa93;hpb=4fb7d637c3bcc3381918636fdd22733ff7bae3ac diff --git a/src/libgame/sound.c b/src/libgame/sound.c index 5ace5922..9d894b3c 100644 --- a/src/libgame/sound.c +++ b/src/libgame/sound.c @@ -59,9 +59,9 @@ #define SOUND_VOLUME_LOOPS(v) SOUND_VOLUME_FROM_PERCENT(v, setup.volume_loops) #define SOUND_VOLUME_MUSIC(v) SOUND_VOLUME_FROM_PERCENT(v, setup.volume_music) -#define SETUP_SOUND_VOLUME(v,s) ((s) == SND_CTRL_PLAY_MUSIC ? \ +#define SETUP_SOUND_VOLUME(v,s) ((s) & SND_CTRL_MUSIC ? \ SOUND_VOLUME_MUSIC(v) : \ - (s) == SND_CTRL_PLAY_LOOP ? \ + (s) & SND_CTRL_LOOP ? \ SOUND_VOLUME_LOOPS(v) : \ SOUND_VOLUME_SIMPLE(v)) @@ -116,18 +116,21 @@ static MusicInfo **Music_NoConf = NULL; static int num_music_noconf = 0; static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1]; +static char *currently_playing_music_filename = NULL; + /* ========================================================================= */ /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */ static struct SoundControl mixer[NUM_MIXER_CHANNELS]; static int mixer_active_channels = 0; +static boolean expire_loop_sounds = FALSE; -static void ReloadCustomSounds(); -static void ReloadCustomMusic(); +static void ReloadCustomSounds(void); +static void ReloadCustomMusic(void); static void FreeSound(void *); static void FreeMusic(void *); -static void FreeAllMusic_NoConf(); +static void FreeAllMusic_NoConf(void); static SoundInfo *getSoundInfoEntryFromSoundID(int); static MusicInfo *getMusicInfoEntryFromMusicID(int); @@ -137,7 +140,7 @@ static MusicInfo *getMusicInfoEntryFromMusicID(int); /* mixer functions */ /* ------------------------------------------------------------------------- */ -void Mixer_InitChannels() +void Mixer_InitChannels(void) { int i; @@ -150,7 +153,8 @@ static void Mixer_ResetChannelExpiration(int channel) { mixer[channel].playing_starttime = Counter(); - if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel])) + if (expire_loop_sounds && + IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel])) Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME); } @@ -159,7 +163,8 @@ static boolean Mixer_ChannelExpired(int channel) if (!mixer[channel].active) return TRUE; - if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) && + if (expire_loop_sounds && + IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) && DelayReached(&mixer[channel].playing_starttime, SOUND_LOOP_EXPIRATION_TIME)) return TRUE; @@ -210,16 +215,28 @@ static void Mixer_PlayChannel(int channel) mixer_active_channels++; } -static void Mixer_PlayMusicChannel() +static void Mixer_PlayMusicChannel(void) { Mixer_PlayChannel(audio.music_channel); if (mixer[audio.music_channel].type != MUS_TYPE_WAV) { - /* Mix_VolumeMusic() must be called _after_ Mix_PlayMusic() -- - this looks like a bug in the SDL_mixer library */ - Mix_PlayMusic(mixer[audio.music_channel].data_ptr, -1); + int loops = (IS_LOOP(mixer[audio.music_channel]) ? -1 : 1); + + // use short fade-in to prevent "plop" sound for certain music files + // (this may happen when switching on music while playing the game) Mix_VolumeMusic(mixer[audio.music_channel].volume); + Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, loops, 100); + +#if defined(PLATFORM_WIN32) + // playing MIDI music is broken since Windows Vista, as it sets the volume + // for MIDI music also for all other sounds and music, which cannot be set + // back to normal unless playing MIDI music again with that desired volume + // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253) + // => workaround: always play MIDI music with maximum volume + if (Mix_GetMusicType(NULL) == MUS_MID) + Mix_VolumeMusic(SOUND_MAX_VOLUME); +#endif } } @@ -234,11 +251,13 @@ static void Mixer_StopChannel(int channel) mixer_active_channels--; } -static void Mixer_StopMusicChannel() +static void Mixer_StopMusicChannel(void) { Mixer_StopChannel(audio.music_channel); Mix_HaltMusic(); + + setString(¤tly_playing_music_filename, NULL); } static void Mixer_FadeChannel(int channel) @@ -251,11 +270,23 @@ static void Mixer_FadeChannel(int channel) Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL); } -static void Mixer_FadeMusicChannel() +static void Mixer_FadeMusicChannel(void) { Mixer_FadeChannel(audio.music_channel); Mix_FadeOutMusic(SOUND_FADING_INTERVAL); + +#if defined(PLATFORM_WIN32) + // playing MIDI music is broken since Windows Vista, as it sets the volume + // for MIDI music also for all other sounds and music, which cannot be set + // back to normal unless playing MIDI music again with that desired volume + // (more details: https://www.artsoft.org/forum/viewtopic.php?f=7&t=2253) + // => workaround: never fade MIDI music to lower volume, but just stop it + if (Mix_GetMusicType(NULL) == MUS_MID) + Mixer_StopMusicChannel(); +#endif + + setString(¤tly_playing_music_filename, NULL); } static void Mixer_UnFadeChannel(int channel) @@ -274,32 +305,11 @@ static void Mixer_InsertSound(SoundControl snd_ctrl) { SoundInfo *snd_info; int i, k; - int num_sounds = getSoundListSize(); - int num_music = getMusicListSize(); if (IS_MUSIC(snd_ctrl)) - { - if (snd_ctrl.nr >= num_music) /* invalid music */ - return; - - if (snd_ctrl.nr < 0) /* undefined music */ - { - if (num_music_noconf == 0) /* no fallback music available */ - return; - - snd_ctrl.nr = UNMAP_NOCONF_MUSIC(snd_ctrl.nr) % num_music_noconf; - snd_info = Music_NoConf[snd_ctrl.nr]; - } - else - snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr); - } + snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr); else - { - if (snd_ctrl.nr < 0 || snd_ctrl.nr >= num_sounds) - return; - snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr); - } if (snd_info == NULL) return; @@ -319,6 +329,9 @@ static void Mixer_InsertSound(SoundControl snd_ctrl) mixer[audio.music_channel] = snd_ctrl; Mixer_PlayMusicChannel(); + setString(¤tly_playing_music_filename, + getBaseNamePtr(snd_info->source_filename)); + return; } @@ -478,6 +491,10 @@ static void HandleSoundRequest(SoundControl snd_ctrl) if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl)) Mixer_StopChannel(i); } + else if (SET_EXPIRE_LOOPS(snd_ctrl)) /* set loop expiration on or off */ + { + expire_loop_sounds = snd_ctrl.active; + } else if (snd_ctrl.active) /* add new sound to mixer */ { Mixer_InsertSound(snd_ctrl); @@ -516,7 +533,7 @@ static void *Load_WAV(char *filename) if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL) { - Error(ERR_WARN, "cannot read sound file '%s'", filename); + Error(ERR_WARN, "cannot read sound file '%s': %s", filename, Mix_GetError()); free(snd_info); return NULL; } @@ -540,7 +557,7 @@ static void *Load_MOD(char *filename) if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL) { - Error(ERR_WARN, "cannot read music file '%s'", filename); + Error(ERR_WARN, "cannot read music file '%s': %s", filename, Mix_GetError()); free(mod_info); return NULL; } @@ -561,7 +578,7 @@ static void *Load_WAV_or_MOD(char *filename) return NULL; } -void LoadCustomMusic_NoConf(void) +static void LoadCustomMusic_NoConf(void) { static boolean draw_init_text = TRUE; /* only draw at startup */ static char *last_music_directory = NULL; @@ -637,13 +654,13 @@ void LoadCustomMusic_NoConf(void) draw_init_text = FALSE; } -int getSoundListSize() +int getSoundListSize(void) { return (sound_info->num_file_list_entries + sound_info->num_dynamic_file_list_entries); } -int getMusicListSize() +int getMusicListSize(void) { return (music_info->num_file_list_entries + music_info->num_dynamic_file_list_entries); @@ -651,60 +668,101 @@ int getMusicListSize() struct FileInfo *getSoundListEntry(int pos) { + int num_sounds = getSoundListSize(); int num_list_entries = sound_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); + if (pos < 0 || pos >= num_sounds) /* invalid sound */ + return NULL; + return (pos < num_list_entries ? &sound_info->file_list[list_pos] : &sound_info->dynamic_file_list[list_pos]); } struct FileInfo *getMusicListEntry(int pos) { + int num_music = getMusicListSize(); int num_list_entries = music_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); + if (pos < 0 || pos >= num_music) /* invalid music */ + return NULL; + return (pos < num_list_entries ? &music_info->file_list[list_pos] : &music_info->dynamic_file_list[list_pos]); } static SoundInfo *getSoundInfoEntryFromSoundID(int pos) { + int num_sounds = getSoundListSize(); int num_list_entries = sound_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); SoundInfo **snd_info = (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list : sound_info->dynamic_artwork_list); + if (pos < 0 || pos >= num_sounds) /* invalid sound */ + return NULL; + return snd_info[list_pos]; } static MusicInfo *getMusicInfoEntryFromMusicID(int pos) { + int num_music = getMusicListSize(); int num_list_entries = music_info->num_file_list_entries; int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); MusicInfo **mus_info = (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list : music_info->dynamic_artwork_list); + if (pos >= num_music) /* invalid music */ + return NULL; + + if (pos < 0) /* undefined music */ + { + if (num_music_noconf == 0) /* no fallback music available */ + return NULL; + + pos = UNMAP_NOCONF_MUSIC(pos) % num_music_noconf; + + return Music_NoConf[pos]; + } + return mus_info[list_pos]; } -int getSoundListPropertyMappingSize() +char *getMusicInfoEntryFilename(int pos) +{ + MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos); + + if (mus_info == NULL) + return NULL; + + return getBaseNamePtr(mus_info->source_filename); +} + +char *getCurrentlyPlayingMusicFilename(void) +{ + return currently_playing_music_filename; +} + +int getSoundListPropertyMappingSize(void) { return sound_info->num_property_mapping_entries; } -int getMusicListPropertyMappingSize() +int getMusicListPropertyMappingSize(void) { return music_info->num_property_mapping_entries; } -struct PropertyMapping *getSoundListPropertyMapping() +struct PropertyMapping *getSoundListPropertyMapping(void) { return sound_info->property_mapping; } -struct PropertyMapping *getMusicListPropertyMapping() +struct PropertyMapping *getMusicListPropertyMapping(void) { return music_info->property_mapping; } @@ -867,6 +925,14 @@ void PlayMusic(int nr) PlaySoundMusic(nr); } +void PlayMusicLoop(int nr) +{ + if (!audio.music_available) + return; + + PlaySoundMusicLoop(nr); +} + void PlaySound(int nr) { if (!setup.sound_simple) @@ -899,6 +965,14 @@ void PlaySoundMusic(int nr) PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC); } +void PlaySoundMusicLoop(int nr) +{ + if (!setup.sound_music) + return; + + PlaySoundExt(nr, SOUND_MAX_VOLUME, SOUND_MIDDLE, SND_CTRL_PLAY_MUSIC_LOOP); +} + void PlaySoundExt(int nr, int volume, int stereo_position, int state) { SoundControl snd_ctrl; @@ -944,12 +1018,12 @@ void FadeSound(int nr) StopSoundExt(nr, SND_CTRL_FADE_SOUND); } -void FadeSounds() +void FadeSounds(void) { StopSoundExt(-1, SND_CTRL_FADE_ALL); } -void FadeSoundsAndMusic() +void FadeSoundsAndMusic(void) { FadeSounds(); FadeMusic(); @@ -968,7 +1042,7 @@ void StopSound(int nr) StopSoundExt(nr, SND_CTRL_STOP_SOUND); } -void StopSounds() +void StopSounds(void) { StopMusic(); StopSoundExt(-1, SND_CTRL_STOP_ALL); @@ -990,13 +1064,28 @@ void StopSoundExt(int nr, int state) HandleSoundRequest(snd_ctrl); } -static void ReloadCustomSounds() +void ExpireSoundLoops(boolean active) +{ + SoundControl snd_ctrl; + + if (!audio.sound_available) + return; + + clear_mem(&snd_ctrl, sizeof(SoundControl)); /* to make valgrind happy */ + + snd_ctrl.active = active; + snd_ctrl.state = SND_CTRL_EXPIRE_LOOPS; + + HandleSoundRequest(snd_ctrl); +} + +static void ReloadCustomSounds(void) { LoadArtworkConfig(sound_info); ReloadCustomArtworkList(sound_info); } -static void ReloadCustomMusic() +static void ReloadCustomMusic(void) { LoadArtworkConfig(music_info); ReloadCustomArtworkList(music_info); @@ -1056,7 +1145,7 @@ void FreeMusic(void *ptr) free(music); } -static void FreeAllMusic_NoConf() +static void FreeAllMusic_NoConf(void) { int i; @@ -1072,12 +1161,12 @@ static void FreeAllMusic_NoConf() num_music_noconf = 0; } -void FreeAllSounds() +void FreeAllSounds(void) { FreeCustomArtworkLists(sound_info); } -void FreeAllMusic() +void FreeAllMusic(void) { FreeCustomArtworkLists(music_info); FreeAllMusic_NoConf();