From 6af96fd59d98d95b84f6b1bcd490d84784c67b38 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 9 Dec 2011 22:53:50 +0000 Subject: Fix framewalk_to_beats with non-beat-aligned starting positions. git-svn-id: svn://localhost/ardour2/branches/3.0@10956 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/tempo.cc | 34 ++++++++++++++- libs/ardour/test/framewalk_to_beats_test.cc | 68 ++++++++++++++++++++++++++++- libs/ardour/test/framewalk_to_beats_test.h | 2 + 3 files changed, 101 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 017ea20011..617553129c 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -2118,6 +2118,8 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter); + double last_dpos = 0; + while (ddist > 0) { /* if we're nearly at the end, but have a fractional beat left, @@ -2131,6 +2133,7 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const /* walk one beat */ + last_dpos = dpos; ddist -= frames_per_beat; dpos += frames_per_beat; beats += 1.0; @@ -2140,7 +2143,34 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const */ if (i != metrics->end()) { - if ((*i)->frame() <= (framepos_t) dpos) { + + double const f = (*i)->frame (); + + if (f <= (framepos_t) dpos) { + + /* We just went past a tempo/meter section start at (*i)->frame(), + which will be on a beat. + + So what we have is + + (*i)->frame() [f] + beat beat beat beat + | | | | + | | | | + ^ ^ + | | + | new + | dpos [q] + last + dpos [p] + + We need to go back to last_dpos (1 beat ago) and re-add + (f - p) beats using the old frames per beat and (q - f) beats + using the new. + */ + + beats -= 1; + beats += (f - last_dpos) / frames_per_beat; if ((t = dynamic_cast(*i)) != 0) { tempo = t; @@ -2149,6 +2179,8 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const } ++i; frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter); + + beats += (dpos - f) / frames_per_beat; } } } diff --git a/libs/ardour/test/framewalk_to_beats_test.cc b/libs/ardour/test/framewalk_to_beats_test.cc index c7fb45cada..c5bd47b62a 100644 --- a/libs/ardour/test/framewalk_to_beats_test.cc +++ b/libs/ardour/test/framewalk_to_beats_test.cc @@ -23,11 +23,75 @@ FramewalkToBeatsTest::singleTempoTest () map.add_meter (meter, BBT_Time (1, 1, 0)); map.add_tempo (tempo, BBT_Time (1, 1, 0)); - /* Add 1 beats-worth of frames to a 2 beat starting point */ + /* Walk 1 beats-worth of frames from beat 3 */ double r = map.framewalk_to_beats (frames_per_beat * 2, frames_per_beat * 1); CPPUNIT_ASSERT (r == 1); - /* Add 6 beats-worth of frames to a 3 beat starting point */ + /* Walk 6 beats-worth of frames from beat 4 */ r = map.framewalk_to_beats (frames_per_beat * 3, frames_per_beat * 6); CPPUNIT_ASSERT (r == 6); + + /* Walk 1.5 beats-worth of frames from beat 3 */ + r = map.framewalk_to_beats (frames_per_beat * 2, frames_per_beat * 1.5); + CPPUNIT_ASSERT (r == 1.5); + + /* Walk 1.5 beats-worth of frames from beat 2.5 */ + r = map.framewalk_to_beats (frames_per_beat * 2.5, frames_per_beat * 1.5); + CPPUNIT_ASSERT (r == 1.5); } + +void +FramewalkToBeatsTest::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 */ + + /* Walk 1 beat from 1.2 */ + double r = map.framewalk_to_beats (24e3, 24e3); + assert (r == 1); + + /* Walk 2 beats from 3.3 to 4.1 (over the tempo change) */ + r = map.framewalk_to_beats (264e3, (24e3 + 12e3)); + assert (r == 2); + + /* Walk 2.5 beats from 3.3-and-a-half to 4.2 (over the tempo change) */ + r = map.framewalk_to_beats (264e3 - 12e3, (24e3 + 12e3 + 12e3)); + assert (r == 2.5); + + /* Walk 3 beats from 3.3-and-a-half to 4.2-and-a-half (over the tempo change) */ + r = map.framewalk_to_beats (264e3 - 12e3, (24e3 + 12e3 + 12e3 + 6e3)); + assert (r == 3); + + /* Walk 3.5 beats from 3.3-and-a-half to 4.3 (over the tempo change) */ + r = map.framewalk_to_beats (264e3 - 12e3, (24e3 + 12e3 + 12e3 + 12e3)); + assert (r == 3.5); +} + diff --git a/libs/ardour/test/framewalk_to_beats_test.h b/libs/ardour/test/framewalk_to_beats_test.h index 3dd24553e2..ae6ae646eb 100644 --- a/libs/ardour/test/framewalk_to_beats_test.h +++ b/libs/ardour/test/framewalk_to_beats_test.h @@ -6,6 +6,7 @@ class FramewalkToBeatsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (FramewalkToBeatsTest); CPPUNIT_TEST (singleTempoTest); + CPPUNIT_TEST (doubleTempoTest); CPPUNIT_TEST_SUITE_END (); public: @@ -13,5 +14,6 @@ public: void tearDown () {} void singleTempoTest (); + void doubleTempoTest (); }; -- cgit v1.2.3