temporal: refactor to expose superbeat tech debt

A group of functionality was only used once, in
TempoPoint::quarters_at_superclock . Keep things simple and enable
further refactoring and cleanup by inlining everything and dropping
superbeat, big_numerator and super_note_type_per_second from Tempo.

The use of big_numerator right next to superclock_ticks_per_second
seems error prone. It should perhaps just be refactored to work in
superclock domain all the time.

It seems weird that the ramped case is much simpler than the non-ramped.

This (pretty much) removes the last references to "superbeat", which
I thus doesn't have to understand ;-)
This commit is contained in:
Mads Kiilerich 2022-11-18 21:41:58 +01:00 committed by Paul Davis
parent e5ec516611
commit cbcb7b1ce2
2 changed files with 14 additions and 37 deletions

View File

@ -98,9 +98,6 @@ Tempo::Tempo (XMLNode const & node)
_superclocks_per_note_type = double_npm_to_scpn (_npm);
_end_superclocks_per_note_type = double_npm_to_scpn (_enpm);
_super_note_type_per_second = double_npm_to_snps (_npm);
_end_super_note_type_per_second = double_npm_to_snps (_enpm);
if (!node.get_property (X_("note-type"), _note_type)) {
throw failed_constructor ();
}
@ -121,14 +118,12 @@ Tempo::set_note_types_per_minute (double npm)
{
_npm = npm;
_superclocks_per_note_type = double_npm_to_scpn (_npm);
_super_note_type_per_second = double_npm_to_snps (_npm);
}
void
Tempo::set_end_npm (double npm)
{
_enpm = npm;
_end_super_note_type_per_second = double_npm_to_snps (_enpm);
_end_superclocks_per_note_type = double_npm_to_scpn (_enpm);
}
@ -165,8 +160,6 @@ Tempo::set_state (XMLNode const & node, int /*version*/)
_superclocks_per_note_type = double_npm_to_scpn (_npm);
_end_superclocks_per_note_type = double_npm_to_scpn (_enpm);
_super_note_type_per_second = double_npm_to_snps (_npm);
_end_super_note_type_per_second = double_npm_to_snps (_enpm);
node.get_property (X_("note-type"), _note_type);
@ -589,14 +582,22 @@ TempoPoint::quarters_at_superclock (superclock_t sc) const
const superclock_t whole_seconds = sc_delta / superclock_ticks_per_second();
const superclock_t remainder = sc_delta - (whole_seconds * superclock_ticks_per_second());
/* big number to allow most (fractional) BPMs to be represented as an integer "super note type per second"
*
* It is not required that big_numerator equal superclock_ticks_per_second but since the values in both cases have similar
* desired properties (many, many factors), it doesn't hurt to use the same number.
*/
const superclock_t big_numerator = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
uint64_t _super_note_type_per_second = (uint64_t) llround (_npm * big_numerator / 60);
const int64_t supernotes = ((_super_note_type_per_second) * whole_seconds) + muldiv_round (superclock_t (_super_note_type_per_second), remainder, superclock_ticks_per_second());
const int64_t superbeats = muldiv_round (supernotes, 4, (superclock_t) _note_type);
/* convert superbeats to beats:ticks */
int32_t b;
int32_t t;
Tempo::superbeats_to_beats_ticks (superbeats, b, t);
int32_t b = superbeats / big_numerator;
int64_t remain = superbeats - (b * big_numerator);
int32_t t = PBD::muldiv_round (Temporal::ticks_per_beat, remain, big_numerator);
DEBUG_TRACE (DEBUG::TemporalMap, string_compose ("%8 => \nsc %1 delta %9 = %2 secs rem = %3 rem snotes %4 sbeats = %5 => %6 : %7\n", sc, whole_seconds, remainder, supernotes, superbeats, b , t, *this, sc_delta));
@ -3038,9 +3039,9 @@ std::ostream&
std::operator<<(std::ostream& str, Tempo const & t)
{
if (t.ramped()) {
return str << t.note_types_per_minute() << " .. " << t.end_note_types_per_minute() << " 1/" << t.note_type() << " RAMPED notes per minute [ " << t.super_note_type_per_second() << " => " << t.end_super_note_type_per_second() << " sntpm ] (" << t.superclocks_per_note_type() << " sc-per-1/" << t.note_type() << ')';
return str << t.note_types_per_minute() << " .. " << t.end_note_types_per_minute() << " 1/" << t.note_type() << " RAMPED notes per minute (" << t.superclocks_per_note_type() << " .. " << t.end_superclocks_per_note_type() << " sc-per-1/" << t.note_type() << ')';
} else {
return str << t.note_types_per_minute() << " 1/" << t.note_type() << " notes per minute [" << t.super_note_type_per_second() << " sntpm] (" << t.superclocks_per_note_type() << " sc-per-1/" << t.note_type() << ')';
return str << t.note_types_per_minute() << " 1/" << t.note_type() << " notes per minute (" << t.superclocks_per_note_type() << " sc-per-1/" << t.note_type() << ')';
}
}

View File

@ -161,14 +161,6 @@ class /*LIBTEMPORAL_API*/ Point : public point_hook, public MapOwned {
*/
class LIBTEMPORAL_API Tempo {
private:
/* beats per minute * big_numerator => rational number expressing (possibly fractional) bpm as superbeats-per-minute
*
* It is not required that big_numerator equal superclock_ticks_per_second but since the values in both cases have similar
* desired properties (many, many factors), it doesn't hurt to use the same number.
*/
static const superclock_t big_numerator = 508032000; // 2^10 * 3^4 * 5^3 * 7^2
public:
enum Type {
Ramped,
@ -189,8 +181,6 @@ class LIBTEMPORAL_API Tempo {
, _enpm (npm)
, _superclocks_per_note_type (double_npm_to_scpn (npm))
, _end_superclocks_per_note_type (double_npm_to_scpn (npm))
, _super_note_type_per_second (double_npm_to_snps (npm))
, _end_super_note_type_per_second (double_npm_to_snps (npm))
, _note_type (note_type)
, _locked_to_meter (false)
, _continuing (false)
@ -201,8 +191,6 @@ class LIBTEMPORAL_API Tempo {
, _enpm (npm)
, _superclocks_per_note_type (double_npm_to_scpn (npm))
, _end_superclocks_per_note_type (double_npm_to_scpn (enpm))
, _super_note_type_per_second (double_npm_to_snps (npm))
, _end_super_note_type_per_second (double_npm_to_snps (enpm))
, _note_type (note_type)
, _locked_to_meter (false)
, _continuing (false)
@ -240,12 +228,6 @@ class LIBTEMPORAL_API Tempo {
return end_superclocks_per_note_type (4);
}
static void superbeats_to_beats_ticks (int64_t sb, int32_t& b, int32_t& t) {
b = sb / big_numerator;
int64_t remain = sb - (b * big_numerator);
t = PBD::muldiv_round (Temporal::ticks_per_beat, remain, big_numerator);
}
bool locked_to_meter () const { return _locked_to_meter; }
void set_locked_to_meter (bool yn) { _locked_to_meter = yn; }
@ -274,21 +256,15 @@ class LIBTEMPORAL_API Tempo {
_continuing != other._continuing;
}
uint64_t super_note_type_per_second() const { return _super_note_type_per_second; }
uint64_t end_super_note_type_per_second() const { return _end_super_note_type_per_second; }
protected:
double _npm;
double _enpm;
superclock_t _superclocks_per_note_type;
superclock_t _end_superclocks_per_note_type;
uint64_t _super_note_type_per_second;
uint64_t _end_super_note_type_per_second;
int8_t _note_type;
bool _locked_to_meter; /* XXX name has unclear meaning with nutempo */
bool _continuing;
static inline uint64_t double_npm_to_snps (double npm) { return (uint64_t) llround (npm * big_numerator / 60); }
static inline superclock_t double_npm_to_scpn (double npm) { return (superclock_t) llround ((60./npm) * superclock_ticks_per_second()); }
protected: