diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2011-12-01 22:54:50 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2011-12-01 22:54:50 +0000 |
commit | 93d8451d9ea57fbf04625773edc0390c8c92daf5 (patch) | |
tree | e15b36e6159b5afde26e386bac3698046c6808be /libs | |
parent | bcaccc5ece1f75999001bd03d732f1c7a43677e0 (diff) |
significantly reduce rounding error when doing framepos_t + BBT math
git-svn-id: svn://localhost/ardour2/branches/3.0@10852 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/tempo.cc | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 6dd92aa119..017ea20011 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -1939,18 +1939,12 @@ TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const framepos_t TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const { - /* XXX: this is a little inaccurate as small errors are introduced - every time a probably-fractional product of something and - frames_per_beat is rounded. Other errors can be introduced - by op.ticks' integer nature. - */ - Metrics::const_iterator i; const MeterSection* meter; const MeterSection* m; const TempoSection* tempo; const TempoSection* t; - framecnt_t frames_per_beat; + double frames_per_beat; meter = &first_meter (); tempo = &first_tempo (); @@ -1986,9 +1980,11 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter); + uint64_t bars = 0; + while (op.bars) { - pos += llrint (frames_per_beat * meter->beats_per_bar()); + bars++; op.bars--; /* check if we need to use a new metric section: has adding frames moved us @@ -1998,6 +1994,15 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const if (i != metrics->end()) { if ((*i)->frame() <= pos) { + /* about to change tempo or meter, so add the + * number of frames for the bars we've just + * traversed before we change the + * frames_per_beat value. + */ + + pos += llrint (frames_per_beat * (bars * meter->beats_per_bar())); + bars = 0; + if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) { tempo = t; } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { @@ -2011,11 +2016,15 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const } + pos += llrint (frames_per_beat * (bars * meter->beats_per_bar())); + + uint64_t beats = 0; + while (op.beats) { /* given the current meter, have we gone past the end of the bar ? */ - pos += frames_per_beat; + beats++; op.beats--; /* check if we need to use a new metric section: has adding frames moved us @@ -2025,6 +2034,15 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const if (i != metrics->end()) { if ((*i)->frame() <= pos) { + /* about to change tempo or meter, so add the + * number of frames for the beats we've just + * traversed before we change the + * frames_per_beat value. + */ + + pos += llrint (beats * frames_per_beat); + beats = 0; + if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) { tempo = t; } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { @@ -2036,10 +2054,13 @@ TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const } } + pos += llrint (beats * frames_per_beat); + if (op.ticks) { if (op.ticks >= BBT_Time::ticks_per_beat) { - pos += frames_per_beat; - pos += llrint (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) / (double) BBT_Time::ticks_per_beat)); + pos += llrint (frames_per_beat + /* extra beat */ + (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) / + (double) BBT_Time::ticks_per_beat))); } else { pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat)); } @@ -2130,7 +2151,6 @@ TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter); } } - } return beats; |