From d95ac699a090b0ff9eaabb882336791e21cb4659 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 7 Aug 2025 10:20:15 -0600 Subject: [PATCH 01/32] pianoroll: correctly disconnect from update timer --- gtk2_ardour/pianoroll.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gtk2_ardour/pianoroll.cc b/gtk2_ardour/pianoroll.cc index bdfa9acce9..bb389989cc 100644 --- a/gtk2_ardour/pianoroll.cc +++ b/gtk2_ardour/pianoroll.cc @@ -1378,6 +1378,7 @@ Pianoroll::set_region (std::shared_ptr region) std::shared_ptr r (std::dynamic_pointer_cast (region)); if (!r || !region) { + _update_connection.disconnect (); return; } @@ -1748,9 +1749,7 @@ Pianoroll::set_session (ARDOUR::Session* s) map_transport_state (); } - if (!_session) { - _update_connection.disconnect (); - } else { + if (_session) { zoom_to_show (timecnt_t (timepos_t (max_extents_scale() * max_zoom_extent ().second.samples()))); } } From da2ddda05f28cce7003a08fe02b4fdf2ca7eaba6 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 7 Aug 2025 16:03:41 +0200 Subject: [PATCH 02/32] NO-OP: sort config variable --- gtk2_ardour/ui_config_vars.inc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk2_ardour/ui_config_vars.inc.h b/gtk2_ardour/ui_config_vars.inc.h index 2518e476c5..9b59b2c3da 100644 --- a/gtk2_ardour/ui_config_vars.inc.h +++ b/gtk2_ardour/ui_config_vars.inc.h @@ -126,10 +126,10 @@ UI_CONFIG_VARIABLE (uint32_t, action_table_columns, "action-table-columns", 3) UI_CONFIG_VARIABLE (bool, hide_splash_screen, "hide-splash-screen", true) UI_CONFIG_VARIABLE (bool, check_announcements, "check-announcements,", true) UI_CONFIG_VARIABLE (bool, use_wm_visibility, "use-wm-visibility", true) +UI_CONFIG_VARIABLE (std::string, stripable_color_palette, "stripable-color-palette", "#AA3939:#FFAAAA:#D46A6A:#801515:#550000:#AA8E39:#FFEAAA:#D4BA6A:#806515:#554000:#343477:#8080B3:#565695:#1A1A59:#09093B:#2D882D:#88CC88:#55AA55:#116611:#004400") /* Gtk::ColorSelection::palette_to_string */ UI_CONFIG_VARIABLE (bool, use_palette_for_new_track, "use-palette-for-new-track", true) UI_CONFIG_VARIABLE (bool, use_palette_for_new_bus, "use-palette-for-new-bus", true) UI_CONFIG_VARIABLE (bool, use_palette_for_new_vca, "use-palette-for-new-vca", true) -UI_CONFIG_VARIABLE (std::string, stripable_color_palette, "stripable-color-palette", "#AA3939:#FFAAAA:#D46A6A:#801515:#550000:#AA8E39:#FFEAAA:#D4BA6A:#806515:#554000:#343477:#8080B3:#565695:#1A1A59:#09093B:#2D882D:#88CC88:#55AA55:#116611:#004400") /* Gtk::ColorSelection::palette_to_string */ UI_CONFIG_VARIABLE (bool, use_note_bars_for_velocity, "use-note-bars-for-velocity", true) UI_CONFIG_VARIABLE (bool, use_note_color_for_velocity, "use-note-color-for-velocity", true) UI_CONFIG_VARIABLE (bool, show_snapped_cursor, "show-snapped-cursor", true) From 3320e7d5f9069dadb6ba530cf281963fe2b5405d Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 7 Aug 2025 19:45:58 +0200 Subject: [PATCH 03/32] Set MIDI region color to use track's color or default fg. This broke in a550b6482f1 --- gtk2_ardour/midi_streamview.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index b266129dbd..5a7ab3c2ad 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -122,11 +122,11 @@ MidiStreamView::create_region_view (std::shared_ptr r, bool /*wfd*/, boo if (recording) { region_view = new MidiRegionView ( _region_group, _trackview.editor(), _trackview, region, - _samples_per_pixel, MidiViewBackground::region_color(), recording, + _samples_per_pixel, StreamView::region_color, recording, TimeAxisViewItem::Visibility(TimeAxisViewItem::ShowFrame)); } else { region_view = new MidiRegionView (_region_group, _trackview.editor(), _trackview, region, - _samples_per_pixel, MidiViewBackground::region_color()); + _samples_per_pixel, StreamView::region_color); } region_view->init (false); From b5f1c5b0dd1f7060aef5235a1b0ed8c488ff6d1c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 7 Aug 2025 12:26:12 -0600 Subject: [PATCH 04/32] Fix potential infinite loop when iterating over ControlLists If you have the "wrong" kind of MIDI CC, the interpolation for the list is set to Linear, which causes interpolation to return audio time stamps instead of beat time. Because of the asymmetrical transforms, this causes iterators over the Sequence to go haywire and create an infinite loop. This fix changes ControlList behavior to always return times in the time domain of the list. --- libs/evoral/ControlList.cc | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/libs/evoral/ControlList.cc b/libs/evoral/ControlList.cc index b6ec83b3ad..6ef47917b0 100644 --- a/libs/evoral/ControlList.cc +++ b/libs/evoral/ControlList.cc @@ -1883,20 +1883,33 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const& } /* This method is ONLY used for interpolating to generate value/time - * duples not present in the actual ControlList, and because of this, - * the desired time domain is always audio time. + * duples not present in the actual ControlList */ - double a = first->when.superclocks (); - double b = next->when.superclocks (); - const double slope = (b - a) / (next->value - first->value); - assert (slope != 0); + double slope; + + if (time_domain() == Temporal::AudioTime) { + double a = first->when.superclocks (); + double b = next->when.superclocks (); + slope = (b - a) / (next->value - first->value); + assert (slope != 0); + double t = start_time.superclocks (); + double dt = fmod (t, fabs (slope)); + t += fabs (slope) - dt; + x = timecnt_t::from_superclock (t + 1); + y = rint (first->value + (t - a) / slope); + } else { + double a = first->when.beats().to_ticks(); + double b = next->when.beats().to_ticks(); + slope = (b - a) / (next->value - first->value); + assert (slope != 0); + double t = start_time.beats ().to_ticks(); + double dt = fmod (t, fabs (slope)); + t += fabs (slope) - dt; + x = timecnt_t::from_ticks (t + 1); + y = rint (first->value + (t - a) / slope); + } - double t = start_time.superclocks (); - double dt = fmod (t, fabs (slope)); - t += fabs (slope) - dt; - x = timecnt_t::from_superclock (t + 1); - y = rint (first->value + (t - a) / slope); if (slope > 0) { y = std::max (first->value, std::min (next->value, y)); } else { From dfa12dedcd1ccae61aab50d1f55a696df0b177d2 Mon Sep 17 00:00:00 2001 From: Franke Burgarino Date: Thu, 7 Aug 2025 10:59:15 -0500 Subject: [PATCH 05/32] MCU: make dynamics subview show actual values --- libs/surfaces/mackie/strip.cc | 11 +++++++++++ libs/surfaces/mackie/subview.cc | 6 +----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc index 453b7a4808..a47dbb7cbc 100644 --- a/libs/surfaces/mackie/strip.cc +++ b/libs/surfaces/mackie/strip.cc @@ -719,6 +719,17 @@ Strip::remove_units (std::string s) { s = std::regex_replace (s, std::regex(" dB$"), ""); s = std::regex_replace (s, std::regex(" ms$"), ""); + // convert seconds to milliseconds + if (s.rfind(" s") != string::npos) { + char buf[32]; + s = std::regex_replace (s, std::regex(" s$"), ""); + if (sprintf(buf, "%2.0f", 1000.0*stof(s)) >= 0) { + s = std::string (buf); + } else { + DEBUG_TRACE (DEBUG::MackieControl, "couldn't convert string to float\n"); + } + } + return s; } diff --git a/libs/surfaces/mackie/subview.cc b/libs/surfaces/mackie/subview.cc index c9045e3de5..a4f8b82ac4 100644 --- a/libs/surfaces/mackie/subview.cc +++ b/libs/surfaces/mackie/subview.cc @@ -550,11 +550,7 @@ DynamicsSubview::notify_change (std::weak_ptr pc, uin if (control) { float val = control->get_value(); - if (control == _subview_stripable->mapped_control (Comp_Mode)) { - pending_display[1] = control->get_user_string (); - } else { - do_parameter_display(pending_display[1], control->desc(), val, strip, true); - } + pending_display[1] = Strip::remove_units(control->get_user_string()); /* update pot/encoder */ strip->surface()->write (vpot->set (control->internal_to_interface (val), true, Pot::wrap)); } From e3710bd0a2a5c61a5607b755720b372d420ee2db Mon Sep 17 00:00:00 2001 From: Franke Burgarino Date: Thu, 7 Aug 2025 16:16:19 -0500 Subject: [PATCH 06/32] MCU: allow scrolling to gate controls in the dynamics subview --- libs/surfaces/mackie/subview.cc | 31 +++++++++++++++++++++++++++---- libs/surfaces/mackie/subview.h | 5 +++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/libs/surfaces/mackie/subview.cc b/libs/surfaces/mackie/subview.cc index a4f8b82ac4..7398f2db7f 100644 --- a/libs/surfaces/mackie/subview.cc +++ b/libs/surfaces/mackie/subview.cc @@ -420,6 +420,7 @@ void EQSubview::notify_change (std::weak_ptr pc, uint DynamicsSubview::DynamicsSubview(MackieControlProtocol& mcp, std::shared_ptr subview_stripable) : Subview(mcp, subview_stripable) + , _current_bank(0) {} DynamicsSubview::~DynamicsSubview() @@ -450,13 +451,15 @@ void DynamicsSubview::setup_vpot( Pot* vpot, std::string pending_display[2]) { - const uint32_t global_strip_position = _mcp.global_index (*strip); - store_pointers(strip, vpot, pending_display, global_strip_position); + const uint32_t global_strip_position = _mcp.global_index (*strip) + _current_bank; + store_pointers(strip, vpot, pending_display, global_strip_position - _current_bank); if (!_subview_stripable) { return; } + available.clear(); + std::shared_ptr hpfc = _subview_stripable->mapped_control (HPF_Freq); std::shared_ptr lpfc = _subview_stripable->mapped_control (LPF_Freq); std::shared_ptr fec = _subview_stripable->mapped_control (HPF_Enable); // shared HP/LP @@ -478,7 +481,6 @@ void DynamicsSubview::setup_vpot( * order shown above. */ - std::vector, std::string > > available; std::vector params; //Mixbus32C needs to spill the filter controls into the comp section @@ -535,7 +537,7 @@ DynamicsSubview::notify_change (std::weak_ptr pc, uin Strip* strip = 0; Pot* vpot = 0; std::string* pending_display = 0; - if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position)) + if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position - _current_bank)) { return; } @@ -556,6 +558,27 @@ DynamicsSubview::notify_change (std::weak_ptr pc, uin } } +bool DynamicsSubview::handle_cursor_left_press() +{ + if (_current_bank >= 1) + { + _current_bank -= 1; + mcp().redisplay_subview_mode(); + } + + return true; +} + +bool DynamicsSubview::handle_cursor_right_press() +{ + if (available.size() > _current_bank + 1) { + _current_bank += 1; + mcp().redisplay_subview_mode(); + } + + return true; +} + SendsSubview::SendsSubview(MackieControlProtocol& mcp, std::shared_ptr subview_stripable) diff --git a/libs/surfaces/mackie/subview.h b/libs/surfaces/mackie/subview.h index 5a5135cd82..4b0a1987ee 100644 --- a/libs/surfaces/mackie/subview.h +++ b/libs/surfaces/mackie/subview.h @@ -142,6 +142,11 @@ class DynamicsSubview : public Subview { Pot* vpot, std::string pending_display[2]); void notify_change (std::weak_ptr, uint32_t global_strip_position, bool force, bool propagate_mode_change); + virtual bool handle_cursor_left_press(); + virtual bool handle_cursor_right_press(); + protected: + uint32_t _current_bank; + std::vector, std::string>> available; }; class SendsSubview : public Subview { From ba86481d37789874f567652353bc6d159db27a5d Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 8 Aug 2025 01:56:34 +0200 Subject: [PATCH 07/32] Fix region UI State save error message XMLTree::write() returns true on success. Start sentence with an upper-case letter. --- gtk2_ardour/region_ui_settings.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk2_ardour/region_ui_settings.cc b/gtk2_ardour/region_ui_settings.cc index c4f4efe523..d208c5f03e 100644 --- a/gtk2_ardour/region_ui_settings.cc +++ b/gtk2_ardour/region_ui_settings.cc @@ -141,8 +141,8 @@ RegionUISettingsManager::save (std::string const & path) state_tree.set_root (&get_state()); state_tree.set_filename (path); - if (state_tree.write()) { - error << string_compose (_("could not save region GUI settings to %1"), path) << endmsg; + if (!state_tree.write()) { + error << string_compose (_("Could not save region GUI settings to %1"), path) << endmsg; } } From 2be15f035d496e9d70e91b00dcec6be1b1e3c6a7 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 8 Aug 2025 11:59:02 +0200 Subject: [PATCH 08/32] Fix Lua Bindings (amend 1ca53a99d91) Already registered classes can be extended as-is. Deriving them again will override previous bindings. --- libs/ardour/luabindings.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc index 119a3cdb83..4b8db7f199 100644 --- a/libs/ardour/luabindings.cc +++ b/libs/ardour/luabindings.cc @@ -3528,7 +3528,7 @@ LuaBindings::non_rt (lua_State* L) .addFunction ("add_master_bus", &Session::add_master_bus) .endClass () - .deriveWSPtrClass ("Route") + .beginWSPtrClass ("Route") .addFunction ("save_as_template", &Route::save_as_template) .addFunction ("add_sidechain", &Route::add_sidechain) .addFunction ("remove_sidechain", &Route::remove_sidechain) From 4f5848d85c968e1a1158bfd53108127e5846049b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 11:35:14 -0600 Subject: [PATCH 09/32] action-ify stationary playhead mgmt; fix up follow-playhead action handling --- gtk2_ardour/ardour.keys.in | 4 +-- gtk2_ardour/ardour.menus.in | 2 +- gtk2_ardour/editing_context.cc | 65 ++++++++++++++++++++++++---------- gtk2_ardour/editing_context.h | 13 ++++++- gtk2_ardour/editor.cc | 25 ++----------- gtk2_ardour/editor.h | 12 ------- gtk2_ardour/editor_actions.cc | 2 -- gtk2_ardour/public_editor.h | 5 --- 8 files changed, 63 insertions(+), 65 deletions(-) diff --git a/gtk2_ardour/ardour.keys.in b/gtk2_ardour/ardour.keys.in index 5bad418aed..839936a471 100644 --- a/gtk2_ardour/ardour.keys.in +++ b/gtk2_ardour/ardour.keys.in @@ -210,8 +210,8 @@ This mode provides many different operations on both regions and control points, @edit|Editor/multi-duplicate| <@SECONDARY@>d|duplicate (multi) @select|Editor/select-all-in-punch-range| <@TERTIARY@>d|select all in punch range @vis|Editor/fit-selection| f|fit selection vertically -@edit|Editing/toggle-follow-playhead| <@PRIMARY@>f|toggle playhead tracking -@edit|Editor/toggle-stationary-playhead| <@TERTIARY@>f|toggle stationary playhead +@edit|EditorEditing/toggle-follow-playhead| <@PRIMARY@>f|toggle playhead tracking +@edit|EditorEditing/toggle-stationary-playhead| <@TERTIARY@>f|toggle stationary playhead @rop|Region/show-rhythm-ferret| <@SECONDARY@>f|show rhythm ferret window @wvis|Common/ToggleMaximalEditor| <@PRIMARY@><@SECONDARY@>f|maximise editor space @wvis|Common/ToggleMaximalMixer| <@PRIMARY@><@TERTIARY@>f|maximise mixer space diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index d66a2fb919..8e18630777 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -187,7 +187,7 @@ - + diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 3200666009..723f520142 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -153,6 +153,8 @@ EditingContext::EditingContext (std::string const & name) , grid_lines (nullptr) , time_line_group (nullptr) , temporary_zoom_focus_change (false) + , _dragging_playhead (false) + { using namespace Gtk::Menu_Helpers; @@ -338,6 +340,10 @@ EditingContext::set_action_defaults () follow_playhead_action->set_active (true); follow_playhead_action->set_active (false); #endif + + stationary_playhead_action->set_active (true); + stationary_playhead_action->set_active (false); + mouse_mode_actions[Editing::MouseObject]->set_active (false); mouse_mode_actions[Editing::MouseObject]->set_active (true); zoom_focus_actions[Editing::ZoomFocusLeft]->set_active (false); @@ -373,10 +379,8 @@ EditingContext::register_common_actions (Bindings* common_bindings, std::string reg_sens (_common_actions, "temporal-zoom-out", _("Zoom Out"), sigc::bind (sigc::mem_fun (*this, &EditingContext::temporal_zoom_step), true)); reg_sens (_common_actions, "temporal-zoom-in", _("Zoom In"), sigc::bind (sigc::mem_fun (*this, &EditingContext::temporal_zoom_step), false)); - /* toggle action that represents state */ - follow_playhead_action = toggle_reg_sens (_common_actions, "follow-playhead", _("Follow Playhead"), sigc::mem_fun (*this, &EditingContext::follow_playhead_chosen)); - /* invokable action that toggles the stateful action */ - reg_sens (_common_actions, "toggle-follow-playhead", _("Follow Playhead"), sigc::mem_fun (*this, &EditingContext::toggle_follow_playhead)); + follow_playhead_action = toggle_reg_sens (_common_actions, "toggle-follow-playhead", _("Follow Playhead"), sigc::mem_fun (*this, &EditingContext::follow_playhead_chosen)); + stationary_playhead_action = toggle_reg_sens (_common_actions, "toggle-stationary-playhead", _("Stationary Playhead"), (mem_fun(*this, &EditingContext::stationary_playhead_chosen))); undo_action = reg_sens (_common_actions, "undo", S_("Command|Undo"), sigc::bind (sigc::mem_fun (*this, &EditingContext::undo), 1U)); redo_action = reg_sens (_common_actions, "redo", _("Redo"), sigc::bind (sigc::mem_fun (*this, &EditingContext::redo), 1U)); @@ -1174,6 +1178,34 @@ EditingContext::time_domain () const return Temporal::BeatTime; } +void +EditingContext::toggle_stationary_playhead () +{ + stationary_playhead_action->set_active (!stationary_playhead_action->get_active ()); +} + +void +EditingContext::stationary_playhead_chosen () +{ + instant_save (); +} + +void +EditingContext::set_stationary_playhead (bool yn) +{ + stationary_playhead_action->set_active (yn); +} + +bool +EditingContext::stationary_playhead () const +{ + if (!stationary_playhead_action) { + return false; + } + + return stationary_playhead_action->get_active (); +} + void EditingContext::toggle_follow_playhead () { @@ -1200,6 +1232,16 @@ EditingContext::set_follow_playhead (bool yn, bool catch_up) } } +bool +EditingContext::follow_playhead() const +{ + if (!follow_playhead_action) { + return false; + } + + return follow_playhead_action->get_active (); +} + double EditingContext::time_to_pixel (timepos_t const & pos) const { @@ -2552,11 +2594,6 @@ EditingContext::play_note_selection_clicked () UIConfiguration::instance().set_sound_midi_notes (!UIConfiguration::instance().get_sound_midi_notes()); } -void -EditingContext::follow_playhead_clicked () -{ -} - void EditingContext::cycle_zoom_focus () { @@ -3227,13 +3264,3 @@ EditingContext::center_screen_internal (samplepos_t sample, float page) reset_x_origin (sample); } - -bool -EditingContext::follow_playhead() const -{ - if (!follow_playhead_action) { - return false; - } - - return follow_playhead_action->get_active (); -} diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index 75fcb70d98..0b5fa4ae87 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -503,6 +503,14 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, void enable_automation_bindings (); void disable_automation_bindings (); + /* playhead/screen stuff */ + + void set_stationary_playhead (bool yn); + void toggle_stationary_playhead (); + bool stationary_playhead() const; + + bool dragging_playhead () const { return _dragging_playhead; } + protected: std::string _name; bool within_track_canvas; @@ -573,7 +581,6 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, virtual void play_note_selection_clicked(); virtual void note_mode_clicked() {} - virtual void follow_playhead_clicked (); virtual void full_zoom_clicked() {}; virtual void set_visible_channel (int) {} @@ -596,6 +603,9 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, Glib::RefPtr follow_playhead_action; void follow_playhead_chosen (); + Glib::RefPtr stationary_playhead_action; + void stationary_playhead_chosen (); + /* selection process */ Selection* selection; @@ -821,4 +831,5 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, virtual void automation_move_points_earlier () {}; bool temporary_zoom_focus_change; + bool _dragging_playhead; }; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 7ebf1a198b..b5a11c3cd2 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -315,9 +315,7 @@ Editor::Editor () , ignore_gui_changes (false) , lock_dialog (nullptr) , _last_event_time (g_get_monotonic_time ()) - , _dragging_playhead (false) , ignore_map_change (false) - , _stationary_playhead (false) , _maximised (false) , global_rect_group (nullptr) , tempo_marker_menu (nullptr) @@ -2358,7 +2356,7 @@ Editor::get_state () const node->set_property ("maximised", _maximised); node->set_property ("follow-playhead", follow_playhead()); - node->set_property ("stationary-playhead", _stationary_playhead); + node->set_property ("stationary-playhead", stationary_playhead()); node->set_property ("mouse-mode", current_mouse_mode()); node->set_property ("join-object-range", smart_mode_action->get_active ()); @@ -3406,25 +3404,6 @@ Editor::cycle_marker_click_behavior () } } -void -Editor::toggle_stationary_playhead () -{ - RefPtr tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead")); - set_stationary_playhead (tact->get_active()); -} - -void -Editor::set_stationary_playhead (bool yn) -{ - if (_stationary_playhead != yn) { - if ((_stationary_playhead = yn) == true) { - /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */ - // update_current_screen (); - } - instant_save (); - } -} - bool Editor::show_touched_automation() const { @@ -5310,7 +5289,7 @@ Editor::super_rapid_screen_update () return; } - if (!_stationary_playhead) { + if (!stationary_playhead()) { reset_x_origin_to_follow_playhead (); } else { samplepos_t const sample = _playhead_cursor->current_sample (); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index b2d0b57f03..3729088504 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -320,14 +320,6 @@ public: void sequence_regions (); - /* playhead/screen stuff */ - - void set_stationary_playhead (bool yn); - void toggle_stationary_playhead (); - bool stationary_playhead() const { return _stationary_playhead; } - - bool dragging_playhead () const { return _dragging_playhead; } - void toggle_zero_line_visibility (); void set_summary (); void set_group_tabs (); @@ -1488,8 +1480,6 @@ private: ARDOUR::PlaylistSet motion_frozen_playlists; - bool _dragging_playhead; - void marker_drag_motion_callback (GdkEvent*); void marker_drag_finished_callback (GdkEvent*); @@ -1645,8 +1635,6 @@ private: /* display control */ - /// true if we scroll the tracks rather than the playhead - bool _stationary_playhead; /// true if we are in fullscreen mode bool _maximised; diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 24093e3636..2e5970bced 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -478,8 +478,6 @@ Editor::register_actions () act = reg_sens (editor_actions, "remove-last-capture", _("Remove Last Capture"), (sigc::mem_fun(*this, &Editor::remove_last_capture))); act = reg_sens (editor_actions, "tag-last-capture", _("Tag Last Capture"), (sigc::mem_fun(*this, &Editor::tag_last_capture))); - ActionManager::register_toggle_action (editor_actions, "toggle-stationary-playhead", _("Stationary Playhead"), (mem_fun(*this, &Editor::toggle_stationary_playhead))); - show_touched_automation_action = ActionManager::register_toggle_action (editor_actions, "show-touched-automation", _("Show Automation Lane on Touch"), (mem_fun(*this, &Editor::toggle_show_touched_automation))); act = reg_sens (editor_actions, "insert-time", _("Insert Time"), (sigc::mem_fun(*this, &Editor::do_insert_time))); diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 295a0081a6..eb0e46b9bf 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -278,14 +278,9 @@ public: virtual void hide_track_in_display (TimeAxisView* tv, bool apply_to_selection = false) = 0; virtual void show_track_in_display (TimeAxisView* tv, bool move_into_view = false) = 0; - virtual void set_stationary_playhead (bool yn) = 0; - virtual void toggle_stationary_playhead () = 0; - virtual bool stationary_playhead() const = 0; - virtual void toggle_cue_behavior () = 0; /** @return true if the playhead is currently being dragged, otherwise false */ - virtual bool dragging_playhead () const = 0; virtual samplepos_t leftmost_sample() const = 0; virtual samplecnt_t current_page_samples() const = 0; virtual double visible_canvas_height () const = 0; From 28e00828684d4b68c809541de2770ce099e3a51f Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 12:12:09 -0600 Subject: [PATCH 10/32] use std::unique_ptr for a couple of EditingContext members --- gtk2_ardour/audio_clip_editor.cc | 2 -- gtk2_ardour/editing_context.cc | 9 ++------- gtk2_ardour/editing_context.h | 8 ++++---- gtk2_ardour/editor.cc | 1 - gtk2_ardour/editor_canvas.cc | 2 +- gtk2_ardour/editor_drag.cc | 18 +++++++++--------- gtk2_ardour/midi_view.cc | 8 ++++---- gtk2_ardour/pianoroll.cc | 2 +- gtk2_ardour/velocity_display.cc | 6 +++--- 9 files changed, 24 insertions(+), 32 deletions(-) diff --git a/gtk2_ardour/audio_clip_editor.cc b/gtk2_ardour/audio_clip_editor.cc index 18420b0ca6..5b77c2fead 100644 --- a/gtk2_ardour/audio_clip_editor.cc +++ b/gtk2_ardour/audio_clip_editor.cc @@ -230,8 +230,6 @@ AudioClipEditor::build_canvas () cursor_scroll_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars)); h_scroll_group->set_position (Duple (_timeline_origin, 0.)); - _verbose_cursor = new VerboseCursor (*this); - // _playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event, X_("playhead")); _playhead_cursor = new EditorCursor (*this, X_("playhead")); _playhead_cursor->set_sensitive (UIConfiguration::instance().get_sensitize_playhead()); diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 723f520142..3b23559397 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -129,7 +129,6 @@ EditingContext::EditingContext (std::string const & name) , selection (new Selection (this, true)) , cut_buffer (new Selection (this, false)) , _selection_memento (new SelectionMemento()) - , _verbose_cursor (nullptr) , samples_per_pixel (2048) , bbt_ruler_scale (bbt_show_many) , bbt_bars (0) @@ -256,9 +255,6 @@ EditingContext::~EditingContext() ActionManager::drop_action_group (channel_actions); ActionManager::drop_action_group (velocity_actions); ActionManager::drop_action_group (zoom_actions); - - delete _verbose_cursor; - delete grid_lines; } void @@ -3080,8 +3076,7 @@ void EditingContext::drop_grid () { hide_grid_lines (); - delete grid_lines; - grid_lines = nullptr; + grid_lines.reset (); } void @@ -3100,7 +3095,7 @@ EditingContext::maybe_draw_grid_lines (ArdourCanvas::Container* group) } if (!grid_lines) { - grid_lines = new GridLines (*this, group, ArdourCanvas::LineSet::Vertical); + grid_lines.reset (new GridLines (*this, group, ArdourCanvas::LineSet::Vertical)); } diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index 0b5fa4ae87..08caf25ff1 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -385,8 +385,8 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, static MouseCursors const* cursors () { return _cursors; } - virtual VerboseCursor* verbose_cursor () const { - return _verbose_cursor; + virtual VerboseCursor& verbose_cursor () const { + return *_verbose_cursor; } virtual void set_snapped_cursor_position (Temporal::timepos_t const & pos) = 0; @@ -616,7 +616,7 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, static MouseCursors* _cursors; - VerboseCursor* _verbose_cursor; + std::unique_ptr _verbose_cursor; samplecnt_t samples_per_pixel; @@ -785,7 +785,7 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, ARDOUR::Location* transport_loop_location(); std::vector grid_marks; - GridLines* grid_lines; + std::unique_ptr grid_lines; ArdourCanvas::Container* time_line_group; void drop_grid (); diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index b5a11c3cd2..2401dd0326 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -738,7 +738,6 @@ Editor::~Editor() delete _track_canvas_viewport; delete _drags; delete nudge_clock; - delete _verbose_cursor; delete _region_peak_cursor; delete quantize_dialog; delete _summary; diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index f854970a59..d3e5f97936 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -95,7 +95,7 @@ Editor::initialize_canvas () */ no_scroll_group = new ArdourCanvas::Container (_track_canvas->root()); - _verbose_cursor = new VerboseCursor (*this); + _verbose_cursor.reset (new VerboseCursor (*this)); ArdourCanvas::ScrollGroup* hsg; ArdourCanvas::ScrollGroup* hg; diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index a586e51fe1..ebaa890d92 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -425,8 +425,8 @@ Drag::end_grab (GdkEvent* event) _item->ungrab (); finished (event, _starting_point_passed); - - editing_context.verbose_cursor ()->hide (); + + editing_context.verbose_cursor().hide (); return _starting_point_passed; } @@ -595,28 +595,28 @@ Drag::abort () aborted (_move_threshold_passed); editing_context.stop_canvas_autoscroll (); - editing_context.verbose_cursor ()->hide (); + editing_context.verbose_cursor().hide (); } void Drag::show_verbose_cursor_time (timepos_t const& pos) { - editing_context.verbose_cursor ()->set_time (pos.samples ()); - editing_context.verbose_cursor ()->show (); + editing_context.verbose_cursor().set_time (pos.samples ()); + editing_context.verbose_cursor().show (); } void Drag::show_verbose_cursor_duration (timepos_t const& start, timepos_t const& end, double /*xoffset*/) { - editing_context.verbose_cursor ()->set_duration (start.samples (), end.samples ()); - editing_context.verbose_cursor ()->show (); + editing_context.verbose_cursor().set_duration (start.samples (), end.samples ()); + editing_context.verbose_cursor().show (); } void Drag::show_verbose_cursor_text (string const& text) { - editing_context.verbose_cursor ()->set (text); - editing_context.verbose_cursor ()->show (); + editing_context.verbose_cursor().set (text); + editing_context.verbose_cursor().show (); } void diff --git a/gtk2_ardour/midi_view.cc b/gtk2_ardour/midi_view.cc index 4ea88a833d..aa932d7005 100644 --- a/gtk2_ardour/midi_view.cc +++ b/gtk2_ardour/midi_view.cc @@ -4478,7 +4478,7 @@ MidiView::remove_ghost_note () void MidiView::hide_verbose_cursor () { - _editing_context.verbose_cursor()->hide (); + _editing_context.verbose_cursor().hide (); _midi_context.set_note_highlight (NO_MIDI_NOTE); } @@ -4865,9 +4865,9 @@ MidiView::show_verbose_cursor (std::shared_ptr n) const void MidiView::show_verbose_cursor (string const & text, double xoffset, double yoffset) const { - _editing_context.verbose_cursor()->set (text); - _editing_context.verbose_cursor()->show (); - _editing_context.verbose_cursor()->set_offset (ArdourCanvas::Duple (xoffset, yoffset)); + _editing_context.verbose_cursor().set (text); + _editing_context.verbose_cursor().show (); + _editing_context.verbose_cursor().set_offset (ArdourCanvas::Duple (xoffset, yoffset)); } diff --git a/gtk2_ardour/pianoroll.cc b/gtk2_ardour/pianoroll.cc index bb389989cc..eb4b164592 100644 --- a/gtk2_ardour/pianoroll.cc +++ b/gtk2_ardour/pianoroll.cc @@ -453,7 +453,7 @@ Pianoroll::build_canvas () cursor_scroll_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars)); h_scroll_group->set_position (Duple (_timeline_origin, 0.)); - _verbose_cursor = new VerboseCursor (*this); + _verbose_cursor.reset (new VerboseCursor (*this)); // _playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event, X_("playhead")); _playhead_cursor = new EditorCursor (*this, X_("playhead")); diff --git a/gtk2_ardour/velocity_display.cc b/gtk2_ardour/velocity_display.cc index 806a837ad0..2a1fb9f1d9 100644 --- a/gtk2_ardour/velocity_display.cc +++ b/gtk2_ardour/velocity_display.cc @@ -327,9 +327,9 @@ VelocityDisplay::drag_lolli (ArdourCanvas::Lollipop* l, GdkEventMotion* ev) snprintf (buf, sizeof (buf), "Velocity %d (%d)", verbose_velocity, verbose_velocity - oldvel); } - editing_context.verbose_cursor()->set (buf); - editing_context.verbose_cursor()->show (); - editing_context.verbose_cursor()->set_offset (ArdourCanvas::Duple (10., 10.)); + editing_context.verbose_cursor().set (buf); + editing_context.verbose_cursor().show (); + editing_context.verbose_cursor().set_offset (ArdourCanvas::Duple (10., 10.)); } int From ed594c52177204166d2df9ccf38fcd059136564f Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 12:39:45 -0600 Subject: [PATCH 11/32] fix order of assembly for audio clip editor --- gtk2_ardour/audio_clip_editor.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gtk2_ardour/audio_clip_editor.cc b/gtk2_ardour/audio_clip_editor.cc index 5b77c2fead..adf5f4fd29 100644 --- a/gtk2_ardour/audio_clip_editor.cc +++ b/gtk2_ardour/audio_clip_editor.cc @@ -112,11 +112,9 @@ AudioClipEditor::AudioClipEditor (std::string const & name, bool with_transport) load_bindings (); register_actions (); - build_canvas (); - build_grid_type_menu (); - build_upper_toolbar (); + build_canvas (); build_lower_toolbar (); set_action_defaults (); From cee0ad349fc9a7eeba5bae6ec17ece04a69c1855 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 12:40:02 -0600 Subject: [PATCH 12/32] rename audio clip editor ruler member and fix colors --- gtk2_ardour/audio_clip_editor.cc | 20 ++++++++++---------- gtk2_ardour/audio_clip_editor.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gtk2_ardour/audio_clip_editor.cc b/gtk2_ardour/audio_clip_editor.cc index adf5f4fd29..321f04800c 100644 --- a/gtk2_ardour/audio_clip_editor.cc +++ b/gtk2_ardour/audio_clip_editor.cc @@ -211,14 +211,14 @@ AudioClipEditor::build_canvas () CANVAS_DEBUG_NAME (time_line_group, "audioclip time line group"); n_timebars = 0; - minsec_ruler = new ArdourCanvas::Ruler (time_line_group, clip_metric, ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height)); - // minsec_ruler->set_name ("audio clip editor ruler"); - minsec_ruler->set_font_description (UIConfiguration::instance ().get_SmallerFont ()); - minsec_ruler->set_fill_color (UIConfiguration::instance().color (X_("theme:bg1"))); - minsec_ruler->set_outline_color (UIConfiguration::instance().color (X_("theme:contrasting less"))); + main_ruler = new ArdourCanvas::Ruler (time_line_group, clip_metric, ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height)); + // main_ruler->set_name ("audio clip editor ruler"); + main_ruler->set_font_description (UIConfiguration::instance ().get_SmallerFont ()); + main_ruler->set_fill_color (UIConfiguration::instance().color (X_("ruler base"))); + main_ruler->set_outline_color (UIConfiguration::instance().color (X_("ruler text"))); n_timebars++; - minsec_ruler->Event.connect (sigc::mem_fun (*this, &CueEditor::ruler_event)); + main_ruler->Event.connect (sigc::mem_fun (*this, &CueEditor::ruler_event)); data_group = new ArdourCanvas::Container (hv_scroll_group); CANVAS_DEBUG_NAME (data_group, "cue data group"); @@ -387,8 +387,8 @@ AudioClipEditor::set_trigger (TriggerReference& tr) CueEditor::set_trigger (tr); rec_box.show (); - minsec_ruler->show (); - minsec_ruler->set_range (0, pixel_to_sample (_visible_canvas_width - 2.)); + main_ruler->show (); + main_ruler->set_range (0, pixel_to_sample (_visible_canvas_width - 2.)); } void @@ -421,7 +421,7 @@ AudioClipEditor::set_region (std::shared_ptr region) delete clip_metric; clip_metric = new ClipBBTMetric (ref); - minsec_ruler->set_metric (clip_metric); + main_ruler->set_metric (clip_metric); uint32_t n_chans = r->n_channels (); samplecnt_t len; @@ -478,7 +478,7 @@ AudioClipEditor::canvas_allocate (Gtk::Allocation& alloc) /* no track header here, "track width" is the whole canvas */ _track_canvas_width = _visible_canvas_width; - minsec_ruler->set (ArdourCanvas::Rect (2, 2, alloc.get_width() - 4, timebar_height)); + main_ruler->set (ArdourCanvas::Rect (2, 2, alloc.get_width() - 4, timebar_height)); position_lines (); diff --git a/gtk2_ardour/audio_clip_editor.h b/gtk2_ardour/audio_clip_editor.h index 81060fec57..511b804cc6 100644 --- a/gtk2_ardour/audio_clip_editor.h +++ b/gtk2_ardour/audio_clip_editor.h @@ -134,7 +134,7 @@ public: ArdourCanvas::Line* end_line; ArdourCanvas::Line* loop_line; ArdourCanvas::Container* ruler_container; - ArdourCanvas::Ruler* minsec_ruler; + ArdourCanvas::Ruler* main_ruler; class ClipBBTMetric : public ArdourCanvas::Ruler::Metric { From 12e846c3e9d76f42af9c078ea5b1b3c71bbb15b4 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 8 Aug 2025 21:51:36 +0200 Subject: [PATCH 13/32] macOS: allow Ardour to load unsigned plugins --- tools/osx_packaging/entitlements.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/osx_packaging/entitlements.plist b/tools/osx_packaging/entitlements.plist index cbd83446da..c407f7765c 100644 --- a/tools/osx_packaging/entitlements.plist +++ b/tools/osx_packaging/entitlements.plist @@ -18,5 +18,7 @@ com.apple.security.device.usb + com.apple.security.cs.disable-library-validation + From e682e1fde4e86b8691bc523b5669314597f00e1e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 14:20:04 -0600 Subject: [PATCH 14/32] refinements to infrastructure for an EditingContext's locally scoped tempo map --- gtk2_ardour/editing_context.cc | 14 ++++++++++---- gtk2_ardour/editing_context.h | 23 +++++++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 3b23559397..925ec6d29c 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -1629,11 +1629,17 @@ EditingContext::snap_relative_time_to_relative_time (timepos_t const & origin, t return origin.distance (snapped); } -std::shared_ptr -EditingContext::start_local_tempo_map (std::shared_ptr) +void +EditingContext::start_local_tempo_map (std::shared_ptr map) { - /* default is a no-op */ - return Temporal::TempoMap::use (); + _local_tempo_map = map; +} + +void +EditingContext::end_local_tempo_map () +{ + _local_tempo_map.reset (); + Temporal::TempoMap::fetch (); } bool diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index 08caf25ff1..a59bfeb677 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -87,18 +87,17 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, Temporal::TimeDomain time_domain () const; - struct TempoMapScope { TempoMapScope (EditingContext& context, std::shared_ptr map) : ec (context) { - old_map = ec.start_local_tempo_map (map); + ec.start_local_tempo_map (map); + ec.ensure_local_tempo_scope (); } ~TempoMapScope () { - ec.end_local_tempo_map (old_map); + ec.end_local_tempo_map (); } EditingContext& ec; - std::shared_ptr old_map; }; DragManager* drags () const { @@ -666,8 +665,9 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, QuantizeDialog* quantize_dialog; friend struct TempoMapScope; - virtual std::shared_ptr start_local_tempo_map (std::shared_ptr); - virtual void end_local_tempo_map (std::shared_ptr) { /* no-op by default */ } + void set_local_tempo_map (std::shared_ptr); + void start_local_tempo_map (std::shared_ptr); + void end_local_tempo_map (); virtual bool button_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) = 0; virtual bool button_press_handler_1 (ArdourCanvas::Item*, GdkEvent*, ItemType) = 0; @@ -832,4 +832,15 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, bool temporary_zoom_focus_change; bool _dragging_playhead; + + std::shared_ptr _local_tempo_map; + void ensure_local_tempo_scope () { + if (_local_tempo_map) { + Temporal::TempoMap::set (_local_tempo_map); + _local_tempo_map.reset (); + } + } }; + +#define EC_LOCAL_TEMPO_SCOPE ensure_local_tempo_scope () +#define EC_GIVEN_LOCAL_TEMPO_SCOPE(ec) ec.ensure_local_tempo_scope () From a07ba74c9d2ef77ff9737810f58f3521c380b5e5 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 14:33:26 -0600 Subject: [PATCH 15/32] fix constness in relationship to EditingContext:: local tempo map --- gtk2_ardour/editing_context.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index a59bfeb677..30028dcc68 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -833,8 +833,8 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, bool temporary_zoom_focus_change; bool _dragging_playhead; - std::shared_ptr _local_tempo_map; - void ensure_local_tempo_scope () { + mutable std::shared_ptr _local_tempo_map; + void ensure_local_tempo_scope () const { if (_local_tempo_map) { Temporal::TempoMap::set (_local_tempo_map); _local_tempo_map.reset (); From 4e23772b5deb795b1d2e6207d9467c2df740cd22 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 14:33:58 -0600 Subject: [PATCH 16/32] ensure (possible) local tempo map at start of every EditingContext method This still needs to be done for derived, non-Editor classes --- gtk2_ardour/editing_context.cc | 278 +++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 925ec6d29c..6fb3e7666f 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -155,6 +155,8 @@ EditingContext::EditingContext (std::string const & name) , _dragging_playhead (false) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Gtk::Menu_Helpers; if (!button_bindings) { @@ -247,6 +249,8 @@ EditingContext::EditingContext (std::string const & name) EditingContext::~EditingContext() { + EC_LOCAL_TEMPO_SCOPE; + ActionManager::drop_action_group (_midi_actions); ActionManager::drop_action_group (_common_actions); ActionManager::drop_action_group (editor_actions); @@ -260,6 +264,8 @@ EditingContext::~EditingContext() void EditingContext::ui_parameter_changed (string parameter) { + EC_LOCAL_TEMPO_SCOPE; + if (parameter == "sound-midi-notes") { if (UIConfiguration::instance().get_sound_midi_notes()) { play_note_selection_button.set_active_state (Gtkmm2ext::ExplicitActive); @@ -273,11 +279,15 @@ EditingContext::ui_parameter_changed (string parameter) void EditingContext::parameter_changed (string parameter) { + EC_LOCAL_TEMPO_SCOPE; + } void EditingContext::set_session (ARDOUR::Session* s) { + EC_LOCAL_TEMPO_SCOPE; + SessionHandlePtr::set_session (s); disable_automation_bindings (); } @@ -285,6 +295,8 @@ EditingContext::set_session (ARDOUR::Session* s) void EditingContext::set_selected_midi_region_view (MidiRegionView& mrv) { + EC_LOCAL_TEMPO_SCOPE; + /* clear note selection in all currently selected MidiRegionViews */ if (get_selection().regions.contains (&mrv) && get_selection().regions.size() == 1) { @@ -299,6 +311,8 @@ EditingContext::set_selected_midi_region_view (MidiRegionView& mrv) void EditingContext::register_automation_actions (Bindings* automation_bindings, std::string const & prefix) { + EC_LOCAL_TEMPO_SCOPE; + _automation_actions = ActionManager::create_action_group (automation_bindings, prefix + X_("Automation")); reg_sens (_automation_actions, "create-point", _("Create Automation Point"), sigc::mem_fun (*this, &EditingContext::automation_create_point_at_edit_point)); @@ -313,6 +327,8 @@ EditingContext::register_automation_actions (Bindings* automation_bindings, std: void EditingContext::enable_automation_bindings () { + EC_LOCAL_TEMPO_SCOPE; + if (_automation_actions) { ActionManager::set_sensitive (_automation_actions, true); } @@ -321,6 +337,8 @@ EditingContext::enable_automation_bindings () void EditingContext::disable_automation_bindings () { + EC_LOCAL_TEMPO_SCOPE; + if (_automation_actions) { ActionManager::set_sensitive (_automation_actions, false); } @@ -329,6 +347,8 @@ EditingContext::disable_automation_bindings () void EditingContext::set_action_defaults () { + EC_LOCAL_TEMPO_SCOPE; + #ifndef LIVETRAX follow_playhead_action->set_active (false); follow_playhead_action->set_active (true); @@ -370,6 +390,8 @@ EditingContext::set_action_defaults () void EditingContext::register_common_actions (Bindings* common_bindings, std::string const & prefix) { + EC_LOCAL_TEMPO_SCOPE; + _common_actions = ActionManager::create_action_group (common_bindings, prefix + X_("Editing")); reg_sens (_common_actions, "temporal-zoom-out", _("Zoom Out"), sigc::bind (sigc::mem_fun (*this, &EditingContext::temporal_zoom_step), true)); @@ -457,6 +479,8 @@ EditingContext::register_common_actions (Bindings* common_bindings, std::string void EditingContext::register_midi_actions (Bindings* midi_bindings, std::string const & prefix) { + EC_LOCAL_TEMPO_SCOPE; + _midi_actions = ActionManager::create_action_group (midi_bindings, prefix + X_("Notes")); /* two versions to allow same action for Delete and Backspace */ @@ -587,6 +611,8 @@ EditingContext::register_midi_actions (Bindings* midi_bindings, std::string cons void EditingContext::midi_action (void (MidiView::*method)()) { + EC_LOCAL_TEMPO_SCOPE; + MidiRegionSelection ms = get_selection().midi_regions(); if (ms.empty()) { @@ -614,6 +640,8 @@ EditingContext::midi_action (void (MidiView::*method)()) void EditingContext::next_grid_choice () { + EC_LOCAL_TEMPO_SCOPE; + switch (grid_type()) { case Editing::GridTypeBeatDiv32: set_grid_type (Editing::GridTypeNone); @@ -659,6 +687,8 @@ EditingContext::next_grid_choice () void EditingContext::prev_grid_choice () { + EC_LOCAL_TEMPO_SCOPE; + switch (grid_type()) { case Editing::GridTypeBeatDiv32: set_grid_type (Editing::GridTypeBeatDiv16); @@ -704,6 +734,8 @@ EditingContext::prev_grid_choice () void EditingContext::grid_type_chosen (GridType gt) { + EC_LOCAL_TEMPO_SCOPE; + /* this is driven by a toggle on a radio group, and so is invoked twice, once for the item that became inactive and once for the one that became active. @@ -753,6 +785,8 @@ EditingContext::grid_type_chosen (GridType gt) void EditingContext::draw_length_chosen (GridType type) { + EC_LOCAL_TEMPO_SCOPE; + /* this is driven by a toggle on a radio group, and so is invoked twice, once for the item that became inactive and once for the one that became active. @@ -781,6 +815,8 @@ EditingContext::draw_length_chosen (GridType type) void EditingContext::draw_velocity_chosen (int v) { + EC_LOCAL_TEMPO_SCOPE; + /* this is driven by a toggle on a radio group, and so is invoked twice, once for the item that became inactive and once for the one that became active. @@ -812,6 +848,8 @@ EditingContext::draw_velocity_chosen (int v) void EditingContext::draw_channel_chosen (int c) { + EC_LOCAL_TEMPO_SCOPE; + /* this is driven by a toggle on a radio group, and so is invoked twice, once for the item that became inactive and once for the one that became active. @@ -843,6 +881,8 @@ EditingContext::draw_channel_chosen (int c) void EditingContext::cycle_snap_mode () { + EC_LOCAL_TEMPO_SCOPE; + switch (snap_mode()) { case SnapOff: case SnapNormal: @@ -857,6 +897,8 @@ EditingContext::cycle_snap_mode () void EditingContext::snap_mode_chosen (SnapMode mode) { + EC_LOCAL_TEMPO_SCOPE; + /* this is driven by a toggle on a radio group, and so is invoked twice, once for the item that became inactive and once for the one that became active. @@ -888,6 +930,8 @@ EditingContext::snap_mode_chosen (SnapMode mode) GridType EditingContext::grid_type() const { + EC_LOCAL_TEMPO_SCOPE; + for (auto const & [grid_type,action] : grid_actions) { if (action->get_active()) { return grid_type; @@ -900,6 +944,8 @@ EditingContext::grid_type() const GridType EditingContext::draw_length() const { + EC_LOCAL_TEMPO_SCOPE; + for (auto const & [len,action] : draw_length_actions) { if (action->get_active()) { return len; @@ -912,6 +958,8 @@ EditingContext::draw_length() const int EditingContext::draw_velocity() const { + EC_LOCAL_TEMPO_SCOPE; + for (auto const & [vel,action] : draw_velocity_actions) { if (action->get_active()) { return vel; @@ -924,6 +972,8 @@ EditingContext::draw_velocity() const int EditingContext::draw_channel() const { + EC_LOCAL_TEMPO_SCOPE; + for (auto const & [chn,action] : draw_channel_actions) { if (action->get_active()) { return chn; @@ -936,12 +986,16 @@ EditingContext::draw_channel() const bool EditingContext::grid_musical() const { + EC_LOCAL_TEMPO_SCOPE; + return grid_type_is_musical (grid_type()); } bool EditingContext::grid_type_is_musical(GridType gt) const { + EC_LOCAL_TEMPO_SCOPE; + switch (gt) { case GridTypeBeatDiv32: case GridTypeBeatDiv28: @@ -973,6 +1027,8 @@ EditingContext::grid_type_is_musical(GridType gt) const SnapMode EditingContext::snap_mode() const { + EC_LOCAL_TEMPO_SCOPE; + for (auto const & [mode,action] : snap_mode_actions) { if (action->get_active()) { return mode; @@ -985,12 +1041,16 @@ EditingContext::snap_mode() const void EditingContext::set_draw_length (GridType gt) { + EC_LOCAL_TEMPO_SCOPE; + draw_length_actions[gt]->set_active (true); } void EditingContext::set_draw_velocity (int v) { + EC_LOCAL_TEMPO_SCOPE; + if (v == DRAW_VEL_AUTO) { draw_velocity_actions[v]->set_active (true); } else { @@ -1001,6 +1061,8 @@ EditingContext::set_draw_velocity (int v) void EditingContext::set_draw_channel (int c) { + EC_LOCAL_TEMPO_SCOPE; + if (c == DRAW_CHAN_AUTO) { draw_channel_actions[c]->set_active (true); } else { @@ -1011,18 +1073,24 @@ EditingContext::set_draw_channel (int c) void EditingContext::set_grid_type (GridType gt) { + EC_LOCAL_TEMPO_SCOPE; + grid_actions[gt]->set_active (true); } void EditingContext::set_snap_mode (SnapMode mode) { + EC_LOCAL_TEMPO_SCOPE; + snap_mode_actions[mode]->set_active (true);; } void EditingContext::build_grid_type_menu () { + EC_LOCAL_TEMPO_SCOPE; + using namespace Menu_Helpers; /* there's no Grid, but if Snap is engaged, the Snap preferences will be applied */ @@ -1078,6 +1146,8 @@ EditingContext::build_grid_type_menu () void EditingContext::build_draw_midi_menus () { + EC_LOCAL_TEMPO_SCOPE; + using namespace Menu_Helpers; /* Note-Length when drawing */ @@ -1135,18 +1205,24 @@ EditingContext::build_draw_midi_menus () bool EditingContext::drag_active () const { + EC_LOCAL_TEMPO_SCOPE; + return _drags->active(); } bool EditingContext::preview_video_drag_active () const { + EC_LOCAL_TEMPO_SCOPE; + return _drags->preview_video (); } Temporal::TimeDomain EditingContext::time_domain () const { + EC_LOCAL_TEMPO_SCOPE; + if (_session) { return _session->config.get_default_time_domain(); } @@ -1177,24 +1253,32 @@ EditingContext::time_domain () const void EditingContext::toggle_stationary_playhead () { + EC_LOCAL_TEMPO_SCOPE; + stationary_playhead_action->set_active (!stationary_playhead_action->get_active ()); } void EditingContext::stationary_playhead_chosen () { + EC_LOCAL_TEMPO_SCOPE; + instant_save (); } void EditingContext::set_stationary_playhead (bool yn) { + EC_LOCAL_TEMPO_SCOPE; + stationary_playhead_action->set_active (yn); } bool EditingContext::stationary_playhead () const { + EC_LOCAL_TEMPO_SCOPE; + if (!stationary_playhead_action) { return false; } @@ -1205,12 +1289,16 @@ EditingContext::stationary_playhead () const void EditingContext::toggle_follow_playhead () { + EC_LOCAL_TEMPO_SCOPE; + set_follow_playhead (!follow_playhead_action->get_active(), true); } void EditingContext::follow_playhead_chosen () { + EC_LOCAL_TEMPO_SCOPE; + instant_save (); } @@ -1220,6 +1308,8 @@ EditingContext::follow_playhead_chosen () void EditingContext::set_follow_playhead (bool yn, bool catch_up) { + EC_LOCAL_TEMPO_SCOPE; + assert (follow_playhead_action); follow_playhead_action->set_active (yn); if (yn && catch_up) { @@ -1231,6 +1321,8 @@ EditingContext::set_follow_playhead (bool yn, bool catch_up) bool EditingContext::follow_playhead() const { + EC_LOCAL_TEMPO_SCOPE; + if (!follow_playhead_action) { return false; } @@ -1241,30 +1333,40 @@ EditingContext::follow_playhead() const double EditingContext::time_to_pixel (timepos_t const & pos) const { + EC_LOCAL_TEMPO_SCOPE; + return sample_to_pixel (pos.samples()); } double EditingContext::time_to_pixel_unrounded (timepos_t const & pos) const { + EC_LOCAL_TEMPO_SCOPE; + return sample_to_pixel_unrounded (pos.samples()); } double EditingContext::time_delta_to_pixel (timepos_t const& start, timepos_t const& end) const { + EC_LOCAL_TEMPO_SCOPE; + return sample_to_pixel (end.samples()) - sample_to_pixel (start.samples ()); } double EditingContext::duration_to_pixels (timecnt_t const & dur) const { + EC_LOCAL_TEMPO_SCOPE; + return sample_to_pixel (dur.samples()); } double EditingContext::duration_to_pixels_unrounded (timecnt_t const & dur) const { + EC_LOCAL_TEMPO_SCOPE; + return sample_to_pixel_unrounded (dur.samples()); } @@ -1276,6 +1378,8 @@ EditingContext::duration_to_pixels_unrounded (timecnt_t const & dur) const void EditingContext::snap_to_with_modifier (timepos_t& start, GdkEvent const * event, Temporal::RoundMode direction, SnapPref pref, bool ensure_snap) const { + EC_LOCAL_TEMPO_SCOPE; + if (!_session || !event) { return; } @@ -1298,6 +1402,8 @@ EditingContext::snap_to_with_modifier (timepos_t& start, GdkEvent const * event, void EditingContext::snap_to (timepos_t& start, Temporal::RoundMode direction, SnapPref pref, bool ensure_snap) const { + EC_LOCAL_TEMPO_SCOPE; + if (!_session || (snap_mode() == SnapOff && !ensure_snap)) { return; } @@ -1308,12 +1414,16 @@ EditingContext::snap_to (timepos_t& start, Temporal::RoundMode direction, SnapPr timepos_t EditingContext::snap_to_bbt (timepos_t const & presnap, Temporal::RoundMode direction, SnapPref gpref) const { + EC_LOCAL_TEMPO_SCOPE; + return snap_to_bbt_via_grid (presnap, direction, gpref, grid_type()); } timepos_t EditingContext::snap_to_bbt_via_grid (timepos_t const & presnap, Temporal::RoundMode direction, SnapPref gpref, GridType grid_type) const { + EC_LOCAL_TEMPO_SCOPE; + timepos_t ret(presnap); TempoMap::SharedPtr tmap (TempoMap::use()); @@ -1416,6 +1526,8 @@ EditingContext::snap_to_bbt_via_grid (timepos_t const & presnap, Temporal::Round void EditingContext::check_best_snap (timepos_t const & presnap, timepos_t &test, timepos_t &dist, timepos_t &best) const { + EC_LOCAL_TEMPO_SCOPE; + timepos_t diff = timepos_t (presnap.distance (test).abs ()); if (diff < dist) { dist = diff; @@ -1428,6 +1540,8 @@ EditingContext::check_best_snap (timepos_t const & presnap, timepos_t &test, tim timepos_t EditingContext::canvas_event_time (GdkEvent const * event, double* pcx, double* pcy) const { + EC_LOCAL_TEMPO_SCOPE; + timepos_t pos (canvas_event_sample (event, pcx, pcy)); if (time_domain() == Temporal::AudioTime) { @@ -1440,6 +1554,8 @@ EditingContext::canvas_event_time (GdkEvent const * event, double* pcx, double* samplepos_t EditingContext::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { + EC_LOCAL_TEMPO_SCOPE; + double x; double y; @@ -1469,6 +1585,8 @@ EditingContext::canvas_event_sample (GdkEvent const * event, double* pcx, double uint32_t EditingContext::count_bars (Beats const & start, Beats const & end) const { + EC_LOCAL_TEMPO_SCOPE; + TempoMapPoints bar_grid; TempoMap::SharedPtr tmap (TempoMap::use()); bar_grid.reserve (4096); @@ -1481,6 +1599,8 @@ EditingContext::count_bars (Beats const & start, Beats const & end) const void EditingContext::compute_bbt_ruler_scale (samplepos_t lower, samplepos_t upper) { + EC_LOCAL_TEMPO_SCOPE; + if (_session == 0) { return; } @@ -1575,6 +1695,8 @@ EditingContext::compute_bbt_ruler_scale (samplepos_t lower, samplepos_t upper) Quantize* EditingContext::get_quantize_op () { + EC_LOCAL_TEMPO_SCOPE; + if (!quantize_dialog) { quantize_dialog = new QuantizeDialog (*this); } @@ -1600,6 +1722,8 @@ EditingContext::get_quantize_op () timecnt_t EditingContext::relative_distance (timepos_t const & origin, timecnt_t const & duration, Temporal::TimeDomain domain) { + EC_LOCAL_TEMPO_SCOPE; + return Temporal::TempoMap::use()->convert_duration (duration, origin, domain); } @@ -1612,6 +1736,8 @@ EditingContext::relative_distance (timepos_t const & origin, timecnt_t const & d timecnt_t EditingContext::snap_relative_time_to_relative_time (timepos_t const & origin, timecnt_t const & x, bool ensure_snap) const { + EC_LOCAL_TEMPO_SCOPE; + /* x is relative to origin, convert it to global absolute time */ timepos_t const session_pos = origin + x; @@ -1632,12 +1758,16 @@ EditingContext::snap_relative_time_to_relative_time (timepos_t const & origin, t void EditingContext::start_local_tempo_map (std::shared_ptr map) { + EC_LOCAL_TEMPO_SCOPE; + _local_tempo_map = map; } void EditingContext::end_local_tempo_map () { + EC_LOCAL_TEMPO_SCOPE; + _local_tempo_map.reset (); Temporal::TempoMap::fetch (); } @@ -1645,6 +1775,8 @@ EditingContext::end_local_tempo_map () bool EditingContext::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type) { + EC_LOCAL_TEMPO_SCOPE; + if (!session () || session()->loading () || session()->deletion_in_progress ()) { return false; } @@ -1689,6 +1821,8 @@ EditingContext::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType void EditingContext::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Menu_Helpers; NoteBase* note = reinterpret_cast(item->get_data("notebase")); @@ -1734,6 +1868,8 @@ EditingContext::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* eve XMLNode* EditingContext::button_settings () const { + EC_LOCAL_TEMPO_SCOPE; + XMLNode* settings = ARDOUR_UI::instance()->editor_settings(); XMLNode* node = find_named_node (*settings, X_("Buttons")); @@ -1747,12 +1883,16 @@ EditingContext::button_settings () const EditingContext::MidiViews EditingContext::filter_to_unique_midi_region_views (RegionSelection const & rs) const { + EC_LOCAL_TEMPO_SCOPE; + return filter_to_unique_midi_region_views (midiviews_from_region_selection (rs)); } EditingContext::MidiViews EditingContext::filter_to_unique_midi_region_views (MidiViews const & mvs) const { + EC_LOCAL_TEMPO_SCOPE; + typedef std::pair,timepos_t> MapEntry; std::set single_region_set; @@ -1782,6 +1922,8 @@ EditingContext::filter_to_unique_midi_region_views (MidiViews const & mvs) const EditingContext::MidiViews EditingContext::midiviews_from_region_selection (RegionSelection const & rs) const { + EC_LOCAL_TEMPO_SCOPE; + MidiViews views; for (auto & rv : rs) { @@ -1797,6 +1939,8 @@ EditingContext::midiviews_from_region_selection (RegionSelection const & rs) con void EditingContext::quantize_region () { + EC_LOCAL_TEMPO_SCOPE; + if (_session) { quantize_regions (midiviews_from_region_selection (region_selection())); } @@ -1805,6 +1949,8 @@ EditingContext::quantize_region () void EditingContext::quantize_regions (const MidiViews& rs) { + EC_LOCAL_TEMPO_SCOPE; + if (rs.empty()) { std::cerr << "no regions\n"; return; @@ -1826,6 +1972,8 @@ EditingContext::quantize_regions (const MidiViews& rs) void EditingContext::legatize_region (bool shrink_only) { + EC_LOCAL_TEMPO_SCOPE; + if (_session) { legatize_regions (midiviews_from_region_selection (region_selection ()), shrink_only); } @@ -1834,6 +1982,8 @@ EditingContext::legatize_region (bool shrink_only) void EditingContext::legatize_regions (const MidiViews& rs, bool shrink_only) { + EC_LOCAL_TEMPO_SCOPE; + if (rs.empty()) { return; } @@ -1845,6 +1995,8 @@ EditingContext::legatize_regions (const MidiViews& rs, bool shrink_only) void EditingContext::transform_region () { + EC_LOCAL_TEMPO_SCOPE; + if (_session) { transform_regions (midiviews_from_region_selection (region_selection ())); } @@ -1853,6 +2005,8 @@ EditingContext::transform_region () void EditingContext::transform_regions (const MidiViews& rs) { + EC_LOCAL_TEMPO_SCOPE; + if (rs.empty()) { return; } @@ -1872,6 +2026,8 @@ EditingContext::transform_regions (const MidiViews& rs) void EditingContext::transpose_region () { + EC_LOCAL_TEMPO_SCOPE; + if (_session) { transpose_regions (midiviews_from_region_selection (region_selection ())); } @@ -1880,6 +2036,8 @@ EditingContext::transpose_region () void EditingContext::transpose_regions (const MidiViews& rs) { + EC_LOCAL_TEMPO_SCOPE; + if (rs.empty()) { return; } @@ -1896,6 +2054,8 @@ EditingContext::transpose_regions (const MidiViews& rs) void EditingContext::edit_notes (MidiView* mrv) { + EC_LOCAL_TEMPO_SCOPE; + MidiView::Selection const & s = mrv->selection(); if (s.empty ()) { @@ -1911,6 +2071,8 @@ EditingContext::edit_notes (MidiView* mrv) void EditingContext::note_edit_done (int r, EditNoteDialog* d) { + EC_LOCAL_TEMPO_SCOPE; + d->done (r); delete d; } @@ -1918,6 +2080,8 @@ EditingContext::note_edit_done (int r, EditNoteDialog* d) PBD::Command* EditingContext::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiView& mrv) { + EC_LOCAL_TEMPO_SCOPE; + Evoral::Sequence::Notes selected; mrv.selection_as_notelist (selected, true); @@ -1936,12 +2100,16 @@ EditingContext::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiView& m void EditingContext::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs) { + EC_LOCAL_TEMPO_SCOPE; + apply_midi_note_edit_op (op, midiviews_from_region_selection (rs)); } void EditingContext::apply_midi_note_edit_op (MidiOperator& op, const MidiViews& rs) { + EC_LOCAL_TEMPO_SCOPE; + if (rs.empty()) { return; } @@ -1972,12 +2140,16 @@ EditingContext::apply_midi_note_edit_op (MidiOperator& op, const MidiViews& rs) double EditingContext::horizontal_position () const { + EC_LOCAL_TEMPO_SCOPE; + return horizontal_adjustment.get_value(); } void EditingContext::set_horizontal_position (double p) { + EC_LOCAL_TEMPO_SCOPE; + p = std::max (0., p); horizontal_adjustment.set_value (p); @@ -1987,6 +2159,8 @@ EditingContext::set_horizontal_position (double p) Gdk::Cursor* EditingContext::get_canvas_cursor () const { + EC_LOCAL_TEMPO_SCOPE; + Glib::RefPtr win = get_canvas_viewport()->get_window(); if (win) { @@ -1999,6 +2173,8 @@ EditingContext::get_canvas_cursor () const void EditingContext::set_canvas_cursor (Gdk::Cursor* cursor) { + EC_LOCAL_TEMPO_SCOPE; + Glib::RefPtr win = get_canvas()->get_window(); if (win && !_cursors->is_invalid (cursor)) { @@ -2017,6 +2193,8 @@ EditingContext::set_canvas_cursor (Gdk::Cursor* cursor) void EditingContext::pack_draw_box (bool with_channel) { + EC_LOCAL_TEMPO_SCOPE; + /* Draw - these MIDI tools are only visible when in Draw mode */ draw_box.set_spacing (2); draw_box.set_border_width (2); @@ -2043,6 +2221,8 @@ EditingContext::pack_draw_box (bool with_channel) void EditingContext::pack_snap_box () { + EC_LOCAL_TEMPO_SCOPE; + snap_box.pack_start (snap_mode_button, false, false); snap_box.pack_start (grid_type_selector, false, false); } @@ -2050,6 +2230,8 @@ EditingContext::pack_snap_box () void EditingContext::bind_mouse_mode_buttons () { + EC_LOCAL_TEMPO_SCOPE; + RefPtr act; act = ActionManager::get_action ((_name + X_("Editing")).c_str(), X_("temporal-zoom-in")); @@ -2102,6 +2284,8 @@ EditingContext::bind_mouse_mode_buttons () Editing::MouseMode EditingContext::current_mouse_mode() const { + EC_LOCAL_TEMPO_SCOPE; + for (auto & [mode,action] : mouse_mode_actions) { if (action->get_active()) { return mode; @@ -2114,6 +2298,8 @@ EditingContext::current_mouse_mode() const void EditingContext::set_mouse_mode (MouseMode m, bool force) { + EC_LOCAL_TEMPO_SCOPE; + if (_drags->active ()) { return; } @@ -2128,6 +2314,8 @@ EditingContext::set_mouse_mode (MouseMode m, bool force) bool EditingContext::on_velocity_scroll_event (GdkEventScroll* ev) { + EC_LOCAL_TEMPO_SCOPE; + int v = PBD::atoi (draw_velocity_selector.get_text ()); switch (ev->direction) { case GDK_SCROLL_DOWN: @@ -2146,6 +2334,8 @@ EditingContext::on_velocity_scroll_event (GdkEventScroll* ev) void EditingContext::set_common_editing_state (XMLNode const & node) { + EC_LOCAL_TEMPO_SCOPE; + double z; if (node.get_property ("zoom", z)) { /* older versions of ardour used floating point samples_per_pixel */ @@ -2191,6 +2381,8 @@ EditingContext::set_common_editing_state (XMLNode const & node) void EditingContext::get_common_editing_state (XMLNode& node) const { + EC_LOCAL_TEMPO_SCOPE; + node.set_property ("zoom", samples_per_pixel); node.set_property ("grid-type", grid_type()); node.set_property ("snap-mode", snap_mode()); @@ -2204,6 +2396,8 @@ EditingContext::get_common_editing_state (XMLNode& node) const bool EditingContext::snap_mode_button_clicked (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (ev->button != 3) { cycle_snap_mode(); return true; @@ -2221,6 +2415,8 @@ EditingContext::snap_mode_button_clicked (GdkEventButton* ev) void EditingContext::ensure_visual_change_idle_handler () { + EC_LOCAL_TEMPO_SCOPE; + if (pending_visual_change.idle_handler_id < 0) { /* see comment in add_to_idle_resize above. */ pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL); @@ -2237,6 +2433,8 @@ EditingContext::_idle_visual_changer (void* arg) int EditingContext::idle_visual_changer () { + EC_LOCAL_TEMPO_SCOPE; + pending_visual_change.idle_handler_id = -1; if (pending_visual_change.pending == 0) { @@ -2279,6 +2477,8 @@ EditingContext::idle_visual_changer () void EditingContext::reset_x_origin (samplepos_t sample) { + EC_LOCAL_TEMPO_SCOPE; + pending_visual_change.add (VisualChange::TimeOrigin); pending_visual_change.time_origin = sample; ensure_visual_change_idle_handler (); @@ -2287,6 +2487,8 @@ EditingContext::reset_x_origin (samplepos_t sample) void EditingContext::reset_y_origin (double y) { + EC_LOCAL_TEMPO_SCOPE; + pending_visual_change.add (VisualChange::YOrigin); pending_visual_change.y_origin = y; ensure_visual_change_idle_handler (); @@ -2295,6 +2497,8 @@ EditingContext::reset_y_origin (double y) void EditingContext::reset_zoom (samplecnt_t spp) { + EC_LOCAL_TEMPO_SCOPE; + if (_track_canvas_width <= 0) { return; } @@ -2318,6 +2522,8 @@ EditingContext::reset_zoom (samplecnt_t spp) void EditingContext::pre_render () { + EC_LOCAL_TEMPO_SCOPE; + visual_change_queued = false; if (pending_visual_change.pending != 0) { @@ -2354,6 +2560,8 @@ EditingContext::radio_reg_sens (RefPtr action_group, RadioAction::G void EditingContext::update_undo_redo_actions (PBD::UndoHistory const & history) { + EC_LOCAL_TEMPO_SCOPE; + string label; if (undo_action) { @@ -2382,6 +2590,8 @@ EditingContext::update_undo_redo_actions (PBD::UndoHistory const & history) int32_t EditingContext::get_grid_beat_divisions (GridType gt) const { + EC_LOCAL_TEMPO_SCOPE; + switch (gt) { case GridTypeBeatDiv32: return 32; case GridTypeBeatDiv28: return 28; @@ -2419,12 +2629,16 @@ EditingContext::get_grid_beat_divisions (GridType gt) const int32_t EditingContext::get_grid_music_divisions (Editing::GridType gt, uint32_t event_state) const { + EC_LOCAL_TEMPO_SCOPE; + return get_grid_beat_divisions (gt); } Temporal::Beats EditingContext::get_grid_type_as_beats (bool& success, timepos_t const & position) const { + EC_LOCAL_TEMPO_SCOPE; + success = true; int32_t const divisions = get_grid_beat_divisions (grid_type()); @@ -2504,6 +2718,8 @@ EditingContext::get_grid_type_as_beats (bool& success, timepos_t const & positio Temporal::Beats EditingContext::get_draw_length_as_beats (bool& success, timepos_t const & position) const { + EC_LOCAL_TEMPO_SCOPE; + success = true; GridType grid_to_use = draw_length() == DRAW_LEN_AUTO ? grid_type() : draw_length(); int32_t const divisions = get_grid_beat_divisions (grid_to_use); @@ -2519,6 +2735,8 @@ EditingContext::get_draw_length_as_beats (bool& success, timepos_t const & posit void EditingContext::select_automation_line (GdkEventButton* event, ArdourCanvas::Item* item, ARDOUR::SelectionOperation op) { + EC_LOCAL_TEMPO_SCOPE; + AutomationLine* al = reinterpret_cast (item->get_data ("line")); std::list selectables; double mx = event->x; @@ -2569,6 +2787,8 @@ EditingContext::select_automation_line (GdkEventButton* event, ArdourCanvas::Ite void EditingContext::reset_point_selection () { + EC_LOCAL_TEMPO_SCOPE; + for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { ARDOUR::AutomationList::iterator j = (*i)->model (); (*j)->value = (*i)->line().the_list()->descriptor ().normal; @@ -2578,6 +2798,8 @@ EditingContext::reset_point_selection () void EditingContext::choose_canvas_cursor_on_entry (ItemType type) { + EC_LOCAL_TEMPO_SCOPE; + if (_drags->active()) { return; } @@ -2593,12 +2815,16 @@ EditingContext::choose_canvas_cursor_on_entry (ItemType type) void EditingContext::play_note_selection_clicked () { + EC_LOCAL_TEMPO_SCOPE; + UIConfiguration::instance().set_sound_midi_notes (!UIConfiguration::instance().get_sound_midi_notes()); } void EditingContext::cycle_zoom_focus () { + EC_LOCAL_TEMPO_SCOPE; + switch (zoom_focus()) { case ZoomFocusLeft: set_zoom_focus (ZoomFocusRight); @@ -2624,6 +2850,8 @@ EditingContext::cycle_zoom_focus () void EditingContext::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale) { + EC_LOCAL_TEMPO_SCOPE; + ZoomFocus old_zf (zoom_focus()); PBD::Unwinder uw (temporary_zoom_focus_change, true); set_zoom_focus (Editing::ZoomFocusMouse); @@ -2634,18 +2862,24 @@ EditingContext::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scal void EditingContext::temporal_zoom_step_mouse_focus (bool zoom_out) { + EC_LOCAL_TEMPO_SCOPE; + temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0); } void EditingContext::temporal_zoom_step (bool zoom_out) { + EC_LOCAL_TEMPO_SCOPE; + temporal_zoom_step_scale (zoom_out, 2.0); } void EditingContext::temporal_zoom_step_scale (bool zoom_out, double scale) { + EC_LOCAL_TEMPO_SCOPE; + ENSURE_GUI_THREAD (*this, &EditingContext::temporal_zoom_step, zoom_out, scale) samplecnt_t nspp = samples_per_pixel; @@ -2676,6 +2910,8 @@ EditingContext::temporal_zoom_step_scale (bool zoom_out, double scale) void EditingContext::temporal_zoom (samplecnt_t spp) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -2807,6 +3043,8 @@ EditingContext::temporal_zoom (samplecnt_t spp) void EditingContext::calc_extra_zoom_edges (samplepos_t &start, samplepos_t &end) { + EC_LOCAL_TEMPO_SCOPE; + /* this func helps make sure we leave a little space at each end of the editor so that the zoom doesn't fit the region precisely to the screen. @@ -2839,6 +3077,8 @@ EditingContext::calc_extra_zoom_edges (samplepos_t &start, samplepos_t &end) void EditingContext::temporal_zoom_by_sample (samplepos_t start, samplepos_t end) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) return; if ((start == 0 && end == 0) || end < start) { @@ -2867,6 +3107,8 @@ EditingContext::temporal_zoom_by_sample (samplepos_t start, samplepos_t end) void EditingContext::temporal_zoom_to_sample (bool coarser, samplepos_t sample) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -2918,6 +3160,8 @@ EditingContext::temporal_zoom_to_sample (bool coarser, samplepos_t sample) bool EditingContext::mouse_sample (samplepos_t& where, bool& in_track_canvas) const { + EC_LOCAL_TEMPO_SCOPE; + /* gdk_window_get_pointer() has X11's XQueryPointer semantics in that it only * pays attentions to subwindows. this means that menu windows are ignored, and * if the pointer is in a menu, the return window from the call will be the @@ -2966,6 +3210,8 @@ EditingContext::mouse_sample (samplepos_t& where, bool& in_track_canvas) const samplepos_t EditingContext::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { + EC_LOCAL_TEMPO_SCOPE; + ArdourCanvas::Duple d; if (!gdk_event_get_coords (event, &d.x, &d.y)) { @@ -2991,6 +3237,8 @@ EditingContext::window_event_sample (GdkEvent const * event, double* pcx, double Editing::ZoomFocus EditingContext::zoom_focus () const { + EC_LOCAL_TEMPO_SCOPE; + for (auto & [mode,action] : zoom_focus_actions) { if (action->get_active()) { return mode; @@ -3003,6 +3251,8 @@ EditingContext::zoom_focus () const void EditingContext::zoom_focus_chosen (ZoomFocus focus) { + EC_LOCAL_TEMPO_SCOPE; + if (temporary_zoom_focus_change) { /* we are just changing settings momentarily, no need to do anything */ return; @@ -3024,6 +3274,8 @@ EditingContext::zoom_focus_chosen (ZoomFocus focus) void EditingContext::alt_delete_ () { + EC_LOCAL_TEMPO_SCOPE; + delete_ (); } @@ -3031,6 +3283,8 @@ EditingContext::alt_delete_ () void EditingContext::cut () { + EC_LOCAL_TEMPO_SCOPE; + cut_copy (Cut); } @@ -3038,12 +3292,16 @@ EditingContext::cut () void EditingContext::copy () { + EC_LOCAL_TEMPO_SCOPE; + cut_copy (Copy); } void EditingContext::load_shared_bindings () { + EC_LOCAL_TEMPO_SCOPE; + Bindings* m = Bindings::get_bindings (X_("MIDI")); Bindings* b = Bindings::get_bindings (X_("Editing")); Bindings* a = Bindings::get_bindings (X_("Automation")); @@ -3081,6 +3339,8 @@ EditingContext::load_shared_bindings () void EditingContext::drop_grid () { + EC_LOCAL_TEMPO_SCOPE; + hide_grid_lines (); grid_lines.reset (); } @@ -3088,6 +3348,8 @@ EditingContext::drop_grid () void EditingContext::hide_grid_lines () { + EC_LOCAL_TEMPO_SCOPE; + if (grid_lines) { grid_lines->hide(); } @@ -3096,6 +3358,8 @@ EditingContext::hide_grid_lines () void EditingContext::maybe_draw_grid_lines (ArdourCanvas::Container* group) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -3127,6 +3391,8 @@ EditingContext::maybe_draw_grid_lines (ArdourCanvas::Container* group) void EditingContext::update_grid () { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -3141,6 +3407,8 @@ EditingContext::update_grid () Location* EditingContext::transport_loop_location() { + EC_LOCAL_TEMPO_SCOPE; + if (_session) { return _session->locations()->auto_loop_location(); } else { @@ -3151,6 +3419,8 @@ EditingContext::transport_loop_location() void EditingContext::set_loop_range (timepos_t const & start, timepos_t const & end, string cmd) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -3183,6 +3453,8 @@ EditingContext::set_loop_range (timepos_t const & start, timepos_t const & end, bool EditingContext::allow_trim_cursors () const { + EC_LOCAL_TEMPO_SCOPE; + auto mouse_mode = current_mouse_mode(); return mouse_mode == MouseContent || mouse_mode == MouseTimeFX || mouse_mode == MouseDraw; } @@ -3191,6 +3463,8 @@ EditingContext::allow_trim_cursors () const void EditingContext::reset_x_origin_to_follow_playhead () { + EC_LOCAL_TEMPO_SCOPE; + assert (_session); samplepos_t const sample = _playhead_cursor->current_sample (); @@ -3242,6 +3516,8 @@ EditingContext::reset_x_origin_to_follow_playhead () void EditingContext::center_screen (samplepos_t sample) { + EC_LOCAL_TEMPO_SCOPE; + samplecnt_t const page = _visible_canvas_width * samples_per_pixel; /* if we're off the page, then scroll. @@ -3255,6 +3531,8 @@ EditingContext::center_screen (samplepos_t sample) void EditingContext::center_screen_internal (samplepos_t sample, float page) { + EC_LOCAL_TEMPO_SCOPE; + page /= 2; if (sample > page) { From 22abddcd95265713db540355cd22b6ff2c3ddb31 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 14:39:40 -0600 Subject: [PATCH 17/32] no local tempo scope for constructors --- gtk2_ardour/editing_context.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 6fb3e7666f..f53eabd25c 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -155,8 +155,6 @@ EditingContext::EditingContext (std::string const & name) , _dragging_playhead (false) { - EC_LOCAL_TEMPO_SCOPE; - using namespace Gtk::Menu_Helpers; if (!button_bindings) { @@ -249,8 +247,6 @@ EditingContext::EditingContext (std::string const & name) EditingContext::~EditingContext() { - EC_LOCAL_TEMPO_SCOPE; - ActionManager::drop_action_group (_midi_actions); ActionManager::drop_action_group (_common_actions); ActionManager::drop_action_group (editor_actions); From 1ecb28da474ad52ee01c0a4d957d8b36139ec898 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 15:03:11 -0600 Subject: [PATCH 18/32] tweak local tempo scope infrastructure --- gtk2_ardour/editing_context.cc | 4 ---- gtk2_ardour/editing_context.h | 1 - 2 files changed, 5 deletions(-) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index f53eabd25c..f119a877cc 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -1754,16 +1754,12 @@ EditingContext::snap_relative_time_to_relative_time (timepos_t const & origin, t void EditingContext::start_local_tempo_map (std::shared_ptr map) { - EC_LOCAL_TEMPO_SCOPE; - _local_tempo_map = map; } void EditingContext::end_local_tempo_map () { - EC_LOCAL_TEMPO_SCOPE; - _local_tempo_map.reset (); Temporal::TempoMap::fetch (); } diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index 30028dcc68..f438993922 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -837,7 +837,6 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider, void ensure_local_tempo_scope () const { if (_local_tempo_map) { Temporal::TempoMap::set (_local_tempo_map); - _local_tempo_map.reset (); } } }; From 56647acc25aa91ccf920e5ac21452bccf35b78e7 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 15:03:41 -0600 Subject: [PATCH 19/32] add local tempo scope calls to CueEditor, PianoRoll and AudioClipEditor --- gtk2_ardour/audio_clip_editor.cc | 56 ++++++++++ gtk2_ardour/cue_editor.cc | 158 ++++++++++++++++++++++++++++ gtk2_ardour/pianoroll.cc | 174 +++++++++++++++++++++++++++++++ 3 files changed, 388 insertions(+) diff --git a/gtk2_ardour/audio_clip_editor.cc b/gtk2_ardour/audio_clip_editor.cc index 321f04800c..e6913305ca 100644 --- a/gtk2_ardour/audio_clip_editor.cc +++ b/gtk2_ardour/audio_clip_editor.cc @@ -123,6 +123,8 @@ AudioClipEditor::AudioClipEditor (std::string const & name, bool with_transport) void AudioClipEditor::load_shared_bindings () { + EC_LOCAL_TEMPO_SCOPE; + /* Full shared binding loading must have preceded this in some other EditingContext */ assert (!need_shared_actions); @@ -144,6 +146,8 @@ AudioClipEditor::load_shared_bindings () void AudioClipEditor::pack_inner (Gtk::Box& box) { + EC_LOCAL_TEMPO_SCOPE; + box.pack_start (snap_box, false, false); box.pack_start (grid_box, false, false); } @@ -151,6 +155,8 @@ AudioClipEditor::pack_inner (Gtk::Box& box) void AudioClipEditor::pack_outer (Gtk::Box& box) { + EC_LOCAL_TEMPO_SCOPE; + if (with_transport_controls) { box.pack_start (play_box, false, false); } @@ -162,12 +168,16 @@ AudioClipEditor::pack_outer (Gtk::Box& box) void AudioClipEditor::build_lower_toolbar () { + EC_LOCAL_TEMPO_SCOPE; + _toolbox.pack_start (*_canvas_hscrollbar, false, false); } void AudioClipEditor::build_canvas () { + EC_LOCAL_TEMPO_SCOPE; + _canvas.set_background_color (UIConfiguration::instance().color ("arrange base")); _canvas.signal_event().connect (sigc::mem_fun (*this, &CueEditor::canvas_pre_event), false); _canvas.use_nsglview (UIConfiguration::instance().get_nsgl_view_mode () == NSGLHiRes); @@ -270,6 +280,8 @@ AudioClipEditor::build_canvas () AudioClipEditor::~AudioClipEditor () { + EC_LOCAL_TEMPO_SCOPE; + drop_waves (); delete clip_metric; } @@ -277,6 +289,8 @@ AudioClipEditor::~AudioClipEditor () bool AudioClipEditor::line_event_handler (GdkEvent* ev, ArdourCanvas::Line* l) { + EC_LOCAL_TEMPO_SCOPE; + std::cerr << "event type " << Gtkmm2ext::event_type_string (ev->type) << " on line " << std::endl; switch (ev->type) { @@ -313,12 +327,16 @@ AudioClipEditor::line_event_handler (GdkEvent* ev, ArdourCanvas::Line* l) bool AudioClipEditor::key_press (GdkEventKey* ev) { + EC_LOCAL_TEMPO_SCOPE; + return false; } void AudioClipEditor::position_lines () { + EC_LOCAL_TEMPO_SCOPE; + if (!_region) { return; } @@ -358,6 +376,8 @@ AudioClipEditor::LineDrag::motion (GdkEventMotion* ev) void AudioClipEditor::set_colors () { + EC_LOCAL_TEMPO_SCOPE; + _canvas.set_background_color (UIConfiguration::instance ().color (X_("theme:bg"))); start_line->set_outline_color (UIConfiguration::instance ().color (X_("theme:contrasting clock"))); @@ -370,6 +390,8 @@ AudioClipEditor::set_colors () void AudioClipEditor::drop_waves () { + EC_LOCAL_TEMPO_SCOPE; + for (auto& wave : waves) { delete wave; } @@ -380,6 +402,8 @@ AudioClipEditor::drop_waves () void AudioClipEditor::set_trigger (TriggerReference& tr) { + EC_LOCAL_TEMPO_SCOPE; + if (tr == ref) { return; } @@ -394,6 +418,8 @@ AudioClipEditor::set_trigger (TriggerReference& tr) void AudioClipEditor::set_region (std::shared_ptr region) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_region (region); if (_visible_pending_region) { @@ -470,6 +496,8 @@ AudioClipEditor::set_region (std::shared_ptr region) void AudioClipEditor::canvas_allocate (Gtk::Allocation& alloc) { + EC_LOCAL_TEMPO_SCOPE; + _canvas.size_allocate (alloc); _visible_canvas_width = alloc.get_width(); @@ -496,6 +524,8 @@ AudioClipEditor::canvas_allocate (Gtk::Allocation& alloc) void AudioClipEditor::set_spp_from_length (samplecnt_t len) { + EC_LOCAL_TEMPO_SCOPE; + if (_visible_canvas_width) { set_samples_per_pixel (floor (len / _visible_canvas_width)); } @@ -504,6 +534,8 @@ AudioClipEditor::set_spp_from_length (samplecnt_t len) void AudioClipEditor::set_wave_heights () { + EC_LOCAL_TEMPO_SCOPE; + if (waves.empty ()) { return; } @@ -522,6 +554,8 @@ AudioClipEditor::set_wave_heights () void AudioClipEditor::set_waveform_colors () { + EC_LOCAL_TEMPO_SCOPE; + Gtkmm2ext::Color clip = UIConfiguration::instance ().color ("clipped waveform"); Gtkmm2ext::Color zero = UIConfiguration::instance ().color ("zero line"); Gtkmm2ext::Color fill = UIConfiguration::instance ().color ("waveform fill"); @@ -538,17 +572,23 @@ AudioClipEditor::set_waveform_colors () Gtk::Widget& AudioClipEditor::contents () { + EC_LOCAL_TEMPO_SCOPE; + return _contents; } void AudioClipEditor::region_changed (const PBD::PropertyChange& what_changed) { + EC_LOCAL_TEMPO_SCOPE; + } void AudioClipEditor::set_samples_per_pixel (samplecnt_t spp) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_samples_per_pixel (spp); clip_metric->units_per_pixel = samples_per_pixel; @@ -568,12 +608,16 @@ AudioClipEditor::set_samples_per_pixel (samplecnt_t spp) samplecnt_t AudioClipEditor::current_page_samples() const { + EC_LOCAL_TEMPO_SCOPE; + return (samplecnt_t) _track_canvas_width * samples_per_pixel; } bool AudioClipEditor::canvas_enter_leave (GdkEventCrossing* ev) { + EC_LOCAL_TEMPO_SCOPE; + switch (ev->type) { case GDK_ENTER_NOTIFY: if (ev->detail != GDK_NOTIFY_INFERIOR) { @@ -598,26 +642,36 @@ AudioClipEditor::canvas_enter_leave (GdkEventCrossing* ev) void AudioClipEditor::begin_write () { + EC_LOCAL_TEMPO_SCOPE; + } void AudioClipEditor::end_write () { + EC_LOCAL_TEMPO_SCOPE; + } void AudioClipEditor::show_count_in (std::string const &) { + EC_LOCAL_TEMPO_SCOPE; + } void AudioClipEditor::hide_count_in () { + EC_LOCAL_TEMPO_SCOPE; + } void AudioClipEditor::maybe_update () { + EC_LOCAL_TEMPO_SCOPE; + ARDOUR::TriggerPtr playing_trigger; if (ref.trigger()) { @@ -675,6 +729,8 @@ AudioClipEditor::maybe_update () void AudioClipEditor::unset (bool trigger_too) { + EC_LOCAL_TEMPO_SCOPE; + drop_waves (); CueEditor::unset (trigger_too); } diff --git a/gtk2_ardour/cue_editor.cc b/gtk2_ardour/cue_editor.cc index 1f4b682cdc..4c731a5767 100644 --- a/gtk2_ardour/cue_editor.cc +++ b/gtk2_ardour/cue_editor.cc @@ -71,11 +71,15 @@ CueEditor::~CueEditor () void CueEditor::set_snapped_cursor_position (Temporal::timepos_t const & pos) { + EC_LOCAL_TEMPO_SCOPE; + } std::vector CueEditor::filter_to_unique_midi_region_views (RegionSelection const & ms) const { + EC_LOCAL_TEMPO_SCOPE; + std::vector mrv; return mrv; } @@ -83,17 +87,23 @@ CueEditor::filter_to_unique_midi_region_views (RegionSelection const & ms) const void CueEditor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const { + EC_LOCAL_TEMPO_SCOPE; + } StripableTimeAxisView* CueEditor::get_stripable_time_axis_by_id (const PBD::ID& id) const { + EC_LOCAL_TEMPO_SCOPE; + return nullptr; } TrackViewList CueEditor::axis_views_from_routes (std::shared_ptr) const { + EC_LOCAL_TEMPO_SCOPE; + TrackViewList tvl; return tvl; } @@ -101,42 +111,56 @@ CueEditor::axis_views_from_routes (std::shared_ptr) const ARDOUR::Location* CueEditor::find_location_from_marker (ArdourMarker*, bool&) const { + EC_LOCAL_TEMPO_SCOPE; + return nullptr; } ArdourMarker* CueEditor::find_marker_from_location_id (PBD::ID const&, bool) const { + EC_LOCAL_TEMPO_SCOPE; + return nullptr; } TempoMarker* CueEditor::find_marker_for_tempo (Temporal::TempoPoint const &) { + EC_LOCAL_TEMPO_SCOPE; + return nullptr; } MeterMarker* CueEditor::find_marker_for_meter (Temporal::MeterPoint const &) { + EC_LOCAL_TEMPO_SCOPE; + return nullptr; } void CueEditor::redisplay_grid (bool immediate_redraw) { + EC_LOCAL_TEMPO_SCOPE; + update_grid (); } Temporal::timecnt_t CueEditor::get_nudge_distance (Temporal::timepos_t const & pos, Temporal::timecnt_t& next) const { + EC_LOCAL_TEMPO_SCOPE; + return Temporal::timecnt_t (Temporal::AudioTime); } void CueEditor::instant_save() { + EC_LOCAL_TEMPO_SCOPE; + if (!_region) { return; } @@ -158,42 +182,58 @@ CueEditor::instant_save() void CueEditor::begin_selection_op_history () { + EC_LOCAL_TEMPO_SCOPE; + } void CueEditor::begin_reversible_selection_op (std::string cmd_name) { + EC_LOCAL_TEMPO_SCOPE; + } void CueEditor::commit_reversible_selection_op () { + EC_LOCAL_TEMPO_SCOPE; + } void CueEditor::abort_reversible_selection_op () { + EC_LOCAL_TEMPO_SCOPE; + } void CueEditor::undo_selection_op () { + EC_LOCAL_TEMPO_SCOPE; + } void CueEditor::redo_selection_op () { + EC_LOCAL_TEMPO_SCOPE; + } double CueEditor::get_y_origin () const { + EC_LOCAL_TEMPO_SCOPE; + return 0.; } void CueEditor::set_zoom_focus (Editing::ZoomFocus zf) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Editing; /* We don't allow playhead for zoom focus here */ @@ -208,6 +248,8 @@ CueEditor::set_zoom_focus (Editing::ZoomFocus zf) void CueEditor::set_samples_per_pixel (samplecnt_t n) { + EC_LOCAL_TEMPO_SCOPE; + samples_per_pixel = n; ZoomChanged(); /* EMIT SIGNAL */ } @@ -215,12 +257,16 @@ CueEditor::set_samples_per_pixel (samplecnt_t n) samplecnt_t CueEditor::get_current_zoom () const { + EC_LOCAL_TEMPO_SCOPE; + return samples_per_pixel; } void CueEditor::reposition_and_zoom (samplepos_t pos, double spp) { + EC_LOCAL_TEMPO_SCOPE; + pending_visual_change.add (VisualChange::ZoomLevel); pending_visual_change.samples_per_pixel = spp; @@ -233,22 +279,30 @@ CueEditor::reposition_and_zoom (samplepos_t pos, double spp) void CueEditor::set_mouse_mode (Editing::MouseMode, bool force) { + EC_LOCAL_TEMPO_SCOPE; + } void CueEditor::step_mouse_mode (bool next) { + EC_LOCAL_TEMPO_SCOPE; + } Gdk::Cursor* CueEditor::get_canvas_cursor () const { + EC_LOCAL_TEMPO_SCOPE; + return nullptr; } std::shared_ptr CueEditor::start_local_tempo_map (std::shared_ptr map) { + EC_LOCAL_TEMPO_SCOPE; + std::shared_ptr tmp = Temporal::TempoMap::use(); Temporal::TempoMap::set (map); return tmp; @@ -257,12 +311,16 @@ CueEditor::start_local_tempo_map (std::shared_ptr map) void CueEditor::end_local_tempo_map (std::shared_ptr map) { + EC_LOCAL_TEMPO_SCOPE; + Temporal::TempoMap::set (map); } void CueEditor::do_undo (uint32_t n) { + EC_LOCAL_TEMPO_SCOPE; + if (_drags->active ()) { _drags->abort (); } @@ -273,6 +331,8 @@ CueEditor::do_undo (uint32_t n) void CueEditor::do_redo (uint32_t n) { + EC_LOCAL_TEMPO_SCOPE; + if (_drags->active ()) { _drags->abort (); } @@ -283,12 +343,16 @@ CueEditor::do_redo (uint32_t n) void CueEditor::history_changed () { + EC_LOCAL_TEMPO_SCOPE; + update_undo_redo_actions (_history); } Temporal::timepos_t CueEditor::_get_preferred_edit_position (Editing::EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas) { + EC_LOCAL_TEMPO_SCOPE; + samplepos_t where; bool in_track_canvas = false; @@ -302,6 +366,8 @@ CueEditor::_get_preferred_edit_position (Editing::EditIgnoreOption ignore, bool void CueEditor::build_upper_toolbar () { + EC_LOCAL_TEMPO_SCOPE; + using namespace Gtk::Menu_Helpers; Gtk::HBox* mode_box = manage(new Gtk::HBox); @@ -423,6 +489,8 @@ CueEditor::build_upper_toolbar () void CueEditor::build_zoom_focus_menu () { + EC_LOCAL_TEMPO_SCOPE; + using namespace Gtk::Menu_Helpers; using namespace Editing; @@ -436,6 +504,8 @@ CueEditor::build_zoom_focus_menu () bool CueEditor::bang_button_press (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (!ref.trigger()) { return true; } @@ -448,6 +518,8 @@ CueEditor::bang_button_press (GdkEventButton* ev) bool CueEditor::play_button_press (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (_session && _region) { _session->request_locate (_region->position().samples()); _session->request_roll (); @@ -459,6 +531,8 @@ CueEditor::play_button_press (GdkEventButton* ev) bool CueEditor::loop_button_press (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (!_region) { return true; } @@ -476,6 +550,8 @@ CueEditor::loop_button_press (GdkEventButton* ev) bool CueEditor::solo_button_press (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (!_track) { return true; } @@ -488,6 +564,8 @@ CueEditor::solo_button_press (GdkEventButton* ev) bool CueEditor::rec_button_press (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (ev->button != 1) { return false; } @@ -510,6 +588,8 @@ CueEditor::rec_button_press (GdkEventButton* ev) void CueEditor::blink_rec_enable (bool onoff) { + EC_LOCAL_TEMPO_SCOPE; + if (onoff) { rec_enable_button.set_active_state (Gtkmm2ext::ExplicitActive); } else { @@ -520,6 +600,8 @@ CueEditor::blink_rec_enable (bool onoff) void CueEditor::trigger_arm_change () { + EC_LOCAL_TEMPO_SCOPE; + if (!ref.trigger()) { return; } @@ -536,6 +618,8 @@ CueEditor::trigger_arm_change () void CueEditor::rec_enable_change () { + EC_LOCAL_TEMPO_SCOPE; + if (!ref.box()) { return; } @@ -568,12 +652,16 @@ CueEditor::rec_enable_change () void CueEditor::set_recording_length (Temporal::BBT_Offset dur) { + EC_LOCAL_TEMPO_SCOPE; + rec_length = dur; } void CueEditor::scrolled () { + EC_LOCAL_TEMPO_SCOPE; + pending_visual_change.add (VisualChange::TimeOrigin); pending_visual_change.time_origin = horizontal_adjustment.get_value() * samples_per_pixel; ensure_visual_change_idle_handler (); @@ -582,6 +670,8 @@ CueEditor::scrolled () bool CueEditor::canvas_pre_event (GdkEvent* ev) { + EC_LOCAL_TEMPO_SCOPE; + switch (ev->type) { case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: @@ -599,6 +689,8 @@ CueEditor::canvas_pre_event (GdkEvent* ev) bool CueEditor::autoscroll_active () const { + EC_LOCAL_TEMPO_SCOPE; + return autoscroll_connection.connected (); } @@ -610,6 +702,8 @@ CueEditor::autoscroll_active () const void CueEditor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers) { + EC_LOCAL_TEMPO_SCOPE; + if (!UIConfiguration::instance().get_autoscroll_editor () || autoscroll_active ()) { return; } @@ -681,6 +775,8 @@ CueEditor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_header bool CueEditor::autoscroll_canvas () { + EC_LOCAL_TEMPO_SCOPE; + using std::max; using std::min; int x, y; @@ -881,6 +977,8 @@ CueEditor::autoscroll_canvas () void CueEditor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -904,6 +1002,8 @@ CueEditor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const Ard void CueEditor::stop_canvas_autoscroll () { + EC_LOCAL_TEMPO_SCOPE; + autoscroll_connection.disconnect (); autoscroll_cnt = 0; } @@ -911,6 +1011,8 @@ CueEditor::stop_canvas_autoscroll () void CueEditor::visual_changer (const VisualChange& vc) { + EC_LOCAL_TEMPO_SCOPE; + /** * Changed first so the correct horizontal canvas position is calculated in * EditingContext::set_horizontal_position @@ -951,6 +1053,8 @@ CueEditor::visual_changer (const VisualChange& vc) void CueEditor::catch_pending_show_region () { + EC_LOCAL_TEMPO_SCOPE; + if (_visible_pending_region) { std::shared_ptr r (_visible_pending_region); _visible_pending_region.reset (); @@ -961,6 +1065,8 @@ CueEditor::catch_pending_show_region () RegionSelection CueEditor::region_selection() { + EC_LOCAL_TEMPO_SCOPE; + RegionSelection rs; /* there is never any region-level selection in a pianoroll */ return rs; @@ -969,6 +1075,8 @@ CueEditor::region_selection() void CueEditor::mouse_mode_chosen (Editing::MouseMode m) { + EC_LOCAL_TEMPO_SCOPE; + if (!mouse_mode_actions[m]->get_active()) { /* this was just the notification that the old mode has been * left. we'll get called again with the new mode active in a @@ -989,6 +1097,8 @@ CueEditor::mouse_mode_chosen (Editing::MouseMode m) std::pair CueEditor::max_zoom_extent() const { + EC_LOCAL_TEMPO_SCOPE; + if (_region) { Temporal::Beats len; @@ -1011,6 +1121,8 @@ CueEditor::max_zoom_extent() const void CueEditor::zoom_to_show (Temporal::timecnt_t const & duration) { + EC_LOCAL_TEMPO_SCOPE; + if (!_track_canvas_width) { zoom_in_allocate = true; return; @@ -1022,6 +1134,8 @@ CueEditor::zoom_to_show (Temporal::timecnt_t const & duration) void CueEditor::full_zoom_clicked() { + EC_LOCAL_TEMPO_SCOPE; + /* XXXX NEED LOCAL TEMPO MAP */ std::pair dur (max_zoom_extent()); @@ -1032,12 +1146,16 @@ CueEditor::full_zoom_clicked() void CueEditor::set_show_source (bool yn) { + EC_LOCAL_TEMPO_SCOPE; + show_source = yn; } void CueEditor::update_solo_display () { + EC_LOCAL_TEMPO_SCOPE; + if (_track->solo_control()->get_value()) { solo_button.set_active_state (Gtkmm2ext::ExplicitActive); } else { @@ -1048,6 +1166,8 @@ CueEditor::update_solo_display () void CueEditor::set_track (std::shared_ptr t) { + EC_LOCAL_TEMPO_SCOPE; + _track = t; _track->solo_control()->Changed.connect (object_connections, invalidator (*this), std::bind (&CueEditor::update_solo_display, this), gui_context()); update_solo_display (); @@ -1056,6 +1176,8 @@ CueEditor::set_track (std::shared_ptr t) void CueEditor::set_region (std::shared_ptr r) { + EC_LOCAL_TEMPO_SCOPE; + if (r == _region) { return; } @@ -1074,6 +1196,8 @@ CueEditor::set_region (std::shared_ptr r) void CueEditor::maybe_set_from_rsu () { + EC_LOCAL_TEMPO_SCOPE; + RegionUISettingsManager::iterator rsu = ARDOUR_UI::instance()->region_ui_settings_manager.find (_region->id()); if (rsu != ARDOUR_UI::instance()->region_ui_settings_manager.end()) { set_from_rsu (rsu->second); @@ -1083,6 +1207,8 @@ CueEditor::maybe_set_from_rsu () void CueEditor::set_from_rsu (RegionUISettings& rsu) { + EC_LOCAL_TEMPO_SCOPE; + follow_playhead_action->set_active (rsu.follow_playhead); /* XXXX play selection */ @@ -1101,6 +1227,8 @@ CueEditor::set_from_rsu (RegionUISettings& rsu) void CueEditor::set_trigger (TriggerReference& tref) { + EC_LOCAL_TEMPO_SCOPE; + if (tref == ref) { return; } @@ -1122,6 +1250,8 @@ CueEditor::set_trigger (TriggerReference& tref) void CueEditor::ruler_locate (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -1143,6 +1273,8 @@ CueEditor::ruler_locate (GdkEventButton* ev) void CueEditor::maybe_set_count_in () { + EC_LOCAL_TEMPO_SCOPE; + if (!ref.box()) { std::cerr << "msci no box\n"; return; @@ -1179,6 +1311,8 @@ CueEditor::maybe_set_count_in () void CueEditor::count_in (Temporal::timepos_t audible, unsigned int clock_interval_msecs) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -1224,6 +1358,8 @@ CueEditor::count_in (Temporal::timepos_t audible, unsigned int clock_interval_ms bool CueEditor::ruler_event (GdkEvent* ev) { + EC_LOCAL_TEMPO_SCOPE; + switch (ev->type) { case GDK_BUTTON_RELEASE: if (ev->button.button == 1) { @@ -1240,6 +1376,8 @@ CueEditor::ruler_event (GdkEvent* ev) void CueEditor::data_captured (samplecnt_t total_duration) { + EC_LOCAL_TEMPO_SCOPE; + data_capture_duration = total_duration; if (!idle_update_queued.exchange (1)) { @@ -1250,6 +1388,8 @@ CueEditor::data_captured (samplecnt_t total_duration) bool CueEditor::idle_data_captured () { + EC_LOCAL_TEMPO_SCOPE; + if (!ref.box()) { return false; } @@ -1274,6 +1414,8 @@ CueEditor::idle_data_captured () void CueEditor::unset (bool trigger_too) { + EC_LOCAL_TEMPO_SCOPE; + _history.clear (); history_connection.disconnect(); _update_connection.disconnect(); @@ -1293,6 +1435,8 @@ CueEditor::unset (bool trigger_too) void CueEditor::session_going_away () { + EC_LOCAL_TEMPO_SCOPE; + EditingContext::session_going_away (); unset (true); } @@ -1300,6 +1444,8 @@ CueEditor::session_going_away () void CueEditor::load_bindings () { + EC_LOCAL_TEMPO_SCOPE; + load_shared_bindings (); for (auto & b : bindings) { b->associate (); @@ -1310,6 +1456,8 @@ CueEditor::load_bindings () void CueEditor::register_actions () { + EC_LOCAL_TEMPO_SCOPE; + editor_actions = ActionManager::create_action_group (own_bindings, editor_name()); bind_mouse_mode_buttons (); } @@ -1317,12 +1465,16 @@ CueEditor::register_actions () ArdourCanvas::GtkCanvasViewport* CueEditor::get_canvas_viewport() const { + EC_LOCAL_TEMPO_SCOPE; + return const_cast(&_canvas_viewport); } ArdourCanvas::GtkCanvas* CueEditor::get_canvas() const { + EC_LOCAL_TEMPO_SCOPE; + return &_canvas; } @@ -1330,6 +1482,8 @@ CueEditor::get_canvas() const int CueEditor::set_state (XMLNode const & node, int version) { + EC_LOCAL_TEMPO_SCOPE; + set_common_editing_state (node); return 0; } @@ -1337,6 +1491,8 @@ CueEditor::set_state (XMLNode const & node, int version) XMLNode& CueEditor::get_state () const { + EC_LOCAL_TEMPO_SCOPE; + XMLNode* node (new XMLNode (editor_name())); get_common_editing_state (*node); return *node; @@ -1354,6 +1510,8 @@ edit_last_mark_label (std::vector& marks, const std:: void CueEditor::metric_get_bbt (std::vector& marks, samplepos_t leftmost, samplepos_t rightmost, gint /*maxchars*/) { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } diff --git a/gtk2_ardour/pianoroll.cc b/gtk2_ardour/pianoroll.cc index eb4b164592..6f3fa256cb 100644 --- a/gtk2_ardour/pianoroll.cc +++ b/gtk2_ardour/pianoroll.cc @@ -105,6 +105,8 @@ Pianoroll::~Pianoroll () void Pianoroll::set_show_source (bool yn) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_show_source (yn); if (view) { view->set_show_source (yn); @@ -114,6 +116,8 @@ Pianoroll::set_show_source (bool yn) void Pianoroll::rebuild_parameter_button_map() { + EC_LOCAL_TEMPO_SCOPE; + parameter_button_map.clear (); parameter_button_map.insert (std::make_pair (velocity_button, Evoral::Parameter (ARDOUR::MidiVelocityAutomation, _visible_channel))); parameter_button_map.insert (std::make_pair (bender_button, Evoral::Parameter (ARDOUR::MidiPitchBenderAutomation, _visible_channel))); @@ -129,6 +133,8 @@ Pianoroll::rebuild_parameter_button_map() void Pianoroll::reset_user_cc_choice (std::string name, Evoral::Parameter param, MetaButton* metabutton) { + EC_LOCAL_TEMPO_SCOPE; + ParameterButtonMap::iterator iter; for (iter = parameter_button_map.begin(); iter != parameter_button_map.end(); ++iter) { @@ -149,6 +155,8 @@ Pianoroll::add_single_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, const std::string& name, ArdourWidgets::MetaButton* mb) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Gtk::Menu_Helpers; const uint16_t selected_channels = 0xffff; @@ -174,6 +182,8 @@ Pianoroll::add_multi_controller_item (Gtk::Menu_Helpers::MenuList&, const std::string& name, MetaButton* mb) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Gtk; using namespace Gtk::Menu_Helpers; @@ -223,6 +233,8 @@ Pianoroll::add_multi_controller_item (Gtk::Menu_Helpers::MenuList&, void Pianoroll::build_lower_toolbar () { + EC_LOCAL_TEMPO_SCOPE; + horizontal_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &Pianoroll::scrolled)); ArdourButton::Element elements = ArdourButton::Element (ArdourButton::Text|ArdourButton::Indicator|ArdourButton::Edge|ArdourButton::Body); @@ -292,6 +304,8 @@ Pianoroll::build_lower_toolbar () void Pianoroll::pack_inner (Gtk::Box& box) { + EC_LOCAL_TEMPO_SCOPE; + box.pack_start (snap_box, false, false); box.pack_start (grid_box, false, false); box.pack_start (draw_box, false, false); @@ -300,6 +314,8 @@ Pianoroll::pack_inner (Gtk::Box& box) void Pianoroll::pack_outer (Gtk::Box& box) { + EC_LOCAL_TEMPO_SCOPE; + if (with_transport_controls) { box.pack_start (play_box, false, false); } @@ -314,6 +330,8 @@ Pianoroll::pack_outer (Gtk::Box& box) void Pianoroll::set_visible_channel (int n) { + EC_LOCAL_TEMPO_SCOPE; + PBD::Unwinder uw (ignore_channel_changes, true); _visible_channel = n; @@ -332,6 +350,8 @@ Pianoroll::set_visible_channel (int n) void Pianoroll::build_canvas () { + EC_LOCAL_TEMPO_SCOPE; + _canvas.set_background_color (UIConfiguration::instance().color ("arrange base")); _canvas.signal_event().connect (sigc::mem_fun (*this, &Pianoroll::canvas_pre_event), false); dynamic_cast(&_canvas)->use_nsglview (UIConfiguration::instance().get_nsgl_view_mode () == NSGLHiRes); @@ -473,6 +493,8 @@ Pianoroll::build_canvas () void Pianoroll::visible_channel_changed () { + EC_LOCAL_TEMPO_SCOPE; + if (ignore_channel_changes) { /* We're changing it */ return; @@ -491,6 +513,8 @@ Pianoroll::visible_channel_changed () void Pianoroll::bindings_changed () { + EC_LOCAL_TEMPO_SCOPE; + bindings.clear (); load_shared_bindings (); } @@ -498,6 +522,8 @@ Pianoroll::bindings_changed () void Pianoroll::maybe_update () { + EC_LOCAL_TEMPO_SCOPE; + ARDOUR::TriggerPtr playing_trigger; if (ref.trigger()) { @@ -555,6 +581,8 @@ Pianoroll::maybe_update () bool Pianoroll::canvas_enter_leave (GdkEventCrossing* ev) { + EC_LOCAL_TEMPO_SCOPE; + switch (ev->type) { case GDK_ENTER_NOTIFY: if (ev->detail != GDK_NOTIFY_INFERIOR) { @@ -579,6 +607,8 @@ Pianoroll::canvas_enter_leave (GdkEventCrossing* ev) void Pianoroll::canvas_allocate (Gtk::Allocation alloc) { + EC_LOCAL_TEMPO_SCOPE; + _visible_canvas_width = alloc.get_width(); _visible_canvas_height = alloc.get_height(); @@ -610,6 +640,8 @@ Pianoroll::canvas_allocate (Gtk::Allocation alloc) timepos_t Pianoroll::snap_to_grid (timepos_t const & presnap, Temporal::RoundMode direction, SnapPref gpref) const { + EC_LOCAL_TEMPO_SCOPE; + /* BBT time only */ return snap_to_bbt (presnap, direction, gpref); } @@ -617,6 +649,8 @@ Pianoroll::snap_to_grid (timepos_t const & presnap, Temporal::RoundMode directio void Pianoroll::snap_to_internal (timepos_t& start, Temporal::RoundMode direction, SnapPref pref, bool ensure_snap) const { + EC_LOCAL_TEMPO_SCOPE; + UIConfiguration const& uic (UIConfiguration::instance ()); const timepos_t presnap = start; @@ -649,6 +683,8 @@ Pianoroll::snap_to_internal (timepos_t& start, Temporal::RoundMode direction, Sn void Pianoroll::set_samples_per_pixel (samplecnt_t spp) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_samples_per_pixel (spp); if (view) { @@ -666,54 +702,72 @@ Pianoroll::set_samples_per_pixel (samplecnt_t spp) samplecnt_t Pianoroll::current_page_samples() const { + EC_LOCAL_TEMPO_SCOPE; + return (samplecnt_t) _track_canvas_width * samples_per_pixel; } bool Pianoroll::canvas_bg_event (GdkEvent* event, ArdourCanvas::Item* item) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, RegionItem); } bool Pianoroll::canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item* item, ControlPoint* cp) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, ControlPointItem); } bool Pianoroll::canvas_note_event (GdkEvent* event, ArdourCanvas::Item* item) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, NoteItem); } bool Pianoroll::canvas_velocity_base_event (GdkEvent* event, ArdourCanvas::Item* item) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, VelocityBaseItem); } bool Pianoroll::canvas_velocity_event (GdkEvent* event, ArdourCanvas::Item* item) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, VelocityItem); } bool Pianoroll::canvas_cue_start_event (GdkEvent* event, ArdourCanvas::Item* item) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, ClipStartItem); } bool Pianoroll::canvas_cue_end_event (GdkEvent* event, ArdourCanvas::Item* item) { + EC_LOCAL_TEMPO_SCOPE; + return typed_event (item, event, ClipEndItem); } void Pianoroll::set_trigger_start (Temporal::timepos_t const & p) { + EC_LOCAL_TEMPO_SCOPE; + if (ref.trigger()) { ref.trigger()->the_region()->trim_front (p); } else { @@ -728,6 +782,8 @@ Pianoroll::set_trigger_start (Temporal::timepos_t const & p) void Pianoroll::set_trigger_end (Temporal::timepos_t const & p) { + EC_LOCAL_TEMPO_SCOPE; + if (ref.trigger()) { ref.trigger()->the_region()->trim_end (p); } else { @@ -742,12 +798,16 @@ Pianoroll::set_trigger_end (Temporal::timepos_t const & p) Gtk::Widget& Pianoroll::contents () { + EC_LOCAL_TEMPO_SCOPE; + return _contents; } bool Pianoroll::idle_data_captured () { + EC_LOCAL_TEMPO_SCOPE; + if (!ref.box()) { return false; } @@ -764,6 +824,8 @@ Pianoroll::idle_data_captured () bool Pianoroll::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { + EC_LOCAL_TEMPO_SCOPE; + if (event->type != GDK_BUTTON_PRESS) { return false; } @@ -792,6 +854,8 @@ Pianoroll::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, Item bool Pianoroll::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { + EC_LOCAL_TEMPO_SCOPE; + NoteBase* note = nullptr; Editing::MouseMode mouse_mode = current_mouse_mode(); switch (item_type) { @@ -894,12 +958,16 @@ Pianoroll::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, It bool Pianoroll::button_press_handler_2 (ArdourCanvas::Item*, GdkEvent*, ItemType) { + EC_LOCAL_TEMPO_SCOPE; + return true; } bool Pianoroll::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { + EC_LOCAL_TEMPO_SCOPE; + if (!Keyboard::is_context_menu_event (&event->button)) { /* see if we're finishing a drag */ @@ -941,6 +1009,8 @@ Pianoroll::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, It void Pianoroll::popup_region_context_menu (ArdourCanvas::Item* item, GdkEvent* event) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Gtk::Menu_Helpers; if (!view) { @@ -976,6 +1046,8 @@ Pianoroll::popup_region_context_menu (ArdourCanvas::Item* item, GdkEvent* event) bool Pianoroll::button_press_dispatch (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + /* this function is intended only for buttons 4 and above. */ Gtkmm2ext::MouseButton b (ev->state, ev->button); @@ -985,6 +1057,8 @@ Pianoroll::button_press_dispatch (GdkEventButton* ev) bool Pianoroll::button_release_dispatch (GdkEventButton* ev) { + EC_LOCAL_TEMPO_SCOPE; + /* this function is intended only for buttons 4 and above. */ Gtkmm2ext::MouseButton b (ev->state, ev->button); @@ -994,6 +1068,8 @@ Pianoroll::button_release_dispatch (GdkEventButton* ev) bool Pianoroll::motion_handler (ArdourCanvas::Item*, GdkEvent* event, bool from_autoscroll) { + EC_LOCAL_TEMPO_SCOPE; + if (_drags->active ()) { //drags change the snapped_cursor location, because we are snapping the thing being dragged, not the actual mouse cursor return _drags->motion_handler (event, from_autoscroll); @@ -1005,6 +1081,8 @@ Pianoroll::motion_handler (ArdourCanvas::Item*, GdkEvent* event, bool from_autos bool Pianoroll::key_press_handler (ArdourCanvas::Item*, GdkEvent* ev, ItemType) { + EC_LOCAL_TEMPO_SCOPE; + switch (ev->key.keyval) { case GDK_d: @@ -1021,12 +1099,16 @@ Pianoroll::key_press_handler (ArdourCanvas::Item*, GdkEvent* ev, ItemType) bool Pianoroll::key_release_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) { + EC_LOCAL_TEMPO_SCOPE; + return true; } void Pianoroll::set_mouse_mode (Editing::MouseMode m, bool force) { + EC_LOCAL_TEMPO_SCOPE; + if (m != Editing::MouseDraw && m != Editing::MouseContent) { return; } @@ -1037,6 +1119,8 @@ Pianoroll::set_mouse_mode (Editing::MouseMode m, bool force) void Pianoroll::midi_action (void (MidiView::*method)()) { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1047,6 +1131,8 @@ Pianoroll::midi_action (void (MidiView::*method)()) void Pianoroll::escape () { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1057,12 +1143,16 @@ Pianoroll::escape () Gdk::Cursor* Pianoroll::which_track_cursor () const { + EC_LOCAL_TEMPO_SCOPE; + return _cursors->grabber; } Gdk::Cursor* Pianoroll::which_mode_cursor () const { + EC_LOCAL_TEMPO_SCOPE; + Gdk::Cursor* mode_cursor = MouseCursors::invalid_cursor (); switch (current_mouse_mode()) { @@ -1084,6 +1174,8 @@ Pianoroll::which_mode_cursor () const Gdk::Cursor* Pianoroll::which_trim_cursor (bool left_side) const { + EC_LOCAL_TEMPO_SCOPE; + abort (); /*NOTREACHED*/ return nullptr; @@ -1093,6 +1185,8 @@ Pianoroll::which_trim_cursor (bool left_side) const Gdk::Cursor* Pianoroll::which_canvas_cursor (ItemType type) const { + EC_LOCAL_TEMPO_SCOPE; + Gdk::Cursor* cursor = which_mode_cursor (); Editing::MouseMode mouse_mode = current_mouse_mode (); @@ -1180,6 +1274,8 @@ Pianoroll::which_canvas_cursor (ItemType type) const bool Pianoroll::enter_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) { + EC_LOCAL_TEMPO_SCOPE; + choose_canvas_cursor_on_entry (item_type); switch (item_type) { @@ -1209,6 +1305,8 @@ Pianoroll::enter_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_ bool Pianoroll::leave_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) { + EC_LOCAL_TEMPO_SCOPE; + EditorAutomationLine* al; set_canvas_cursor (which_mode_cursor()); @@ -1242,6 +1340,8 @@ Pianoroll::leave_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_ std::list Pianoroll::selectable_owners() { + EC_LOCAL_TEMPO_SCOPE; + if (view) { return view->selectable_owners(); } @@ -1252,6 +1352,8 @@ Pianoroll::selectable_owners() void Pianoroll::trigger_prop_change (PBD::PropertyChange const & what_changed) { + EC_LOCAL_TEMPO_SCOPE; + if (what_changed.contains (Properties::region)) { std::shared_ptr mr = std::dynamic_pointer_cast (ref.trigger()->the_region()); if (mr) { @@ -1263,6 +1365,8 @@ Pianoroll::trigger_prop_change (PBD::PropertyChange const & what_changed) void Pianoroll::region_prop_change (PBD::PropertyChange const & what_changed) { + EC_LOCAL_TEMPO_SCOPE; + if (what_changed.contains (Properties::length)) { std::shared_ptr mr = view->midi_region(); if (mr) { @@ -1274,6 +1378,8 @@ Pianoroll::region_prop_change (PBD::PropertyChange const & what_changed) void Pianoroll::set_trigger (TriggerReference & tref) { + EC_LOCAL_TEMPO_SCOPE; + if (ref == tref) { return; } @@ -1309,6 +1415,8 @@ Pianoroll::set_trigger (TriggerReference & tref) void Pianoroll::make_a_region () { + EC_LOCAL_TEMPO_SCOPE; + std::shared_ptr new_source = _session->create_midi_source_for_session (_track->name()); SourceList sources; sources.push_back (new_source); @@ -1334,6 +1442,8 @@ Pianoroll::make_a_region () void Pianoroll::unset (bool trigger_too) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::unset (trigger_too); view->set_region (nullptr); } @@ -1341,6 +1451,8 @@ Pianoroll::unset (bool trigger_too) void Pianoroll::set_track (std::shared_ptr track) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_track (track); if (view) { @@ -1369,6 +1481,8 @@ Pianoroll::set_track (std::shared_ptr track) void Pianoroll::set_region (std::shared_ptr region) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_region (region); if (_visible_pending_region) { @@ -1438,6 +1552,8 @@ Pianoroll::set_region (std::shared_ptr region) bool Pianoroll::user_automation_button_event (GdkEventButton* ev, MetaButton* mb) { + EC_LOCAL_TEMPO_SCOPE; + if (mb->is_menu_popup_event (ev)) { return false; } @@ -1462,6 +1578,8 @@ Pianoroll::user_automation_button_event (GdkEventButton* ev, MetaButton* mb) void Pianoroll::user_led_click (GdkEventButton* ev, MetaButton* metabutton) { + EC_LOCAL_TEMPO_SCOPE; + if (ev->button != 1) { return; } @@ -1478,6 +1596,8 @@ Pianoroll::user_led_click (GdkEventButton* ev, MetaButton* metabutton) bool Pianoroll::automation_button_event (GdkEventButton* ev, Evoral::ParameterType type, int id) { + EC_LOCAL_TEMPO_SCOPE; + if (ev->button != 1) { return false; } @@ -1492,6 +1612,8 @@ Pianoroll::automation_button_event (GdkEventButton* ev, Evoral::ParameterType ty void Pianoroll::automation_led_click (GdkEventButton* ev, Evoral::ParameterType type, int id) { + EC_LOCAL_TEMPO_SCOPE; + if (ev->button != 1) { return; } @@ -1511,6 +1633,8 @@ Pianoroll::automation_led_click (GdkEventButton* ev, Evoral::ParameterType type, void Pianoroll::automation_state_changed () { + EC_LOCAL_TEMPO_SCOPE; + assert (view); for (ParameterButtonMap::iterator i = parameter_button_map.begin(); i != parameter_button_map.end(); ++i) { @@ -1537,6 +1661,8 @@ Pianoroll::automation_state_changed () void Pianoroll::note_mode_clicked () { + EC_LOCAL_TEMPO_SCOPE; + assert (bg); if (bg->note_mode() == Sustained) { @@ -1549,6 +1675,8 @@ Pianoroll::note_mode_clicked () void Pianoroll::set_note_mode (NoteMode nm) { + EC_LOCAL_TEMPO_SCOPE; + assert (bg); if (nm != bg->note_mode()) { @@ -1564,6 +1692,8 @@ Pianoroll::set_note_mode (NoteMode nm) void Pianoroll::point_selection_changed () { + EC_LOCAL_TEMPO_SCOPE; + if (view) { view->point_selection_changed (); } @@ -1572,6 +1702,8 @@ Pianoroll::point_selection_changed () void Pianoroll::delete_ () { + EC_LOCAL_TEMPO_SCOPE; + /* Editor has a lot to do here, potentially. But we don't */ cut_copy (Editing::Delete); } @@ -1579,6 +1711,8 @@ Pianoroll::delete_ () void Pianoroll::paste (float times, bool from_context_menu) { + EC_LOCAL_TEMPO_SCOPE; + if (view) { // view->paste (Editing::Cut); } @@ -1587,6 +1721,8 @@ Pianoroll::paste (float times, bool from_context_menu) void Pianoroll::keyboard_paste () { + EC_LOCAL_TEMPO_SCOPE; + } /** Cut, copy or clear selected regions, automation points or a time range. @@ -1596,6 +1732,8 @@ Pianoroll::keyboard_paste () void Pianoroll::cut_copy (Editing::CutCopyOp op) { + EC_LOCAL_TEMPO_SCOPE; + using namespace Editing; /* only cancel selection if cut/copy is successful.*/ @@ -1655,6 +1793,8 @@ Pianoroll::cut_copy (Editing::CutCopyOp op) void Pianoroll::select_all_within (Temporal::timepos_t const & start, Temporal::timepos_t const & end, double y0, double y1, std::list const & ignored, ARDOUR::SelectionOperation op, bool preserve_if_selected) { + EC_LOCAL_TEMPO_SCOPE; + std::list found; if (!view) { @@ -1737,6 +1877,8 @@ Pianoroll::select_all_within (Temporal::timepos_t const & start, Temporal::timep void Pianoroll::set_session (ARDOUR::Session* s) { + EC_LOCAL_TEMPO_SCOPE; + CueEditor::set_session (s); if (with_transport_controls) { @@ -1757,6 +1899,8 @@ Pianoroll::set_session (ARDOUR::Session* s) void Pianoroll::map_transport_state () { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { loop_button.unset_active_state (); play_button.unset_active_state (); @@ -1794,6 +1938,8 @@ Pianoroll::map_transport_state () bool Pianoroll::allow_trim_cursors () const { + EC_LOCAL_TEMPO_SCOPE; + auto mouse_mode = current_mouse_mode (); return mouse_mode == Editing::MouseContent || mouse_mode == Editing::MouseTimeFX; } @@ -1801,6 +1947,8 @@ Pianoroll::allow_trim_cursors () const void Pianoroll::shift_midi (timepos_t const & t, bool model) { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1811,6 +1959,8 @@ Pianoroll::shift_midi (timepos_t const & t, bool model) InstrumentInfo* Pianoroll::instrument_info () const { + EC_LOCAL_TEMPO_SCOPE; + if (!view || !view->midi_track()) { return nullptr; } @@ -1821,6 +1971,8 @@ Pianoroll::instrument_info () const void Pianoroll::update_tempo_based_rulers () { + EC_LOCAL_TEMPO_SCOPE; + if (!_session) { return; } @@ -1833,6 +1985,8 @@ Pianoroll::update_tempo_based_rulers () void Pianoroll::set_note_selection (uint8_t note) { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1847,6 +2001,8 @@ Pianoroll::set_note_selection (uint8_t note) void Pianoroll::add_note_selection (uint8_t note) { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1861,6 +2017,8 @@ Pianoroll::add_note_selection (uint8_t note) void Pianoroll::extend_note_selection (uint8_t note) { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1875,6 +2033,8 @@ Pianoroll::extend_note_selection (uint8_t note) void Pianoroll::toggle_note_selection (uint8_t note) { + EC_LOCAL_TEMPO_SCOPE; + if (!view) { return; } @@ -1889,6 +2049,8 @@ Pianoroll::toggle_note_selection (uint8_t note) void Pianoroll::begin_write () { + EC_LOCAL_TEMPO_SCOPE; + if (view) { view->begin_write (); } @@ -1897,6 +2059,8 @@ Pianoroll::begin_write () void Pianoroll::end_write () { + EC_LOCAL_TEMPO_SCOPE; + if (view) { view->end_write (); } @@ -1905,6 +2069,8 @@ Pianoroll::end_write () void Pianoroll::manage_possible_header (Gtk::Allocation& alloc) { + EC_LOCAL_TEMPO_SCOPE; + if (prh) { double w, h; prh->size_request (w, h); @@ -1916,6 +2082,8 @@ Pianoroll::manage_possible_header (Gtk::Allocation& alloc) void Pianoroll::show_count_in (std::string const & str) { + EC_LOCAL_TEMPO_SCOPE; + if (view) { view->set_overlay_text (str); } @@ -1924,6 +2092,8 @@ Pianoroll::show_count_in (std::string const & str) void Pianoroll::hide_count_in () { + EC_LOCAL_TEMPO_SCOPE; + if (view) { view->hide_overlay_text (); } @@ -1932,6 +2102,8 @@ Pianoroll::hide_count_in () void Pianoroll::instant_save () { + EC_LOCAL_TEMPO_SCOPE; + region_ui_settings.draw_length = draw_length(); region_ui_settings.draw_velocity = draw_velocity(); region_ui_settings.channel = draw_channel(); @@ -1944,6 +2116,8 @@ Pianoroll::instant_save () void Pianoroll::parameter_changed (std::string param) { + EC_LOCAL_TEMPO_SCOPE; + if (param == X_("note-name-display")) { if (prh) { prh->instrument_info_change (); From f66207f2a27ec6617218054f8a8a1e5d55f73939 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 8 Aug 2025 23:36:16 +0200 Subject: [PATCH 20/32] Replace git.ardour link with github git.ardour.org no longer allows to show individual commits or source files (thanks to LLM scrapers trying to get them all). --- doc/mainpage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mainpage.md b/doc/mainpage.md index cf5a01a7ff..67eca802c4 100755 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -91,7 +91,7 @@ A few specific libraries are compiled statically (e.g. fluidsynth for use in plu Mini Ardour inside Ardour to export audio-files from sessions. It is a combination of AudioGrapher::Source and AudioGrapher::Sink classes that are chained together by ARDOUR::ExportGraphBuilder as shown in the ASCII art - [Export Graph](https://git.ardour.org/ardour/ardour/src/commit/0df0e14e2309a00d433827fa34b87638b87f4fff/libs/ardour/export_graph_builder.cc#L73-L154). + [Export Graph](https://github.com/Ardour/ardour/blob/56647acc25aa91ccf920e5ac21452bccf35b78e7/libs/ardour/export_graph_builder.cc#L73-L154). * `libs/ardour/` From 20269df975f4c6edd127d0cb4a114f9e89b7a4e1 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 15:41:32 -0600 Subject: [PATCH 21/32] Regions get their own tempo and meter This defaults to the usual 120bpm 4/4 but is also not used anywhere yet --- libs/ardour/ardour/region.h | 7 +++++++ libs/ardour/region.cc | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index d682ac9e0f..bccdbf78f0 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -29,6 +29,7 @@ #include "temporal/domain_swap.h" #include "temporal/timeline.h" #include "temporal/range.h" +#include "temporal/tempo.h" #include "pbd/undo.h" #include "pbd/signals.h" @@ -541,6 +542,9 @@ public: } } + Temporal::Tempo tempo() const { return _tempo; } + Temporal::Meter meter() const { return _meter; } + protected: virtual XMLNode& state () const; @@ -593,6 +597,9 @@ protected: uint32_t _fx_tail; RegionFxList _plugins; + Temporal::Tempo _tempo; + Temporal::Meter _meter; + PBD::Property _sync_marked; PBD::Property _left_of_split; PBD::Property _right_of_split; diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index ac7d2ab2b6..6da010e635 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -228,7 +228,9 @@ Region::register_properties () } #define REGION_DEFAULT_STATE(s,l) \ - _sync_marked (Properties::sync_marked, false) \ + _tempo (120, 4) \ + , _meter (4, 4) \ + , _sync_marked (Properties::sync_marked, false) \ , _left_of_split (Properties::left_of_split, false) \ , _right_of_split (Properties::right_of_split, false) \ , _valid_transients (Properties::valid_transients, false) \ @@ -259,7 +261,9 @@ Region::register_properties () , _contents (Properties::contents, false) #define REGION_COPY_STATE(other) \ - _sync_marked (Properties::sync_marked, other->_sync_marked) \ + _tempo (other->_tempo) \ + , _meter (other->_meter) \ + , _sync_marked (Properties::sync_marked, other->_sync_marked) \ , _left_of_split (Properties::left_of_split, other->_left_of_split) \ , _right_of_split (Properties::right_of_split, other->_right_of_split) \ , _valid_transients (Properties::valid_transients, other->_valid_transients) \ @@ -1420,6 +1424,9 @@ Region::state () const node->set_property ("id", id ()); node->set_property ("type", _type); + node->add_child_nocopy (_tempo.get_state()); + node->add_child_nocopy (_meter.get_state()); + std::string fe; switch (_first_edit) { @@ -1619,6 +1626,10 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang } _plugins.push_back (rfx); changed = true; + } else if (child->name() == Temporal::Tempo::xml_node_name) { + _tempo.set_state (*child, version); + } else if (child->name() == Temporal::Meter::xml_node_name) { + _meter.set_state (*child, version); } } lm.release (); From c61cbe8b026a2ba4eff4eab5dc64aef2487eaa89 Mon Sep 17 00:00:00 2001 From: Franke Burgarino Date: Fri, 8 Aug 2025 16:10:24 -0500 Subject: [PATCH 22/32] MCU: move filter controls from dynamics subview to eq subview --- libs/surfaces/mackie/subview.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libs/surfaces/mackie/subview.cc b/libs/surfaces/mackie/subview.cc index 7398f2db7f..02e42bd87d 100644 --- a/libs/surfaces/mackie/subview.cc +++ b/libs/surfaces/mackie/subview.cc @@ -357,6 +357,18 @@ void EQSubview::setup_vpot( pc = _subview_stripable->mapped_control(EQ_Enable); pot_id = "EQ"; break; + case 11: + pc = _subview_stripable->mapped_control(LPF_Freq); + pot_id = "LPF"; + break; + case 12: + pc = _subview_stripable->mapped_control(HPF_Freq); + pot_id = "HPF"; + break; + case 13: + pc = _subview_stripable->mapped_control(HPF_Enable); // shared HP/LP + pot_id = "Filter"; + break; } } else { //mixbus or master bus ( these are currently the same for MB & 32C ) @@ -460,10 +472,6 @@ void DynamicsSubview::setup_vpot( available.clear(); - std::shared_ptr hpfc = _subview_stripable->mapped_control (HPF_Freq); - std::shared_ptr lpfc = _subview_stripable->mapped_control (LPF_Freq); - std::shared_ptr fec = _subview_stripable->mapped_control (HPF_Enable); // shared HP/LP - std::shared_ptr ctc = _subview_stripable->mapped_control (Comp_Threshold); std::shared_ptr crc = _subview_stripable->mapped_control (Comp_Ratio); std::shared_ptr cac = _subview_stripable->mapped_control (Comp_Attack); @@ -483,11 +491,6 @@ void DynamicsSubview::setup_vpot( std::vector params; - //Mixbus32C needs to spill the filter controls into the comp section - if (hpfc) { available.push_back (std::make_pair (hpfc, "HPF")); } - if (lpfc) { available.push_back (std::make_pair (lpfc, "LPF")); } - if (fec) { available.push_back (std::make_pair (fec, "FiltIn")); } - if (ctc) { available.push_back (std::make_pair (ctc, "Thresh")); } if (crc) { available.push_back (std::make_pair (crc, "Ratio")); } if (cac) { available.push_back (std::make_pair (cac, "Attk")); } From 947223fdfbcaaa113814cf9a788c3e8b97de9853 Mon Sep 17 00:00:00 2001 From: Franke Burgarino Date: Fri, 8 Aug 2025 16:18:12 -0500 Subject: [PATCH 23/32] MCU: rename/reorder dynamics subview controls --- libs/surfaces/mackie/subview.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/libs/surfaces/mackie/subview.cc b/libs/surfaces/mackie/subview.cc index 02e42bd87d..f5e0ffc271 100644 --- a/libs/surfaces/mackie/subview.cc +++ b/libs/surfaces/mackie/subview.cc @@ -472,18 +472,18 @@ void DynamicsSubview::setup_vpot( available.clear(); + std::shared_ptr cec = _subview_stripable->mapped_control (Comp_Enable); std::shared_ptr ctc = _subview_stripable->mapped_control (Comp_Threshold); std::shared_ptr crc = _subview_stripable->mapped_control (Comp_Ratio); std::shared_ptr cac = _subview_stripable->mapped_control (Comp_Attack); std::shared_ptr csc = _subview_stripable->mapped_control (Comp_Release); std::shared_ptr ckc = _subview_stripable->mapped_control (Comp_Makeup); - std::shared_ptr cec = _subview_stripable->mapped_control (Comp_Enable); + std::shared_ptr gec = _subview_stripable->mapped_control (Gate_Enable); std::shared_ptr gtc = _subview_stripable->mapped_control (Gate_Threshold); std::shared_ptr gdc = _subview_stripable->mapped_control (Gate_Depth); std::shared_ptr gac = _subview_stripable->mapped_control (Gate_Attack); std::shared_ptr gsc = _subview_stripable->mapped_control (Gate_Release); - std::shared_ptr gec = _subview_stripable->mapped_control (Gate_Enable); /* we will control the global_strip_position-th available parameter, from the list in the * order shown above. @@ -491,18 +491,18 @@ void DynamicsSubview::setup_vpot( std::vector params; - if (ctc) { available.push_back (std::make_pair (ctc, "Thresh")); } - if (crc) { available.push_back (std::make_pair (crc, "Ratio")); } - if (cac) { available.push_back (std::make_pair (cac, "Attk")); } - if (csc) { available.push_back (std::make_pair (csc, "Rels")); } - if (ckc) { available.push_back (std::make_pair (ckc, "Makeup")); } - if (cec) { available.push_back (std::make_pair (cec, "on/off")); } + if (cec) { available.push_back (std::make_pair (cec, "Comp")); } + if (ctc) { available.push_back (std::make_pair (ctc, "CThrsh")); } + if (crc) { available.push_back (std::make_pair (crc, "CRatio")); } + if (cac) { available.push_back (std::make_pair (cac, "CAttk")); } + if (csc) { available.push_back (std::make_pair (csc, "CRels")); } + if (ckc) { available.push_back (std::make_pair (ckc, "CMkup")); } - if (gtc) { available.push_back (std::make_pair (gtc, "Thresh")); } - if (gdc) { available.push_back (std::make_pair (gdc, "Depth")); } - if (gac) { available.push_back (std::make_pair (gac, "Attk")); } - if (gsc) { available.push_back (std::make_pair (gsc, "Rels")); } - if (gec) { available.push_back (std::make_pair (gec, "on/off")); } + if (gec) { available.push_back (std::make_pair (gec, "Gate")); } + if (gtc) { available.push_back (std::make_pair (gtc, "GThrsh")); } + if (gdc) { available.push_back (std::make_pair (gdc, "GDepth")); } + if (gac) { available.push_back (std::make_pair (gac, "GAttk")); } + if (gsc) { available.push_back (std::make_pair (gsc, "GRels")); } if (global_strip_position >= available.size()) { /* this knob is not needed to control the available parameters */ From 900706320cc8392d5d34f0906f123f95321711d9 Mon Sep 17 00:00:00 2001 From: Franke Burgarino Date: Fri, 8 Aug 2025 16:42:48 -0500 Subject: [PATCH 24/32] MCU: change 'Strip::notify_eq_type_changed()' to 'Strip::notify_subview_type_changed()' since it applies to dynamics as well --- libs/surfaces/mackie/strip.cc | 4 ++-- libs/surfaces/mackie/strip.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc index a47dbb7cbc..1fc71d51aa 100644 --- a/libs/surfaces/mackie/strip.cc +++ b/libs/surfaces/mackie/strip.cc @@ -234,7 +234,7 @@ Strip::set_stripable (std::shared_ptr r, bool /*with_messages*/) _stripable->solo_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, std::bind (&Strip::notify_solo_changed, this), ui_context()); _stripable->mute_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, std::bind (&Strip::notify_mute_changed, this), ui_context()); - _stripable->MappedControlsChanged.connect (stripable_connections, MISSING_INVALIDATOR, std::bind (&Strip::notify_eq_type_changed, this), ui_context()); + _stripable->MappedControlsChanged.connect (stripable_connections, MISSING_INVALIDATOR, std::bind (&Strip::notify_subview_type_changed, this), ui_context()); std::shared_ptr pan_control = _stripable->pan_azimuth_control(); if (pan_control) { @@ -350,7 +350,7 @@ Strip::notify_record_enable_changed () } void -Strip::notify_eq_type_changed () +Strip::notify_subview_type_changed () { if (_stripable) { _surface->mcp().MackieControlProtocol::redisplay_subview_mode(); diff --git a/libs/surfaces/mackie/strip.h b/libs/surfaces/mackie/strip.h index fbb7863a69..c944bc86ad 100644 --- a/libs/surfaces/mackie/strip.h +++ b/libs/surfaces/mackie/strip.h @@ -157,7 +157,7 @@ private: void notify_solo_changed (); void notify_mute_changed (); void notify_record_enable_changed (); - void notify_eq_type_changed (); + void notify_subview_type_changed (); void notify_gain_changed (bool force_update = true); void notify_property_changed (const PBD::PropertyChange&); void notify_panner_azi_changed (bool force_update = true); From c59dddfdaea789ed3b30ffdabff3034eabe57240 Mon Sep 17 00:00:00 2001 From: Franke Burgarino Date: Fri, 8 Aug 2025 16:57:24 -0500 Subject: [PATCH 25/32] MCU: add scrolling in eq subview --- libs/surfaces/mackie/subview.cc | 28 +++++++++++++++++++++++++--- libs/surfaces/mackie/subview.h | 4 ++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/libs/surfaces/mackie/subview.cc b/libs/surfaces/mackie/subview.cc index f5e0ffc271..a9eb36324d 100644 --- a/libs/surfaces/mackie/subview.cc +++ b/libs/surfaces/mackie/subview.cc @@ -278,6 +278,7 @@ void NoneSubview::setup_vpot( EQSubview::EQSubview(MackieControlProtocol& mcp, std::shared_ptr subview_stripable) : Subview(mcp, subview_stripable) + , _current_bank(0) {} EQSubview::~EQSubview() @@ -308,8 +309,8 @@ void EQSubview::setup_vpot( Pot* vpot, std::string pending_display[2]) { - const uint32_t global_strip_position = _mcp.global_index (*strip); - store_pointers(strip, vpot, pending_display, global_strip_position); + const uint32_t global_strip_position = _mcp.global_index (*strip) + _current_bank; + store_pointers(strip, vpot, pending_display, global_strip_position - _current_bank); if (!_subview_stripable) { return; @@ -414,7 +415,7 @@ void EQSubview::notify_change (std::weak_ptr pc, uint Strip* strip = 0; Pot* vpot = 0; std::string* pending_display = 0; - if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position)) + if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position - _current_bank)) { return; } @@ -428,6 +429,27 @@ void EQSubview::notify_change (std::weak_ptr pc, uint } } +bool EQSubview::handle_cursor_left_press() +{ + if (_current_bank >= 1) + { + _current_bank -= 1; + mcp().redisplay_subview_mode(); + } + + return true; +} + +bool EQSubview::handle_cursor_right_press() +{ + if (/* todo: generate this value on redisplay */ 14 > _current_bank + 1) { + _current_bank += 1; + mcp().redisplay_subview_mode(); + } + + return true; +} + DynamicsSubview::DynamicsSubview(MackieControlProtocol& mcp, std::shared_ptr subview_stripable) diff --git a/libs/surfaces/mackie/subview.h b/libs/surfaces/mackie/subview.h index 4b0a1987ee..25ea4511b8 100644 --- a/libs/surfaces/mackie/subview.h +++ b/libs/surfaces/mackie/subview.h @@ -127,6 +127,10 @@ class EQSubview : public Subview { Pot* vpot, std::string pending_display[2]); void notify_change (std::weak_ptr, uint32_t global_strip_position, bool force); + virtual bool handle_cursor_left_press(); + virtual bool handle_cursor_right_press(); + protected: + uint32_t _current_bank; }; class DynamicsSubview : public Subview { From cec3db54f010c4c9afec400a1b9de4680aa6d0bb Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 17:52:25 -0600 Subject: [PATCH 26/32] refactor AudioTrigger::estimate_tempo() into ARDOUR::estimate_audio_tempo() --- libs/ardour/ardour/utils.h | 7 ++ libs/ardour/triggerbox.cc | 120 ++------------------------------- libs/ardour/utils.cc | 131 ++++++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 117 deletions(-) diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h index 73b3ccc0d6..dfc71a5c88 100644 --- a/libs/ardour/ardour/utils.h +++ b/libs/ardour/ardour/utils.h @@ -44,10 +44,15 @@ class XMLNode; +namespace Temporal { + class Meter; +} + namespace ARDOUR { class Route; class Track; +class Region; LIBARDOUR_API std::string legalize_for_path (const std::string& str); LIBARDOUR_API std::string legalize_for_universal_path (const std::string& str); @@ -146,6 +151,8 @@ template std::shared_ptr stripable_list_to_co return cl; } +LIBARDOUR_API bool estimate_audio_tempo (std::shared_ptr region, Sample* data, samplecnt_t data_length, samplecnt_t sample_rate, double& qpm, Temporal::Meter& meter, double& beatcount); + #if __APPLE__ LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef); #endif // __APPLE__ diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index a73a091cde..1c6ccb0cc5 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -1773,123 +1773,11 @@ AudioTrigger::set_region_in_worker_thread_internal (std::shared_ptr r, b void AudioTrigger::estimate_tempo () { - using namespace Temporal; - TempoMap::SharedPtr tm (TempoMap::use()); + double beatcount; + ARDOUR::estimate_audio_tempo (_region, data[0], data.length, _box.session().sample_rate(), _estimated_tempo, _meter, beatcount); + /* initialize our follow_length to match the beatcnt ... user can later change this value to have the clip end sooner or later than its data length */ + set_follow_length(Temporal::BBT_Offset( 0, rint(beatcount), 0)); - TimelineRange range (_region->start(), _region->start() + _region->length(), 0); - SegmentDescriptor segment; - bool have_segment; - - have_segment = _region->source (0)->get_segment_descriptor (range, segment); - - if (have_segment) { - - _estimated_tempo = segment.tempo().quarter_notes_per_minute (); - _meter = segment.meter(); - DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1: tempo and meter from segment descriptor\n", index())); - - } else { - /* not a great guess, but what else can we do? */ - - TempoMetric const & metric (tm->metric_at (timepos_t (AudioTime))); - - _meter = metric.meter (); - - /* check the name to see if there's a (heuristically obvious) hint - * about the tempo. - */ - - string str = _region->name(); - string::size_type bi; - string::size_type ni; - double text_tempo = -1.; - - if (((bi = str.find (" bpm")) != string::npos) || - ((bi = str.find ("bpm")) != string::npos) || - ((bi = str.find (" BPM")) != string::npos) || - ((bi = str.find ("BPM")) != string::npos) ){ - - string sub (str.substr (0, bi)); - - if ((ni = sub.find_last_of ("0123456789.,_-")) != string::npos) { - - int nni = ni; /* ni is unsigned, nni is signed */ - - while (nni >= 0) { - if (!isdigit (sub[nni]) && - (sub[nni] != '.') && - (sub[nni] != ',')) { - break; - } - --nni; - } - - if (nni > 0) { - std::stringstream p (sub.substr (nni + 1)); - p >> text_tempo; - if (!p) { - text_tempo = -1.; - } else { - _estimated_tempo = text_tempo; - } - } - } - } - - if (text_tempo < 0) { - - breakfastquay::MiniBPM mbpm (_box.session().sample_rate()); - - _estimated_tempo = mbpm.estimateTempoOfSamples (data[0], data.length); - - //cerr << name() << "MiniBPM Estimated: " << _estimated_tempo << " bpm from " << (double) data.length / _box.session().sample_rate() << " seconds\n"; - } - } - - const double seconds = (double) data.length / _box.session().sample_rate(); - - /* now check the determined tempo and force it to a value that gives us - an integer beat/quarter count. This is a heuristic that tries to - avoid clips that slightly over- or underrun a quantization point, - resulting in small or larger gaps in output if they are repeating. - */ - - if ((_estimated_tempo != 0.)) { - /* fractional beatcnt */ - double maybe_beats = (seconds / 60.) * _estimated_tempo; - double beatcount = round (maybe_beats); - - /* the vast majority of third-party clips are 1,2,4,8, or 16-bar 'beats'. - * Given no other metadata, it makes things 'just work' if we assume 4/4 time signature, and power-of-2 bars (1,2,4,8 or 16) - * TODO: someday we could provide a widget for users who have unlabeled, un-metadata'd, clips that they *know* are 3/4 or 5/4 or 11/4 */ - { - double barcount = round (beatcount/4); - if (barcount <= 18) { /* why not 16 here? fuzzy logic allows minibpm to misjudge the clip a bit */ - for (int pwr = 0; pwr <= 4; pwr++) { - float bc = pow(2,pwr); - if (barcount <= bc) { - barcount = bc; - break; - } - } - } - beatcount = round(barcount * 4); - } - - DEBUG_RESULT (double, est, _estimated_tempo); - _estimated_tempo = beatcount / (seconds/60.); - DEBUG_TRACE (DEBUG::Triggers, string_compose ("given original estimated tempo %1, rounded beatcnt is %2 : resulting in working bpm = %3\n", est, _beatcnt, _estimated_tempo)); - - /* initialize our follow_length to match the beatcnt ... user can later change this value to have the clip end sooner or later than its data length */ - set_follow_length(Temporal::BBT_Offset( 0, rint(beatcount), 0)); - } - -#if 0 - cerr << "estimated tempo: " << _estimated_tempo << endl; - const samplecnt_t one_beat = tm->bbt_duration_at (timepos_t (AudioTime), BBT_Offset (0, 1, 0)).samples(); - cerr << "one beat in samples: " << one_beat << endl; - cerr << "rounded beatcount = " << round (beatcount) << endl; -#endif } bool diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index c42d400839..2bf45bd7fc 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -60,8 +60,14 @@ #include "pbd/strsplit.h" #include "pbd/replace_all.h" -#include "ardour/utils.h" +#include "temporal/tempo.h" + +#include "ardour/minibpm.h" +#include "ardour/region.h" #include "ardour/rc_configuration.h" +#include "ardour/segment_descriptor.h" +#include "ardour/source.h" +#include "ardour/utils.h" #include "pbd/i18n.h" @@ -793,3 +799,126 @@ ARDOUR::compute_sha1_of_file (std::string path) sha1_result_hash (&s, hash); return std::string (hash); } + +bool +ARDOUR::estimate_audio_tempo (std::shared_ptr region, Sample* data, samplecnt_t data_length, samplecnt_t sample_rate, double& qpm, Temporal::Meter& meter, double& beatcount) +{ + using namespace Temporal; + TempoMap::SharedPtr tm (TempoMap::use()); + + TimelineRange range (region->start(), region->start() + region->length(), 0); + SegmentDescriptor segment; + bool have_segment; + + have_segment = region->source (0)->get_segment_descriptor (range, segment); + + if (have_segment) { + + qpm = segment.tempo().quarter_notes_per_minute (); + meter = segment.meter(); + // DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1: tempo and meter from segment descriptor\n", index())); + + } else { + /* not a great guess, but what else can we do? */ + + TempoMetric const & metric (tm->metric_at (timepos_t (AudioTime))); + + meter = metric.meter (); + + /* check the name to see if there's a (heuristically obvious) hint + * about the tempo. + */ + + string str = region->name(); + string::size_type bi; + string::size_type ni; + double text_tempo = -1.; + + if (((bi = str.find (" bpm")) != string::npos) || + ((bi = str.find ("bpm")) != string::npos) || + ((bi = str.find (" BPM")) != string::npos) || + ((bi = str.find ("BPM")) != string::npos) ){ + + string sub (str.substr (0, bi)); + + if ((ni = sub.find_last_of ("0123456789.,_-")) != string::npos) { + + int nni = ni; /* ni is unsigned, nni is signed */ + + while (nni >= 0) { + if (!isdigit (sub[nni]) && + (sub[nni] != '.') && + (sub[nni] != ',')) { + break; + } + --nni; + } + + if (nni > 0) { + std::stringstream p (sub.substr (nni + 1)); + p >> text_tempo; + if (!p) { + text_tempo = -1.; + } else { + qpm = text_tempo; + } + } + } + } + + if (text_tempo < 0) { + + breakfastquay::MiniBPM mbpm (sample_rate); + + qpm = mbpm.estimateTempoOfSamples (data, data_length); + + //cerr << name() << "MiniBPM Estimated: " << qpm << " bpm from " << (double) data.length / _box.session().sample_rate() << " seconds\n"; + } + } + + const double seconds = (double) data_length / sample_rate; + + /* now check the determined tempo and force it to a value that gives us + an integer beat/quarter count. This is a heuristic that tries to + avoid clips that slightly over- or underrun a quantization point, + resulting in small or larger gaps in output if they are repeating. + */ + + if ((qpm != 0.)) { + /* fractional beatcnt */ + double maybe_beats = (seconds / 60.) * qpm; + beatcount = round (maybe_beats); + + /* the vast majority of third-party clips are 1,2,4,8, or 16-bar 'beats'. + * Given no other metadata, it makes things 'just work' if we assume 4/4 time signature, and power-of-2 bars (1,2,4,8 or 16) + * TODO: someday we could provide a widget for users who have unlabeled, un-metadata'd, clips that they *know* are 3/4 or 5/4 or 11/4 */ + { + double barcount = round (beatcount/4); + if (barcount <= 18) { /* why not 16 here? fuzzy logic allows minibpm to misjudge the clip a bit */ + for (int pwr = 0; pwr <= 4; pwr++) { + float bc = pow(2,pwr); + if (barcount <= bc) { + barcount = bc; + break; + } + } + } + beatcount = round(barcount * 4); + } + + // DEBUG_RESULT (double, est, qpm); + qpm = beatcount / (seconds/60.); + // DEBUG_TRACE (DEBUG::Triggers, string_compose ("given original estimated tempo %1, rounded beatcnt is %2 : resulting in working bpm = %3\n", est, _beatcnt, qpm)); + + } + +#if 0 + cerr << "estimated tempo: " << qpm << endl; + const samplecnt_t one_beat = tm->bbt_duration_at (timepos_t (AudioTime), BBT_Offset (0, 1, 0)).samples(); + cerr << "one beat in samples: " << one_beat << endl; + cerr << "rounded beatcount = " << round (beatcount) << endl; +#endif + + return true; +} + From be913373cb4d28d7c0c2056f3813ef1970f48700 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 22:26:04 -0600 Subject: [PATCH 27/32] give MIDIRegion a tempo/meter based on their SMF or the SMF standard (120, 4/4) --- libs/ardour/ardour/midi_region.h | 2 ++ libs/ardour/midi_region.cc | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index d5f8d97877..795bf8f8a9 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -157,6 +157,8 @@ class LIBARDOUR_API MidiRegion : public Region void model_shifted (timecnt_t qn_distance); void model_automation_state_changed (Evoral::Parameter const &); + void set_tempo_stuff_from_source (); + std::set _filtered_parameters; ///< parameters that we ask our source not to return when reading PBD::ScopedConnection _model_connection; PBD::ScopedConnection _model_shift_connection; diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index dd9dc1d49b..348d0f7bbc 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -70,6 +70,8 @@ MidiRegion::MidiRegion (const SourceList& srcs) : Region (srcs) , _ignore_shift (false) { + set_tempo_stuff_from_source (); + /* by default MIDI regions are transparent, * this should probably be set depending on use-case, * (eg. loop recording, vs copy/edit/paste) @@ -106,6 +108,26 @@ MidiRegion::~MidiRegion () { } +void +MidiRegion::set_tempo_stuff_from_source () +{ + std::shared_ptr smf = std::dynamic_pointer_cast (midi_source ()); + assert (smf); + + bool provided; + Temporal::TempoMap::SharedPtr new_map (smf->tempo_map (provided)); + + if (!provided) { + new_map.reset (new Temporal::TempoMap()); + } + + Temporal::TempoPoint const tp (new_map->tempo_at (start())); + Temporal::MeterPoint const mp (new_map->meter_at (start())); + + _tempo = tp; + _meter = mp; +} + /** Export the MIDI data of the MidiRegion to a new MIDI file (SMF). */ bool From 577cdd5f611b4354112ab8adf7302f64bb9b597c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 22:26:35 -0600 Subject: [PATCH 28/32] MIDITrigger::get_segment_descriptor() does something sensible with Region tempo/meter --- libs/ardour/triggerbox.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 1c6ccb0cc5..d3c1b729c8 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -2645,14 +2645,9 @@ SegmentDescriptor MIDITrigger::get_segment_descriptor () const { SegmentDescriptor sd; - std::shared_ptr mr = std::dynamic_pointer_cast (_region); - assert (mr); - - sd.set_extent (Temporal::Beats(), mr->length().beats()); - - /* we don't really have tempo information for MIDI yet */ - sd.set_tempo (Temporal::Tempo (120, 4)); + sd.set_extent (Temporal::Beats(), _region->length().beats()); + sd.set_tempo (_region->tempo()); return sd; } From ff648b67209c110a4d1bb6d0b3b9eb1a5655a697 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 22:46:16 -0600 Subject: [PATCH 29/32] cue editor: fix local tempo scope and use region tempo map --- gtk2_ardour/cue_editor.cc | 24 ++++-------------------- gtk2_ardour/cue_editor.h | 3 --- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/gtk2_ardour/cue_editor.cc b/gtk2_ardour/cue_editor.cc index 4c731a5767..cec71ef348 100644 --- a/gtk2_ardour/cue_editor.cc +++ b/gtk2_ardour/cue_editor.cc @@ -298,24 +298,6 @@ CueEditor::get_canvas_cursor () const return nullptr; } -std::shared_ptr -CueEditor::start_local_tempo_map (std::shared_ptr map) -{ - EC_LOCAL_TEMPO_SCOPE; - - std::shared_ptr tmp = Temporal::TempoMap::use(); - Temporal::TempoMap::set (map); - return tmp; -} - -void -CueEditor::end_local_tempo_map (std::shared_ptr map) -{ - EC_LOCAL_TEMPO_SCOPE; - - Temporal::TempoMap::set (map); -} - void CueEditor::do_undo (uint32_t n) { @@ -1186,6 +1168,9 @@ CueEditor::set_region (std::shared_ptr r) _region = r; + std::shared_ptr tmap (new TempoMap (_region->tempo(), _region->meter())); + start_local_tempo_map (tmap); + if (!get_canvas()->is_visible()) { _visible_pending_region = r; } else { @@ -1414,8 +1399,7 @@ CueEditor::idle_data_captured () void CueEditor::unset (bool trigger_too) { - EC_LOCAL_TEMPO_SCOPE; - + end_local_tempo_map (); _history.clear (); history_connection.disconnect(); _update_connection.disconnect(); diff --git a/gtk2_ardour/cue_editor.h b/gtk2_ardour/cue_editor.h index 95c62e93df..9f4335aa0d 100644 --- a/gtk2_ardour/cue_editor.h +++ b/gtk2_ardour/cue_editor.h @@ -113,9 +113,6 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner std::vector filter_to_unique_midi_region_views (RegionSelection const & ms) const; - std::shared_ptr start_local_tempo_map (std::shared_ptr); - void end_local_tempo_map (std::shared_ptr); - void scrolled (); bool canvas_pre_event (GdkEvent*); void catch_pending_show_region (); From 4586b39e8b09f58fd9be504d88fa43f9f6f6344f Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 23:11:59 -0600 Subject: [PATCH 30/32] add a method to compute tempo & meter for an audio source (not used yet) --- libs/ardour/ardour/audioregion.h | 2 ++ libs/ardour/audioregion.cc | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index bb078ef2f7..7f0723f5f1 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -291,6 +291,8 @@ class LIBARDOUR_API AudioRegion : public Region, public AudioReadable int _set_state (const XMLNode&, int version, PBD::PropertyChange& what_changed, bool send_signal); void send_change (const PBD::PropertyChange&); void ensure_length_sanity (); + + void set_tempo_stuff_from_source (); }; } /* namespace ARDOUR */ diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 3010687d38..0637e91126 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -433,6 +433,21 @@ AudioRegion::~AudioRegion () } } +void +AudioRegion::set_tempo_stuff_from_source () +{ + samplecnt_t data_size = _session.sample_rate() * 10; + std::unique_ptr data (new Sample[data_size]); + + if (read (data.get(), 0, data_size, 0) == data_size) { + double tempo; + double beatcount; + + estimate_audio_tempo (shared_from_this(), data.get(), data_size, _session.sample_rate(), tempo, _meter, beatcount); + _tempo = Temporal::Tempo (tempo, 4); + } +} + void AudioRegion::post_set (const PropertyChange& /*ignored*/) { @@ -2740,4 +2755,3 @@ AudioRegion::ensure_length_sanity () _length = timecnt_t (timepos_t (_length.val().samples()), _length.val().position()); } } - From 217890cf8570d7420155aa9a6c314bf578724a03 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 23:29:55 -0600 Subject: [PATCH 31/32] add DEBUG::TempoEstimation to libardour --- libs/ardour/ardour/debug.h | 1 + libs/ardour/debug.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h index 61b84ad16a..c5e71d5c13 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -117,6 +117,7 @@ namespace PBD { LIBARDOUR_API extern DebugBits WiimoteControl; LIBARDOUR_API extern DebugBits Freesound; LIBARDOUR_API extern DebugBits ClipRecording; + LIBARDOUR_API extern DebugBits TempoEstimation; } } diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc index 55171fef8f..b738c3f7b7 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -113,3 +113,4 @@ PBD::DebugBits PBD::DEBUG::VSTCallbacks = PBD::new_debug_bit ("vstcallbacks"); PBD::DebugBits PBD::DEBUG::WiimoteControl = PBD::new_debug_bit ("wiimotecontrol"); PBD::DebugBits PBD::DEBUG::Freesound = PBD::new_debug_bit ("freesound"); PBD::DebugBits PBD::DEBUG::ClipRecording = PBD::new_debug_bit ("cliprecording"); +PBD::DebugBits PBD::DEBUG::TempoEstimation = PBD::new_debug_bit ("tempoestimation"); From af5ab40bf2643bffc662150ce34497cd2bb30bdd Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 8 Aug 2025 23:34:31 -0600 Subject: [PATCH 32/32] use DEBUG::TempoEstimation --- libs/ardour/utils.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index 2bf45bd7fc..cacb5f79db 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -62,6 +62,7 @@ #include "temporal/tempo.h" +#include "ardour/debug.h" #include "ardour/minibpm.h" #include "ardour/region.h" #include "ardour/rc_configuration.h" @@ -816,7 +817,7 @@ ARDOUR::estimate_audio_tempo (std::shared_ptr region, Sample* data, samp qpm = segment.tempo().quarter_notes_per_minute (); meter = segment.meter(); - // DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1: tempo and meter from segment descriptor\n", index())); + DEBUG_TRACE (DEBUG::TempoEstimation, string_compose ("%1: tempo and meter from segment descriptor\n", region->name())); } else { /* not a great guess, but what else can we do? */ @@ -906,9 +907,9 @@ ARDOUR::estimate_audio_tempo (std::shared_ptr region, Sample* data, samp beatcount = round(barcount * 4); } - // DEBUG_RESULT (double, est, qpm); + DEBUG_RESULT (double, est, qpm); qpm = beatcount / (seconds/60.); - // DEBUG_TRACE (DEBUG::Triggers, string_compose ("given original estimated tempo %1, rounded beatcnt is %2 : resulting in working bpm = %3\n", est, _beatcnt, qpm)); + DEBUG_TRACE (DEBUG::TempoEstimation, string_compose ("given original estimated tempo %1, rounded beatcnt is %2 : resulting in working bpm = %3\n", est, beatcount, qpm)); }