diff --git a/libs/temporal/tempo.cc b/libs/temporal/tempo.cc index ec6b3eca2a..66a49853b2 100644 --- a/libs/temporal/tempo.cc +++ b/libs/temporal/tempo.cc @@ -662,7 +662,7 @@ TempoMetric::bbt_at (timepos_t const & pos) const the current meter, which we'll call "grid" */ - const int64_t note_value_count = int_div_round (dq.get_beats() * _meter->note_value(), 4); + const int64_t note_value_count = int_div_round (dq.get_beats() * _meter->note_value(), int64_t (4)); /* now construct a BBT_Offset using the count in grid units */ diff --git a/libs/temporal/temporal/beats.h b/libs/temporal/temporal/beats.h index 9eee691e07..030be30a65 100644 --- a/libs/temporal/temporal/beats.h +++ b/libs/temporal/temporal/beats.h @@ -66,45 +66,11 @@ class /*LIBTEMPORAL_API*/ Beats { public: LIBTEMPORAL_API static const int32_t PPQN = Temporal::ticks_per_beat; - Beats() : _beats(0), _ticks(0) {} - Beats(const Beats& other) : _beats(other._beats), _ticks(other._ticks) {} - - /** Normalize so ticks is within PPQN. */ - void normalize() { - // First, fix negative ticks with positive beats - while (_beats > 0 && _ticks < 0) { - --_beats; - _ticks += PPQN; - } - - // Now fix positive ticks with negative beats - while (_beats < 0 && _ticks > 0) { - ++_beats; - _ticks -= PPQN; - } - - assert ((_beats < 0 && _ticks <= 0) || (_beats > 0 && _ticks >= 0) || _beats == 0); - - // Work with positive beats and ticks to normalize - const int32_t sign = _beats < 0 ? -1 : _ticks < 0 ? -1 : 1; - int32_t beats = ::abs(_beats); - int32_t ticks = ::abs(_ticks); - - // Fix ticks greater than 1 beat - while (ticks >= PPQN) { - ++beats; - ticks -= PPQN; - } - - // Set fields with appropriate sign - _beats = sign * beats; - _ticks = sign * ticks; - } + Beats() : _ticks(0) {} + Beats(const Beats& other) : _ticks(other._ticks) {} /** Create from a precise beats:ticks pair. */ - explicit Beats(int32_t b, int32_t t) : _beats(b), _ticks(t) { - normalize(); - } + explicit Beats(int32_t b, int32_t t) : _ticks ((b*PPQN) + t) {} /** Create from a real number of beats. */ static Beats from_double (double beats) { @@ -120,8 +86,7 @@ public: /** Create from ticks at the standard PPQN. */ static Beats ticks(int64_t ticks) { - assert (ticks/PPQN < std::numeric_limits::max()); - return Beats (ticks / PPQN, ticks % PPQN); + return Beats (0, ticks); } /** Create from ticks at a given rate. @@ -135,25 +100,18 @@ public: return Beats(ticks / ppqn, (ticks % ppqn) * PPQN / ppqn); } - static int64_t make_ticks (Beats const & b) { return b.get_beats() * ticks_per_beat + b.get_ticks(); } + int64_t to_ticks () const { return _ticks; } + int64_t to_ticks (uint32_t ppqn) const { return (_ticks * ppqn) / PPQN; } - int64_t to_ticks() const { return (int64_t)_beats * PPQN + _ticks; } - int64_t to_ticks(uint32_t ppqn) const { return (int64_t)_beats * ppqn + (_ticks * ppqn / PPQN); } - - int32_t get_beats() const { return _beats; } - int32_t get_ticks() const { return _ticks; } + int64_t get_beats () const { return _ticks / PPQN; } + int32_t get_ticks () const { return _ticks % PPQN; } Beats& operator=(double time) { - double whole; - const double frac = modf(time, &whole); - - _beats = whole; - _ticks = frac * PPQN; + *this = from_double (time); return *this; } Beats& operator=(const Beats& other) { - _beats = other._beats; _ticks = other._ticks; return *this; } @@ -170,32 +128,32 @@ public: } Beats round_to_beat() const { - return (_ticks >= (PPQN/2)) ? Beats (_beats + 1, 0) : Beats (_beats, 0); + return (get_ticks() >= (PPQN/2)) ? Beats (get_beats() + 1, 0) : Beats (get_beats(), 0); } Beats round_up_to_beat() const { - return (_ticks == 0) ? *this : Beats(_beats + 1, 0); + return (get_ticks() == 0) ? *this : Beats(get_beats() + 1, 0); } Beats round_down_to_beat() const { - return Beats(_beats, 0); + return Beats(get_beats(), 0); } Beats prev_beat() const { /* always moves backwards even if currently on beat */ - return Beats (_beats-1, 0); + return Beats (get_beats()-1, 0); } Beats next_beat() const { /* always moves forwards even if currently on beat */ - return Beats (_beats+1, 0); + return Beats (get_beats()+1, 0); } LIBTEMPORAL_API Beats round_to_subdivision (int subdivision, RoundMode dir) const; Beats abs () const { - return Beats (::abs (_beats), ::abs (_ticks)); + return ticks (::abs (_ticks)); } Beats diff (Beats const & other) const { @@ -206,11 +164,11 @@ public: } inline bool operator==(const Beats& b) const { - return _beats == b._beats && _ticks == b._ticks; + return _ticks == b._ticks; } inline bool operator==(int beats) const { - return _beats == beats; + return get_beats() == beats; } inline bool operator!=(const Beats& b) const { @@ -218,38 +176,31 @@ public: } inline bool operator<(const Beats& b) const { - return _beats < b._beats || (_beats == b._beats && _ticks < b._ticks); + return _ticks < b._ticks; } inline bool operator<=(const Beats& b) const { - return _beats < b._beats || (_beats == b._beats && _ticks <= b._ticks); + return _ticks <= b._ticks; } inline bool operator>(const Beats& b) const { - return _beats > b._beats || (_beats == b._beats && _ticks > b._ticks); + return _ticks > b._ticks; } inline bool operator>=(const Beats& b) const { - return _beats > b._beats || (_beats == b._beats && _ticks >= b._ticks); + return _ticks >= b._ticks; } Beats operator+(const Beats& b) const { - return Beats(_beats + b._beats, _ticks + b._ticks); + return ticks (_ticks + b._ticks); } Beats operator-(const Beats& b) const { - return Beats(_beats - b._beats, _ticks - b._ticks); + return ticks (_ticks - b._ticks); } Beats operator-() const { - /* must avoid normalization here, which will convert a negative - value into a valid beat position before zero, which is not - we want here. - */ - Beats b (_beats, _ticks); - b._beats = -b._beats; - b._ticks = -b._ticks; - return b; + return ticks (-_ticks); } Beats operator*(int32_t factor) const {return ticks (to_ticks() * factor); } @@ -261,7 +212,6 @@ public: Beats operator%= (Beats const & b) { const Beats B (Beats::ticks (to_ticks() % b.to_ticks())); - _beats = B._beats; _ticks = B._ticks; return *this; } @@ -275,27 +225,22 @@ public: } Beats& operator+=(const Beats& b) { - _beats += b._beats; _ticks += b._ticks; - normalize(); return *this; } Beats& operator-=(const Beats& b) { - _beats -= b._beats; _ticks -= b._ticks; - normalize(); return *this; } - bool operator!() const { return _beats == 0 && _ticks == 0; } - explicit operator bool () const { return _beats != 0 || _ticks != 0; } + bool operator!() const { return _ticks == 0; } + explicit operator bool () const { return _ticks != 0; } static Beats one_tick() { return Beats(0, 1); } protected: - int32_t _beats; - int32_t _ticks; + int64_t _ticks; }; @@ -307,7 +252,7 @@ class DoubleableBeats : public Beats { public: DoubleableBeats (Beats const & b) : Beats (b) {} - double to_double() const { return (double)_beats + (_ticks / (double)PPQN); } + double to_double() const { return (double)get_beats() + (get_ticks() / (double)PPQN); } }; diff --git a/libs/temporal/test/BeatTest.cc b/libs/temporal/test/BeatTest.cc index f67b704b3a..30e716443a 100644 --- a/libs/temporal/test/BeatTest.cc +++ b/libs/temporal/test/BeatTest.cc @@ -14,21 +14,21 @@ void BeatsTest::createTest() { const Beats a(1, 2); - CPPUNIT_ASSERT_EQUAL(1, a.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(1), a.get_beats()); CPPUNIT_ASSERT_EQUAL(2, a.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(1 + 2 / (double)Beats::PPQN, DoubleableBeats(a).to_double(), delta); const Beats b = Beats::from_double (1.5); - CPPUNIT_ASSERT_EQUAL(1, b.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(1), b.get_beats()); CPPUNIT_ASSERT_EQUAL(Beats::PPQN / 2, b.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(1.5, DoubleableBeats (b).to_double(), delta); const Beats c = Beats::beats(6); - CPPUNIT_ASSERT_EQUAL(6, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(6), c.get_beats()); CPPUNIT_ASSERT_EQUAL(0, c.get_ticks()); const Beats d = Beats::ticks(7); - CPPUNIT_ASSERT_EQUAL(0, d.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(0), d.get_beats()); CPPUNIT_ASSERT_EQUAL(7, d.get_ticks()); Beats e(8, 9); @@ -50,7 +50,7 @@ BeatsTest::addTest() // Positive + positive const Beats c = a + b; - CPPUNIT_ASSERT_EQUAL(4, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(4), c.get_beats()); CPPUNIT_ASSERT_EQUAL(6, c.get_ticks()); const Beats n1 = Beats::from_double (-12.34); @@ -62,19 +62,19 @@ BeatsTest::addTest() // Positive + negative const Beats p1 = Beats::from_double (1.0); const Beats p_n = p1 + n1; - CPPUNIT_ASSERT_EQUAL(-11, p_n.get_beats()); + CPPUNIT_ASSERT_EQUAL(-int64_t(11), p_n.get_beats()); CPPUNIT_ASSERT_EQUAL((int32_t) rint (Beats::PPQN * -0.34), p_n.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.34, DoubleableBeats (p_n).to_double(), delta); // Negative + positive const Beats n_p = n1 + p1; - CPPUNIT_ASSERT_EQUAL(-11, n_p.get_beats()); + CPPUNIT_ASSERT_EQUAL(-int64_t(11), n_p.get_beats()); CPPUNIT_ASSERT_EQUAL((int32_t) rint (Beats::PPQN * -0.34), n_p.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.34, DoubleableBeats (n_p).to_double(), delta); // Negative + negative const Beats sum = n1 + n2; - CPPUNIT_ASSERT_EQUAL(-69, sum.get_beats()); + CPPUNIT_ASSERT_EQUAL(-int64_t(69), sum.get_beats()); //CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.12), n_p.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(-69.12, DoubleableBeats (sum).to_double(), delta); } @@ -87,7 +87,7 @@ BeatsTest::subtractTest() // Positive - positive const Beats c = b - a; - CPPUNIT_ASSERT_EQUAL(2, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(2), c.get_beats()); CPPUNIT_ASSERT_EQUAL(2, c.get_ticks()); const Beats n1 = Beats::from_double (-12.34); @@ -99,19 +99,19 @@ BeatsTest::subtractTest() // Positive - negative const Beats p1= Beats::from_double (1.0); const Beats p_n = p1 - n1; - CPPUNIT_ASSERT_EQUAL(13, p_n.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(13), p_n.get_beats()); CPPUNIT_ASSERT_EQUAL((int32_t) rint (Beats::PPQN * 0.34), p_n.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(13.34, DoubleableBeats (p_n).to_double(), delta); // Negative - positive const Beats n_p = n1 - p1; - CPPUNIT_ASSERT_EQUAL(-13, n_p.get_beats()); + CPPUNIT_ASSERT_EQUAL(-int64_t(13), n_p.get_beats()); CPPUNIT_ASSERT_EQUAL((int32_t) rint (Beats::PPQN * -0.34), n_p.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(-13.34, DoubleableBeats (n_p).to_double(), delta); // Negative - negative const Beats diff = n1 - n2; - CPPUNIT_ASSERT_EQUAL(44, diff.get_beats()); + CPPUNIT_ASSERT_EQUAL(int64_t(44), diff.get_beats()); CPPUNIT_ASSERT_EQUAL((int32_t)lrint(Beats::PPQN * 0.44), diff.get_ticks()); CPPUNIT_ASSERT_DOUBLES_EQUAL(44.44, DoubleableBeats (diff).to_double(), delta); } @@ -131,12 +131,12 @@ BeatsTest::roundTest() // Round a up const Beats au = a.round_up_to_beat(); - CPPUNIT_ASSERT_EQUAL(au.get_beats(), 2); + CPPUNIT_ASSERT_EQUAL(au.get_beats(), int64_t(2)); CPPUNIT_ASSERT_EQUAL(au.get_ticks(), 0); // Round a down const Beats ad = a.round_down_to_beat(); - CPPUNIT_ASSERT_EQUAL(ad.get_beats(), 1); + CPPUNIT_ASSERT_EQUAL(ad.get_beats(), int64_t (1)); CPPUNIT_ASSERT_EQUAL(ad.get_ticks(), 0); // Round result down again @@ -149,7 +149,7 @@ BeatsTest::roundTest() // Snap to 1.5 const Beats snapped = a.round_to_multiple (Beats::from_double (1.5)); - CPPUNIT_ASSERT_EQUAL(snapped.get_beats(), 1); + CPPUNIT_ASSERT_EQUAL(snapped.get_beats(), int64_t (1)); CPPUNIT_ASSERT_EQUAL(snapped.get_ticks(), Beats::PPQN / 2); } @@ -157,12 +157,12 @@ void BeatsTest::convertTest() { const Beats a = Beats::ticks_at_rate(72000, 48000); - CPPUNIT_ASSERT_DOUBLES_EQUAL(1, a.get_beats(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(int64_t (1), a.get_beats(), delta); CPPUNIT_ASSERT_DOUBLES_EQUAL(Beats::PPQN / 2, a.get_ticks(), delta); CPPUNIT_ASSERT_DOUBLES_EQUAL(1.5, DoubleableBeats(a).to_double(), delta); const Beats b = Beats::ticks_at_rate(8, 48000); - CPPUNIT_ASSERT_DOUBLES_EQUAL(0, b.get_beats(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(int64_t (0), b.get_beats(), delta); CPPUNIT_ASSERT_DOUBLES_EQUAL(Beats::PPQN * 8 / 48000, b.get_ticks(), delta); CPPUNIT_ASSERT_DOUBLES_EQUAL((8 / 48000.0), DoubleableBeats (b).to_double(), delta);