- /* We now have:
-
- meter -> the Meter for "lower"
- tempo -> the Tempo for "lower"
- i -> for first new metric after "lower", possibly metrics->end()
-
- Now start generating points.
- */
-
- divisions_per_bar = meter->divisions_per_bar ();
- frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
- beat_frames = meter->frames_per_division (*tempo,_frame_rate);
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Start with beat frames = %1 bar = %2\n", beat_frames, frames_per_bar));
-
- if (meter->frame() > tempo->frame()) {
- bar = meter->start().bars;
- beat = meter->start().beats;
- current = meter->frame();
- } else {
- bar = tempo->start().bars;
- beat = tempo->start().beats;
- current = tempo->frame();
- }
-
- /* initialize current to point to the bar/beat just prior to the
- lower frame bound passed in. assumes that current is initialized
- above to be on a beat.
- */
-
- delta_bars = (lower-current) / frames_per_bar;
- delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
- current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
-
- // adjust bars and beats too
- bar += (uint32_t) (floor(delta_bars));
- beat += (uint32_t) (floor(delta_beats));
-
- points = new BBTPointList;
-
- do {
-
- /* we're going to add bar or beat points until we hit the
- earlier of:
-
- (1) the end point of this request
- (2) the next metric section
- */
-
- if (next_metric == metrics->end()) {
- limit = upper;
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to end of request @ %1\n", limit));
- } else {
- limit = (*next_metric)->frame();
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to next metric section @ %1\n", limit));
- }
-
- limit = min (limit, upper);
-
- bool reset_current_to_metric_section = true;
- bool bar_adjusted = false;
- TempoSection* ts;
-
- while (current < limit) {
-
- /* if we're at the start of a bar, add bar point */
-
- if (beat == 1) {
- if (current >= lower) {
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", bar, current));
- points->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current), Bar, bar, 1));
-
- }
- }
-
- /* add some beats if we can */
-
- beat_frame = current;
-
- const uint32_t max_divs = ceil (divisions_per_bar);
-
- while (beat <= max_divs && beat_frame < limit) {
-
- if (beat_frame >= lower) {
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", bar, beat, beat_frame));
- points->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(beat_frame), Beat, bar, beat));
- }
-
- beat_frame += beat_frames;
- current = beat_frame;
- beat++;
- }
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("break in beats addition @ end ? %1 out of bpb ? %2 beat frame @ %3 vs %4 beat @ %5 vs %6\n",
- (next_metric == metrics->end()), (beat > max_divs), beat_frame, limit, beat, max_divs));
-
- if (beat <= max_divs) {
-
- /* we didn't reach the end of the bar.
-
- this could be be because we hit "upper"
- or a new metric section.
-
- */
-
- if (next_metric != metrics->end() && limit == (*next_metric)->frame()) {
-
- /* we bumped into a new metric
- * section. meter sections are always
- * at bar boundaries, but tempo
- * sections can begin anywhere and need
- * special handling if they are not on
- * a beat boundary.
- */
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stopped at metric at %1 @ 2\n", (*next_metric)->start(), (*next_metric)->frame()));
-
- if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0) && ts->start().ticks != 0) {
-
- /* compute current at the *next* beat,
- using the tempo section we just
- bumped into.
- */
-
- /* recompute how many frames per
- * division using the tempo we've just
- * found
- */
-
- double next_beat_frames = meter->frames_per_division (*ts,_frame_rate);
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
- (*next_metric)->start(), (*next_metric)->frame(), ts->bar_offset()));
-
- current -= beat_frames;
- current += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
-
- /* avoid resetting current to position
- of the next metric section as we
- iterate through "metrics"
- further on below.
- */
-
- reset_current_to_metric_section = false;
-
- } else if (dynamic_cast<MeterSection*> (*next_metric)) {
-
- /* we hit a new meter
- * section. nothing to do - the
- * right thing will happen as
- * we move to the next metric
- * section down below.
- */
-
- } else {
-
- /* we hit a tempo mark that is
- * precisely on beat. nothing
- * to do here - the
- * right thing will happen as
- * we move to the next metric
- * section down below.
- */
- }
-
- } else {
-
- /* we hit either:
-
- - the end of the requested range
-
- we'll exit from the outer loop soon.
- */
- }
-
- } else if ((beat > max_divs) || (next_metric != metrics->end() && dynamic_cast<MeterSection*>(*next_metric))) {
-
- /* we've arrived at either the end of a bar or
- a new **meter** marker (not tempo 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 > max_divs) {
- /* next bar goes where the numbers suggest */
- current -= beat_frames * (max_divs - divisions_per_bar);
- DEBUG_TRACE (DEBUG::TempoMath, "++ next bar from numbers\n");
- } else {
- /* next bar goes where the next meter metric is */
- current = limit;
- DEBUG_TRACE (DEBUG::TempoMath, "++ next bar at next metric\n");
- }
-
- bar++;
- beat = 1;
- bar_adjusted = true;
- }
- }
-
- /* if we're done, then we're done */
-
- if (current >= upper) {
- break;
- }
-
- /* i is an iterator that refers to the next metric (or none).
- if there is a next metric, move to it, and continue.
- */
-
- if (next_metric != metrics->end()) {
-
- if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
- tempo = t;
- } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
- meter = m;
-
- if (!bar_adjusted) {
- /* new MeterSection, beat always returns to 1 */
- beat = 1;
- }
- }
-
- if (reset_current_to_metric_section) {
- current = (*next_metric)->frame ();
- }
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("loop around with current @ %1\n", current));
-
- divisions_per_bar = meter->divisions_per_bar ();
- frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
- beat_frames = meter->frames_per_division (*tempo, _frame_rate);
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 bar = %2 dpb %3 meter %4 tempo %5\n",
- beat_frames, frames_per_bar, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
-
- ++next_metric;
- }
-
- } while (1);
-
- return points;