summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2011-12-10 13:49:08 +0000
committerCarl Hetherington <carl@carlh.net>2011-12-10 13:49:08 +0000
commite02e25e3f31bafbdbb12cb76dcde4b34917a939d (patch)
tree2632b898a0284cf61c3ce061d6d82cf82c0be2e5
parent2a9ceb74c4f8ec316c639722c371e5bcb78de548 (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.h2
-rw-r--r--libs/ardour/beats_frames_converter.cc2
-rw-r--r--libs/ardour/tempo.cc69
-rw-r--r--libs/ardour/test/framepos_plus_beats_test.cc134
-rw-r--r--libs/ardour/test/framepos_plus_beats_test.h21
-rw-r--r--libs/ardour/wscript3
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()