diff --git a/src/i_sound.h b/src/i_sound.h index 94548456c..3c8a2ca62 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -251,10 +251,15 @@ void I_SetInternalMusicVolume(UINT8 volume); void I_StopFadingMusic(void); -boolean I_FadeMusicFromLevel(UINT8 target_volume, UINT16 source_volume, UINT32 ms); +boolean I_FadeMusicFromLevel(UINT8 target_volume, UINT8 source_volume, UINT32 ms, boolean stopafterfade); boolean I_FadeMusic(UINT8 target_volume, UINT32 ms); +boolean I_FadeOutStopMusic(UINT32 ms); + +boolean I_FadeInStartDigSong(const char *musicname, UINT16 track, boolean looping, UINT32 position, UINT32 fadeinms, boolean queuepostfade); +#define I_QueueDigSongPostFade(a,b,c,d,e) I_FadeInStartDigSong(a,b,c,d,e,1) + /** \brief The I_StartDigSong function \param musicname music lump name diff --git a/src/s_sound.c b/src/s_sound.c index 46ceb549d..9e96480e1 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1379,7 +1379,7 @@ static boolean S_DigMusic(const char *mname, boolean looping) return true; } -void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) +void S_ChangeMusicWithFade(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms) { if ((nomidimusic || music_disabled) && (nodigimusic || digital_disabled)) return; @@ -1402,13 +1402,47 @@ void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) if (strncmp(music_name, newmusic, 6)) { - S_StopMusic(); // shutdown old music - if (!S_DigMusic(newmusic, looping) && !S_MIDIMusic(newmusic, looping)) + if (S_MusicExists(newmusic, false, true) && !nodigimusic && !digital_disabled) // digmusic? { - CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic); - return; + if (prefadems) //have to queue post-fade + { + I_FadeOutStopMusic(prefadems); + I_QueueDigSongPostFade(newmusic, mflags & MUSIC_TRACKMASK, looping, position, fadeinms); + + // HACK: set the vars now and hope everything works out + strncpy(music_name, newmusic, 7); + music_name[6] = 0; + music_lumpnum = LUMPERROR; + music_data = NULL; + music_handle = 0; + return; + } + else + { + S_StopMusic(); + if (!S_DigMusic(newmusic, looping)) + { + CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic); + return; + } + } + } + else if (S_MusicExists(newmusic, true, false) && !nomidimusic && !music_disabled) // midimusic? + { + // HACK: We don't support fade for MIDI right now, so + // just fall to old behavior verbatim. This technically should be implemented in + // the interfaces, even as a stub. + + S_StopMusic(); + + if (!S_MIDIMusic(newmusic, looping)) + { + CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic); + return; + } } } + I_SetSongTrack(mflags & MUSIC_TRACKMASK); } @@ -1491,7 +1525,12 @@ boolean S_FadeMusicFromLevel(UINT8 target_volume, INT16 source_volume, UINT32 ms if (source_volume < 0) return I_FadeMusic(target_volume, ms); else - return I_FadeMusicFromLevel(target_volume, source_volume, ms); + return I_FadeMusicFromLevel(target_volume, source_volume, ms, false); +} + +boolean S_FadeOutStopMusic(UINT32 ms) +{ + return I_FadeOutStopMusic(ms); } void S_SetDigMusicVolume(INT32 volume) diff --git a/src/s_sound.h b/src/s_sound.h index 20a0f81e0..cdcacd14e 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -130,8 +130,10 @@ void S_StopSound(void *origin); // note: music flags 12 bits for tracknum (gme, other formats with more than one track) // 13-15 aren't used yet // and the last bit we ignore (internal game flag for resetting music on reload) -#define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b) -void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping); +void S_ChangeMusicWithFade(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms); +#define S_FadeInChangeMusic(a,b,c,d) S_ChangeMusicWithFade(a,b,c,0,0,d) +#define S_ChangeMusicInternal(a,b) S_ChangeMusicWithFade(a,0,b,0,0,0) +#define S_ChangeMusic(a,b,c) S_ChangeMusicWithFade(a,b,c,0,0,0) // Get music type musictype_t S_MusicType(); @@ -176,6 +178,7 @@ boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi); void S_StopFadingMusic(void); boolean S_FadeMusicFromLevel(UINT8 target_volume, INT16 source_volume, UINT32 ms); #define S_FadeMusic(a, b) S_FadeMusicFromLevel(a, -1, b) +boolean S_FadeOutStopMusic(UINT32 ms); // // Updates music & sounds diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 1b7c81008..71421ea62 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -75,6 +75,12 @@ static UINT8 fading_target; static UINT32 fading_steps; static INT16 fading_volume_step; static INT32 fading_id; +static char queue_music_name[7]; // up to 6-character name +static UINT16 queue_track; +static boolean queue_looping; +static UINT32 queue_position; +static UINT32 queue_fadeinms; +static boolean queue_stopafterfade; #ifdef HAVE_LIBGME static Music_Emu *gme; @@ -93,6 +99,14 @@ static void varcleanup(void) internal_volume = 100; } +static void queuecleanup(void) +{ + queue_track = queue_looping =\ + queue_position = queue_fadeinms =\ + queue_stopafterfade = 0; + queue_music_name[0] = 0; +} + static UINT32 get_real_volume(UINT8 volume) { // convert volume to mixer's 128 scale @@ -115,6 +129,7 @@ void I_StartupSound(void) } varcleanup(); + queuecleanup(); music = NULL; music_volume = midi_volume = sfx_volume = 0; @@ -508,14 +523,31 @@ static void music_loop(void) I_StopDigSong(); } +static void run_queue() +{ + if (queue_stopafterfade) + I_StopDigSong(); + else if (queue_music_name[0] && I_StartDigSong(queue_music_name, queue_looping)) + { + I_SetSongTrack(queue_track); + if (queue_fadeinms) + I_FadeMusicFromLevel(100, 0, queue_fadeinms, false); + if (queue_position) + I_SetMusicPosition(queue_position); + } + queuecleanup(); +} + static UINT32 music_fade(UINT32 interval, void *param) { if (!is_fading || + midimode || // stub out MIDI, see bug in I_SetMIDIMusicVolume internal_volume == fading_target || fading_steps == 0 || fading_volume_step == 0) { I_StopFadingMusic(); + queuecleanup(); return 0; } else if ( @@ -524,6 +556,7 @@ static UINT32 music_fade(UINT32 interval, void *param) { internal_volume = fading_target; Mix_VolumeMusic(get_real_volume(midimode ? midi_volume : music_volume)); + run_queue(); return 0; } else @@ -644,6 +677,7 @@ void I_ShutdownDigMusic(void) if (!music) return; varcleanup(); + queuecleanup(); SDL_RemoveTimer(fading_id); Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); Mix_HookMusicFinished(NULL); @@ -1176,7 +1210,7 @@ boolean I_SetSongTrack(int track) void I_SetInternalMusicVolume(UINT8 volume) { internal_volume = volume; - if (!music) + if (midimode || !music) // stub out MIDI, see bug in I_SetMIDIMusicVolume return; Mix_VolumeMusic(get_real_volume(midimode ? midi_volume : music_volume)); } @@ -1189,23 +1223,39 @@ void I_StopFadingMusic(void) fading_target = fading_steps = fading_volume_step = fading_id = 0; } -boolean I_FadeMusicFromLevel(UINT8 target_volume, UINT8 source_volume, UINT32 ms) +boolean I_FadeMusicFromLevel(UINT8 target_volume, UINT8 source_volume, UINT32 ms, boolean stopafterfade) { UINT32 target_steps, ms_per_step; INT16 target_volume_step, volume_delta; source_volume = min(source_volume, 100); - volume_delta = (INT16)(target_volume - source_volume)); + volume_delta = (INT16)(target_volume - source_volume); I_StopFadingMusic(); if (!ms && volume_delta) { - I_SetInternalMusicVolume(target_volume); - return true; + if (stopafterfade) + { + I_StopDigSong(); + return true; + } + else + { + I_SetInternalMusicVolume(target_volume); + return true; + } } else if (!volume_delta) - return true; + { + if (stopafterfade) + { + I_StopDigSong(); + return true; + } + else + return true; + } // Round MS to nearest 10 // If n - lower > higher - n, then round up @@ -1229,6 +1279,7 @@ boolean I_FadeMusicFromLevel(UINT8 target_volume, UINT8 source_volume, UINT32 ms fading_target = target_volume; fading_steps = target_steps; fading_volume_step = target_volume_step; + queue_stopafterfade = stopafterfade; if (internal_volume != source_volume) I_SetInternalMusicVolume(source_volume); @@ -1240,7 +1291,45 @@ boolean I_FadeMusicFromLevel(UINT8 target_volume, UINT8 source_volume, UINT32 ms boolean I_FadeMusic(UINT8 target_volume, UINT32 ms) { - return I_FadeMusicFromLevel(target_volume, internal_volume, ms); + return I_FadeMusicFromLevel(target_volume, internal_volume, ms, false); +} + +boolean I_FadeOutStopMusic(UINT32 ms) +{ + return I_FadeMusicFromLevel(0, internal_volume, ms, true); +} + +boolean I_FadeInStartDigSong(const char *musicname, UINT16 track, boolean looping, UINT32 position, UINT32 fadeinms, boolean queuepostfade) +{ + if (musicname[0] == 0) + return true; // nothing to play + else if (queuepostfade && is_fading) + { + strncpy(queue_music_name, musicname, 7); + queue_music_name[6] = 0; + queue_track = track; + queue_looping = looping; + queue_position = position; + queue_fadeinms = fadeinms; + queue_stopafterfade = false; + + return true; + } + else + { + if (I_StartDigSong(musicname, looping)) + { + I_SetSongTrack(track); + if (fadeinms) + I_FadeMusicFromLevel(100, 0, fadeinms, false); + if (position) + I_SetMusicPosition(position); + return true; + } + else + return false; + } + } // @@ -1264,10 +1353,18 @@ void I_ShutdownMIDIMusic(void) void I_SetMIDIMusicVolume(UINT8 volume) { - midi_volume = volume; + // HACK: Until we stop using native MIDI, + // disable volume changes + // Why: In Windows, MIDI volume messes with the executable's volume setting + // in the OS volume mixer. So any EXE sharing that same filename and directory + // will be affected by this volume bug. + + (void)volume; + midi_volume = 31; + //midi_volume = volume; if (!midimode || !music) return; - Mix_VolumeMusic(get_real_volume(volume)); + Mix_VolumeMusic((UINT32)midi_volume*128/31); } INT32 I_RegisterSong(void *data, size_t len)