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 / beats_per_bar);
- bbt.beats = (uint32_t)fmod((double)bbt.beats, beats_per_bar);
-
- /* 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. */
- double beat_fraction = beats_per_bar - floor(beats_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(beats_per_bar) && bbt.ticks >= ticks_on_last_beat) {
+ 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 / beats_per_bar);
+ bbt.beats = (uint32_t)fmod((double)bbt.beats, beats_per_bar);
+
+ /* 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. */
+ double beat_fraction = beats_per_bar - floor(beats_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(beats_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++; // correction for 1-based counting, see above for matching operation.
// cerr << "-----\t RETURN " << bbt << endl;
}
framecnt_t
TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
{
- /* for this to work with fractional measure types, start and end have to be "legal" BBT types,
- that means that the beats and ticks should be inside a bar
+ /* for this to work with fractional measure types, start and end have to be
+ "legal" BBT types, that means that the beats and ticks should be inside
+ a bar
*/
framecnt_t frames = 0;
+ start.ticks/BBT_Time::ticks_per_beat;
- start_frame = m.frame() + (framepos_t) rint( beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
+ start_frame = m.frame() + (framepos_t) rint(beat_offset * m.tempo().frames_per_beat(_frame_rate, m.meter()));
m = metric_at(end);
framecnt_t
TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
{
- /* this is used in timestamping the metrics by actually counting the beats */
+ /* this is used in timestamping the metrics by actually counting the beats */
framecnt_t frames = 0;
uint32_t bar = start.bars;
{
BBT_Time start ; /* 1|1|0 */
- return count_frames_between ( start, bbt);
+ return count_frames_between (start, bbt);
}
framecnt_t
TempoMetric metric = metric_at(result);
beats_per_bar = metric.meter().beats_per_bar();
-
-
- /*reduce things to legal bbt values
- we have to handle possible fractional=shorter beats at the end of measures
- and things like 0|11|9000 as a duration in a 4.5/4 measure
- the musical decision is that the fractional beat is also a beat , although a shorter one
+ /* Reduce things to legal bbt values we have to handle possible
+ fractional=shorter beats at the end of measures and things like 0|11|9000
+ as a duration in a 4.5/4 measure the musical decision is that the
+ fractional beat is also a beat , although a shorter one
*/
-
if (dir >= 0) {
result.beats = when.beats + bbt.beats;
result.ticks = when.ticks + bbt.ticks;
beats_per_bar = metric.meter().beats_per_bar();
}
- /*we now counted the beats and landed in the target measure, now deal with ticks
- this seems complicated, but we want to deal with the corner case of a sequence of time signatures like 0.2/4-0.7/4
- and with request like bbt = 3|2|9000 ,so we repeat the same loop but add ticks
+
+ /* We now counted the beats and landed in the target measure, now deal
+ with ticks this seems complicated, but we want to deal with the
+ corner case of a sequence of time signatures like 0.2/4-0.7/4 and
+ with request like bbt = 3|2|9000 ,so we repeat the same loop but add
+ ticks
*/
/* of course gtk_ardour only allows bar with at least 1.0 beats .....
*/
- uint32_t ticks_at_beat = (uint32_t) ( result.beats == ceil(beats_per_bar) ?
+ uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(beats_per_bar) ?
(1 - (ceil(beats_per_bar) - beats_per_bar))* BBT_Time::ticks_per_beat
: BBT_Time::ticks_per_beat );
metric = metric_at(result); // maybe there is a meter change
beats_per_bar = metric.meter().beats_per_bar();
}
- ticks_at_beat= (uint32_t) ( result.beats == ceil(beats_per_bar) ?
+ ticks_at_beat= (uint32_t) (result.beats == ceil(beats_per_bar) ?
(1 - (ceil(beats_per_bar) - beats_per_bar) ) * BBT_Time::ticks_per_beat
: BBT_Time::ticks_per_beat);
-
}
} else {
uint32_t b = bbt.beats;
- /* count beats */
- while( b > when.beats ) {
-
- result.bars = max(1U,result.bars-- ) ;
+ /* count beats */
+ while (b > when.beats) {
+ --result.bars;
+ result.bars = max(1U, result.bars);
metric = metric_at(result); // maybe there is a meter change
beats_per_bar = metric.meter().beats_per_bar();
if (b >= ceil(beats_per_bar)) {
-
b -= (uint32_t) ceil(beats_per_bar);
} else {
b = (uint32_t) ceil(beats_per_bar) - b + when.beats ;
}
result.beats = when.beats - b;
- /*count ticks */
+ /* count ticks */
if (bbt.ticks <= when.ticks) {
result.ticks = when.ticks - bbt.ticks;
do {
if (result.beats == 1) {
- result.bars = max(1U, result.bars-- ) ;
+ --result.bars;
+ result.bars = max(1U, result.bars) ;
metric = metric_at(result); // maybe there is a meter change
beats_per_bar = metric.meter().beats_per_bar();
result.beats = (uint32_t) ceil(beats_per_bar);
ticks_at_beat = (uint32_t) ((1 - (ceil(beats_per_bar) - beats_per_bar)) * BBT_Time::ticks_per_beat) ;
} else {
- result.beats --;
+ --result.beats;
ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
}
}
- if (dir < 0 ) {
- frames = count_frames_between( result,when);
+ if (dir < 0) {
+ frames = count_frames_between(result, when);
} else {
frames = count_frames_between(when,result);
}
framepos_t
TempoMap::round_to_bar (framepos_t fr, int dir)
{
- {
- Glib::RWLock::ReaderLock lm (lock);
+ {
+ Glib::RWLock::ReaderLock lm (lock);
return round_to_type (fr, dir, Bar);
}
}
framepos_t
TempoMap::round_to_beat (framepos_t fr, int dir)
{
- {
- Glib::RWLock::ReaderLock lm (lock);
+ {
+ Glib::RWLock::ReaderLock lm (lock);
return round_to_type (fr, dir, Beat);
}
}
difference = mod;
}
- try {
- the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
- } catch (...) {
- /* can't go backwards from wherever pos is, so just return it */
- return fr;
- }
-
+ try {
+ the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
+ } catch (...) {
+ /* can't go backwards from wherever pos is, so just return it */
+ return fr;
+ }
} else {
/* round to nearest */
beat_frame = current;
- while (beat <= ceil( beats_per_bar) && beat_frame < limit) {
+ while (beat <= ceil(beats_per_bar) && beat_frame < limit) {
if (beat_frame >= lower) {
// cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
XMLNode *root = new XMLNode ("TempoMap");
{
- Glib::RWLock::ReaderLock lm (lock);
+ Glib::RWLock::ReaderLock lm (lock);
for (i = metrics->begin(); i != metrics->end(); ++i) {
- root->add_child_nocopy ((*i)->get_state());
+ root->add_child_nocopy ((*i)->get_state());
}
}
return result;
}
-/**
- * add the BBT interval @param increment to @param start and return the result
- */
+/** Add the BBT interval op to pos and return the result */
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;
+ framecnt_t frames_per_beat;
meter = &first_meter ();
tempo = &first_tempo ();
- assert (meter);
- assert (tempo);
+ assert (meter);
+ assert (tempo);
/* find the starting metrics for tempo & meter */
for (i = metrics->begin(); i != metrics->end(); ++i) {
-
+
if ((*i)->frame() > pos) {
break;
}
-
+
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
tempo = t;
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
checking for a new metric on every beat.
*/
- frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
+ frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
- while (op.bars) {
+ while (op.bars) {
- pos += llrint (frames_per_beat * meter->beats_per_bar());
+ pos += llrint (frames_per_beat * meter->beats_per_bar());
op.bars--;
/* check if we need to use a new metric section: has adding frames moved us
to or after the start of the next metric section? in which case, use it.
*/
-
- if (i != metrics->end()) {
- if ((*i)->frame() <= pos) {
- if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
- tempo = t;
- } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
- meter = m;
- }
- ++i;
- frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
+ if (i != metrics->end()) {
+ if ((*i)->frame() <= pos) {
- }
+ if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
+ meter = m;
+ }
+ ++i;
+ frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
+
+ }
}
- }
+ }
while (op.beats) {
/* given the current meter, have we gone past the end of the bar ? */
-
- pos += frames_per_beat;
+
+ pos += frames_per_beat;
op.beats--;
/* check if we need to use a new metric section: has adding frames moved us
to or after the start of the next metric section? in which case, use it.
*/
-
- if (i != metrics->end()) {
- if ((*i)->frame() <= pos) {
-
- if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
- tempo = t;
- } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
- meter = m;
- }
- ++i;
- frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
- }
- }
- }
-
- 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));
- } else {
- pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
- }
- }
+
+ if (i != metrics->end()) {
+ if ((*i)->frame() <= pos) {
+
+ if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
+ meter = m;
+ }
+ ++i;
+ frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
+ }
+ }
+ }
+
+ 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));
+ } else {
+ pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
+ }
+ }
return pos;
}
-/**
- * add the BBT interval @param increment to @param start and return the result
- */
+/** 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
{
Metrics::const_iterator i;
- double beats = 0;
+ double beats = 0;
const MeterSection* meter;
const MeterSection* m;
const TempoSection* tempo;
const TempoSection* t;
- double frames_per_beat;
+ double frames_per_beat;
- double ddist = distance;
- double dpos = pos;
+ double ddist = distance;
+ double dpos = pos;
meter = &first_meter ();
tempo = &first_tempo ();
- assert (meter);
- assert (tempo);
+ assert (meter);
+ assert (tempo);
/* find the starting metrics for tempo & meter */
for (i = metrics->begin(); i != metrics->end(); ++i) {
-
+
if ((*i)->frame() > pos) {
break;
}
-
+
if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
tempo = t;
} else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
checking for a new metric on every beat.
*/
- frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
-
- while (ddist > 0) {
+ frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
- /* if we're nearly at the end, but have a fractional beat left,
- compute the fraction and then its all over
- */
+ while (ddist > 0) {
- if (ddist < frames_per_beat) {
- beats += BBT_Time::ticks_per_beat * (ddist/frames_per_beat);
- break;
- }
+ /* if we're nearly at the end, but have a fractional beat left,
+ compute the fraction and then its all over
+ */
- /* walk one beat */
+ if (ddist < frames_per_beat) {
+ beats += ddist / frames_per_beat;
+ break;
+ }
+
+ /* walk one beat */
+
+ ddist -= frames_per_beat;
+ dpos += frames_per_beat;
+ beats += 1.0;
- ddist -= frames_per_beat;
- dpos += frames_per_beat;
- beats += 1.0;
-
/* check if we need to use a new metric section: has adding frames moved us
to or after the start of the next metric section? in which case, use it.
*/
-
- if (i != metrics->end()) {
- if ((*i)->frame() <= (framepos_t) dpos) {
- if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
- tempo = t;
- } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
- meter = m;
- }
- ++i;
- frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
- }
+ if (i != metrics->end()) {
+ if ((*i)->frame() <= (framepos_t) dpos) {
+
+ if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
+ tempo = t;
+ } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
+ meter = m;
+ }
+ ++i;
+ frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
+ }
}
- }
+ }
return beats;
}