From ba981a14c4fb7e6bfe1a7434e81cdecac422c838 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 16 Jan 2015 12:17:09 -0500 Subject: initial version of playback priority design. No GUI control over options yet Conflicts: libs/ardour/ardour/session.h libs/ardour/ardour/types.h libs/ardour/enums.cc libs/ardour/session_transport.cc system_config --- gtk2_ardour/ardour_ui_ed.cc | 2 +- gtk2_ardour/editor_selection.cc | 30 +++++++++- libs/ardour/ardour/rc_configuration_vars.h | 1 + libs/ardour/ardour/session.h | 16 +++++ libs/ardour/ardour/types.h | 10 +++- libs/ardour/enums.cc | 25 +++++++- libs/ardour/session.cc | 31 ++++++++++ libs/ardour/session_transport.cc | 96 +++++++++++++++++++----------- system_config | 1 + 9 files changed, 172 insertions(+), 40 deletions(-) diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index c82c41c000..4455e72832 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -221,7 +221,7 @@ if (Profile->get_mixbus()) ActionManager::register_action (common_actions, X_("Forums"), _("User Forums"), mem_fun(*this, &ARDOUR_UI::launch_forums)); ActionManager::register_action (common_actions, X_("Howto_Report"), _("How to report a bug"), mem_fun(*this, &ARDOUR_UI::launch_howto_report)); - act = ActionManager::register_action (common_actions, X_("Save"), _("Save"), sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::save_state), string(""), false)); + act = ActionManager::register_action (common_actions, X_("Save"), _("Save"), sigc::hide_return (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::save_state), string(""), false))); ActionManager::session_sensitive_actions.push_back (act); ActionManager::write_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index b071ed6e1b..135f15da29 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -652,9 +652,12 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op) if (press) goto out; else { - get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id); - selection->set(all_equivalent_regions); - commit = true; + if (selection->regions.size() > 1) { + /* collapse region selection down to just this one region (and its equivalents) */ + get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id); + selection->set(all_equivalent_regions); + commit = true; + } } } break; @@ -1027,6 +1030,16 @@ Editor::time_selection_changed () } else { ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true); } + + /* propagate into backend */ + + if (_session) { + if (selection->time.length() != 0) { + _session->set_range_selection (selection->time.start(), selection->time.end_frame()); + } else { + _session->clear_range_selection (); + } + } } /** Set all region actions to have a given sensitivity */ @@ -1337,6 +1350,17 @@ Editor::region_selection_changed () if (_session && !_session->transport_rolling() && !selection->regions.empty()) { maybe_locate_with_edit_preroll (selection->regions.start()); } + + /* propagate into backend */ + + if (_session) { + if (!selection->regions.empty()) { + _session->set_object_selection (selection->regions.start(), selection->regions.end_frame()); + } else { + _session->clear_object_selection (); + } + } + } void diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 10587aba2e..1defe3d54a 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -163,6 +163,7 @@ CONFIG_VARIABLE (ShuttleUnits, shuttle_units, "shuttle-units", Percentage) CONFIG_VARIABLE (float, shuttle_max_speed, "shuttle-max-speed", 8.0f) CONFIG_VARIABLE (bool, locate_while_waiting_for_sync, "locate-while-waiting-for-sync", false) CONFIG_VARIABLE (bool, disable_disarm_during_roll, "disable-disarm-during-roll", false) +CONFIG_VARIABLE (AutoReturnTarget, auto_return_target_list, "auto-return-target-list", AutoReturnTarget(LastLocate|RangeSelectionStart|Loop|RegionSelectionStart)) /* metering */ diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 48243179f8..0714077302 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -847,6 +847,14 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void maybe_update_session_range (framepos_t, framepos_t); + /* temporary hacks to allow selection to be pushed from GUI into backend. + Whenever we move the selection object into libardour, these will go away. + */ + void set_range_selection (framepos_t start, framepos_t end); + void set_object_selection (framepos_t start, framepos_t end); + void clear_range_selection (); + void clear_object_selection (); + /* buffers for gain and pan */ gain_t* gain_automation_buffer () const; @@ -1445,6 +1453,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void engine_halted (); void xrun_recovery (); void set_track_loop (bool); + bool select_playhead_priority_target (framepos_t&); + void follow_playhead_priority (); /* These are synchronous and so can only be called from within the process * cycle @@ -1669,6 +1679,12 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void set_play_range (std::list&, bool leave_rolling); void unset_play_range (); + /* temporary hacks to allow selection to be pushed from GUI into backend + Whenever we move the selection object into libardour, these will go away. + */ + Evoral::Range _range_selection; + Evoral::Range _object_selection; + /* main outs */ uint32_t main_outs; diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 8d7fb125a1..ba521f3b71 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -635,6 +635,13 @@ namespace ARDOUR { Custom, }; + enum AutoReturnTarget { + LastLocate = 0x1, + RangeSelectionStart = 0x2, + Loop = 0x4, + RegionSelectionStart = 0x8, + }; + } // namespace ARDOUR @@ -662,6 +669,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::PositionLockStyle& sf); std::istream& operator>>(std::istream& o, ARDOUR::FadeShape& sf); std::istream& operator>>(std::istream& o, ARDOUR::RegionSelectionAfterSplit& sf); std::istream& operator>>(std::istream& o, ARDOUR::BufferingPreset& var); +std::istream& operator>>(std::istream& o, ARDOUR::AutoReturnTarget& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::SampleFormat& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::HeaderFormat& sf); @@ -684,7 +692,7 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::PositionLockStyle& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::FadeShape& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::RegionSelectionAfterSplit& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::BufferingPreset& var); - +std::ostream& operator<<(std::ostream& o, const ARDOUR::AutoReturnTarget& sf); /* because these operators work on types which can be used when making a UI_CONFIG_VARIABLE (in gtk2_ardour) we need them to be exported. diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 6bad252516..24b060ec28 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -131,7 +131,8 @@ setup_enum_writer () MTC_Status _MIDI_MTC_Status; Evoral::OverlapType _OverlapType; BufferingPreset _BufferingPreset; - + AutoReturnTarget _AutoReturnTarget; + #define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e) @@ -666,6 +667,12 @@ setup_enum_writer () REGISTER_ENUM (Large); REGISTER_ENUM (Custom); REGISTER(_BufferingPreset); + + REGISTER_ENUM (LastLocate); + REGISTER_ENUM (RangeSelectionStart); + REGISTER_ENUM (Loop); + REGISTER_ENUM (RegionSelectionStart); + REGISTER_BITS (_AutoReturnTarget); } } /* namespace ARDOUR */ @@ -1025,3 +1032,19 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::BufferingPreset& var) std::string s = enum_2_string (var); return o << s; } + +std::istream& operator>>(std::istream& o, AutoReturnTarget& var) +{ + std::string s; + o >> s; + var = (AutoReturnTarget) string_2_enum (s, var); + return o; +} + +std::ostream& operator<<(std::ostream& o, const AutoReturnTarget& var) +{ + std::string s = enum_2_string (var); + return o << s; +} + + diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index b02bcb8dec..27b1aa461f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -271,6 +271,8 @@ Session::Session (AudioEngine &eng, , click_emphasis_length (0) , _clicks_cleared (0) , _play_range (false) + , _range_selection (-1,-1) + , _object_selection (-1,-1) , main_outs (0) , first_file_data_format_reset (true) , first_file_header_format_reset (true) @@ -6109,3 +6111,32 @@ Session::reconnect_ltc_output () #endif } } + +void +Session::set_range_selection (framepos_t start, framepos_t end) +{ + cerr << "set range selection " << start << " .. " << end << endl; + _range_selection = Evoral::Range (start, end); + follow_playhead_priority (); +} + +void +Session::set_object_selection (framepos_t start, framepos_t end) +{ + _object_selection = Evoral::Range (start, end); + follow_playhead_priority (); +} + +void +Session::clear_range_selection () +{ + _range_selection = Evoral::Range (-1,-1); + follow_playhead_priority (); +} + +void +Session::clear_object_selection () +{ + _object_selection = Evoral::Range (-1,-1); + follow_playhead_priority (); +} diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 2656fd0d83..994a4b89a1 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -494,6 +494,62 @@ Session::non_realtime_locate () clear_clicks (); } +bool +Session::select_playhead_priority_target (framepos_t& jump_to) +{ + jump_to = -1; + + AutoReturnTarget autoreturn = Config->get_auto_return_target_list (); + + if (!autoreturn) { + return false; + } + + /* Note that the order of checking each AutoReturnTarget flag defines + the priority each flag. + */ + + if (autoreturn & LastLocate) { + jump_to = _last_roll_location; + } + + if (jump_to < 0 && (autoreturn & RangeSelectionStart)) { + if (!_range_selection.empty()) { + jump_to = _range_selection.from; + } + } + + if (jump_to < 0 && (autoreturn & Loop)) { + /* don't try to handle loop play when synced to JACK */ + + if (!synced_to_engine()) { + Location *location = _locations->auto_loop_location(); + + if (location) { + jump_to = location->start(); + } + } + } + + if (jump_to < 0 && (autoreturn & RegionSelectionStart)) { + if (!_object_selection.empty()) { + jump_to = _object_selection.from; + } + } + + return jump_to >= 0; +} + +void +Session::follow_playhead_priority () +{ + framepos_t target; + + if (select_playhead_priority_target (target)) { + request_locate (target); + } +} + void Session::non_realtime_stop (bool abort, int on_entry, bool& finished) { @@ -576,8 +632,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) update_latency_compensation (); } - bool const auto_return_enabled = - (!config.get_external_sync() && (config.get_auto_return() || abort)); + bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort)); if (auto_return_enabled || (ptw & PostTransportLocate) || @@ -603,40 +658,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) do_locate = true; } else { - if (config.get_auto_return()) { - - if (play_loop) { - - /* don't try to handle loop play when synced to JACK */ + framepos_t jump_to; - if (!synced_to_engine()) { + if (select_playhead_priority_target (jump_to)) { - Location *location = _locations->auto_loop_location(); - - if (location != 0) { - _transport_frame = location->start(); - } else { - _transport_frame = _last_roll_location; - } - do_locate = true; - } - - } else if (_play_range) { - - /* return to start of range */ - - if (!current_audio_range.empty()) { - _transport_frame = current_audio_range.front().start; - do_locate = true; - } - - } else { - - /* regular auto-return */ + _transport_frame = jump_to; + do_locate = true; - _transport_frame = _last_roll_location; - do_locate = true; - } } else if (abort) { _transport_frame = _last_roll_location; @@ -1218,7 +1246,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a } _engine.transport_stop (); } else { - bool const auto_return_enabled = (!config.get_external_sync() && (config.get_auto_return() || abort)); + bool const auto_return_enabled = (!config.get_external_sync() && (Config->get_auto_return_target_list() || abort)); if (!auto_return_enabled) { _requested_return_frame = destination_frame; diff --git a/system_config b/system_config index 82fb5e9df1..d745da22b5 100644 --- a/system_config +++ b/system_config @@ -127,6 +127,7 @@