RingRacers/src/music_tune.hpp
James R 39f46a0f20 Replace music handling
(This commit does not compile. Sound test and tunes
command code needs to be ported after this.)

This is a big one. Here's the rundown:

The old music system was very direct, much of the time
just a proxy to the real sound API in i_sound.h.

You could change the music on command, but there wasn't
a consistent way to prevent some music from playing over
others. P_RestoreMusic is one example of needing to
address this problem. The jingles system was intended as
another solution. Furthermore, sound test (Stereo) has its
own needs.

I am removing all of that. Music handling in general is
now a very deliberate system, kind of similar to jingles.

In the new system, "tunes" are registered. The tune stores
info such as whether it should loop or fade out. Most of
the configuration is intended to be initialized only ONCE.
Tunes can be mapped to an actual music lump. They can be
remapped at any time too.

Tunes are also configured with a priority number. This
determines which tune is heard, if multiple are supposed
to be playing at a time. You can even tell a tune how long
it should play, so it's unnecessary to track this with
bespoke timers.
2023-08-06 17:31:45 -07:00

194 lines
3.6 KiB
C++

// 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 <algorithm>
#include <optional>
#include <string>
#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<tic_t> pause_;
};
}; // namespace srb2::music
#endif // MUSIC_TUNE_HPP