Checkpoint: Revised fading routines for new load/play pattern

* Perform fade-out/fade-in using callbacks
* Move queued music from interface to s_sound
This commit is contained in:
mazmazz 2018-08-24 08:20:09 -04:00
parent b5ef4e04d8
commit bf61dbb6e2
3 changed files with 127 additions and 194 deletions

View file

@ -233,17 +233,11 @@ boolean I_SetSongTrack(INT32 track);
/// ------------------------ /// ------------------------
void I_SetInternalMusicVolume(UINT8 volume); void I_SetInternalMusicVolume(UINT8 volume);
void I_StopFadingSong(void); void I_StopFadingSong(void);
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, boolean stopafterfade); boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeSong(UINT8 target_volume, UINT32 ms);
boolean I_FadeOutStopSong(UINT32 ms); boolean I_FadeOutStopSong(UINT32 ms);
boolean I_FadeInPlaySong(UINT32 ms, boolean looping);
boolean I_FadeInStartDigSong(const char *musicname, UINT16 track, boolean looping, UINT32 position, UINT32 fadeinms, boolean queuepostfade);
#define I_QueueDigSong(a,b,c,d,e) I_FadeInStartDigSong(a,b,c,d,e,1)
/// ------------------------ /// ------------------------
// CD MUSIC I/O // CD MUSIC I/O

View file

@ -1354,6 +1354,12 @@ static char music_name[7]; // up to 6-character name
static UINT16 music_flags; static UINT16 music_flags;
static boolean music_looping; static boolean music_looping;
static char queue_name[7];
static UINT16 queue_flags;
static boolean queue_looping;
static UINT32 queue_position;
static UINT32 queue_fadeinms;
/// ------------------------ /// ------------------------
/// Music Status /// Music Status
/// ------------------------ /// ------------------------
@ -1500,118 +1506,108 @@ static void S_UnloadMusic(void)
music_looping = false; music_looping = false;
} }
static boolean S_PlayMusic(boolean looping) static boolean S_PlayMusic(boolean looping, UINT32 fadeinms)
{ {
if (S_MusicDisabled()) if (S_MusicDisabled())
return false; return false;
if (!I_PlaySong(looping)) if ((!fadeinms && !I_PlaySong(looping)) ||
(fadeinms && !I_FadeInPlaySong(fadeinms, looping)))
{ {
S_UnloadMusic(); S_UnloadMusic();
return false; return false;
} }
S_InitMusicVolume(); // switch between digi and sequence volume S_InitMusicVolume(); // switch between digi and sequence volume
return true; return true;
} }
static void S_QueueMusic(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 fadeinms)
{
strncpy(queue_name, mmusic, 7);
queue_flags = mflags;
queue_looping = looping;
queue_position = position;
queue_fadeinms = fadeinms;
}
static void S_ClearQueue(void)
{
queue_name[0] = queue_flags = queue_looping = queue_position = queue_fadeinms = 0;
}
static void S_ChangeMusicToQueue(void)
{
S_ChangeMusicAdvanced(queue_name, queue_flags, queue_looping, queue_position, 0, queue_fadeinms);
S_ClearQueue();
}
void S_ChangeMusicAdvanced(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms) void S_ChangeMusicAdvanced(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms)
{ {
if (S_MusicDisabled()) if (S_MusicDisabled())
return; return;
char newmusic[7]; char newmusic[7];
boolean digiexists = S_DigExists(mmusic);
boolean midiexists = S_MIDIExists(mmusic);
#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) #if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
if(LUAh_MusicChange(music_name, mmusic, newmusic, &mflags, &looping)) if(LUAh_MusicChange(music_name, mmusic, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms))
return; return;
#else #else
strncpy(newmusic, mmusic, 7); strncpy(newmusic, mmusic, 7);
#endif #endif
newmusic[6] = 0; newmusic[6] = 0;
int i;
for (i = 0; newmusic[i]; i++) {
newmusic[i] = tolower(newmusic[i]);
}
// No Music (empty string) // No Music (empty string)
if (newmusic[0] == 0) if (newmusic[0] == 0)
{ {
S_StopMusic(); if (prefadems)
I_FadeSong(0, prefadems, &S_StopMusic);
else
S_StopMusic();
return; return;
} }
CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic); if (prefadems && S_MusicPlaying()) // queue music change for after fade // allow even if the music is the same
if (digiexists && !digital_disabled) // digmusic?
{ {
if (prefadems && I_SongType() != MU_MID) //have to queue post-fade // allow even if the music is the same CONS_Debug(DBG_DETAILED, "Now fading out song %s\n", music_name);
{ S_QueueMusic(newmusic, mflags, looping, position, fadeinms);
I_FadeOutStopSong(prefadems); I_FadeSong(0, prefadems, S_ChangeMusicToQueue);
I_QueueDigSong(newmusic, mflags & MUSIC_TRACKMASK, looping, position, fadeinms); return;
// 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 if (strncmp(music_name, newmusic, 6))
{
S_StopMusic();
if (position || fadeinms)
{
if(!I_FadeInStartDigSong(newmusic, mflags & MUSIC_TRACKMASK, looping, position, fadeinms, false))
{
CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic);
return;
}
else
{
strncpy(music_name, newmusic, 7);
music_name[6] = 0;
music_lumpnum = LUMPERROR;
music_data = NULL;
music_handle = 0;
return;
}
}
else if (!S_DigMusic(newmusic, looping))
{
CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic);
return;
}
else
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
}
} }
else if (strncmp(music_name, newmusic, 6) && midiexists && !midi_disabled) // midimusic? else if (strncmp(music_name, newmusic, 6))
{ {
// HACK: We don't support fade for MIDI right now, so CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic);
// just fall to old behavior verbatim. This technically should be implemented in
// the interfaces, even as a stub.
S_StopMusic(); // shutdown old music S_StopMusic();
if (!S_LoadMusic(mmusic)) if (!S_LoadMusic(newmusic))
return; return;
music_flags = mflags; music_flags = mflags;
music_looping = looping; music_looping = looping;
if (!S_PlayMusic(looping)) if (!S_PlayMusic(looping, fadeinms))
{ {
CONS_Alert(CONS_ERROR, "Music cannot be played!\n"); CONS_Alert(CONS_ERROR, "Music cannot be played!\n");
return; return;
} }
}
else if (!midiexists && !digiexists)
CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic);
}
musictype_t S_MusicType() if (position)
{ I_SetSongPosition(position);
return I_SongType();
I_SetSongTrack(mflags & MUSIC_TRACKMASK);
}
else if (fadeinms) // let fades happen with same music
{
I_SetSongPosition(position);
I_FadeSong(100, fadeinms, NULL);
}
} }
void S_StopMusic(void) void S_StopMusic(void)
@ -1713,14 +1709,14 @@ void S_StopFadingMusic(void)
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms) boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms)
{ {
if (source_volume < 0) if (source_volume < 0)
return I_FadeSong(target_volume, ms); return I_FadeSong(target_volume, ms, NULL);
else else
return I_FadeSongFromVolume(target_volume, source_volume, ms, false); return I_FadeSongFromVolume(target_volume, source_volume, ms, false);
} }
boolean S_FadeOutStopMusic(UINT32 ms) boolean S_FadeOutStopMusic(UINT32 ms)
{ {
return I_FadeOutStopSong(ms); return I_FadeSong(0, ms, &S_StopMusic);
} }
/// ------------------------ /// ------------------------

View file

@ -76,20 +76,27 @@ static UINT8 fading_target;
static UINT32 fading_steps; static UINT32 fading_steps;
static INT16 fading_volume_step; static INT16 fading_volume_step;
static INT32 fading_id; static INT32 fading_id;
static void (*fading_callback)(void);
// queue
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 #ifdef HAVE_LIBGME
static Music_Emu *gme; static Music_Emu *gme;
static INT32 current_track; static INT32 current_track;
#endif #endif
static void var_cleanup(void)
{
loop_point = song_length =\
music_bytes = fading_target =\
fading_steps = fading_volume_step = 0;
songpaused = is_looping =\
is_fading = false;
fading_callback = NULL;
internal_volume = 100;
}
/// ------------------------ /// ------------------------
/// Audio System /// Audio System
/// ------------------------ /// ------------------------
@ -109,7 +116,6 @@ void I_StartupSound(void)
} }
var_cleanup(); var_cleanup();
queue_cleanup();
music = NULL; music = NULL;
music_volume = sfx_volume = 0; music_volume = sfx_volume = 0;
@ -465,31 +471,18 @@ void I_SetSfxVolume(UINT8 volume)
/// Music Utilities /// Music Utilities
/// ------------------------ /// ------------------------
static void var_cleanup(void)
{
loop_point = song_length =\
music_bytes = fading_target =\
fading_steps = fading_volume_step = 0;
songpaused = is_looping =\
is_fading = false;
internal_volume = 100;
}
static void queue_cleanup(void)
{
queue_track = queue_looping =\
queue_position = queue_fadeinms =\
queue_stopafterfade = 0;
queue_music_name[0] = 0;
}
static UINT32 get_real_volume(UINT8 volume) static UINT32 get_real_volume(UINT8 volume)
{ {
// convert volume to mixer's 128 scale #ifdef _WIN32
// then apply internal_volume as a percentage if (I_SongType() == MU_MID)
return ((UINT32)volume*128/31) * (UINT32)internal_volume / 100; // HACK: Until we stop using native MIDI,
// disable volume changes
return ((UINT32)31*128/31); // volume = 31
else
#endif
// convert volume to mixer's 128 scale
// then apply internal_volume as a percentage
return ((UINT32)volume*128/31) * (UINT32)internal_volume / 100;
} }
static UINT32 get_adjusted_position(UINT32 position) static UINT32 get_adjusted_position(UINT32 position)
@ -503,24 +496,11 @@ static UINT32 get_adjusted_position(UINT32 position)
return position; return position;
} }
static void run_queue() static void do_fading_callback()
{ {
if (queue_stopafterfade) if (fading_callback)
I_StopSong(); (*fading_callback)();
else if (queue_music_name[0]) fading_callback = NULL;
{
I_StopSong();
if (I_StartDigSong(queue_music_name, queue_looping))
{
I_SetSongTrack(queue_track);
if (queue_fadeinms)
I_FadeSongFromVolume(100, 0, queue_fadeinms, false);
if (queue_position)
I_SetSongPosition(queue_position);
}
}
queue_cleanup();
} }
/// ------------------------ /// ------------------------
@ -540,9 +520,7 @@ static void count_music_bytes(int chan, void *stream, int len, void *udata)
static void music_loop(void) static void music_loop(void)
{ {
if (queue_music_name[0] && !is_fading && !is_looping) if (is_looping)
run_queue();
else if (is_looping)
{ {
Mix_PlayMusic(music, 0); Mix_PlayMusic(music, 0);
Mix_SetMusicPosition(loop_point); Mix_SetMusicPosition(loop_point);
@ -555,13 +533,12 @@ static void music_loop(void)
static UINT32 music_fade(UINT32 interval, void *param) static UINT32 music_fade(UINT32 interval, void *param)
{ {
if (!is_fading || if (!is_fading ||
I_SongType() == MU_MID || // stub out MIDI, see bug in I_SetMIDIMusicVolume
internal_volume == fading_target || internal_volume == fading_target ||
fading_steps == 0 || fading_steps == 0 ||
fading_volume_step == 0) fading_volume_step == 0)
{ {
I_StopFadingSong(); I_StopFadingSong();
queue_cleanup(); do_fading_callback();
return 0; return 0;
} }
else if ( else if (
@ -570,7 +547,8 @@ static UINT32 music_fade(UINT32 interval, void *param)
{ {
internal_volume = fading_target; internal_volume = fading_target;
Mix_VolumeMusic(get_real_volume(music_volume)); Mix_VolumeMusic(get_real_volume(music_volume));
run_queue(); I_StopFadingSong();
do_fading_callback();
return 0; return 0;
} }
else else
@ -628,7 +606,6 @@ void I_ShutdownMusic(void)
if (!music) if (!music)
return; return;
var_cleanup(); var_cleanup();
queue_cleanup();
SDL_RemoveTimer(fading_id); SDL_RemoveTimer(fading_id);
Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes); Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes);
Mix_HookMusicFinished(NULL); Mix_HookMusicFinished(NULL);
@ -862,7 +839,7 @@ UINT32 I_GetSongPosition(void)
if (info->length > 0) if (info->length > 0)
position %= info->length; position %= info->length;
else if (info->intro_length + info->loop_length > 0) else if (info->intro_length + info->loop_length > 0)
position = position >= (info->intro_length + info->loop_length) ? (position % info->loop_length) : position position = position >= (info->intro_length + info->loop_length) ? (position % info->loop_length) : position;
else else
position %= 150 * 1000; // 2.5 minutes position %= 150 * 1000; // 2.5 minutes
} }
@ -985,7 +962,6 @@ boolean I_LoadSong(char *data, size_t len)
{ {
gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
gme_set_equalizer(gme, &eq); gme_set_equalizer(gme, &eq);
Mix_HookMusic(mix_gme, gme);
return true; return true;
} }
#endif #endif
@ -1120,19 +1096,21 @@ void I_UnloadSong(void)
boolean I_PlaySong(boolean looping) boolean I_PlaySong(boolean looping)
{ {
if (!music) #ifdef HAVE_LIBGME
return false;
#ifdef HAVE_GME
if (gme) if (gme)
{ {
gme_start_track(gme, 0); gme_start_track(gme, 0);
current_track = 0; current_track = 0;
Mix_HookMusic(mix_gme, gme);
return true; return true;
} }
else
#endif #endif
if (!music)
return false;
if (!song_length && (I_SongType() == MU_OGG || I_SongType() == MU_MP3 || I_SongType() == MU_FLAC)) if (!song_length && (I_SongType() == MU_OGG || I_SongType() == MU_MP3 || I_SongType() == MU_FLAC))
CONS_Debug(DBG_DETAILED, "This song is missing a LENGTHMS= tag! Required to make seeking work properly."); CONS_Debug(DBG_DETAILED, "This song is missing a LENGTHMS= tag! Required to make seeking work properly.\n");
if (I_SongType() != MU_MOD && I_SongType() != MU_MID && Mix_PlayMusic(music, 0) == -1) if (I_SongType() != MU_MOD && I_SongType() != MU_MID && Mix_PlayMusic(music, 0) == -1)
{ {
@ -1179,10 +1157,8 @@ void I_StopSong(void)
music = NULL; music = NULL;
} }
void I_PauseSong(INT32 handle) void I_PauseSong()
{ {
(void)handle;
if(I_SongType() == MU_MID) // really, SDL Mixer? why can't you pause MIDI??? if(I_SongType() == MU_MID) // really, SDL Mixer? why can't you pause MIDI???
return; return;
@ -1197,10 +1173,8 @@ void I_PauseSong(INT32 handle)
songpaused = true; songpaused = true;
} }
void I_ResumeSong(INT32 handle) void I_ResumeSong()
{ {
(void)handle;
if (I_SongType() == MU_MID) if (I_SongType() == MU_MID)
return; return;
@ -1213,7 +1187,7 @@ void I_ResumeSong(INT32 handle)
while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { } while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { }
// HACK: fixes issue of multiple effect callbacks being registered // HACK: fixes issue of multiple effect callbacks being registered
if(music && I_GetSongType() != MU_MOD && I_GetSongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL)) if(music && I_SongType() != MU_MOD && I_SongType() != MU_MID && !Mix_RegisterEffect(MIX_CHANNEL_POST, count_music_bytes, NULL, NULL))
CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError()); CONS_Alert(CONS_WARNING, "Error registering SDL music position counter: %s\n", Mix_GetError());
} }
@ -1235,7 +1209,7 @@ void I_SetMusicVolume(UINT8 volume)
#endif #endif
music_volume = volume; music_volume = volume;
Mix_VolumeMusic((UINT32)music_volume*128/31); Mix_VolumeMusic(get_real_volume(music_volume));
} }
boolean I_SetSongTrack(int track) boolean I_SetSongTrack(int track)
@ -1279,7 +1253,7 @@ boolean I_SetSongTrack(int track)
void I_SetInternalMusicVolume(UINT8 volume) void I_SetInternalMusicVolume(UINT8 volume)
{ {
internal_volume = volume; internal_volume = volume;
if (!music || I_SongType() == MU_MID) // stub out MIDI, see bug in I_SetMIDIMusicVolume if (!music)
return; return;
Mix_VolumeMusic(get_real_volume(music_volume)); Mix_VolumeMusic(get_real_volume(music_volume));
} }
@ -1292,7 +1266,7 @@ void I_StopFadingSong(void)
fading_target = fading_steps = fading_volume_step = fading_id = 0; fading_target = fading_steps = fading_volume_step = fading_id = 0;
} }
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, boolean stopafterfade) boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void))
{ {
UINT32 target_steps, ms_per_step; UINT32 target_steps, ms_per_step;
INT16 target_volume_step, volume_delta; INT16 target_volume_step, volume_delta;
@ -1304,21 +1278,16 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
if (!ms && volume_delta) if (!ms && volume_delta)
{ {
if (stopafterfade) I_SetInternalMusicVolume(target_volume);
{ if (callback)
I_StopSong(); (*callback)();
return true; return true;
}
else
{
I_SetInternalMusicVolume(target_volume);
return true;
}
} }
else if (!volume_delta || I_SongType() == MU_MID) else if (!volume_delta)
{ {
if (stopafterfade) if (callback)
I_StopSong(); (*callback)();
return true; return true;
} }
@ -1344,7 +1313,7 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
fading_target = target_volume; fading_target = target_volume;
fading_steps = target_steps; fading_steps = target_steps;
fading_volume_step = target_volume_step; fading_volume_step = target_volume_step;
queue_stopafterfade = stopafterfade; fading_callback = callback;
if (internal_volume != source_volume) if (internal_volume != source_volume)
I_SetInternalMusicVolume(source_volume); I_SetInternalMusicVolume(source_volume);
@ -1354,47 +1323,21 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
return is_fading; return is_fading;
} }
boolean I_FadeSong(UINT8 target_volume, UINT32 ms) boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{ {
return I_FadeSongFromVolume(target_volume, internal_volume, ms, false); return I_FadeSongFromVolume(target_volume, internal_volume, ms, callback);
} }
boolean I_FadeOutStopSong(UINT32 ms) boolean I_FadeOutStopSong(UINT32 ms)
{ {
return I_FadeSongFromVolume(0, internal_volume, ms, true); return I_FadeSongFromVolume(0, internal_volume, ms, &I_StopSong);
} }
boolean I_FadeInStartDigSong(const char *musicname, UINT16 track, boolean looping, UINT32 position, UINT32 fadeinms, boolean queuepostfade) boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{ {
if (musicname[0] == 0) if (I_PlaySong(looping))
return true; // nothing to play return I_FadeSongFromVolume(100, 0, ms, NULL);
else if (queuepostfade && is_fading && I_SongType() != MU_MID)
{
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 else
{ return false;
if (I_StartDigSong(musicname, looping))
{
I_SetSongTrack(track);
if (fadeinms)
I_FadeSongFromVolume(100, 0, fadeinms, false);
if (position)
I_SetSongPosition(position);
return true;
}
else
return false;
}
} }
#endif #endif