diff --git a/libs/temporal/tempo.cc b/libs/temporal/tempo.cc index 0a30c0f06c..acc7b2b0cd 100644 --- a/libs/temporal/tempo.cc +++ b/libs/temporal/tempo.cc @@ -3180,6 +3180,103 @@ TempoMap::set_continuing (TempoPoint& tp, bool yn) return true; } +#if 1 +void +TempoMap::stretch_tempo (TempoPoint& focus, double tempo_value) +{ + /* Our goal is to alter the outound tempo at @param focus and at the same + * time create & modify a ramp between the previous tempo and @param focus + * so that @param remains in the same location. + * + * The user has placed @param focus at the correct point, but wanfocus to + * adjust the (outbound) tempo without creating an obvious step change + * at @param focus. So we want to ramp from prev to focus + */ + + TempoPoint* prev = const_cast (previous_tempo (focus)); + + TempoPoint old_prev (*prev); + TempoPoint old_focus (focus); + + std::cerr << "using " << tempo_value << " working on " << focus << std::endl; + std::cerr << "\twith prev " << *prev << std::endl; + + std::cerr << "focus then " << focus << std::endl; + focus.set_note_types_per_minute (tempo_value); + focus.set_end_npm (tempo_value); + std::cerr << "focus now " << focus << std::endl; + prev->set_end_npm (tempo_value); + prev->compute_omega_beats_from_next_tempo (focus); + + superclock_t err = prev->superclock_at (focus.beats()) - focus.sclock(); + const superclock_t one_sample = superclock_ticks_per_second() / TEMPORAL_SAMPLE_RATE; + const Beats b (focus.beats() - prev->beats()); + // const double end_scpqn = focus.superclocks_per_quarter_note(); + double scpqn = focus.superclocks_per_quarter_note (); + double new_npm; + int cnt = 0; + + std::cerr << "initial error = " << err / (double) one_sample << std::endl; + reset_starting_at (prev->sclock());; + return; + + while (std::abs(err) >= one_sample) { + + if (err > 0) { + /* estimated > actual: speed end tempo up a little aka + reduce scpqn + */ + scpqn *= 0.99; + } else { + /* estimated < actual: reduce end tempo a little, aka + increase scpqn + */ + scpqn *= 1.01; + } + + if (scpqn < 1.0) { + /* mathematically too small, bail out */ + *prev = old_prev; + focus = old_focus; + return; + } + + /* Convert scpqn to notes-per-minute */ + + new_npm = ((superclock_ticks_per_second() * 60.0) / scpqn) * (focus.note_type() / 4.0); + + /* limit range of possible discovered tempo */ + + if (new_npm < 4.0 && new_npm > 400) { + /* too low of a tempo for our taste, bail out */ + *prev = old_prev; + focus = old_focus; + return; + } + + /* set the (initial) tempo, recompute omega and then compute + * the (new) error (distance between the predicted position of + * the next marker and its actual (fixed) position. + */ + + focus.set_note_types_per_minute (new_npm); + focus.set_end_npm (new_npm); + prev->set_end_npm (new_npm); + prev->compute_omega_beats_from_next_tempo (focus); + err = prev->superclock_at (focus.beats()) - focus.sclock(); + ++cnt; + } + + std::cerr << "that took " << cnt << " iterations to get to < 1 sample\n"; + std::cerr << "final focus: " << focus << std::endl; + std::cerr << "final prev: " << *prev << std::endl; + + reset_starting_at (prev->sclock()); + // dump (std::cerr); +} + +#else + /* Adjusts the outgoing tempo at @p ts so that the next Tempo point is at @p * end_sample, while keeping the beat time positions of both the same. * @@ -3259,6 +3356,9 @@ TempoMap::stretch_tempo (TempoPoint* ts, samplepos_t sample, samplepos_t end_sam new_bpm = std::min (new_bpm, 1000.0); } + + std::cerr << "new bpm: " << new_bpm << std::endl; + /* 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. @@ -3280,6 +3380,8 @@ TempoMap::stretch_tempo (TempoPoint* ts, samplepos_t sample, samplepos_t end_sam reset_starting_at (ts->sclock() + 1); } +#endif + void TempoMap::stretch_tempo_end (TempoPoint* ts, samplepos_t sample, samplepos_t end_sample) { @@ -3328,6 +3430,7 @@ TempoMap::stretch_tempo_end (TempoPoint* ts, samplepos_t sample, samplepos_t end reset_starting_at (prev_t->sclock()); } + void TempoMap::twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_value) { diff --git a/libs/temporal/temporal/tempo.h b/libs/temporal/temporal/tempo.h index dc0ca3251c..b1b8aeafc2 100644 --- a/libs/temporal/temporal/tempo.h +++ b/libs/temporal/temporal/tempo.h @@ -766,7 +766,7 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible LIBTEMPORAL_API int set_state (XMLNode const&, int version); LIBTEMPORAL_API void twist_tempi (TempoPoint& prev, TempoPoint& focus, TempoPoint& next, double tempo_delta); - LIBTEMPORAL_API void stretch_tempo (TempoPoint* ts, samplepos_t sample, samplepos_t end_sample, Beats const & start_qnote, Beats const & end_qnote); + LIBTEMPORAL_API void stretch_tempo (TempoPoint& ts, double new_npm); LIBTEMPORAL_API void stretch_tempo_end (TempoPoint* ts, samplepos_t sample, samplepos_t end_sample); /* END OF MODIFYING METHODS */