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_StopFadingSong(void);
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, boolean stopafterfade);
boolean I_FadeSong(UINT8 target_volume, UINT32 ms);
boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void));
boolean I_FadeOutStopSong(UINT32 ms);
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)
boolean I_FadeInPlaySong(UINT32 ms, boolean looping);
/// ------------------------
// 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 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
/// ------------------------
@ -1500,118 +1506,108 @@ static void S_UnloadMusic(void)
music_looping = false;
}
static boolean S_PlayMusic(boolean looping)
static boolean S_PlayMusic(boolean looping, UINT32 fadeinms)
{
if (S_MusicDisabled())
return false;
if (!I_PlaySong(looping))
if ((!fadeinms && !I_PlaySong(looping)) ||
(fadeinms && !I_FadeInPlaySong(fadeinms, looping)))
{
S_UnloadMusic();
return false;
}
S_InitMusicVolume(); // switch between digi and sequence volume
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)
{
if (S_MusicDisabled())
return;
char newmusic[7];
boolean digiexists = S_DigExists(mmusic);
boolean midiexists = S_MIDIExists(mmusic);
#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;
#else
strncpy(newmusic, mmusic, 7);
#endif
newmusic[6] = 0;
int i;
for (i = 0; newmusic[i]; i++) {
newmusic[i] = tolower(newmusic[i]);
}
// No Music (empty string)
if (newmusic[0] == 0)
{
if (prefadems)
I_FadeSong(0, prefadems, &S_StopMusic);
else
S_StopMusic();
return;
}
CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic);
if (digiexists && !digital_disabled) // digmusic?
if (prefadems && S_MusicPlaying()) // queue music change for after fade // allow even if the music is the same
{
if (prefadems && I_SongType() != MU_MID) //have to queue post-fade // allow even if the music is the same
{
I_FadeOutStopSong(prefadems);
I_QueueDigSong(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;
CONS_Debug(DBG_DETAILED, "Now fading out song %s\n", music_name);
S_QueueMusic(newmusic, mflags, looping, position, fadeinms);
I_FadeSong(0, prefadems, S_ChangeMusicToQueue);
return;
}
else if (strncmp(music_name, newmusic, 6))
{
CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic);
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?
{
// 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(); // shutdown old music
if (!S_LoadMusic(mmusic))
if (!S_LoadMusic(newmusic))
return;
music_flags = mflags;
music_looping = looping;
if (!S_PlayMusic(looping))
if (!S_PlayMusic(looping, fadeinms))
{
CONS_Alert(CONS_ERROR, "Music cannot be played!\n");
return;
}
}
else if (!midiexists && !digiexists)
CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), newmusic);
}
musictype_t S_MusicType()
{
return I_SongType();
if (position)
I_SetSongPosition(position);
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)
@ -1713,14 +1709,14 @@ void S_StopFadingMusic(void)
boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms)
{
if (source_volume < 0)
return I_FadeSong(target_volume, ms);
return I_FadeSong(target_volume, ms, NULL);
else
return I_FadeSongFromVolume(target_volume, source_volume, ms, false);
}
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 INT16 fading_volume_step;
static INT32 fading_id;
// 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;
static void (*fading_callback)(void);
#ifdef HAVE_LIBGME
static Music_Emu *gme;
static INT32 current_track;
#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
/// ------------------------
@ -109,7 +116,6 @@ void I_StartupSound(void)
}
var_cleanup();
queue_cleanup();
music = NULL;
music_volume = sfx_volume = 0;
@ -465,28 +471,15 @@ void I_SetSfxVolume(UINT8 volume)
/// 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)
{
#ifdef _WIN32
if (I_SongType() == MU_MID)
// 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;
@ -503,24 +496,11 @@ static UINT32 get_adjusted_position(UINT32 position)
return position;
}
static void run_queue()
static void do_fading_callback()
{
if (queue_stopafterfade)
I_StopSong();
else if (queue_music_name[0])
{
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();
if (fading_callback)
(*fading_callback)();
fading_callback = NULL;
}
/// ------------------------
@ -540,9 +520,7 @@ static void count_music_bytes(int chan, void *stream, int len, void *udata)
static void music_loop(void)
{
if (queue_music_name[0] && !is_fading && !is_looping)
run_queue();
else if (is_looping)
if (is_looping)
{
Mix_PlayMusic(music, 0);
Mix_SetMusicPosition(loop_point);
@ -555,13 +533,12 @@ static void music_loop(void)
static UINT32 music_fade(UINT32 interval, void *param)
{
if (!is_fading ||
I_SongType() == MU_MID || // stub out MIDI, see bug in I_SetMIDIMusicVolume
internal_volume == fading_target ||
fading_steps == 0 ||
fading_volume_step == 0)
{
I_StopFadingSong();
queue_cleanup();
do_fading_callback();
return 0;
}
else if (
@ -570,7 +547,8 @@ static UINT32 music_fade(UINT32 interval, void *param)
{
internal_volume = fading_target;
Mix_VolumeMusic(get_real_volume(music_volume));
run_queue();
I_StopFadingSong();
do_fading_callback();
return 0;
}
else
@ -628,7 +606,6 @@ void I_ShutdownMusic(void)
if (!music)
return;
var_cleanup();
queue_cleanup();
SDL_RemoveTimer(fading_id);
Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes);
Mix_HookMusicFinished(NULL);
@ -862,7 +839,7 @@ UINT32 I_GetSongPosition(void)
if (info->length > 0)
position %= info->length;
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
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_set_equalizer(gme, &eq);
Mix_HookMusic(mix_gme, gme);
return true;
}
#endif
@ -1120,19 +1096,21 @@ void I_UnloadSong(void)
boolean I_PlaySong(boolean looping)
{
if (!music)
return false;
#ifdef HAVE_GME
#ifdef HAVE_LIBGME
if (gme)
{
gme_start_track(gme, 0);
current_track = 0;
Mix_HookMusic(mix_gme, gme);
return true;
}
else
#endif
if (!music)
return false;
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)
{
@ -1179,10 +1157,8 @@ void I_StopSong(void)
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???
return;
@ -1197,10 +1173,8 @@ void I_PauseSong(INT32 handle)
songpaused = true;
}
void I_ResumeSong(INT32 handle)
void I_ResumeSong()
{
(void)handle;
if (I_SongType() == MU_MID)
return;
@ -1213,7 +1187,7 @@ void I_ResumeSong(INT32 handle)
while(Mix_UnregisterEffect(MIX_CHANNEL_POST, count_music_bytes) != 0) { }
// 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());
}
@ -1235,7 +1209,7 @@ void I_SetMusicVolume(UINT8 volume)
#endif
music_volume = volume;
Mix_VolumeMusic((UINT32)music_volume*128/31);
Mix_VolumeMusic(get_real_volume(music_volume));
}
boolean I_SetSongTrack(int track)
@ -1279,7 +1253,7 @@ boolean I_SetSongTrack(int track)
void I_SetInternalMusicVolume(UINT8 volume)
{
internal_volume = volume;
if (!music || I_SongType() == MU_MID) // stub out MIDI, see bug in I_SetMIDIMusicVolume
if (!music)
return;
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;
}
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;
INT16 target_volume_step, volume_delta;
@ -1303,22 +1277,17 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
I_StopFadingSong();
if (!ms && volume_delta)
{
if (stopafterfade)
{
I_StopSong();
return true;
}
else
{
I_SetInternalMusicVolume(target_volume);
if (callback)
(*callback)();
return true;
}
}
else if (!volume_delta || I_SongType() == MU_MID)
else if (!volume_delta)
{
if (stopafterfade)
I_StopSong();
if (callback)
(*callback)();
return true;
}
@ -1344,7 +1313,7 @@ boolean I_FadeSongFromVolume(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;
fading_callback = callback;
if (internal_volume != source_volume)
I_SetInternalMusicVolume(source_volume);
@ -1354,47 +1323,21 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
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)
{
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)
return true; // nothing to play
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
{
if (I_StartDigSong(musicname, looping))
{
I_SetSongTrack(track);
if (fadeinms)
I_FadeSongFromVolume(100, 0, fadeinms, false);
if (position)
I_SetSongPosition(position);
return true;
}
if (I_PlaySong(looping))
return I_FadeSongFromVolume(100, 0, ms, NULL);
else
return false;
}
}
#endif