summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2012-01-04 03:27:55 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2012-01-04 03:27:55 +0000
commit365a8f7f14bdc653bb012b10be8938a8eaaa69ce (patch)
tree05bad4a94d70807cda2e8fdc02b79f1e8aab8d8d
parentb1a33855ce4254ebbee4f273bb74ceb50628ed05 (diff)
implement TempoMap::framepos_minus_beats() using new bar|beat map structure, and fix accuracy of TempoMap::framepos_plus_bbt()
git-svn-id: svn://localhost/ardour2/branches/3.0@11155 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--libs/ardour/ardour/tempo.h1
-rw-r--r--libs/ardour/tempo.cc120
2 files changed, 46 insertions, 75 deletions
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index b8b64fa37f..3f4b783de7 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -271,6 +271,7 @@ class TempoMap : public PBD::StatefulDestructible
framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b);
framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime);
+ framepos_t framepos_minus_bbt (framepos_t pos, Timecode::BBT_Time b);
framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime);
Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance);
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 3ca314a0da..54bb23d517 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -1632,83 +1632,51 @@ TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats)
framepos_t
TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats)
{
- Metrics::const_iterator i;
- const TempoSection* tempo = 0;
- const TempoSection* t;
-
- /* Find the starting tempo */
-
- for (i = metrics->begin(); i != metrics->end(); ++i) {
-
- /* This is a bit of a hack, but pos could be -ve, and if it is,
- we consider the initial metric changes (at time 0) to actually
- be in effect at pos.
- */
- framepos_t f = (*i)->frame ();
- if (pos < 0 && f == 0) {
- f = pos;
- }
-
- if ((*i)->frame() > pos) {
- break;
- }
-
- if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
- tempo = t;
- }
- }
-
- bool no_more_tempos = false;
-
- /* Move i back to the tempo before "pos" */
- if (i != metrics->begin ()) {
- while (i != metrics->begin ()) {
- --i;
- t = dynamic_cast<TempoSection*> (*i);
- if (t) {
- break;
- }
- }
- } else {
- no_more_tempos = true;
- }
-
- /* We now have:
-
- tempo -> the Tempo for "pos"
- i -> the first metric before "pos", unless no_more_tempos is true
- */
-
- while (beats) {
-
- /* Distance to the end of this section in frames */
- framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
+ return framepos_minus_bbt (pos, BBT_Time (beats));
+}
- /* Distance to the end in beats */
- Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
+framepos_t
+TempoMap::framepos_minus_bbt (framepos_t pos, BBT_Time op)
+{
+ BBTPointList::const_iterator i;
+ framecnt_t extra_frames = 0;
- /* Amount to subtract this time */
- double const sub = min (distance_beats, beats);
+ /* start from the bar|beat right before (or at) pos */
- /* Update */
- beats -= sub;
- pos -= sub * tempo->frames_per_beat (_frame_rate);
+ i = bbt_before_or_at (pos);
+
+ /* we know that (*i).frame is less than or equal to pos */
+ extra_frames = pos - (*i).frame;
+
+ /* walk backwards */
- /* Move i and tempo back, if there's anything to move to */
- if (i != metrics->begin ()) {
- while (i != metrics->begin ()) {
- --i;
- if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
- tempo = t;
- break;
- }
+ while (i != _map.begin() && (op.bars || op.beats)) {
+ --i;
+ if ((*i).is_bar()) {
+ if (op.bars) {
+ op.bars--;
}
} else {
- no_more_tempos = true;
+ if (op.beats) {
+ op.beats--;
+ }
}
}
+
+ /* handle ticks (assumed to be less than
+ * BBT_Time::ticks_per_bar_division, as always.
+ */
- return pos;
+ if (op.ticks) {
+ frameoffset_t tick_frames = llrint ((*i).meter->frames_per_division (*(*i).tempo, _frame_rate) * (op.ticks/BBT_Time::ticks_per_bar_division));
+ framepos_t pre_tick_frames = (*i).frame + extra_frames;
+ if (tick_frames < pre_tick_frames) {
+ return pre_tick_frames - tick_frames;
+ }
+ return 0;
+ } else {
+ return (*i).frame + extra_frames;
+ }
}
/** Add the BBT interval op to pos and return the result */
@@ -1718,6 +1686,7 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
BBT_Time op_copy (op);
int additional_minutes = 1;
BBTPointList::const_iterator i;
+ framecnt_t backup_frames = 0;
while (true) {
@@ -1725,10 +1694,8 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
op = op_copy;
- if ((*i).frame != pos) {
- /* we know that (*i).frame is before pos */
- cerr << "Need to account for offset of " << (pos - (*i).frame) << endl;
- }
+ /* we know that (*i).frame is before or equal to pos */
+ backup_frames = pos - (*i).frame;
while (i != _map.end() && (op.bars || op.beats)) {
++i;
@@ -1754,14 +1721,17 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
additional_minutes *= 2;
/* go back and try again */
- cerr << "reached end of map with op now at " << op << " end = " << _map.back().frame << ' ' << _map.back().bar << '|' << _map.back().beat << ", trying to walk " << op_copy << " ... retry\n";
+ warning << "reached end of map with op now at " << op << " end = "
+ << _map.back().frame << ' ' << _map.back().bar << '|' << _map.back().beat << ", trying to walk "
+ << op_copy << " ... retry"
+ << endmsg;
}
if (op.ticks) {
- return (*i).frame +
+ return (*i).frame - backup_frames +
llrint ((*i).meter->frames_per_division (*(*i).tempo, _frame_rate) * (op.ticks/BBT_Time::ticks_per_bar_division));
} else {
- return (*i).frame;
+ return (*i).frame - backup_frames;
}
}