13
0

remove (almost) all floating point operations from Beats, add DoubleableBeats

The latter is a "wrapper" around Beats that provides ::to_double() for those times when we
absolutely need a floating point representation
This commit is contained in:
Paul Davis 2020-12-18 19:05:29 -07:00
parent 3010bed4ef
commit 3e8f4d80fb
2 changed files with 25 additions and 87 deletions

View File

@ -422,9 +422,9 @@ TempoPoint::compute_omega (samplecnt_t sr, superclock_t end_scpqn, Temporal::Bea
return;
}
_omega = ((1.0/end_scpqn) - (1.0/superclocks_per_quarter_note())) / quarter_duration.to_double();
_omega = ((1.0/end_scpqn) - (1.0/superclocks_per_quarter_note())) / DoubleableBeats (quarter_duration).to_double();
DEBUG_TRACE (DEBUG::TemporalMap, string_compose ("computed omega = %1%2 dur was %3\n", std::setprecision(12),_omega, quarter_duration.to_double()));
DEBUG_TRACE (DEBUG::TemporalMap, string_compose ("computed omega = %1%2 dur was %3\n", std::setprecision(12),_omega, DoubleableBeats (quarter_duration).to_double()));
}
superclock_t
@ -440,7 +440,7 @@ TempoPoint::superclock_at (Temporal::Beats const & qn) const
return (spqn * qn.get_beats()) + int_div_round ((spqn * qn.get_ticks()), superclock_t (Temporal::ticks_per_beat));
}
return _sclock + llrint (log1p (superclocks_per_quarter_note() * _omega * (qn - _quarters).to_double()) / _omega);
return _sclock + llrint (log1p (superclocks_per_quarter_note() * _omega * DoubleableBeats (qn - _quarters).to_double()) / _omega);
}
superclock_t

View File

@ -157,6 +157,10 @@ public:
return *this;
}
Beats snap_to (Temporal::Beats const & snap) const {
return (*this / snap) * snap;
}
Beats round_to_beat() const {
return (_ticks >= (PPQN/2)) ? Beats (_beats + 1, 0) : Beats (_beats, 0);
}
@ -182,11 +186,6 @@ public:
Beats round_to_subdivision (int subdivision, RoundMode dir) const;
Beats snap_to (Temporal::Beats const & snap) const {
const double snap_time = snap.to_double();
return Beats::from_double (ceil(to_double() / snap_time) * snap_time);
}
Beats abs () const {
return Beats (::abs (_beats), ::abs (_ticks));
}
@ -202,11 +201,6 @@ public:
return _beats == b._beats && _ticks == b._ticks;
}
inline bool operator==(double t) const {
/* Acceptable tolerance is 1 tick. */
return fabs(to_double() - t) <= (1.0 / PPQN);
}
inline bool operator==(int beats) const {
return _beats == beats;
}
@ -231,34 +225,6 @@ public:
return _beats > b._beats || (_beats == b._beats && _ticks >= b._ticks);
}
inline bool operator<(double b) const {
/* Acceptable tolerance is 1 tick. */
const double time = to_double();
if (fabs(time - b) <= (1.0 / PPQN)) {
return false; /* Effectively identical. */
} else {
return time < b;
}
}
inline bool operator<=(double b) const {
return operator==(b) || operator<(b);
}
inline bool operator>(double b) const {
/* Acceptable tolerance is 1 tick. */
const double time = to_double();
if (fabs(time - b) <= (1.0 / PPQN)) {
return false; /* Effectively identical. */
} else {
return time > b;
}
}
inline bool operator>=(double b) const {
return operator==(b) || operator>(b);
}
Beats operator+(const Beats& b) const {
return Beats(_beats + b._beats, _ticks + b._ticks);
}
@ -267,32 +233,6 @@ public:
return Beats(_beats - b._beats, _ticks - b._ticks);
}
Beats operator+(double d) const {
return Beats(to_double() + d);
}
Beats operator-(double d) const {
return Beats(to_double() - d);
}
Beats operator+(int b) const {
return Beats (_beats + b, _ticks);
}
Beats operator-(int b) const {
return Beats (_beats - b, _ticks);
}
Beats& operator+=(int b) {
_beats += b;
return *this;
}
Beats& operator-=(int b) {
_beats -= b;
return *this;
}
Beats operator-() const {
/* must avoid normalization here, which will convert a negative
value into a valid beat position before zero, which is not
@ -317,10 +257,12 @@ public:
_ticks = B._ticks;
return *this;
/* avoids calling ::to_double() to compute ratios of two Beat distances
*/
double operator/ (Beats const & other) {
return (double) to_ticks() / (double) other.to_ticks();
Beats operator/ (Beats const & other) const {
return Beats::ticks (int_div_round (to_ticks(), other.to_ticks()));
}
Beats operator* (Beats const & other) const {
return Beats::ticks (to_ticks () * other.to_ticks());
}
Beats& operator+=(const Beats& b) {
@ -342,25 +284,10 @@ public:
static Beats one_tick() { return Beats(0, 1); }
private:
protected:
int32_t _beats;
int32_t _ticks;
/* almost nobody should ever be allowed to use this method */
friend class TempoPoint;
friend class ARDOUR::Track;
friend class ARDOUR::Variant;
friend class ARDOUR::MidiStretch;
friend class ARDOUR::MidiModel;
friend class ARDOUR::AutomationList;
friend class ARDOUR::MidiSource;
friend class ARDOUR::MidiRegion;
friend class ARDOUR::Quantize;
friend class ::QuantizeDialog;
friend class ::NoteDrag;
friend class ::NoteCreateDrag;
double to_double() const { return (double)_beats + (_ticks / (double)PPQN); }
/* this needs to exist because Evoral::Sequence is templated, and some
* other possible template types cannot provide ::from_double
*/
@ -375,6 +302,17 @@ private:
}
};
/* Only contexts that really, absolutely need a floating point representation
* of a Beats value should ever use this.
*/
class DoubleableBeats : public Beats
{
public:
DoubleableBeats (Beats const & b) : Beats (b) {}
double to_double() const { return (double)_beats + (_ticks / (double)PPQN); }
};
/*
TIL, several horrible hours later, that sometimes the compiler looks in the
namespace of a type (Temporal::Beats in this case) for an operator, and