diff options
author | David Robillard <d@drobilla.net> | 2015-10-05 14:27:38 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2016-07-28 09:39:27 -0400 |
commit | b54cc4b19cdf1724fa949f3ea13936b9266ab3a6 (patch) | |
tree | 34597e193d91911378eeff6e202aa2dcb3459d1c | |
parent | f93f388845ded4a9ace74dc8ed2aa41f63388293 (diff) | |
download | ardour-origin/ticktime.zip ardour-origin/ticktime.tar.gz ardour-origin/ticktime.tar.bz2 |
Rewrite Evoral::Beats to use fixed beat:tick timeorigin/ticktime
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 4 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 4 | ||||
-rw-r--r-- | libs/evoral/evoral/Beats.hpp | 161 | ||||
-rw-r--r-- | libs/evoral/src/types.cpp | 6 | ||||
-rw-r--r-- | libs/evoral/test/BeatsTest.cpp | 170 | ||||
-rw-r--r-- | libs/evoral/test/BeatsTest.hpp | 22 | ||||
-rw-r--r-- | libs/evoral/wscript | 1 |
10 files changed, 306 insertions, 74 deletions
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 5419ce9..71a7168 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -4242,7 +4242,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid /* Snap start time backwards, so copy/paste is snap aligned. */ if (midi) { - if (earliest == Evoral::Beats::max()) { + if (earliest == std::numeric_limits<Evoral::Beats>::max()) { earliest = Evoral::Beats(); // Weird... don't offset } earliest.round_down_to_beat(); @@ -4296,7 +4296,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid void Editor::cut_copy_midi (CutCopyOp op) { - Evoral::Beats earliest = Evoral::Beats::max(); + Evoral::Beats earliest = std::numeric_limits<Evoral::Beats>::max(); for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) { MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i); if (mrv) { diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 3d67fef..bd1a593 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -2357,7 +2357,7 @@ MidiRegionView::note_selected (NoteBase* ev, bool add, bool extend) } else { /* find end of latest note selected, select all between that and the start of "ev" */ - Evoral::Beats earliest = Evoral::MaxBeats; + Evoral::Beats earliest = std::numeric_limits<Evoral::Beats>::max(); Evoral::Beats latest = Evoral::Beats(); for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { @@ -2516,7 +2516,7 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) { typedef vector<boost::shared_ptr<NoteType> > PossibleChord; PossibleChord to_play; - Evoral::Beats earliest = Evoral::MaxBeats; + Evoral::Beats earliest = std::numeric_limits<Evoral::Beats>::max(); for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { if ((*i)->note()->time() < earliest) { diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index ea4f178..6180820 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -264,8 +264,8 @@ public: bool write_section_to(boost::shared_ptr<MidiSource> source, const Glib::Threads::Mutex::Lock& source_lock, - Evoral::Beats begin = Evoral::MinBeats, - Evoral::Beats end = Evoral::MaxBeats, + Evoral::Beats begin = Evoral::Beats(), + Evoral::Beats end = std::numeric_limits<Evoral::Beats>::max(), bool offset_events = false); // MidiModel doesn't use the normal AutomationList serialisation code diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index c8b4263..52416e5 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -60,8 +60,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha */ int write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, - Evoral::Beats begin = Evoral::MinBeats, - Evoral::Beats end = Evoral::MaxBeats); + Evoral::Beats begin = Evoral::Beats(), + Evoral::Beats end = std::numeric_limits<Evoral::Beats>::max()); /** Export the midi data in the given time range to another MidiSource * \param newsrc MidiSource to which data will be written. Should be a diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 97bce4b..1926a62 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -411,7 +411,7 @@ MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Ev newsrc->copy_automation_state_from (this); if (_model) { - if (begin == Evoral::MinBeats && end == Evoral::MaxBeats) { + if (!begin && end == std::numeric_limits<Evoral::Beats>::max()) { _model->write_to (newsrc, newsrc_lock); } else { _model->write_section_to (newsrc, newsrc_lock, begin, end); @@ -425,7 +425,7 @@ MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Ev /* force a reload of the model if the range is partial */ - if (begin != Evoral::MinBeats || end != Evoral::MaxBeats) { + if (!!begin || end != std::numeric_limits<Evoral::Beats>::max()) { newsrc->load_model (newsrc_lock, true); } else { newsrc->set_model (newsrc_lock, _model); diff --git a/libs/evoral/evoral/Beats.hpp b/libs/evoral/evoral/Beats.hpp index e0277c4..902008d 100644 --- a/libs/evoral/evoral/Beats.hpp +++ b/libs/evoral/evoral/Beats.hpp @@ -22,6 +22,7 @@ #include <float.h> #include <math.h> #include <stdint.h> +#include <stdlib.h> #include <iostream> #include <limits> @@ -33,62 +34,101 @@ namespace Evoral { /** Musical time in beats. */ class /*LIBEVORAL_API*/ Beats { public: - LIBEVORAL_API static const double PPQN; + LIBEVORAL_API static const int32_t PPQN; + + Beats() : _beats(0), _ticks(0) {} + + /** Normalize so ticks is within PPQN. */ + void normalize() { + // First, fix negative ticks with positive beats + if (_beats >= 0) { + while (_ticks < 0) { + --_beats; + _ticks += PPQN; + } + } + + // Work with positive beats and ticks to normalize + const int32_t sign = _beats < 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; + } - Beats() : _time(0.0) {} + // Set fields with appropriate sign + _beats = sign * beats; + _ticks = sign * ticks; + } + + /** Create from a precise BT time. */ + explicit Beats(int32_t b, int32_t t) : _beats(b), _ticks(t) { + normalize(); + } /** Create from a real number of beats. */ - explicit Beats(double time) : _time(time) {} + explicit Beats(double time) { + double whole; + const double frac = modf(time, &whole); + + _beats = whole; + _ticks = frac * PPQN; + } /** Create from an integer number of beats. */ static Beats beats(int32_t beats) { - return Beats((double)beats); + return Beats(beats, 0); } /** Create from ticks at the standard PPQN. */ - static Beats ticks(uint32_t ticks) { - return Beats(ticks / PPQN); + static Beats ticks(int32_t ticks) { + return Beats(0, ticks); } /** Create from ticks at a given rate. * * Note this can also be used to create from frames by setting ppqn to the - * number of samples per beat. + * number of samples per beat. Note the resulting Beats will, like all + * others, have the default PPQN, so this is a potentially lossy + * conversion. */ - static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn) { - return Beats((double)ticks / (double)ppqn); + static Beats ticks_at_rate(int64_t ticks, uint32_t ppqn) { + return Beats(ticks / ppqn, (ticks % ppqn) * PPQN / ppqn); } Beats& operator=(const Beats& other) { - _time = other._time; + _beats = other._beats; + _ticks = other._ticks; return *this; } Beats round_up_to_beat() const { - return Evoral::Beats(ceil(_time)); + return (_ticks == 0) ? *this : Beats(_beats + 1, 0); } Beats round_down_to_beat() const { - return Evoral::Beats(floor(_time)); + return Beats(_beats, 0); } Beats snap_to(const Evoral::Beats& snap) const { - return Beats(ceil(_time / snap._time) * snap._time); + const double snap_time = snap.to_double(); + return Beats(ceil(to_double() / snap_time) * snap_time); } inline bool operator==(const Beats& b) const { - /* Acceptable tolerance is 1 tick. */ - return fabs(_time - b._time) <= (1.0 / PPQN); + return _beats == b._beats && _ticks == b._ticks; } inline bool operator==(double t) const { /* Acceptable tolerance is 1 tick. */ - return fabs(_time - t) <= (1.0 / PPQN); + return fabs(to_double() - t) <= (1.0 / PPQN); } inline bool operator==(int beats) const { - /* Acceptable tolerance is 1 tick. */ - return fabs(_time - beats) <= (1.0 / PPQN); + return _beats == beats; } inline bool operator!=(const Beats& b) const { @@ -96,37 +136,28 @@ public: } inline bool operator<(const Beats& b) const { - /* Acceptable tolerance is 1 tick. */ - if (fabs(_time - b._time) <= (1.0 / PPQN)) { - return false; /* Effectively identical. */ - } else { - return _time < b._time; - } + return _beats < b._beats || (_beats == b._beats && _ticks < b._ticks); } inline bool operator<=(const Beats& b) const { - return operator==(b) || operator<(b); + return _beats < b._beats || (_beats == b._beats && _ticks <= b._ticks); } inline bool operator>(const Beats& b) const { - /* Acceptable tolerance is 1 tick. */ - if (fabs(_time - b._time) <= (1.0 / PPQN)) { - return false; /* Effectively identical. */ - } else { - return _time > b._time; - } + return _beats > b._beats || (_beats == b._beats && _ticks > b._ticks); } inline bool operator>=(const Beats& b) const { - return operator==(b) || operator>(b); + return _beats > b._beats || (_beats == b._beats && _ticks >= b._ticks); } inline bool operator<(double b) const { /* Acceptable tolerance is 1 tick. */ - if (fabs(_time - b) <= (1.0 / PPQN)) { + const double time = to_double(); + if (fabs(time - b) <= (1.0 / PPQN)) { return false; /* Effectively identical. */ } else { - return _time < b; + return time < b; } } @@ -136,10 +167,11 @@ public: inline bool operator>(double b) const { /* Acceptable tolerance is 1 tick. */ - if (fabs(_time - b) <= (1.0 / PPQN)) { + const double time = to_double(); + if (fabs(time - b) <= (1.0 / PPQN)) { return false; /* Effectively identical. */ } else { - return _time > b; + return time > b; } } @@ -148,60 +180,60 @@ public: } Beats operator+(const Beats& b) const { - return Beats(_time + b._time); + return Beats(_beats + b._beats, _ticks + b._ticks); } Beats operator-(const Beats& b) const { - return Beats(_time - b._time); + return Beats(_beats - b._beats, _ticks - b._ticks); } Beats operator+(double d) const { - return Beats(_time + d); + return Beats(to_double() + d); } Beats operator-(double d) const { - return Beats(_time - d); + return Beats(to_double() - d); } Beats operator-() const { - return Beats(-_time); + return Beats(-_beats, -_ticks); } template<typename Number> Beats operator*(Number factor) const { - return Beats(_time * factor); + return Beats(_beats * factor, _ticks * factor); } Beats& operator+=(const Beats& b) { - _time += b._time; + _beats += b._beats; + _ticks += b._ticks; + normalize(); return *this; } Beats& operator-=(const Beats& b) { - _time -= b._time; + _beats -= b._beats; + _ticks -= b._ticks; + normalize(); return *this; } - double to_double() const { return _time; } - uint64_t to_ticks() const { return lrint(_time * PPQN); } - uint64_t to_ticks(uint32_t ppqn) const { return lrint(_time * ppqn); } + double to_double() const { return (double)_beats + (_ticks / (double)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); } - uint32_t get_beats() const { return floor(_time); } - uint32_t get_ticks() const { return (uint32_t)lrint(fmod(_time, 1.0) * PPQN); } + int32_t get_beats() const { return _beats; } + int32_t get_ticks() const { return _ticks; } - bool operator!() const { return _time == 0; } + bool operator!() const { return _beats == 0 && _ticks == 0; } - static Beats min() { return Beats(DBL_MIN); } - static Beats max() { return Beats(DBL_MAX); } - static Beats tick() { return Beats(1.0 / PPQN); } + static Beats tick() { return Beats(0, 1); } private: - double _time; + int32_t _beats; + int32_t _ticks; }; -extern LIBEVORAL_API const Beats MaxBeats; -extern LIBEVORAL_API const Beats MinBeats; - /* TIL, several horrible hours later, that sometimes the compiler looks in the namespace of a type (Evoral::Beats in this case) for an operator, and @@ -239,8 +271,19 @@ namespace PBD { namespace std { template<> struct numeric_limits<Evoral::Beats> { - static Evoral::Beats min() { return Evoral::Beats::min(); } - static Evoral::Beats max() { return Evoral::Beats::max(); } + static Evoral::Beats lowest() { + return Evoral::Beats(std::numeric_limits<int32_t>::min(), + std::numeric_limits<int32_t>::min()); + } + + /* We don't define min() since this has different behaviour for integral and floating point types, + but Beats is used as both. Better to avoid providing a min at all + than a confusing one. */ + + static Evoral::Beats max() { + return Evoral::Beats(std::numeric_limits<int32_t>::max(), + std::numeric_limits<int32_t>::max()); + } }; } diff --git a/libs/evoral/src/types.cpp b/libs/evoral/src/types.cpp index db061fd..9c055c2 100644 --- a/libs/evoral/src/types.cpp +++ b/libs/evoral/src/types.cpp @@ -16,15 +16,11 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <limits.h> - #include "evoral/Beats.hpp" #include "evoral/types.hpp" namespace Evoral { -const double Beats::PPQN = 1920.0; -const Beats MaxBeats = Evoral::Beats(DBL_MAX); -const Beats MinBeats = Evoral::Beats(DBL_MIN); +const int32_t Beats::PPQN = 1920; } diff --git a/libs/evoral/test/BeatsTest.cpp b/libs/evoral/test/BeatsTest.cpp new file mode 100644 index 0000000..0e3d29a --- /dev/null +++ b/libs/evoral/test/BeatsTest.cpp @@ -0,0 +1,170 @@ +#include <stdlib.h> + +#include "BeatsTest.hpp" +#include "evoral/Beats.hpp" + +CPPUNIT_TEST_SUITE_REGISTRATION(BeatsTest); + +using namespace Evoral; + +static const double delta = 1.5 / (double)Beats::PPQN; + +void +BeatsTest::createTest() +{ + const Beats a(1, 2); + CPPUNIT_ASSERT_EQUAL(1, a.get_beats()); + CPPUNIT_ASSERT_EQUAL(2, a.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1 + 2 / (double)Beats::PPQN, a.to_double(), delta); + + const Beats b(1.5); + CPPUNIT_ASSERT_EQUAL(1, b.get_beats()); + CPPUNIT_ASSERT_EQUAL(Beats::PPQN / 2, b.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.5, b.to_double(), delta); + + const Beats c = Beats::beats(6); + CPPUNIT_ASSERT_EQUAL(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(7, d.get_ticks()); + + Beats e(8, 9); + e = d; + CPPUNIT_ASSERT_EQUAL(d, e); + + + // const Beats diff = n2 - n1; + // CPPUNIT_ASSERT_EQUAL(-44, diff.get_beats()); + // CPPUNIT_ASSERT_EQUAL(44 / Beats::PPQN, diff.get_ticks()); + // CPPUNIT_ASSERT_DOUBLES_EQUAL(diff.to_double(), -44.44, delta); +} + +void +BeatsTest::addTest() +{ + const Beats a(1, 2); + const Beats b(3, 4); + + // Positive + positive + const Beats c = a + b; + CPPUNIT_ASSERT_EQUAL(4, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(6, c.get_ticks()); + + const Beats n1(-12.34); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-12.34, n1.to_double(), delta); + + const Beats n2(-56.78); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-56.78, n2.to_double(), delta); + + // Positive + negative + const Beats p1(1.0); + const Beats p_n = p1 + n1; + CPPUNIT_ASSERT_EQUAL(-11, p_n.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.34), p_n.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.34, p_n.to_double(), delta); + + // Negative + positive + const Beats n_p = n1 + p1; + CPPUNIT_ASSERT_EQUAL(-11, n_p.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.34), n_p.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.34, n_p.to_double(), delta); + + // Negative + negative + const Beats sum = n1 + n2; + CPPUNIT_ASSERT_EQUAL(-69, sum.get_beats()); + //CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.12), n_p.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-69.12, sum.to_double(), delta); +} + +void +BeatsTest::subtractTest() +{ + const Beats a(1, 2); + const Beats b(3, 4); + + // Positive - positive + const Beats c = b - a; + CPPUNIT_ASSERT_EQUAL(2, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(2, c.get_ticks()); + + const Beats n1(-12.34); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-12.34, n1.to_double(), delta); + + const Beats n2(-56.78); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-56.78, n2.to_double(), delta); + + // Positive - negative + const Beats p1(1.0); + const Beats p_n = p1 - n1; + CPPUNIT_ASSERT_EQUAL(13, p_n.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * 0.34), p_n.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(13.34, p_n.to_double(), delta); + + // Negative - positive + const Beats n_p = n1 - p1; + CPPUNIT_ASSERT_EQUAL(-13, n_p.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.34), n_p.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-13.34, n_p.to_double(), delta); + + // Negative - negative + const Beats diff = n1 - n2; + CPPUNIT_ASSERT_EQUAL(44, diff.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)lrint(Beats::PPQN * 0.44), diff.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(44.44, diff.to_double(), delta); +} + +void +BeatsTest::multiplyTest() +{ + CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, (Beats(1.5) * 2.0).to_double(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-10.0, (Beats(5.0) * -2.0).to_double(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-10.0, (Beats(-5.0) * 2.0).to_double(), delta); +} + +void +BeatsTest::roundTest() +{ + Beats a(1, 1); + + // Round a up + const Beats au = a.round_up_to_beat(); + CPPUNIT_ASSERT_EQUAL(au.get_beats(), 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_ticks(), 0); + + // Round result down again + const Beats add = ad.round_down_to_beat(); + CPPUNIT_ASSERT_EQUAL(ad, add); + + // Round result up + const Beats adu = ad.round_up_to_beat(); + CPPUNIT_ASSERT_EQUAL(ad, adu); + + // Snap to 1.5 + const Beats snapped = a.snap_to(Beats(1.5)); + CPPUNIT_ASSERT_EQUAL(snapped.get_beats(), 1); + CPPUNIT_ASSERT_EQUAL(snapped.get_ticks(), Beats::PPQN / 2); +} + +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(Beats::PPQN / 2, a.get_ticks(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.5, 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(Beats::PPQN * 8 / 48000, b.get_ticks(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL((8 / 48000.0), b.to_double(), delta); + + CPPUNIT_ASSERT_EQUAL(int64_t(1.5 * Beats::PPQN), a.to_ticks()); + CPPUNIT_ASSERT_EQUAL(int64_t(1.5 * 192), a.to_ticks(192)); +} diff --git a/libs/evoral/test/BeatsTest.hpp b/libs/evoral/test/BeatsTest.hpp new file mode 100644 index 0000000..0db3831 --- /dev/null +++ b/libs/evoral/test/BeatsTest.hpp @@ -0,0 +1,22 @@ +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +class BeatsTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(BeatsTest); + CPPUNIT_TEST(createTest); + CPPUNIT_TEST(addTest); + CPPUNIT_TEST(subtractTest); + CPPUNIT_TEST(multiplyTest); + CPPUNIT_TEST(convertTest); + CPPUNIT_TEST(roundTest); + CPPUNIT_TEST_SUITE_END(); + +public: + void createTest(); + void addTest(); + void subtractTest(); + void multiplyTest(); + void convertTest(); + void roundTest(); +}; diff --git a/libs/evoral/wscript b/libs/evoral/wscript index 7649bb8..a83a3ca 100644 --- a/libs/evoral/wscript +++ b/libs/evoral/wscript @@ -134,6 +134,7 @@ def build(bld): # Unit tests obj = bld(features = 'cxx cxxprogram') obj.source = ''' + test/BeatsTest.cpp test/SequenceTest.cpp test/SMFTest.cpp test/RangeTest.cpp |