+ if (prev_t && prev_t->pulse() > 0.0) {
+ prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
+ }
+
+ TempoSection* next_t = 0;
+ for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
+ TempoSection* t = 0;
+ if ((*i)->is_tempo()) {
+ t = static_cast<TempoSection*> (*i);
+ if (t->frame() > ts->frame()) {
+ next_t = t;
+ break;
+ }
+ }
+ }
+ /* minimum allowed measurement distance in frames */
+ const framepos_t min_dframe = 2;
+
+ /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
+ constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
+ */
+ double contribution = 0.0;
+
+ if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
+ }
+
+ const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
+
+ const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
+ const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
+
+ double new_bpm;
+
+ if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
+
+ if (prev_t->position_lock_style() == MusicTime) {
+ if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
+
+ new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+ / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
+ } else {
+ /* prev to prev is irrelevant */
+
+ if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
+ new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
+ }
+ } else {
+ /* AudioTime */
+ if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
+
+ new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+ / (double) ((end_frame) - prev_to_prev_t->frame()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
+ } else {
+ /* prev_to_prev_t is irrelevant */
+
+ if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
+ new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
+ }
+ }
+ } else {
+
+ double frame_ratio = 1.0;
+ double pulse_ratio = 1.0;
+ const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
+
+ if (prev_to_prev_t) {
+ if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
+ frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
+ }
+ if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
+ pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
+ }
+ } else {
+ if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
+ frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
+ }
+ pulse_ratio = (start_pulse / end_pulse);
+ }
+ new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
+ }
+
+ /* don't clamp and proceed here.
+ testing has revealed that this can go negative,
+ which is an entirely different thing to just being too low.
+ */
+ if (new_bpm < 0.5) {
+ return;
+ }
+ new_bpm = min (new_bpm, (double) 1000.0);
+ prev_t->set_beats_per_minute (new_bpm);
+ recompute_tempi (future_map);
+ recompute_meters (future_map);
+
+ if (check_solved (future_map)) {
+ ts->set_beats_per_minute (new_bpm);
+ recompute_tempi (_metrics);
+ recompute_meters (_metrics);