// DR ROBOTNIK'S RING RACERS //----------------------------------------------------------------------------- // Copyright (C) 2023 by Kart Krew. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- #ifndef MUSIC_TUNE_HPP #define MUSIC_TUNE_HPP #include #include #include #include "doomdef.h" #include "doomtype.h" #include "music_detail.hpp" namespace srb2::music { class Tune { public: explicit Tune() {} std::string song; // looks up the lump // Higher priority tunes play first. int priority = 0; // Fade at the beginning or end of the tune. int fade_in = 0; // in milliseconds int fade_out = 0; // Fade time subtracts from the duration of the song? int fade_out_inclusive = true; // Fade in when a higher priority tune ends and this one // resumes. int resume_fade_in = 0; // Sync this tune to game logic. bool sync = false; // This tune loops at the end. bool loop = true; // When this tune runs out of duration, keep playing // silence. bool keep_open = false; // This tune does not respect mass stop or pause actions // from TuneManager::stop_all etc. It must be // stopped/paused individually. bool resist = false; // This tune shows a credit when first played (not // resumed). bool credit = false; // Start playing this number of tics into the tune. tic_t seek = 0; // these track state bool can_fade_out = true; bool needs_seek = false; bool resume = false; bool ending = 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_); } tic_t duration() const { return end_ - begin_; } bool playing() const { return begin_ <= detail::tic_time() && (!ending || time_remaining()); } bool paused() const { return pause_.has_value(); } bool can_end() const { return end_ != INFTICS; } float speed() const { // Slow level music down a bit in Encore. (Values are vibe-based. WE GET IT YOU VAPE) if (encoremode && gamestate == GS_LEVEL) { return 0.86471f; } return 1.f; } bool operator <(const Tune& b) const { // If this song is not playing, it has lowest // priority. if (!playing()) { return true; } // If the other song is not playing, we automatically // have higher priority. if (!b.playing()) { return false; } // The highest priority song is preferred. if (priority != b.priority) { return priority < b.priority; } // If both songs have the same priority, prefer the // one that begun later. return begin_ < b.begin_; } void play() { if (!needs_seek) { seek = 0; } can_fade_out = true; needs_seek = true; resume = false; ending = false; begin_ = detail::tic_time(); end_ = INFTICS; pause_.reset(); } void delay_end(tic_t duration) { end_ = detail::tic_time() + duration; if (!fade_out_inclusive) { end_ += detail::msec_to_tics(fade_out); } if (playing()) { can_fade_out = true; ending = false; } } void stop() { begin_ = INFTICS; end_ = 0; pause_.reset(); } void pause() { pause_ = detail::tic_time(); } void unpause() { if (!pause_) { return; } if (playing()) { tic_t n = detail::tic_time() - *pause_; begin_ += n; if (can_end()) { end_ += n; } } pause_.reset(); } private: tic_t begin_ = INFTICS; tic_t end_ = 0; std::optional pause_; }; }; // namespace srb2::music #endif // MUSIC_TUNE_HPP