From fbfa4283b98c5000a43ea0c3eb216d921960767e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 16 Jan 2015 12:17:09 -0500 Subject: [PATCH] initial version of playback priority design. No GUI control over options yet Conflicts: gtk2_ardour/editor_selection.cc libs/ardour/ardour/rc_configuration_vars.h libs/ardour/ardour/types.h libs/ardour/enums.cc --- gtk2_ardour/ardour_ui_ed.cc | 2 +- gtk2_ardour/editor_selection.cc | 21 +++++ libs/ardour/ardour/rc_configuration_vars.h | 1 + libs/ardour/ardour/session.h | 28 +++++-- libs/ardour/ardour/types.h | 25 ++++++ libs/ardour/enums.cc | 38 ++++++++- libs/ardour/session.cc | 31 +++++++ libs/ardour/session_transport.cc | 95 ++++++++++++++-------- system_config | 1 + 9 files changed, 200 insertions(+), 42 deletions(-) diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc index ddce54ffc7..2266476b5c 100644 --- a/gtk2_ardour/ardour_ui_ed.cc +++ b/gtk2_ardour/ardour_ui_ed.cc @@ -669,7 +669,7 @@ ARDOUR_UI::install_actions () ActionManager::register_action (common_actions, X_("OpenMediaFolder"), _("OpenMediaFolder"), mem_fun(*this, &ARDOUR_UI::open_media_folder)); - 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 5c81f7c058..c2adc2ceb2 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -1149,6 +1149,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 */ @@ -1457,6 +1467,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 c4062496a0..1494f68e0e 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -159,6 +159,7 @@ CONFIG_VARIABLE (bool, locate_while_waiting_for_sync, "locate-while-waiting-for- CONFIG_VARIABLE (bool, disable_disarm_during_roll, "disable-disarm-during-roll", false) CONFIG_VARIABLE (bool, follow_edits, "follow-edits", false) CONFIG_VARIABLE (bool, super_rapid_clock_update, "super-rapid-clock-update", 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 2389812768..04c2636f49 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -819,6 +819,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; @@ -1391,13 +1399,15 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void post_transport (); void engine_halted (); void xrun_recovery (); + 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 + */ - /* These are synchronous and so can only be called from within the process - * cycle - */ - - int send_full_time_code (framepos_t, pframes_t nframes); - void send_song_position_pointer (framepos_t); + int send_full_time_code (framepos_t, pframes_t nframes); + void send_song_position_pointer (framepos_t); TempoMap *_tempo_map; void tempo_map_changed (const PBD::PropertyChange&); @@ -1613,6 +1623,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 badf1acc91..b22ddc3ae6 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -598,6 +598,13 @@ namespace ARDOUR { uint32_t max; //< samples }; + enum AutoReturnTarget { + LastLocate = 0x1, + RangeSelectionStart = 0x2, + Loop = 0x4, + RegionSelectionStart = 0x8, + }; + } // namespace ARDOUR @@ -627,6 +634,8 @@ std::istream& operator>>(std::istream& o, ARDOUR::WaveformScale& sf); std::istream& operator>>(std::istream& o, ARDOUR::WaveformShape& sf); 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::AutoReturnTarget& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::SampleFormat& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::HeaderFormat& sf); @@ -650,6 +659,22 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::WaveformScale& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::WaveformShape& sf); 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::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. +*/ +LIBARDOUR_API std::istream& operator>>(std::istream& o, ARDOUR::WaveformScale& sf); +LIBARDOUR_API std::istream& operator>>(std::istream& o, ARDOUR::WaveformShape& sf); +LIBARDOUR_API std::istream& operator>>(std::istream& o, ARDOUR::VUMeterStandard& sf); +LIBARDOUR_API std::istream& operator>>(std::istream& o, ARDOUR::MeterLineUp& sf); + +LIBARDOUR_API std::ostream& operator<<(std::ostream& o, const ARDOUR::WaveformScale& sf); +LIBARDOUR_API std::ostream& operator<<(std::ostream& o, const ARDOUR::WaveformShape& sf); +LIBARDOUR_API std::ostream& operator<<(std::ostream& o, const ARDOUR::VUMeterStandard& sf); +LIBARDOUR_API std::ostream& operator<<(std::ostream& o, const ARDOUR::MeterLineUp& sf); + static inline ARDOUR::framepos_t session_frame_to_track_frame (ARDOUR::framepos_t session_frame, double speed) diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index c58de39b8e..7728856cd4 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -127,7 +127,8 @@ setup_enum_writer () Session::SlaveState _Session_SlaveState; MTC_Status _MIDI_MTC_Status; Evoral::OverlapType _OverlapType; - + 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) @@ -634,6 +635,13 @@ setup_enum_writer () REGISTER_ENUM (Evoral::OverlapEnd); REGISTER_ENUM (Evoral::OverlapExternal); REGISTER(_OverlapType); + + REGISTER_ENUM (LastLocate); + REGISTER_ENUM (RangeSelectionStart); + REGISTER_ENUM (Loop); + REGISTER_ENUM (RegionSelectionStart); + REGISTER_BITS (_AutoReturnTarget); + } } /* namespace ARDOUR */ @@ -951,3 +959,31 @@ std::ostream& operator<<(std::ostream& o, const FadeShape& var) std::string s = enum_2_string (var); return o << s; } + +std::istream& operator>>(std::istream& o, RegionSelectionAfterSplit& var) +{ + std::string s; + o >> s; + var = (RegionSelectionAfterSplit) string_2_enum (s, var); + return o; +} + +std::ostream& operator<<(std::ostream& o, const RegionSelectionAfterSplit& 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 bd5c1568e8..9deb7f4420 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -283,6 +283,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) @@ -5977,3 +5979,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 3e853a5005..6a9e44254a 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -459,6 +459,61 @@ 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) @@ -542,8 +597,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) || @@ -569,40 +623,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) do_locate = true; } else { - if (config.get_auto_return()) { + framepos_t jump_to; - if (play_loop) { + if (select_playhead_priority_target (jump_to)) { - /* don't try to handle loop play when synced to JACK */ + _transport_frame = jump_to; + do_locate = true; - if (!synced_to_engine()) { - - 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 = _last_roll_location; - do_locate = true; - } } else if (abort) { _transport_frame = _last_roll_location; @@ -1133,7 +1160,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 5603209928..aba9863d5b 100644 --- a/system_config +++ b/system_config @@ -41,6 +41,7 @@