diff options
author | Carl Hetherington <carl@carlh.net> | 2011-12-10 13:49:08 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2011-12-10 13:49:08 +0000 |
commit | e02e25e3f31bafbdbb12cb76dcde4b34917a939d (patch) | |
tree | 2632b898a0284cf61c3ce061d6d82cf82c0be2e5 | |
parent | 2a9ceb74c4f8ec316c639722c371e5bcb78de548 (diff) |
Add fixed-up framepos_plus_beats() and use it for the BeatsFramesConverter, since it only ever passed in beats to framepos_plus_bbt anyway.
git-svn-id: svn://localhost/ardour2/branches/3.0@10964 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | libs/ardour/ardour/tempo.h | 2 | ||||
-rw-r--r-- | libs/ardour/beats_frames_converter.cc | 2 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 69 | ||||
-rw-r--r-- | libs/ardour/test/framepos_plus_beats_test.cc | 134 | ||||
-rw-r--r-- | libs/ardour/test/framepos_plus_beats_test.h | 21 | ||||
-rw-r--r-- | libs/ardour/wscript | 3 |
6 files changed, 228 insertions, 3 deletions
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 9f61d1d54d..aa4266f35a 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -30,6 +30,7 @@ #include "pbd/stateful.h" #include "pbd/statefuldestructible.h" +#include "evoral/types.hpp" #include "ardour/ardour.h" @@ -247,6 +248,7 @@ class TempoMap : public PBD::StatefulDestructible Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const; framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const; + framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime) const; double framewalk_to_beats (framepos_t pos, framecnt_t distance) const; void change_existing_tempo_at (framepos_t, double bpm, double note_type); diff --git a/libs/ardour/beats_frames_converter.cc b/libs/ardour/beats_frames_converter.cc index 59c0bb2896..f5d1794abb 100644 --- a/libs/ardour/beats_frames_converter.cc +++ b/libs/ardour/beats_frames_converter.cc @@ -29,7 +29,7 @@ BeatsFramesConverter::to (double beats) const { assert (beats >= 0); - return _tempo_map.framepos_plus_bbt (_origin_b, Timecode::BBT_Time(beats)) - _origin_b; + return _tempo_map.framepos_plus_beats (_origin_b, beats) - _origin_b; } double diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 617553129c..97ec1224f0 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -24,9 +24,9 @@ #include <cmath> - #include <glibmm/thread.h> #include "pbd/xml++.h" +#include "evoral/types.hpp" #include "ardour/debug.h" #include "ardour/tempo.h" #include "ardour/utils.h" @@ -1935,6 +1935,72 @@ TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const return result; } +/** Add some (fractional) beats to a frame position, and return the result in frames */ +framepos_t +TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const +{ + Metrics::const_iterator i; + const TempoSection* tempo; + const MeterSection* meter; + + /* Find the starting metrics for tempo & meter */ + + for (i = metrics->begin(); i != metrics->end(); ++i) { + + if ((*i)->frame() > pos) { + break; + } + + const TempoSection* t; + const MeterSection* m; + + if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) { + tempo = t; + } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { + meter = m; + } + } + + /* We now have: + + meter -> the Meter for "pos" + tempo -> the Tempo for "pos" + i -> for first new metric after "pos", possibly metrics->end() + */ + + while (beats) { + + /* End of this section */ + framepos_t end = i == metrics->end() ? max_framepos : (*i)->frame (); + + /* Distance to the end in beats */ + Evoral::MusicalTime distance_beats = (end - pos) / tempo->frames_per_beat (_frame_rate, *meter); + + /* Amount to subtract this time */ + double const sub = min (distance_beats, beats); + + /* Update */ + beats -= sub; + pos += sub * tempo->frames_per_beat (_frame_rate, *meter); + + /* Move on if there's anything to move to */ + if (i != metrics->end ()) { + const TempoSection* t; + const MeterSection* m; + + if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) { + tempo = t; + } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { + meter = m; + } + + ++i; + } + } + + return pos; +} + /** Add the BBT interval op to pos and return the result */ framepos_t TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const @@ -2069,6 +2135,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const return pos; } + /** Count the number of beats that are equivalent to distance when starting at pos */ double TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const diff --git a/libs/ardour/test/framepos_plus_beats_test.cc b/libs/ardour/test/framepos_plus_beats_test.cc new file mode 100644 index 0000000000..19aa7f29c6 --- /dev/null +++ b/libs/ardour/test/framepos_plus_beats_test.cc @@ -0,0 +1,134 @@ +#include "framepos_plus_beats_test.h" +#include "ardour/tempo.h" +#include "timecode/bbt_time.h" + +CPPUNIT_TEST_SUITE_REGISTRATION (FrameposPlusBeatsTest); + +using namespace std; +using namespace ARDOUR; +using namespace Timecode; + +/* Basic tests with no tempo / meter changes */ +void +FrameposPlusBeatsTest::singleTempoTest () +{ + int const sampling_rate = 48000; + int const bpm = 120; + + double const frames_per_beat = (60 / double (bpm)) * double (sampling_rate); + + TempoMap map (sampling_rate); + Tempo tempo (bpm); + Meter meter (4, 4); + + map.add_meter (meter, BBT_Time (1, 1, 0)); + map.add_tempo (tempo, BBT_Time (1, 1, 0)); + + /* Add 1 beat to beat 3 of the first bar */ + framepos_t r = map.framepos_plus_beats (frames_per_beat * 2, 1); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (frames_per_beat * 3)); +} + +/* Test adding things that overlap a tempo change */ +void +FrameposPlusBeatsTest::doubleTempoTest () +{ + int const sampling_rate = 48000; + + TempoMap map (sampling_rate); + Meter meter (4, 4); + map.add_meter (meter, BBT_Time (1, 1, 0)); + + /* + 120bpm at bar 1, 240bpm at bar 4 + + 120bpm = 24e3 samples per beat + 240bpm = 12e3 samples per beat + */ + + + /* + + 120bpm 240bpm + 0 beats 12 beats + 0 frames 288e3 frames + | | | | | + | 1.1 1.2 1.3 1.4 | 2.1 2.2 2.3.2.4 | 3.1 3.2 3.3 3.4 | 4.1 4.2 4.3 4.4 | + + */ + + Tempo tempoA (120); + map.add_tempo (tempoA, BBT_Time (1, 1, 0)); + Tempo tempoB (240); + map.add_tempo (tempoB, BBT_Time (4, 1, 0)); + + /* Now some tests */ + + /* Add 1 beat to 1|2 */ + framepos_t r = map.framepos_plus_beats (24e3, 1); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (48e3)); + + /* Add 2 beats to 3|4 (over the tempo change) */ + r = map.framepos_plus_beats (264e3, 2); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (264e3 + 24e3 + 12e3)); + + /* Add 2.5 beats to 3|3|960 (over the tempo change) */ + r = map.framepos_plus_beats (264e3 - 12e3, 2.5); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (264e3 + 24e3 + 12e3)); +} + +/* Same as doubleTempoTest () except put a meter change at the same time as the + tempo change (which shouldn't affect anything, since we are just dealing with + beats) +*/ + +void +FrameposPlusBeatsTest::doubleTempoWithMeterTest () +{ + int const sampling_rate = 48000; + + TempoMap map (sampling_rate); + Meter meterA (4, 4); + map.add_meter (meterA, BBT_Time (1, 1, 0)); + + /* + 120bpm at bar 1, 240bpm at bar 4 + + 120bpm = 24e3 samples per beat + 240bpm = 12e3 samples per beat + */ + + + /* + + 120bpm 240bpm + 0 beats 12 beats + 0 frames 288e3 frames + | | | | | + | 1.1 1.2 1.3 1.4 | 2.1 2.2 2.3.2.4 | 3.1 3.2 3.3 3.4 | 4.1 4.2 4.3 | + + */ + + Tempo tempoA (120); + map.add_tempo (tempoA, BBT_Time (1, 1, 0)); + Tempo tempoB (240); + map.add_tempo (tempoB, BBT_Time (4, 1, 0)); + Meter meterB (3, 4); + map.add_meter (meterB, BBT_Time (4, 1, 0)); + + /* Now some tests */ + + /* Add 1 beat to 1|2 */ + framepos_t r = map.framepos_plus_beats (24e3, 1); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (48e3)); + + /* Add 2 beats to 3|4 (over the tempo change) */ + r = map.framepos_plus_beats (264e3, 2); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (264e3 + 24e3 + 12e3)); + + /* Add 2.5 beats to 3|3|960 (over the tempo change) */ + r = map.framepos_plus_beats (264e3 - 12e3, 2.5); + CPPUNIT_ASSERT_EQUAL (r, framepos_t (264e3 + 24e3 + 12e3)); +} + + diff --git a/libs/ardour/test/framepos_plus_beats_test.h b/libs/ardour/test/framepos_plus_beats_test.h new file mode 100644 index 0000000000..4d9ec4bd3c --- /dev/null +++ b/libs/ardour/test/framepos_plus_beats_test.h @@ -0,0 +1,21 @@ +#include <sigc++/sigc++.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +class FrameposPlusBeatsTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (FrameposPlusBeatsTest); + CPPUNIT_TEST (singleTempoTest); + CPPUNIT_TEST (doubleTempoTest); + CPPUNIT_TEST (doubleTempoWithMeterTest); + CPPUNIT_TEST_SUITE_END (); + +public: + void setUp () {} + void tearDown () {} + + void singleTempoTest (); + void doubleTempoTest (); + void doubleTempoWithMeterTest (); +}; + diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 2b9151c385..0eb4f0ceb6 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -427,7 +427,8 @@ def build(bld): test/interpolation_test.cc test/midi_clock_slave_test.cc test/resampled_source_test.cc - test/framewalk_to_beats_test.cc + test/framewalk_to_beats_test.cc + test/framepos_plus_beats_test.cc test/testrunner.cc '''.split() |