From fed42c4cd6afa598650ee9e4be1b7f0d42aeaec4 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Dec 2023 04:23:03 -0800 Subject: [PATCH 1/6] Music Manager: add suspension functionality Suspending a tune makes it inaudible, but doesn't change its timing. During suspension, other tunes may come into priority. After un-suspending, the tune plays from the point where it would be if it had not been suspended at all. --- src/music.cpp | 28 ++++++++++++++++++++++++++++ src/music.h | 10 ++++++++++ src/music_manager.cpp | 2 +- src/music_tune.hpp | 8 ++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/music.cpp b/src/music.cpp index 304948964..ea6e772f0 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -261,6 +261,28 @@ void Music_UnPause(const char* id) } } +void Music_Suspend(const char* id) +{ + Tune* tune = g_tunes.find(id); + + if (tune) + { + tune->suspend = true; + g_tunes.tick(); + } +} + +void Music_UnSuspend(const char* id) +{ + Tune* tune = g_tunes.find(id); + + if (tune) + { + tune->suspend = false; + g_tunes.tick(); + } +} + void Music_PauseAll(void) { g_tunes.for_each([](Tune& tune) { tune.pause(); }); @@ -301,6 +323,12 @@ boolean Music_Paused(const char* id) return tune && tune->paused(); } +boolean Music_Suspended(const char* id) +{ + const Tune* tune = g_tunes.find(id); + return tune && tune->suspend; +} + tic_t Music_Elapsed(const char* id) { const Tune* tune = g_tunes.find(id); diff --git a/src/music.h b/src/music.h index 5b53b4ba1..9d3b5200e 100644 --- a/src/music.h +++ b/src/music.h @@ -75,6 +75,13 @@ void Music_UnPause(const char *id); void Music_PauseAll(void); void Music_UnPauseAll(void); +// Suspend a tune. The manager will switch to a tune that is +// not suspended. Upon unsuspending, the tune resumes from +// the position it would have reached normally (so the +// duration is not extended like with pausing). +void Music_Suspend(const char *id); +void Music_UnSuspend(const char *id); + // // Change properties. May be called before calling Music_Play. @@ -117,6 +124,9 @@ boolean Music_Playing(const char *id); // Returns true if the tune is paused. boolean Music_Paused(const char *id); +// Returns true if the tune is suspended. +boolean Music_Suspended(const char *id); + // Returns the number of tics elapsed since the start of the // tune. tic_t Music_Elapsed(const char *id); diff --git a/src/music_manager.cpp b/src/music_manager.cpp index 05d02d855..a0696e1a3 100644 --- a/src/music_manager.cpp +++ b/src/music_manager.cpp @@ -49,7 +49,7 @@ void TuneManager::tick() Tune* tune = current_tune(); std::string old_song = current_song_; - current_song_ = tune && tune->playing() ? tune->song : std::string{}; + current_song_ = tune && tune->playing() && !tune->suspend ? tune->song : std::string{}; bool changed = current_song_ != old_song; diff --git a/src/music_tune.hpp b/src/music_tune.hpp index ec9aac6dd..b7c800058 100644 --- a/src/music_tune.hpp +++ b/src/music_tune.hpp @@ -75,6 +75,7 @@ public: bool needs_seek = false; bool resume = false; bool ending = false; + bool suspend = false; tic_t elapsed() const { return std::max(pause_.value_or(detail::tic_time()), begin_) - begin_; } tic_t time_remaining() const { return end_ - std::min(pause_.value_or(detail::tic_time()), end_); } @@ -108,14 +109,14 @@ public: { // If this song is not playing, it has lowest // priority. - if (!playing()) + if (!playing() || suspend) { return true; } // If the other song is not playing, we automatically // have higher priority. - if (!b.playing()) + if (!b.playing() || b.suspend) { return false; } @@ -142,6 +143,7 @@ public: needs_seek = true; resume = false; ending = false; + suspend = false; begin_ = detail::tic_time(); end_ = INFTICS; @@ -162,6 +164,8 @@ public: can_fade_out = true; ending = false; } + + suspend = false; } void stop() From 88554868640750faf6b0b1b764bdd3ef47dbac71 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Dec 2023 04:26:05 -0800 Subject: [PATCH 2/6] Add Music_FadeOutDuration --- src/music.cpp | 6 ++++++ src/music.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/music.cpp b/src/music.cpp index ea6e772f0..b2e94f56c 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -347,6 +347,12 @@ tic_t Music_TotalDuration(const char* id) return tune ? tune->duration() : 0u; } +unsigned int Music_FadeOutDuration(const char* id) +{ + const Tune* tune = g_tunes.find(id); + return tune ? tune->fade_out : 0; +} + void Music_Loop(const char* id, boolean loop) { Tune* tune = g_tunes.find(id); diff --git a/src/music.h b/src/music.h index 9d3b5200e..eff0d660b 100644 --- a/src/music.h +++ b/src/music.h @@ -137,6 +137,10 @@ tic_t Music_DurationLeft(const char *id); // Returns the total duration of the tune, in tics. tic_t Music_TotalDuration(const char *id); +// Returns the number of milliseconds a tune is configured to +// fade for. +unsigned int Music_FadeOutDuration(const char *id); + // Returns the song name mapped to a tune. const char *Music_Song(const char *id); From 64aaf02b8ab82622b82ff49b148bf1d539dd7fe1 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Dec 2023 04:30:54 -0800 Subject: [PATCH 3/6] soundtest: refactor to track tune with integer instead of string --- src/k_menudraw.c | 10 +++++--- src/menus/transient/sound-test.c | 6 ++--- src/s_sound.c | 43 ++++++++++++++++---------------- src/s_sound.h | 4 ++- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 290d367d8..00f532780 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -7406,6 +7406,8 @@ void M_DrawSoundTest(void) patch_t *btn = W_CachePatchName("STER_BTN", PU_CACHE); + const char *tune = S_SoundTestTune(0); + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("STER_BG", PU_CACHE), NULL); x = 24; @@ -7479,7 +7481,7 @@ void M_DrawSoundTest(void) } { - UINT32 currenttime = min(Music_Elapsed(soundtest.tune), Music_TotalDuration(soundtest.tune)); + UINT32 currenttime = min(Music_Elapsed(tune), Music_TotalDuration(tune)); V_DrawRightAlignedString(x + 272-1, 18+32, 0, va("%02u:%02u", @@ -7493,7 +7495,7 @@ void M_DrawSoundTest(void) && (soundtest.current->basenoloop[soundtest.currenttrack] == true || soundtest.autosequence == true)) { - UINT32 exittime = Music_TotalDuration(soundtest.tune); + UINT32 exittime = Music_TotalDuration(tune); V_DrawRightAlignedString(x + 272-1, 18+32+10, 0, va("%02u:%02u", @@ -7547,12 +7549,12 @@ void M_DrawSoundTest(void) // The following are springlocks. else if (currentMenu->menuitems[i].mvar2 == stereospecial_pause) // pause { - if (Music_Paused(soundtest.tune) == true) + if (Music_Paused(tune) == true) y = currentMenu->y + 6; } else if (currentMenu->menuitems[i].mvar2 == stereospecial_play) // play { - if (soundtest.playing == true && Music_Paused(soundtest.tune) == false) + if (soundtest.playing == true && Music_Paused(tune) == false) y = currentMenu->y + 6; } else if (currentMenu->menuitems[i].mvar2 == stereospecial_seq) // seq diff --git a/src/menus/transient/sound-test.c b/src/menus/transient/sound-test.c index 1589c07bf..b3a5bcafd 100644 --- a/src/menus/transient/sound-test.c +++ b/src/menus/transient/sound-test.c @@ -37,11 +37,11 @@ static void M_SoundTestMainControl(INT32 choice) if (currentMenu->menuitems[itemOn].mvar1 == 1) // Play { - if (Music_Paused(soundtest.tune) == true) + if (Music_Paused(S_SoundTestTune(0)) == true) { S_SoundTestTogglePause(); } - else if (Music_Paused(soundtest.tune) == false) + else { S_SoundTestPlay(); } @@ -50,7 +50,7 @@ static void M_SoundTestMainControl(INT32 choice) { if (currentMenu->menuitems[itemOn].mvar1 == 2) // Pause { - if (Music_Paused(soundtest.tune) == false) + if (Music_Paused(S_SoundTestTune(0)) == false) { S_SoundTestTogglePause(); } diff --git a/src/s_sound.c b/src/s_sound.c index c201f4cc5..8cc1e7801 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1227,7 +1227,7 @@ void S_AttemptToRestoreMusic(void) musicdef_t *musicdefstart = NULL; struct cursongcredit cursongcredit; // Currently displayed song credit info -struct soundtest soundtest = {.tune = ""}; // Sound Test (sound test) +struct soundtest soundtest; // Sound Test (sound test) static void S_InsertMusicAtSoundTestSequenceTail(const char *musname, UINT16 map, UINT8 altref, musicdef_t ***tail) { @@ -1644,10 +1644,22 @@ updatetrackonly: } } +const char *S_SoundTestTune(UINT8 invert) +{ + return soundtest.tune ^ invert ? "stereo_fade" : "stereo"; +} + +boolean S_SoundTestCanSequenceFade(void) +{ + return + soundtest.current->basenoloop[soundtest.currenttrack] == false && + // Only fade out if we're the last track for this song. + soundtest.currenttrack == soundtest.current->numtracks-1; +} + void S_SoundTestPlay(void) { UINT32 sequencemaxtime = 0; - boolean dosequencefadeout = false; if (soundtest.current == NULL) { @@ -1656,19 +1668,7 @@ void S_SoundTestPlay(void) } soundtest.playing = true; - - soundtest.tune = "stereo"; - - if (soundtest.current->basenoloop[soundtest.currenttrack] == false) - { - // Only fade out if we're the last track for this song. - dosequencefadeout = (soundtest.currenttrack == soundtest.current->numtracks-1); - - if (dosequencefadeout) - { - soundtest.tune = "stereo_fade"; - } - } + soundtest.tune = (soundtest.autosequence == true && S_SoundTestCanSequenceFade() == true); Music_Remap(soundtest.tune, soundtest.current->name[soundtest.currenttrack]); Music_Loop(soundtest.tune, !soundtest.current->basenoloop[soundtest.currenttrack]); @@ -1702,7 +1702,7 @@ void S_SoundTestPlay(void) } // ms to TICRATE conversion - Music_DelayEnd(soundtest.tune, (TICRATE*sequencemaxtime)/1000); + Music_DelayEnd(S_SoundTestTune(0), (TICRATE*sequencemaxtime)/1000); } void S_SoundTestStop(void) @@ -1712,7 +1712,7 @@ void S_SoundTestStop(void) return; } - soundtest.tune = ""; + soundtest.tune = 0; soundtest.playing = false; soundtest.autosequence = false; @@ -1730,13 +1730,14 @@ void S_SoundTestTogglePause(void) return; } - if (Music_Paused(soundtest.tune)) + const char *tune = S_SoundTestTune(0); + if (Music_Paused(tune)) { - Music_UnPause(soundtest.tune); + Music_UnPause(tune); } else { - Music_Pause(soundtest.tune); + Music_Pause(tune); } } @@ -1760,7 +1761,7 @@ void S_TickSoundTest(void) return; } - if (Music_DurationLeft(soundtest.tune) == 0) + if (Music_DurationLeft(S_SoundTestTune(0)) == 0) { goto handlenextsong; } diff --git a/src/s_sound.h b/src/s_sound.h index 5d6b17ecf..cb22dfd74 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -186,7 +186,7 @@ extern struct cursongcredit extern struct soundtest { - const char *tune; // Tune used for music system + UINT8 tune; // Tune used for music system boolean playing; // Music is playing? boolean justopened; // Menu visual assist @@ -208,6 +208,8 @@ void S_SoundTestPlay(void); void S_SoundTestStop(void); void S_SoundTestTogglePause(void); void S_TickSoundTest(void); +const char *S_SoundTestTune(UINT8 invert); +boolean S_SoundTestCanSequenceFade(void); extern musicdef_t *musicdefstart; From 95f4768e462ca5afe4d1619d9659a1c76723fa87 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Dec 2023 04:32:25 -0800 Subject: [PATCH 4/6] Stereo Mode: fix unsequenced track fading at the end - Starts both stereo and stereo_fade in tandem - Suspends the tune which is not to be heard - Swaps suspension when toggling SEQ - Special handling so fade-out can not be interrupted by switching off SEQ --- src/menus/transient/sound-test.c | 21 +++++++++++++++++++++ src/s_sound.c | 19 ++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/menus/transient/sound-test.c b/src/menus/transient/sound-test.c index b3a5bcafd..0bd62b307 100644 --- a/src/menus/transient/sound-test.c +++ b/src/menus/transient/sound-test.c @@ -80,6 +80,27 @@ static void M_SoundTestSeq(INT32 choice) (void)choice; soundtest.autosequence ^= true; + + if (soundtest.playing && S_SoundTestCanSequenceFade()) + { + boolean unfaded = Music_DurationLeft("stereo_fade") > Music_FadeOutDuration("stereo_fade") * TICRATE / 1000; + + // 1) You cannot cancel a fade once it has started + // 2) However, if the fade wasn't heard, switching + // over restarts the fade + if (!unfaded && Music_Suspended("stereo_fade")) + { + Music_DelayEnd("stereo_fade", 0); + unfaded = true; + } + + if (unfaded) + { + soundtest.tune ^= 1; + Music_UnSuspend(S_SoundTestTune(0)); + Music_Suspend(S_SoundTestTune(1)); + } + } } static void M_SoundTestShf(INT32 choice) diff --git a/src/s_sound.c b/src/s_sound.c index 8cc1e7801..66477abec 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1657,6 +1657,12 @@ boolean S_SoundTestCanSequenceFade(void) soundtest.currenttrack == soundtest.current->numtracks-1; } +static void S_SoundTestReconfigure(const char *tune) +{ + Music_Remap(tune, soundtest.current->name[soundtest.currenttrack]); + Music_Play(tune); +} + void S_SoundTestPlay(void) { UINT32 sequencemaxtime = 0; @@ -1670,9 +1676,8 @@ void S_SoundTestPlay(void) soundtest.playing = true; soundtest.tune = (soundtest.autosequence == true && S_SoundTestCanSequenceFade() == true); - Music_Remap(soundtest.tune, soundtest.current->name[soundtest.currenttrack]); - Music_Loop(soundtest.tune, !soundtest.current->basenoloop[soundtest.currenttrack]); - Music_Play(soundtest.tune); + S_SoundTestReconfigure("stereo"); + S_SoundTestReconfigure("stereo_fade"); // Assuming this song is now actually playing sequencemaxtime = I_GetSongLength(); @@ -1701,8 +1706,12 @@ void S_SoundTestPlay(void) } } - // ms to TICRATE conversion - Music_DelayEnd(S_SoundTestTune(0), (TICRATE*sequencemaxtime)/1000); + Music_DelayEnd( + S_SoundTestCanSequenceFade() ? "stereo_fade" : "stereo", + (TICRATE*sequencemaxtime)/1000 // ms to TICRATE conversion + ); + + Music_Suspend(S_SoundTestTune(1)); } void S_SoundTestStop(void) From 076cea7047dd7b783ec63414a4465b8e82f3cf8d Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Dec 2023 07:30:54 -0800 Subject: [PATCH 5/6] Stereo Mode: stop Stereo after unlooped, unsequenced track ends --- src/s_sound.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/s_sound.c b/src/s_sound.c index 66477abec..142eaa4ba 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1764,12 +1764,6 @@ void S_TickSoundTest(void) goto handlenextsong; } - if (soundtest.autosequence == false) - { - // There's nothing else for us here. - return; - } - if (Music_DurationLeft(S_SoundTestTune(0)) == 0) { goto handlenextsong; From e7c240bf7fc20967b7576c3deaa5dc5c07179a1f Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Dec 2023 07:36:08 -0800 Subject: [PATCH 6/6] Stereo Mode: turn on SEQ after the song has looped past its limit -> next track --- src/menus/transient/sound-test.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/menus/transient/sound-test.c b/src/menus/transient/sound-test.c index 0bd62b307..26bb86f4b 100644 --- a/src/menus/transient/sound-test.c +++ b/src/menus/transient/sound-test.c @@ -83,18 +83,17 @@ static void M_SoundTestSeq(INT32 choice) if (soundtest.playing && S_SoundTestCanSequenceFade()) { - boolean unfaded = Music_DurationLeft("stereo_fade") > Music_FadeOutDuration("stereo_fade") * TICRATE / 1000; - // 1) You cannot cancel a fade once it has started // 2) However, if the fade wasn't heard, switching - // over restarts the fade - if (!unfaded && Music_Suspended("stereo_fade")) + // over just skips to the next song + if (Music_DurationLeft("stereo_fade") <= Music_FadeOutDuration("stereo_fade") * TICRATE / 1000) { - Music_DelayEnd("stereo_fade", 0); - unfaded = true; + if (Music_Suspended("stereo_fade")) + { + S_UpdateSoundTestDef((currentMenu->menuitems[itemOn].mvar1 < 0), true, false); + } } - - if (unfaded) + else { soundtest.tune ^= 1; Music_UnSuspend(S_SoundTestTune(0));