dddecc5734
No behavior change; verification-record corrections and one static_assert.
50 lines
1.9 KiB
C++
50 lines
1.9 KiB
C++
// tempo — a validated project tempo and every beats <-> seconds <-> ms conversion a
|
|
// beat-denominated capture value resolves through.
|
|
//
|
|
// A BEAT IS A QUARTER NOTE — REAPER states project tempo in quarter notes per minute
|
|
// regardless of time signature, so a division resolves without one.
|
|
|
|
#pragma once
|
|
|
|
#include <optional>
|
|
#include <type_traits>
|
|
|
|
namespace reasampler::instrument::note {
|
|
|
|
inline constexpr double kMsPerSecond = 1000.0;
|
|
|
|
constexpr double msToSeconds(double ms) { return ms / kMsPerSecond; }
|
|
constexpr double secondsToMs(double seconds) { return seconds * kMsPerSecond; }
|
|
|
|
// The largest magnitude, in beats or in milliseconds, the conversions below are required to
|
|
// keep finite. `fromBpm` validates against it and every caller caps its own domain to it, so
|
|
// the two halves of the totality claim meet at one number. Astronomically above anything
|
|
// musical — a billion milliseconds is eleven days — so nothing real is excluded.
|
|
inline constexpr double kMaxConvertibleMagnitude = 1e9;
|
|
|
|
class Tempo {
|
|
public:
|
|
// Rejects rather than clamps, alone among this module's doors: an unusable BPM has no
|
|
// nearest usable one to fall to. See this directory's CLAUDE.md for the rule.
|
|
static std::optional<Tempo> fromBpm(double beatsPerMinute);
|
|
|
|
double bpm() const { return bpm_; }
|
|
double secondsPerBeat() const;
|
|
|
|
double beatsToSeconds(double beats) const;
|
|
double secondsToBeats(double seconds) const;
|
|
double beatsToMs(double beats) const;
|
|
double msToBeats(double ms) const;
|
|
|
|
private:
|
|
explicit Tempo(double beatsPerMinute) : bpm_(beatsPerMinute) {}
|
|
double bpm_;
|
|
};
|
|
|
|
static_assert(!std::is_default_constructible_v<Tempo>,
|
|
"Tempo must not be constructible without a validated BPM");
|
|
static_assert(!std::is_constructible_v<Tempo, double>,
|
|
"fromBpm must be the only way to give a Tempo a value");
|
|
|
|
} // namespace reasampler::instrument::note
|