mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-30 08:53:08 +01:00
temporal: add reimplemented version of 6.x's TempoMap::gui_stretch_tempo()
This commit is contained in:
parent
db9cc04230
commit
45de3694cc
2 changed files with 90 additions and 0 deletions
|
|
@ -3028,6 +3028,92 @@ TempoMap::set_ramped (TempoPoint & tp, bool yn)
|
|||
reset_starting_at (tp.sclock() + 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TempoMap::stretch_tempo (TempoPoint* ts, const samplepos_t sample, const samplepos_t end_sample, Beats const & start_qnote, Beats const & end_qnote)
|
||||
{
|
||||
/*
|
||||
Ts (future prev_t) Tnext
|
||||
| |
|
||||
| [drag^] |
|
||||
|----------|----------
|
||||
e_f qn_beats(sample)
|
||||
*/
|
||||
|
||||
if (!ts) {
|
||||
return;
|
||||
}
|
||||
|
||||
superclock_t start_sclock = samples_to_superclock (sample, TEMPORAL_SAMPLE_RATE);
|
||||
superclock_t end_sclock = samples_to_superclock (end_sample, TEMPORAL_SAMPLE_RATE);
|
||||
|
||||
/* minimum allowed measurement distance in samples */
|
||||
const superclock_t min_delta_sclock = samples_to_superclock (2, TEMPORAL_SAMPLE_RATE);
|
||||
double new_bpm;
|
||||
|
||||
if (ts->clamped()) {
|
||||
|
||||
/* this tempo point is required to start using the same bpm
|
||||
* that the previous tempo ended with.
|
||||
*/
|
||||
|
||||
TempoPoint* next_t = const_cast<TempoPoint*> (next_tempo (*ts));
|
||||
TempoPoint* prev_to_ts = const_cast<TempoPoint*> (previous_tempo (*ts));
|
||||
assert (prev_to_ts);
|
||||
/* the change in samples is the result of changing the slope of at most 2 previous tempo sections.
|
||||
* constant to constant is straightforward, as the tempo prev to ts has constant slope.
|
||||
*/
|
||||
double contribution = 0.0;
|
||||
if (next_t && prev_to_ts->ramped()) {
|
||||
const DoubleableBeats delta_tp = ts->beats() - prev_to_ts->beats();
|
||||
const DoubleableBeats delta_np = next_t->beats() - prev_to_ts->beats();
|
||||
contribution = delta_tp.to_double() / delta_np.to_double();
|
||||
}
|
||||
samplepos_t const fr_off = end_sclock - start_sclock;
|
||||
sampleoffset_t const ts_sample_contribution = fr_off - (contribution * (double) fr_off);
|
||||
|
||||
if (start_sclock > prev_to_ts->sclock() + min_delta_sclock && (start_sclock + ts_sample_contribution) > prev_to_ts->sclock() + min_delta_sclock) {
|
||||
DoubleableBeats delta_sp = start_qnote - prev_to_ts->beats();
|
||||
DoubleableBeats delta_ep = end_qnote - prev_to_ts->beats();
|
||||
new_bpm = ts->note_types_per_minute() * (delta_sp.to_double() / delta_ep.to_double());
|
||||
} else {
|
||||
new_bpm = ts->note_types_per_minute();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* ts is free to have it's bpm changed to any value (within limits) */
|
||||
|
||||
if (start_sclock > ts->sclock() + min_delta_sclock && end_sclock > ts->sclock() + min_delta_sclock) {
|
||||
new_bpm = ts->note_types_per_minute() * ((start_sclock - ts->sclock()) / (double) (end_sclock - ts->sclock()));
|
||||
} else {
|
||||
new_bpm = ts->note_types_per_minute();
|
||||
}
|
||||
|
||||
new_bpm = std::min (new_bpm, 1000.0);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
ts->set_note_types_per_minute (new_bpm);
|
||||
|
||||
if (ts->clamped()) {
|
||||
TempoPoint* prev = 0;
|
||||
if ((prev = const_cast<TempoPoint*> (previous_tempo (*ts))) != 0) {
|
||||
prev->set_end_note_types_per_minute (ts->note_types_per_minute());
|
||||
}
|
||||
}
|
||||
|
||||
reset_starting_at (ts->sclock() + 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TempoMap::twist_tempi (TempoPoint* ts, timepos_t const & start, timepos_t const & end)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -216,7 +216,9 @@ class LIBTEMPORAL_API Tempo : public Rampable {
|
|||
double quarter_notes_per_minute() const { return (superclock_ticks_per_second() * 60.0 * 4.0) / (_note_type * _superclocks_per_note_type); }
|
||||
double samples_per_note_type(samplecnt_t sr) const { return superclock_to_samples (superclocks_per_note_type (), sr); }
|
||||
double samples_per_quarter_note(samplecnt_t sr) const { return superclock_to_samples (superclocks_per_quarter_note(), sr); }
|
||||
|
||||
void set_note_types_per_minute (double npm) { _superclocks_per_note_type = double_npm_to_scpn (npm); }
|
||||
void set_end_note_types_per_minute (double npm) { _end_superclocks_per_note_type = double_npm_to_scpn (npm); }
|
||||
|
||||
int note_type () const { return _note_type; }
|
||||
Beats note_type_as_beats () const { return Beats (0, (1920 * 4) / _note_type); }
|
||||
|
|
@ -734,6 +736,8 @@ class /*LIBTEMPORAL_API*/ TempoMap : public PBD::StatefulDestructible
|
|||
LIBTEMPORAL_API int set_state (XMLNode const&, int version);
|
||||
|
||||
LIBTEMPORAL_API void twist_tempi (TempoPoint* ts, timepos_t const & start, timepos_t const & end);
|
||||
LIBTEMPORAL_API void stretch_tempo (TempoPoint* ts, const samplepos_t sample, const samplepos_t end_sample, Beats const & start_qnote, Beats const & end_qnote);
|
||||
LIBTEMPORAL_API void stretch_tempo_end (TempoPoint* ts, const samplepos_t sample, const samplepos_t end_sample);
|
||||
|
||||
/* END OF MODIFYING METHODS */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue