From c10b265333eb1ba44071d9a768fdd17b0c1733d6 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 13 Apr 2023 17:47:34 -0600 Subject: [PATCH] tempo mapping: various tweaks and improvements to workflow/Ux --- gtk2_ardour/editor_drag.cc | 59 +++++++++++++++++++------------------ gtk2_ardour/editor_drag.h | 5 ++-- gtk2_ardour/editor_mouse.cc | 50 ++++++++++++++++--------------- 3 files changed, 61 insertions(+), 53 deletions(-) diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 55f2664b47..56826a79bd 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3476,12 +3476,13 @@ BBTMarkerDrag::aborted (bool moved) /******************************************************************************/ -MappingLinearDrag::MappingLinearDrag (Editor* e, ArdourCanvas::Item* i, Temporal::TempoMap::WritableSharedPtr& wmap) +MappingLinearDrag::MappingLinearDrag (Editor* e, ArdourCanvas::Item* i, Temporal::TempoMap::WritableSharedPtr& wmap, TempoPoint& tp, TempoPoint& ap, XMLNode& before) : Drag (e, i, Temporal::BeatTime) - , _tempo (0) + , _tempo (tp) + , _after (ap) , _grab_bpm (0) , map (wmap) - , _before_state (0) + , _before_state (&before) , _drag_valid (true) { DEBUG_TRACE (DEBUG::Drags, "New MappingLinearDrag\n"); @@ -3493,33 +3494,23 @@ MappingLinearDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); - _tempo = const_cast (&map->metric_at (raw_grab_time().beats()).tempo()); - _grab_bpm = _tempo->note_types_per_minute(); - - if (adjusted_current_time (event, false) <= _tempo->time()) { - std::cerr << "too early for " << *_tempo << std::endl; - _drag_valid = false; - return; - } + _grab_bpm = _tempo.note_types_per_minute(); ostringstream sstr; - if (_tempo->continuing()) { - TempoPoint const * prev = map->previous_tempo (*_tempo); + if (_tempo.continuing()) { + TempoPoint const * prev = map->previous_tempo (_tempo); if (prev) { sstr << "end: " << fixed << setprecision(3) << prev->end_note_types_per_minute() << "\n"; } } - sstr << "start: " << fixed << setprecision(3) << _tempo->note_types_per_minute(); + sstr << "start: " << fixed << setprecision(3) << _tempo.note_types_per_minute(); show_verbose_cursor_text (sstr.str()); } void MappingLinearDrag::setup_pointer_offset () { - /* get current state */ - _before_state = &map->get_state(); - Beats grab_qn = max (Beats(), raw_grab_time().beats()); uint32_t divisions = _editor->get_grid_beat_divisions (_editor->grid_type()); @@ -3539,14 +3530,26 @@ MappingLinearDrag::motion (GdkEvent* event, bool first_move) return; } - if (first_move) { - _editor->begin_reversible_command (_("map tempo")); + const double pixel_distance = current_pointer_x() - grab_x(); + const double spp = _editor->get_current_zoom(); + const double scaling_factor = 0.4 * (spp / 1000.); + const double delta = scaling_factor * pixel_distance; + + double new_bpm = std::min (300., std::max (3., _grab_bpm - delta)); + Temporal::Tempo new_tempo (new_bpm, _tempo.note_type()); + + /* Change both the previous tempo and the one under the pointer */ + + map->change_tempo (_tempo, new_tempo); + + /* if the user drags the last tempo, then _tempo and _focus are the + * same object. + */ + + if (_after.sclock() != _tempo.sclock()) { + map->change_tempo (_after, new_tempo); } - double new_bpm = std::max (1.5, _grab_bpm - ((current_pointer_x() - grab_x()) / 5.0)); - stringstream strs; - Temporal::Tempo new_tempo (new_bpm, _tempo->note_type()); - map->change_tempo (*_tempo, new_tempo); _editor->mid_tempo_change (Editor::MappingChanged); } @@ -3554,7 +3557,7 @@ void MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred) { if (!_drag_valid) { - _editor->abort_tempo_mapping (); + aborted (false); return; } @@ -3572,7 +3575,7 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred) XMLNode &after = map->get_state(); - _editor->session()->add_command (new Temporal::TempoCommand (_("move BBT point"), _before_state, &after)); + _editor->session()->add_command (new Temporal::TempoCommand (_("stretch tempo"), _before_state, &after)); _editor->commit_reversible_command (); /* 2nd argument means "update tempo map display after the new map is @@ -3585,8 +3588,9 @@ MappingLinearDrag::finished (GdkEvent* event, bool movement_occurred) } void -MappingLinearDrag::aborted (bool moved) +MappingLinearDrag::aborted (bool /* moved */) { + _editor->abort_reversible_command (); _editor->abort_tempo_mapping (); } @@ -3791,10 +3795,9 @@ MappingTwistDrag::motion (GdkEvent* event, bool first_move) const double pixel_distance = last_pointer_x() - _drags->current_pointer_x(); const double spp = _editor->get_current_zoom(); - const double scaling_factor = 0.4 * (spp / 1000.); + const double scaling_factor = 0.4 * (spp / 1500.); delta += scaling_factor * pixel_distance; - std::cerr << "pixels: " << pixel_distance << " @ " << spp << " spp SF " << scaling_factor << " => delta " << delta << std::endl; map->twist_tempi (prev, focus, next, initial_npm + delta); _editor->mid_tempo_change (Editor::MappingChanged); diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index babd27c2fc..c203ec48ed 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -915,7 +915,7 @@ private: class MappingLinearDrag : public Drag { public: - MappingLinearDrag (Editor *, ArdourCanvas::Item *, Temporal::TempoMap::WritableSharedPtr&); + MappingLinearDrag (Editor *, ArdourCanvas::Item *, Temporal::TempoMap::WritableSharedPtr&, Temporal::TempoPoint&, Temporal::TempoPoint& after, XMLNode& before_state); void start_grab (GdkEvent *, Gdk::Cursor* c = 0); void motion (GdkEvent *, bool); @@ -933,7 +933,8 @@ public: void setup_pointer_offset (); private: - Temporal::TempoPoint* _tempo; + Temporal::TempoPoint& _tempo; + Temporal::TempoPoint& _after; double _grab_bpm; Temporal::TempoMap::WritableSharedPtr map; diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index c2938a27fc..4fff942cb5 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -2928,6 +2928,11 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event) return; } + if (_cursor_stack.empty() || _cursor_stack.back() != cursors()->time_fx) { + /* Not close enough to a beat line to start any mapping drag */ + return; + } + Temporal::TempoMap::WritableSharedPtr map = begin_tempo_mapping (); /* Decide between a tempo twist drag, which we do if the @@ -2941,33 +2946,20 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event) TempoPoint* after = const_cast (map->next_tempo (tempo)); - if (!after || dynamic_cast(after)) { - /* Drag on the bar, not the cursor: just adjust tempo up or - * down. - */ - _drags->set (new MappingLinearDrag (this, item, map), event); - return; - } - - /* Use cursor state to determine if we are close enough to a beat line - * to do a twist. We computed that in the motion handler. - */ - - if (_cursor_stack.empty() || _cursor_stack.back() != cursors()->time_fx) { - return; - } - - - BBT_Argument bbt = map->bbt_at (pointer_time); - bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ()); + /* Create a new marker, or use the under the mouse */ + XMLNode* before_state = &map->get_state(); TempoPoint* before; TempoPoint* focus; - /* Reversible command starts here, must be ended/aborted in drag */ + bool stretch = false; - begin_reversible_command (_("map tempo/twist")); - XMLNode* before_state = &map->get_state(); + if (!after || dynamic_cast(after)) { + stretch = true; + } + + BBT_Argument bbt = map->bbt_at (pointer_time); + bbt = BBT_Argument (bbt.reference(), bbt.round_to_beat ()); if (tempo.bbt() < bbt) { @@ -2988,12 +2980,24 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event) before = const_cast (map->previous_tempo (tempo)); if (!before) { + delete before_state; return; } focus = &tempo; } - _drags->set (new MappingTwistDrag (this, item, map, *before, *focus, *after, *before_state), event); + /* Reversible commands start here, must be ended/aborted in drag */ + if (stretch) { + begin_reversible_command (_("map tempo/stretch")); + std::cerr << "STRETCH\n"; + _drags->set (new MappingLinearDrag (this, item, map, tempo, *focus, *before_state), event); + return; + } + + + std::cerr << "TWIST\n"; + begin_reversible_command (_("map tempo/twist")); + _drags->set (new MappingTwistDrag (this, item, map, *before, *focus, *after, *before_state), event); }