diff options
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 10 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.h | 3 | ||||
-rw-r--r-- | libs/ardour/ardour/tempo.h | 3 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 139 |
4 files changed, 138 insertions, 17 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 0116f9feaa..4ccb1c0ba5 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3478,6 +3478,7 @@ TempoMarkerDrag::aborted (bool moved) BBTRulerDrag::BBTRulerDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) + , _tempo (0) , before_state (0) { DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n"); @@ -3491,13 +3492,18 @@ BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) ostringstream sstr; sstr << fixed << setprecision(3) << map.tempo_at (adjusted_current_frame (event)).beats_per_minute(); show_verbose_cursor_text (sstr.str()); + _tempo = const_cast<TempoSection*> (&map.tempo_section_at (adjusted_current_frame (event, false))); + + if (!_tempo) { + Drag::abort(); + } } void BBTRulerDrag::setup_pointer_frame_offset () { TempoMap& map (_editor->session()->tempo_map()); - _pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (ceil (map.beat_at_frame (raw_grab_frame()))); + _pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (floor (map.beat_at_frame (raw_grab_frame()))); } void @@ -3515,7 +3521,7 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move) if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier())) { /* adjust previous tempo to match pointer frame */ - _editor->session()->tempo_map().gui_dilate_tempo (last_pointer_frame(), pf); + _editor->session()->tempo_map().gui_dilate_tempo (_tempo, last_pointer_frame(), pf); } ostringstream sstr; sstr << fixed << setprecision(3) << map.tempo_at (pf).beats_per_minute(); diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 5b5ca6d432..f75c9a681d 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -37,6 +37,7 @@ namespace ARDOUR { class Location; + class TempoSection; } namespace ArdourCanvas { @@ -763,7 +764,7 @@ public: void setup_pointer_frame_offset (); private: - + ARDOUR::TempoSection* _tempo; XMLNode* before_state; }; diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index ba28e8a44a..81fad2e0fc 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -398,8 +398,9 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible void gui_move_meter (MeterSection*, const framepos_t& frame); void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt); bool gui_change_tempo (TempoSection*, const Tempo& bpm); + void gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame); void gui_dilate_tempo (MeterSection*, const framepos_t& frame); - void gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame); + void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame); bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt); diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 07fa80d52c..e3d25948de 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -2783,7 +2783,7 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame) } void -TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame) +TempoMap::gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame) { Metrics future_map; TempoSection* ts = 0; @@ -2791,13 +2791,22 @@ TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame { Glib::Threads::RWLock::WriterLock lm (lock); - ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1)); + for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) { + TempoSection* t = 0; + if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + if (t->frame() > end_frame) { + ts = t; + break; + } + } + } if (!ts) { - return; + ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1)); } - TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts); + TempoSection* next_t = copy_metrics_and_point (_metrics, future_map, ts); + TempoSection* prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, next_t->frame() - 1)); TempoSection* prev_to_prev_t = 0; const frameoffset_t fr_off = end_frame - frame; @@ -2812,11 +2821,10 @@ TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame double contribution = 0.0; if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) { - /* prev to prev_t's position will remain constant in terms of frame and pulse. lets use frames. */ - contribution = prev_to_prev_t->beats_per_minute() / (prev_to_prev_t->beats_per_minute() + prev_t->beats_per_minute()); + contribution = prev_t->beats_per_minute() / (prev_t->beats_per_minute() + next_t->beats_per_minute()); } - frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off); + frameoffset_t prev_t_frame_contribution = fr_off; const double start_tempo = prev_t->tempo_at_frame (frame, _frame_rate); const double end_tempo = prev_t->tempo_at_frame (frame + prev_t_frame_contribution, _frame_rate); @@ -2856,21 +2864,126 @@ TempoMap::gui_dilate_tempo (const framepos_t& frame, const framepos_t& end_frame } } } else { - const double end_minute = (((frame + prev_t_frame_contribution) - prev_t->frame()) / (double) _frame_rate) / 60.0; + const double end_minute = ((next_t->frame() + prev_t_frame_contribution - prev_t->frame()) / (double) _frame_rate) / 60.0; + const double pulse_delta_at_next = prev_t->pulse_at_frame ((next_t->frame()) + prev_t_frame_contribution, _frame_rate) - next_t->pulse(); + const double target_pulse = (next_t->pulse() - prev_t->pulse()) + (pulse_delta_at_next); - new_bpm = (((start_pulse - prev_t->pulse()) * prev_t->c_func()) - / (exp (end_minute * prev_t->c_func()) - 1)) * (double) prev_t->note_type(); + new_bpm = (prev_t->tempo_at_frame (next_t->frame() - prev_t_frame_contribution, _frame_rate)) * (double) prev_t->note_type(); } - prev_t->set_beats_per_minute (new_bpm); + next_t->set_beats_per_minute (new_bpm); recompute_tempos (future_map); recompute_meters (future_map); if (check_solved (future_map, true)) { + ts->set_beats_per_minute (new_bpm); + recompute_tempos (_metrics); + recompute_meters (_metrics); + } + } - prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1)); - prev_t->set_beats_per_minute (new_bpm); + Metrics::const_iterator d = future_map.begin(); + while (d != future_map.end()) { + delete (*d); + ++d; + } + + MetricPositionChanged (); // Emit Signal +} + +void +TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame) +{ + Metrics future_map; + + { + Glib::Threads::RWLock::WriterLock lm (lock); + + if (!ts) { + return; + } + + TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts); + TempoSection* prev_to_prev_t = 0; + const frameoffset_t fr_off = end_frame - frame; + + if (prev_t && prev_t->pulse() > 0.0) { + prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_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 ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + if (t->frame() > ts->frame()) { + next_t = t; + break; + } + } + } + + /* 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()); + } + + 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) { + new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) + / (double) ((frame + prev_t_frame_contribution) - prev_t->frame())); + + } else { + /* prev to prev is irrelevant */ + + if (start_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) { + new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) + / (double) ((frame + prev_t_frame_contribution) - prev_t->frame())); + } else { + /* prev_to_prev_t is irrelevant */ + + if (end_frame != prev_t->frame()) { + 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 { + const frameoffset_t halfway = ((next_t->frame() + prev_t->frame()) / 2.0); + const frameoffset_t halfway_off = halfway + prev_t_frame_contribution; + const double halfway_pulse = prev_t->pulse_at_frame (halfway, _frame_rate); + const double halfway_off_minute = ((halfway_off - prev_t->frame()) / (double) _frame_rate) / 60.0; + + new_bpm = (((halfway_pulse - prev_t->pulse()) * prev_t->c_func()) + / (exp (halfway_off_minute * prev_t->c_func()) - 1.0)) * (double) prev_t->note_type(); + + } + + prev_t->set_beats_per_minute (new_bpm); + recompute_tempos (future_map); + recompute_meters (future_map); + + if (check_solved (future_map, true)) { + ts->set_beats_per_minute (new_bpm); recompute_tempos (_metrics); recompute_meters (_metrics); } |