summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2011-12-19 18:32:06 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2011-12-19 18:32:06 +0000
commit71bba8053ec54fce4f3de2cd0758a0d686517153 (patch)
tree289e8fac9aeaa417a0772d88cb101152fbc40fa0 /libs
parentfb5f590b113fb5f9794dcc28991889200bbc2640 (diff)
fix a number of errors with BBT time computations, mostly notably ones related to tempo-only change
git-svn-id: svn://localhost/ardour2/branches/3.0@11020 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/tempo.cc133
1 files changed, 69 insertions, 64 deletions
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 24b395db0a..3bb55f76f3 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -53,16 +53,16 @@ Tempo::frames_per_beat (framecnt_t sr) const
/***********************************************************************/
-double
-Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
+double
+Meter::frames_per_division (const Tempo& tempo, framecnt_t sr) const
{
- return (60.0 * sr * _divisions_per_bar) / tempo.beats_per_minute();
+ return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
}
-double
-Meter::frames_per_division (const Tempo& tempo, framecnt_t sr) const
+double
+Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
{
- return (60.0 * sr) / (tempo.beats_per_minute() * _note_type/tempo.note_type());
+ return frames_per_division (tempo, sr) * _divisions_per_bar;
}
/***********************************************************************/
@@ -862,52 +862,54 @@ TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt) const
void
TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetric& metric) const
{
- framecnt_t frame_diff;
-
const double divisions_per_bar = metric.meter().divisions_per_bar();
- const double ticks_per_frame = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
-
- // cerr << "*** Compute BBT time for " << frame
- // << " from metric at " << metric.frame() << " tempo = " << metric.tempo().beats_per_minute () << " meter "
- // << metric.meter().divisions_per_bar() << '/' << metric.meter().note_divisor()
- // << endl;
-
- /* now compute how far beyond that point we actually are. */
+ const double frames_per_tick = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
- frame_diff = frame - metric.frame();
-
- bbt.ticks = metric.start().ticks + (uint32_t)round((double)frame_diff / ticks_per_frame);
- uint32_t xtra_beats = bbt.ticks / (uint32_t)BBT_Time::ticks_per_beat;
- bbt.ticks %= (uint32_t)BBT_Time::ticks_per_beat;
-
- bbt.beats = metric.start().beats + xtra_beats - 1; // correction for 1-based counting, see below for matching operation.
- bbt.bars = metric.start().bars + (uint32_t)floor((double)bbt.beats / divisions_per_bar);
- bbt.beats = (uint32_t)fmod((double)bbt.beats, divisions_per_bar);
+ /* now compute how far beyond the metric we actually are, and add the
+ * relevant number of ticks to the metric's BBT time
+ */
- /* if we have a fractional number of beats per bar, we see if
- we're in the last beat (the fractional one). if so, we
- round ticks appropriately and bump to the next bar.
+ framecnt_t frame_diff = frame - metric.frame();
+ uint32_t tick_diff = (uint32_t) lrint ((double) frame_diff / frames_per_tick);
+
+ bbt.ticks = metric.start().ticks + tick_diff;
+ uint32_t beat_overflow = bbt.ticks / (uint32_t) BBT_Time::ticks_per_beat;
+ bbt.ticks = bbt.ticks % (uint32_t) BBT_Time::ticks_per_beat;
+ bbt.beats = metric.start().beats + beat_overflow;
+ /* bbt.beats uses 1-based counting, so adjust to get the right answer */
+ uint32_t bar_overflow = (bbt.beats - 1) / (uint32_t) divisions_per_bar;
+ bbt.bars = metric.start().bars + bar_overflow;
+
+ /* fmod will map bbt.beats as follows:
+
+ Beats divisions per bar Normalized beat
+ 0 N => 0
+ 1 N => 1
+ 2 N => 2
+ 3 N => 3
+ .
+ .
+ .
+ N-1 N => N-1
+ N N => 0
+ N+1 N => 1
+ .
+ .
+ .
+ 2N-1 N => N-1
+ 2N N => 0
+
+ so, the only special cases are 0, N, 2N etc. however bbt.beats is
+ never zero, so the only actual special cases are N, 2N and so on,
+ allowing us to use a special case check for fmod () == 0 and
+ changing the value to divisions per bar
*/
- double beat_fraction = divisions_per_bar - floor(divisions_per_bar);
-
- /* XXX one problem here is that I'm not sure how to handle
- fractional beats that don't evenly divide ticks_per_beat.
- If they aren't handled consistently, I would guess we'll
- continue to have strange discrepancies occuring. Perhaps
- this will also behave badly in the case of meters like
- 0.1/4, but I can't be bothered to test that.
- */
- uint32_t ticks_on_last_beat = (uint32_t)floor(BBT_Time::ticks_per_beat * beat_fraction);
-
- if (bbt.beats > (uint32_t)floor(divisions_per_bar) && bbt.ticks >= ticks_on_last_beat) {
- bbt.ticks -= ticks_on_last_beat;
- bbt.beats = 0;
- bbt.bars++;
- }
- bbt.beats++; // correction for 1-based counting, see above for matching operation.
+ bbt.beats = (uint32_t) fmod (bbt.beats, divisions_per_bar);
- // cerr << "-----\t RETURN " << bbt << endl;
+ if (bbt.beats == 0) {
+ bbt.beats = divisions_per_bar;
+ }
}
framecnt_t
@@ -1417,6 +1419,8 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
beat_frames = meter->frames_per_division (*tempo,_frame_rate);
+ // cerr << "Start with beat frames = " << beat_frames << " bar = " << frames_per_bar << endl;
+
if (meter->frame() > tempo->frame()) {
bar = meter->start().bars;
beat = meter->start().beats;
@@ -1448,7 +1452,7 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
limit = upper;
// cerr << "== limit set to end of request @ " << limit << endl;
} else {
- // cerr << "== limit set to next metric @ " << (*i)->frame() << endl;
+ // cerr << "== limit set to next meter section @ " << (*i)->frame() << endl;
limit = (*i)->frame();
}
@@ -1486,22 +1490,22 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
// << " beat frame @ " << beat_frame << " vs. " << limit
// << endl;
- if (beat > ceil(divisions_per_bar) || i != metrics->end()) {
-
- /* we walked an entire bar. its
- important to move `current' forward
- by the actual frames_per_bar, not move it to
- an integral beat_frame, so that metrics with
- non-integral beats-per-bar have
- their bar positions set
- correctly. consider a metric with
- 9-1/2 beats-per-bar. the bar we
- just filled had 10 beat marks,
- but the bar end is 1/2 beat before
- the last beat mark.
- And it is also possible that a tempo
- change occured in the middle of a bar,
- so we subtract the possible extra fraction from the current
+ if (beat > ceil(divisions_per_bar) || (i != metrics->end() && dynamic_cast<MeterSection*>(*i))) {
+
+ /* we've arrived at either the end of a bar or
+ a new meter marker.
+
+ its important to move `current' forward by
+ the actual frames_per_bar, not move it to an
+ integral beat_frame, so that metrics with
+ non-integral beats-per-bar have their bar
+ positions set correctly. consider a metric
+ with 9-1/2 beats-per-bar. the bar we just
+ filled had 10 beat marks, but the bar end is
+ 1/2 beat before the last beat mark. And it
+ is also possible that a tempo change occured
+ in the middle of a bar, so we subtract the
+ possible extra fraction from the current
*/
if (beat > ceil (divisions_per_bar)) {
@@ -1516,7 +1520,6 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
bar++;
beat = 1;
}
-
}
/* if we're done, then we're done */
@@ -1546,6 +1549,8 @@ TempoMap::get_points (framepos_t lower, framepos_t upper) const
frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
beat_frames = meter->frames_per_division (*tempo, _frame_rate);
+ // cerr << "New metric with beat frames = " << beat_frames << " bar = " << frames_per_bar << endl;
+
++i;
}