From dfc0b58d14301d59d55cc65b32513756e996cde8 Mon Sep 17 00:00:00 2001 From: Grygorii Zharun Date: Mon, 19 May 2014 18:04:58 -0500 Subject: [PATCH] [Summary] Implemented channel control mechanism [git-p4: depot-paths = "//Abdaw/dev_main/tracks/": change = 461673] --- gtk2_ardour/ardour_ui.cc | 2 +- gtk2_ardour/device_connection_control.cc | 41 ++- gtk2_ardour/device_connection_control.h | 12 +- gtk2_ardour/session_dialog.logic.cc | 3 +- gtk2_ardour/tracks_control_panel.logic.cc | 221 ++++++++++-- gtk2_ardour/tracks_control_panel.logic.h | 7 + gtk2_ardour/wscript | 1 - libs/ardour/ardour/audioengine.h | 2 + .../ardour/ardour}/engine_state_controller.h | 79 ++++- libs/ardour/ardour/rc_configuration_vars.h | 3 + libs/ardour/ardour/session.h | 5 +- libs/ardour/ardour/types.h | 7 + libs/ardour/audioengine.cc | 9 + .../ardour}/engine_state_controller.cc | 320 +++++++++++++++++- libs/ardour/enums.cc | 20 ++ libs/ardour/session.cc | 45 ++- libs/ardour/session_state.cc | 12 +- libs/ardour/wscript | 1 + 18 files changed, 685 insertions(+), 105 deletions(-) rename {gtk2_ardour => libs/ardour/ardour}/engine_state_controller.h (69%) rename {gtk2_ardour => libs/ardour}/engine_state_controller.cc (60%) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index b718bc26fc..c9bd57a8c3 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -68,6 +68,7 @@ #include "ardour/audiofilesource.h" #include "ardour/automation_watch.h" #include "ardour/diskstream.h" +#include "ardour/engine_state_controller.h" #include "ardour/filename_extensions.h" #include "ardour/filesystem_paths.h" #include "ardour/port.h" @@ -95,7 +96,6 @@ typedef uint64_t microseconds_t; #include "add_route_dialog.h" #include "ambiguous_file_dialog.h" #include "ardour_ui.h" -#include "engine_state_controller.h" #include "audio_clock.h" #include "big_clock_window.h" #include "bundle_manager.h" diff --git a/gtk2_ardour/device_connection_control.cc b/gtk2_ardour/device_connection_control.cc index ca536d3194..9ed42a3826 100644 --- a/gtk2_ardour/device_connection_control.cc +++ b/gtk2_ardour/device_connection_control.cc @@ -20,7 +20,7 @@ #include "device_connection_control.h" #include "pbd/convert.h" -DeviceConnectionControl::DeviceConnectionControl (std::string device_capture_name, bool active, uint16_t capture_number, std::string track_name) +DeviceConnectionControl::DeviceConnectionControl (const std::string& device_capture_name, bool active, uint16_t capture_number, const std::string& track_name) : Gtk::Layout() , _active_on_button (NULL) @@ -38,7 +38,7 @@ DeviceConnectionControl::DeviceConnectionControl (std::string device_capture_nam init(device_capture_name, active, capture_number, track_name); } -DeviceConnectionControl::DeviceConnectionControl (std::string device_playback_name, bool active, uint16_t playback_number) +DeviceConnectionControl::DeviceConnectionControl (const std::string& device_playback_name, bool active, uint16_t playback_number) : Gtk::Layout() , _active_on_button (NULL) @@ -55,7 +55,7 @@ DeviceConnectionControl::DeviceConnectionControl (std::string device_playback_na init(device_playback_name, active, playback_number); } -DeviceConnectionControl::DeviceConnectionControl (std::string midi_capture_name, bool active) +DeviceConnectionControl::DeviceConnectionControl (const std::string& midi_capture_name, bool active) : Gtk::Layout() , _active_on_button (NULL) @@ -86,7 +86,7 @@ DeviceConnectionControl::DeviceConnectionControl (bool active) init("", active, NoNumber); } -void DeviceConnectionControl::init(std::string name, bool active, uint16_t number, std::string track_name) +void DeviceConnectionControl::init(const std::string& name, bool active, uint16_t number, const std::string& track_name) { _active_on_button->signal_clicked.connect (sigc::mem_fun (*this, &DeviceConnectionControl::on_active_on)); _active_off_button->signal_clicked.connect (sigc::mem_fun (*this, &DeviceConnectionControl::on_active_off)); @@ -97,17 +97,22 @@ void DeviceConnectionControl::init(std::string name, bool active, uint16_t numbe if (_number_label != NULL) { _number_label->set_text(PBD::to_string (number, std::dec)); + + if (number == NoNumber) { + _number_label->get_parent()->hide (); + } } if (_track_name_label != NULL) { _track_name_label->set_text (track_name); } + set_active(active); } bool -DeviceConnectionControl::build_layout (std::string file_name) +DeviceConnectionControl::build_layout (const std::string& file_name) { const XMLTree* layout = WavesUI::load_layout(file_name); if (layout == NULL) { @@ -144,6 +149,32 @@ DeviceConnectionControl::set_active (bool active) _active = active; } + +void +DeviceConnectionControl::set_track_name (const std::string& new_track_name) +{ + if (_track_name_label != NULL ) { + _track_name_label->set_text (new_track_name); + if (new_track_name.empty() ) { + _track_name_label->get_parent()->hide(); + } else { + _track_name_label->get_parent()->show(); + } + } +} + + +std::string +DeviceConnectionControl::get_name () +{ + std::string name; + if (_name_label != NULL) { + name = _name_label->get_text(); + } + + return name; +} + void DeviceConnectionControl::on_active_on(WavesButton*) { diff --git a/gtk2_ardour/device_connection_control.h b/gtk2_ardour/device_connection_control.h index 10c6cbbd64..a9c487b736 100644 --- a/gtk2_ardour/device_connection_control.h +++ b/gtk2_ardour/device_connection_control.h @@ -33,18 +33,20 @@ class DeviceConnectionControl : public Gtk::Layout NoNumber = 0 }; - DeviceConnectionControl (std::string device_capture_name, bool active, uint16_t capture_number, std::string track_name); - DeviceConnectionControl (std::string device_playback_name, bool active, uint16_t playback_number); - DeviceConnectionControl (std::string midi_capture_name, bool active); + DeviceConnectionControl (const std::string& device_capture_name, bool active, uint16_t capture_number, const std::string& track_name); + DeviceConnectionControl (const std::string& device_playback_name, bool active, uint16_t playback_number); + DeviceConnectionControl (const std::string& midi_capture_name, bool active); DeviceConnectionControl (bool active); - bool build_layout (std::string file_name); + bool build_layout (const std::string& file_name); void set_number (uint16_t number); void set_active (bool active); + void set_track_name (const std::string& new_track_name); + std::string get_name (); sigc::signal2 signal_active_changed; private: - void init(std::string name, bool active, uint16_t number, std::string track_name=""); + void init(const std::string& name, bool active, uint16_t number, const std::string& track_name=""); void on_active_on(WavesButton*); void on_active_off(WavesButton*); diff --git a/gtk2_ardour/session_dialog.logic.cc b/gtk2_ardour/session_dialog.logic.cc index 6d662ca985..cd00c3bb9c 100644 --- a/gtk2_ardour/session_dialog.logic.cc +++ b/gtk2_ardour/session_dialog.logic.cc @@ -28,8 +28,6 @@ #include -#include "engine_state_controller.h" - #include "pbd/failed_constructor.h" #include "pbd/file_utils.h" #include "pbd/replace_all.h" @@ -38,6 +36,7 @@ #include "pbd/openuri.h" #include "ardour/audioengine.h" +#include "ardour/engine_state_controller.h" #include "ardour/filesystem_paths.h" #include "ardour/recent_sessions.h" #include "ardour/session.h" diff --git a/gtk2_ardour/tracks_control_panel.logic.cc b/gtk2_ardour/tracks_control_panel.logic.cc index c89b3f9b2d..064877d49b 100644 --- a/gtk2_ardour/tracks_control_panel.logic.cc +++ b/gtk2_ardour/tracks_control_panel.logic.cc @@ -25,8 +25,9 @@ #include -#include "engine_state_controller.h" +#include "ardour/engine_state_controller.h" #include "ardour/rc_configuration.h" + #include "device_connection_control.h" #include "ardour_ui.h" #include "gui_thread.h" @@ -58,13 +59,17 @@ TracksControlPanel::init () _stereo_out_button.signal_clicked.connect(sigc::mem_fun (*this, &TracksControlPanel::on_stereo_out)); - AudioEngine::instance ()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_running, this), gui_context()); - AudioEngine::instance ()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_stopped, this), gui_context()); - AudioEngine::instance ()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_stopped, this), gui_context()); + EngineStateController::instance ()->EngineRunning.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_running, this), gui_context()); + EngineStateController::instance ()->EngineStopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_stopped, this), gui_context()); + EngineStateController::instance ()->EngineHalted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_stopped, this), gui_context()); - /* Subscribe for udpates from AudioEngine */ + /* Subscribe for udpates from EngineStateController */ EngineStateController::instance()->BufferSizeChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_buffer_size_update, this), gui_context()); EngineStateController::instance()->DeviceListChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_device_list_update, this, _1), gui_context()); + EngineStateController::instance()->InputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_input_configuration_changed, this), gui_context()); + EngineStateController::instance()->OutputConfigChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_output_configuration_changed, this), gui_context()); + + /* Global configuration parameters update */ Config->ParameterChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::on_parameter_changed, this, _1), gui_context()); _engine_combo.signal_changed().connect (sigc::mem_fun (*this, &TracksControlPanel::engine_changed)); @@ -75,6 +80,9 @@ TracksControlPanel::init () populate_engine_combo (); populate_output_mode(); + populate_input_channels(); + populate_output_channels(); + _audio_settings_tab_button.set_active(true); } @@ -227,30 +235,110 @@ TracksControlPanel::populate_output_mode() _stereo_out_button.set_active(Config->get_output_auto_connect() & AutoConnectMaster); } + +void +TracksControlPanel::populate_input_channels() +{ + cleanup_input_channels_list(); + + // process captures (inputs) + std::vector input_states; + EngineStateController::instance()->get_physical_audio_input_states(input_states); + + std::vector::const_iterator input_iter; + + uint16_t number_count = 1; + for (input_iter = input_states.begin(); input_iter != input_states.end(); ++input_iter ) { + + uint16_t number = DeviceConnectionControl::NoNumber; + std::string track_name = ""; + + if (input_iter->active) { + + number = number_count++; + + if (Config->get_tracks_auto_naming() & UseDefaultNames) { + track_name = string_compose ("Track %1", number); + } else if (Config->get_tracks_auto_naming() & NameAfterDriver) { + track_name = input_iter->name; + } + } + + add_device_capture_control (input_iter->name, input_iter->active, number, track_name); + } +} + + +void +TracksControlPanel::populate_output_channels() +{ + cleanup_output_channels_list(); + + // process captures (outputs) + std::vector output_states; + EngineStateController::instance()->get_physical_audio_output_states(output_states); + + std::vector::const_iterator output_iter; + + uint16_t number_count = 1; + for (output_iter = output_states.begin(); output_iter != output_states.end(); ++output_iter ) { + + uint16_t number = DeviceConnectionControl::NoNumber; + + if (output_iter->active) { + number = number_count++; + } + + add_device_playback_control (output_iter->name, output_iter->active, number); + } + +} + + + +void update_channel_numbers() +{ + +} + + +void update_channel_names() +{ + +} + + +void +TracksControlPanel::cleanup_input_channels_list() +{ + std::vector capture_controls = _device_capture_list.get_children(); + + while (capture_controls.size() != 0) { + Gtk::Widget* item = capture_controls.back(); + capture_controls.pop_back(); + _device_capture_list.remove(*item); + delete item; + } +} + + +void +TracksControlPanel::cleanup_output_channels_list() +{ + std::vector playback_controls = _device_playback_list.get_children(); + + while (playback_controls.size() != 0) { + Gtk::Widget* item = playback_controls.back(); + playback_controls.pop_back(); + _device_capture_list.remove(*item); + delete item; + } +} + + void TracksControlPanel::on_control_panel(WavesButton*) { -// ******************************* ATTENTION!!! **************************** -// here is just demo code to remove it in future -// ************************************************************************* -/* - static uint16_t number = 0; - static bool active = false; - - number++; - active = !active; - - std::string name = string_compose (_("Audio Capture %1"), number); - add_device_capture_control (name, active, number, name); - - name = string_compose (_("Audio Playback Output %1"), number); - add_device_playback_control (name, active, number); - - name = string_compose (_("Midi Capture %1"), number); - add_midi_capture_control (name, active); - - add_midi_playback_control (active); -*/ } void TracksControlPanel::engine_changed () @@ -372,6 +460,9 @@ TracksControlPanel::sample_rate_changed() void TracksControlPanel::engine_running () { + populate_input_channels(); + populate_output_channels(); + _buffer_size_combo.set_active_text (bufsize_as_string (EngineStateController::instance()->get_current_buffer_size() ) ); _sample_rate_combo.set_active_text (rate_as_string (EngineStateController::instance()->get_current_sample_rate() ) ); @@ -471,19 +562,13 @@ TracksControlPanel::on_apply (WavesButton*) void TracksControlPanel::on_capture_active_changed(DeviceConnectionControl* capture_control, bool active) { -// ******************************* ATTENTION!!! **************************** -// here is just demo code to replace it with a meaningful app logic in future -// ************************************************************************* - capture_control->set_number ( active ? 1000 : DeviceConnectionControl::NoNumber); + EngineStateController::instance()->set_physical_audio_input_state(capture_control->get_name(), active); } void TracksControlPanel::on_playback_active_changed(DeviceConnectionControl* playback_control, bool active) { -// ******************************* ATTENTION!!! **************************** -// here is just demo code to replace it with a meaningful app logic in future -// ************************************************************************* - playback_control->set_number ( active ? 1000 : DeviceConnectionControl::NoNumber); + EngineStateController::instance()->set_physical_audio_output_state(playback_control->get_name(), active); } @@ -531,9 +616,75 @@ TracksControlPanel::on_parameter_changed (const std::string& parameter_name) { if (parameter_name == "output-auto-connect") { populate_output_mode(); + } else if (parameter_name == "tracks-auto-naming") { + on_input_configuration_changed (); } } - + + +void +TracksControlPanel::on_input_configuration_changed () +{ + std::vector capture_controls = _device_capture_list.get_children(); + + std::vector::iterator control_iter = capture_controls.begin(); + + uint16_t number_count = 1; + for (; control_iter != capture_controls.end(); ++control_iter) { + DeviceConnectionControl* control = dynamic_cast (*control_iter); + + if (control) { + bool new_state = EngineStateController::instance()->get_physical_audio_input_state(control->get_name() ); + + uint16_t number = DeviceConnectionControl::NoNumber; + std::string track_name = ""; + + if (new_state) { + + number = number_count++; + + if (Config->get_tracks_auto_naming() & UseDefaultNames) { + track_name = string_compose ("Track %1", number); + } else if (Config->get_tracks_auto_naming() & NameAfterDriver) { + track_name = control->get_name(); + } + } + + control->set_track_name(track_name); + control->set_number(number); + control->set_active(new_state); + } + } +} + + +void +TracksControlPanel::on_output_configuration_changed() +{ + std::vector playback_controls = _device_playback_list.get_children(); + + std::vector::iterator control_iter = playback_controls.begin(); + + uint16_t number_count = 1; + for (; control_iter != playback_controls.end(); ++control_iter) { + DeviceConnectionControl* control = dynamic_cast (*control_iter); + + if (control) { + bool new_state = EngineStateController::instance()->get_physical_audio_output_state(control->get_name() ); + + uint16_t number = DeviceConnectionControl::NoNumber; + + if (new_state) { + number = number_count++; + } + + control->set_number(number); + control->set_active(new_state); + } + } + +} + std::string TracksControlPanel::bufsize_as_string (uint32_t sz) diff --git a/gtk2_ardour/tracks_control_panel.logic.h b/gtk2_ardour/tracks_control_panel.logic.h index 2e0f7fdd02..530d8243a7 100644 --- a/gtk2_ardour/tracks_control_panel.logic.h +++ b/gtk2_ardour/tracks_control_panel.logic.h @@ -94,11 +94,18 @@ void populate_sample_rate_combo (); void populate_buffer_size_combo (); void populate_output_mode (); + void populate_input_channels(); + void populate_output_channels(); // Engine State update callback handlers void on_buffer_size_update (); void on_device_list_update (bool current_device_disconnected); void on_parameter_changed (const std::string& parameter_name); + void on_input_configuration_changed (); + void on_output_configuration_changed (); + + void cleanup_input_channels_list(); + void cleanup_output_channels_list(); std::string bufsize_as_string (uint32_t sz); diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 08d8da34e9..a4307a3b73 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -96,7 +96,6 @@ gtk2_ardour_sources = [ 'editor_summary.cc', 'editor_tempodisplay.cc', 'editor_timefx.cc', - 'engine_state_controller.cc', 'engine_dialog.cc', 'enums.cc', 'export_channel_selector.cc', diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index e3c224eeee..41076427ea 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -136,6 +136,8 @@ public: void remove_session (); // not a replacement for SessionHandle::session_going_away() Session* session() const { return _session; } + void reconnect_session_routes (); + class NoBackendAvailable : public std::exception { public: virtual const char *what() const throw() { return "could not connect to engine backend"; } diff --git a/gtk2_ardour/engine_state_controller.h b/libs/ardour/ardour/engine_state_controller.h similarity index 69% rename from gtk2_ardour/engine_state_controller.h rename to libs/ardour/ardour/engine_state_controller.h index b365004c39..0e3e5f2172 100644 --- a/gtk2_ardour/engine_state_controller.h +++ b/libs/ardour/ardour/engine_state_controller.h @@ -10,6 +10,7 @@ #define __gtk2_ardour__engine_state_controller__ #include +#include #include "ardour/types.h" #include "ardour/audio_backend.h" @@ -21,6 +22,31 @@ class AudioBackendInfo; class EngineStateController { public: + + // public data types: + struct ChannelState { + std::string name; + bool active; + + ChannelState () + : name(""), + active(true) + { + } + + ChannelState (const std::string& name) + : name(name), + active(true) + { + } + + bool operator==(const ChannelState& rhs) {return rhs.name == name; } + + }; + + typedef std::list ChannelStateList; + + static EngineStateController* instance(); //Interfaces @@ -40,10 +66,21 @@ public: ARDOUR::pframes_t get_default_buffer_size() const; void available_buffer_sizes_for_current_device(std::vector&) const; - uint32_t get_available_inputs_count() const {return 0; } - uint32_t get_available_outputs_count () const {return 0; } + uint32_t get_available_inputs_count() const {return _current_state->input_channel_states.size(); } + uint32_t get_available_outputs_count () const {return _current_state->output_channel_states.size(); } - bool is_setup_required() const {return ARDOUR::AudioEngine::instance()->setup_required (); } + void get_physical_audio_inputs (std::vector&); + void get_physical_audio_outputs (std::vector&); + + void set_physical_audio_input_state(const std::string&, bool); + void set_physical_audio_output_state(const std::string&, bool); + bool get_physical_audio_input_state(const std::string&); + bool get_physical_audio_output_state(const std::string&); + + void get_physical_audio_input_states(std::vector&); + void get_physical_audio_output_states(std::vector&); + + bool is_setup_required() const {return ARDOUR::AudioEngine::instance()->setup_required (); } // set parameters inside the controller, // the state of engine won't change untill we make a "push" of this state to the backend @@ -62,16 +99,26 @@ public: void set_desired_sample_rate(framecnt_t); - //SIGNALS + //DATE UPDATE SIGNALS /* this signal is emitted if the sample rate changes */ PBD::Signal0 SampleRateChanged; - /* this signal is emitted if the buffer size changes */ PBD::Signal0 BufferSizeChanged; - /* this signal is emitted if the device list changes */ PBD::Signal1 DeviceListChanged; + //ENGINE STATE SIGNALS + /* this signal is emitted when the engine is started */ + PBD::Signal0 EngineRunning; + /* this signal is emitted when the engine is stopped */ + PBD::Signal0 EngineStopped; + /* this signal is emitted if the backend ever disconnects us */ + PBD::Signal0 EngineHalted; + + /* this signal is emitted if the i/o channel configuration changes */ + PBD::Signal0 InputConfigChanged; + PBD::Signal0 OutputConfigChanged; + private: EngineStateController(); // singleton @@ -79,7 +126,6 @@ private: EngineStateController(const EngineStateController& ); // prohibited EngineStateController& operator=(const EngineStateController&); // prohibited - // data types: struct State { std::string backend_name; std::string device_name; @@ -87,17 +133,17 @@ private: ARDOUR::pframes_t buffer_size; uint32_t input_latency; uint32_t output_latency; - uint32_t input_channels; - uint32_t output_channels; - bool active; + ChannelStateList input_channel_states; + ChannelStateList output_channel_states; + //bool active; std::string midi_option; State() : input_latency (0) , output_latency (0) - , input_channels (0) - , output_channels (0) - , active (false) + , input_channel_states (0) + , output_channel_states (0) + //, active (false) { } @@ -134,6 +180,10 @@ private: // sets last active state as current state // if no last active state found it loads default state void _set_last_active_state_as_current(); + // get gets available device channels from engine and updates internal controller state + void _update_device_channels_state(bool reconnect_session_routes = true); + // change channel configuration to stereo out mode + void _switch_to_stereo_out_io(); //////////////////////////////////////// // internal helper functions//////////// @@ -144,11 +194,12 @@ private: //////////////////////////////////////// // callbacks void _on_engine_running(); - void _on_engine_halted(const char*); + void _on_engine_halted(); void _on_engine_stopped(); void _on_sample_rate_change(ARDOUR::framecnt_t); void _on_buffer_size_change(ARDOUR::pframes_t); void _on_device_list_change(); + void _on_parameter_changed (const std::string&); //////////////////////////////////////// //////////////////////////////////////// diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 57275f4783..c43a6d7eef 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -33,6 +33,9 @@ CONFIG_VARIABLE (bool, auto_connect_standard_busses, "auto-connect-standard-buss CONFIG_VARIABLE (AutoConnectOption, output_auto_connect, "output-auto-connect", AutoConnectPhysical) CONFIG_VARIABLE (AutoConnectOption, input_auto_connect, "input-auto-connect", AutoConnectPhysical) +/* Naming */ +CONFIG_VARIABLE (TracksAutoNamingRule, tracks_auto_naming, "tracks-auto-naming", UseDefaultNames) + /* MIDI and MIDI related */ CONFIG_VARIABLE (bool, trace_midi_input, "trace-midi-input", false) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 4c61c72276..7515d49700 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -890,8 +890,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop friend class AudioEngine; void set_block_size (pframes_t nframes); void set_frame_rate (framecnt_t nframes); - void reconnect_existing_routes (bool withLock, bool reconnect_master = false); - + void reconnect_existing_routes (bool withLock, bool reconnect_master = false); + protected: friend class Route; void schedule_curve_reallocation (); @@ -1337,7 +1337,6 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop void route_solo_changed (bool self_solo_change, void *src, boost::weak_ptr); void route_solo_isolated_changed (void *src, boost::weak_ptr); void update_route_solo_state (boost::shared_ptr r = boost::shared_ptr()); - void update_output_mode(); void listen_position_changed (); void solo_control_mode_changed (); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index ab76208c0b..07ff29ff8a 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -440,6 +440,11 @@ namespace ARDOUR { AutoConnectPhysical = 0x1, AutoConnectMaster = 0x2 }; + + enum TracksAutoNamingRule { + UseDefaultNames = 0x1, + NameAfterDriver = 0x2 + }; enum SampleFormat { FormatFloat = 0, @@ -613,6 +618,7 @@ namespace ARDOUR { std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::HeaderFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::AutoConnectOption& sf); +std::istream& operator>>(std::istream& o, ARDOUR::TracksAutoNamingRule& sf); std::istream& operator>>(std::istream& o, ARDOUR::EditMode& sf); std::istream& operator>>(std::istream& o, ARDOUR::MonitorModel& sf); std::istream& operator>>(std::istream& o, ARDOUR::VUMeterStandard& sf); @@ -636,6 +642,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::PositionLockStyle& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::SampleFormat& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::HeaderFormat& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::AutoConnectOption& sf); +std::ostream& operator<<(std::ostream& o, const ARDOUR::TracksAutoNamingRule& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::EditMode& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::MonitorModel& sf); std::ostream& operator<<(std::ostream& o, const ARDOUR::VUMeterStandard& sf); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index eff4ccb658..27d719f73e 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -442,6 +442,15 @@ AudioEngine::remove_session () } +void +AudioEngine::reconnect_session_routes() +{ + if (_session) { + _session->reconnect_existing_routes(true, true); + } +} + + void AudioEngine::died () { diff --git a/gtk2_ardour/engine_state_controller.cc b/libs/ardour/engine_state_controller.cc similarity index 60% rename from gtk2_ardour/engine_state_controller.cc rename to libs/ardour/engine_state_controller.cc index 5cdece9df8..e8467b5f5f 100644 --- a/gtk2_ardour/engine_state_controller.cc +++ b/libs/ardour/engine_state_controller.cc @@ -6,13 +6,15 @@ // Copyright (c) 2014 Waves. All rights reserved. // -#include "engine_state_controller.h" +#include "ardour/engine_state_controller.h" -#include "ardour_ui.h" #include "ardour/audioengine.h" +#include "ardour/rc_configuration.h" +#include "ardour/data_type.h" + #include "pbd/error.h" #include "i18n.h" -#include "gui_thread.h" + using namespace ARDOUR; using namespace PBD; @@ -50,14 +52,17 @@ EngineStateController::EngineStateController() , _have_control(false) { - AudioEngine::instance ()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&EngineStateController::_on_engine_running, this), gui_context()); - AudioEngine::instance ()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineStateController::_on_engine_stopped, this), gui_context()); - AudioEngine::instance ()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&EngineStateController::_on_engine_stopped, this), gui_context()); + AudioEngine::instance ()->Running.connect_same_thread (running_connection, boost::bind (&EngineStateController::_on_engine_running, this) ); + AudioEngine::instance ()->Stopped.connect_same_thread (stopped_connection, boost::bind (&EngineStateController::_on_engine_stopped, this) ); + AudioEngine::instance ()->Halted.connect_same_thread (stopped_connection, boost::bind (&EngineStateController::_on_engine_stopped, this) ); /* Subscribe for udpates from AudioEngine */ - AudioEngine::instance()->SampleRateChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&EngineStateController::_on_sample_rate_change, this, _1), gui_context()); - AudioEngine::instance()->BufferSizeChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&EngineStateController::_on_buffer_size_change, this, _1), gui_context()); - AudioEngine::instance()->DeviceListChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&EngineStateController::_on_device_list_change, this), gui_context()); + AudioEngine::instance()->SampleRateChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_sample_rate_change, this, _1) ); + AudioEngine::instance()->BufferSizeChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_buffer_size_change, this, _1) ); + AudioEngine::instance()->DeviceListChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_device_list_change, this) ); + + /* Global configuration parameters update */ + Config->ParameterChanged.connect_same_thread (update_connections, boost::bind (&EngineStateController::_on_parameter_changed, this, _1) ); _deserialize_and_load_states(); _set_last_active_state_as_current(); @@ -97,8 +102,7 @@ EngineStateController::_set_last_active_state_as_current() std::vector backends = AudioEngine::instance()->available_backends(); - if (!backends.empty() ) - { + if (!backends.empty() ) { if (!set_new_backend_as_current(backends.front()->name ) ) { std::cerr << "\tfailed to set backend [" << backends.front()->name << "]\n"; @@ -378,6 +382,186 @@ EngineStateController::set_new_buffer_size_in_controller(pframes_t buffer_size) } +void +EngineStateController::get_physical_audio_inputs(std::vector& port_names) +{ + port_names.clear(); + + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + // update audio input states + std::vector phys_audio_inputs; + backend->get_physical_inputs(DataType::AUDIO, phys_audio_inputs); + + ChannelStateList &input_states = _current_state->input_channel_states; + + std::vector::const_iterator input_iter = phys_audio_inputs.begin(); + for (; input_iter != phys_audio_inputs.end(); ++input_iter) { + + ChannelStateList::const_iterator found_state_iter; + found_state_iter = std::find(input_states.begin(), input_states.end(), ChannelState(*input_iter) ); + + if (found_state_iter != input_states.end() && found_state_iter->active) { + port_names.push_back(found_state_iter->name); + } + } +} + + +void +EngineStateController::get_physical_audio_outputs(std::vector& port_names) +{ + port_names.clear(); + + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + // update audio input states + std::vector phys_audio_outputs; + backend->get_physical_outputs(DataType::AUDIO, phys_audio_outputs); + + ChannelStateList &output_states = _current_state->output_channel_states; + + std::vector::const_iterator output_iter = phys_audio_outputs.begin(); + for (; output_iter != phys_audio_outputs.end(); ++output_iter) { + + ChannelStateList::const_iterator found_state_iter; + found_state_iter = std::find(output_states.begin(), output_states.end(), ChannelState(*output_iter) ); + + if (found_state_iter != output_states.end() && found_state_iter->active) { + port_names.push_back(found_state_iter->name); + } + } +} + + +void +EngineStateController::set_physical_audio_input_state(const std::string& port_name, bool state) +{ + ChannelStateList &input_states = _current_state->input_channel_states; + ChannelStateList::iterator found_state_iter; + found_state_iter = std::find(input_states.begin(), input_states.end(), ChannelState(port_name) ); + + if (found_state_iter != input_states.end() && found_state_iter->active != state ) { + found_state_iter->active = state; + AudioEngine::instance()->reconnect_session_routes(); + + InputConfigChanged(); + } +} + + +void +EngineStateController::set_physical_audio_output_state(const std::string& port_name, bool state) +{ + ChannelStateList &output_states = _current_state->output_channel_states; + ChannelStateList::iterator target_state_iter; + target_state_iter = std::find(output_states.begin(), output_states.end(), ChannelState(port_name) ); + + if (target_state_iter != output_states.end() && target_state_iter->active != state ) { + target_state_iter->active = state; + + // if StereoOut mode is used + if (Config->get_output_auto_connect() & AutoConnectMaster) { + + // get next element + ChannelStateList::iterator next_state_iter(target_state_iter); + + // loopback + if (++next_state_iter == output_states.end() ) { + next_state_iter = output_states.begin(); + } + + // if current was set to active - activate next and disable the rest + if (target_state_iter->active ) { + next_state_iter->active = true; + } else { + // if current was deactivated but the next is active + if (next_state_iter->active) { + if (++next_state_iter == output_states.end() ) { + next_state_iter = output_states.begin(); + } + next_state_iter->active = true; + } else { + // if current was deactivated but the previous is active - restore the state of current + target_state_iter->active = true; // state restored; + --target_state_iter; // switch to previous to make it stop point + target_state_iter->active = true; + } + } + + while (++next_state_iter != target_state_iter) { + + if (next_state_iter == output_states.end() ) { + next_state_iter = output_states.begin(); + // we jumped, so additional check is required + if (next_state_iter == target_state_iter) { + break; + } + } + + next_state_iter->active = false; + } + + } + + AudioEngine::instance()->reconnect_session_routes(); + OutputConfigChanged(); + } +} + + +bool +EngineStateController::get_physical_audio_input_state(const std::string& port_name) +{ + bool state = false; + + ChannelStateList &input_states = _current_state->input_channel_states; + ChannelStateList::iterator found_state_iter; + found_state_iter = std::find(input_states.begin(), input_states.end(), ChannelState(port_name) ); + + if (found_state_iter != input_states.end() ) { + state = found_state_iter->active; + } + + return state; +} + + +bool +EngineStateController::get_physical_audio_output_state(const std::string& port_name) +{ + bool state = false; + + ChannelStateList &output_states = _current_state->output_channel_states; + ChannelStateList::iterator found_state_iter; + found_state_iter = std::find(output_states.begin(), output_states.end(), ChannelState(port_name) ); + + if (found_state_iter != output_states.end() ) { + state = found_state_iter->active; + } + + return state; +} + + +void +EngineStateController::get_physical_audio_input_states(std::vector& channel_states) +{ + ChannelStateList &input_states = _current_state->input_channel_states; + channel_states.assign(input_states.begin(), input_states.end()); +} + + +void +EngineStateController::get_physical_audio_output_states(std::vector& channel_states) +{ + ChannelStateList &output_states = _current_state->output_channel_states; + channel_states.assign(output_states.begin(), output_states.end()); +} + + void EngineStateController::_on_sample_rate_change(framecnt_t new_sample_rate) { @@ -471,17 +655,125 @@ EngineStateController::_on_device_list_change() } +void +EngineStateController::_update_device_channels_state(bool reconnect_session_routes/*=true*/) +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + // update audio input states + std::vector phys_audio_inputs; + backend->get_physical_inputs(DataType::AUDIO, phys_audio_inputs); + + ChannelStateList new_input_states; + ChannelStateList &input_states = _current_state->input_channel_states; + + std::vector::const_iterator input_iter = phys_audio_inputs.begin(); + for (; input_iter != phys_audio_inputs.end(); ++input_iter) { + + ChannelState state(*input_iter); + ChannelStateList::const_iterator found_state_iter = std::find(input_states.begin(), input_states.end(), state); + + if (found_state_iter != input_states.end() ) { + new_input_states.push_back(*found_state_iter); + } else { + new_input_states.push_back(state); + } + } + _current_state->input_channel_states = new_input_states; + + // update audio output state + std::vector phys_audio_outputs; + backend->get_physical_outputs(DataType::AUDIO, phys_audio_outputs); + + ChannelStateList new_output_states; + ChannelStateList &output_states = _current_state->output_channel_states; + + std::vector::const_iterator output_iter = phys_audio_outputs.begin(); + for (; output_iter != phys_audio_outputs.end(); ++output_iter) { + + ChannelState state(*output_iter); + ChannelStateList::const_iterator found_state_iter = std::find(output_states.begin(), output_states.end(), state); + + if (found_state_iter != output_states.end() ) { + new_output_states.push_back(*found_state_iter); + } else { + new_output_states.push_back(state); + } + } + + _current_state->output_channel_states = new_output_states; + + if (Config->get_output_auto_connect() & AutoConnectMaster) { + _switch_to_stereo_out_io(); + } + + // update midi channels + /* provide implementation */ + + if (reconnect_session_routes) { + AudioEngine::instance()->reconnect_session_routes(); + } +} + + +void +EngineStateController::_switch_to_stereo_out_io() +{ + ChannelStateList &output_states = _current_state->output_channel_states; + ChannelStateList::iterator iter = output_states.begin(); + + uint32_t active_channels = 2; + + for (; iter != output_states.end(); ++iter) { + if (active_channels) { + iter->active = true; + --active_channels; + } else { + iter->active = false; + } + } +} + + void EngineStateController::_on_engine_running () { + _update_device_channels_state(); + _serialize_and_save_current_state(); + + EngineRunning(); } void EngineStateController::_on_engine_stopped () { + EngineStopped(); } + +void +EngineStateController::_on_engine_halted () +{ + EngineHalted(); +} + + +void +EngineStateController::_on_parameter_changed (const std::string& parameter_name) +{ + if (parameter_name == "output-auto-connect") { + + if (Config->get_output_auto_connect() & AutoConnectMaster) { + _switch_to_stereo_out_io(); + AudioEngine::instance()->reconnect_session_routes(); + OutputConfigChanged(); // emit a signal + } + } +} + + bool EngineStateController::push_current_state_to_backend(bool start) { @@ -501,7 +793,7 @@ EngineStateController::push_current_state_to_backend(bool start) if (state_changed) { if (was_running) { - if (ARDOUR_UI::instance()->disconnect_from_engine () ) { + if (AudioEngine::instance()->stop () ) { return false; } } @@ -539,10 +831,8 @@ EngineStateController::push_current_state_to_backend(bool start) //} } - _serialize_and_save_current_state(); - if(start || (was_running && state_changed) ) { - if (ARDOUR_UI::instance()->reconnect_to_engine () ) { + if (AudioEngine::instance()->start () ) { return false; } } diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index e32fe329af..af764389df 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -95,6 +95,7 @@ setup_enum_writer () AutoState _AutoState; AutoStyle _AutoStyle; AutoConnectOption _AutoConnectOption; + TracksAutoNamingRule _TracksAutoNamingRule; Session::StateOfTheState _Session_StateOfTheState; Route::Flag _Route_Flag; Source::Flag _Source_Flag; @@ -314,6 +315,10 @@ setup_enum_writer () REGISTER_ENUM (AutoConnectMaster); REGISTER_BITS (_AutoConnectOption); + REGISTER_ENUM (UseDefaultNames); + REGISTER_ENUM (NameAfterDriver); + REGISTER_BITS (_TracksAutoNamingRule); + REGISTER_ENUM (FormatFloat); REGISTER_ENUM (FormatInt24); REGISTER_ENUM (FormatInt16); @@ -657,6 +662,7 @@ std::ostream& operator<<(std::ostream& o, const SampleFormat& var) std::string s = enum_2_string (var); return o << s; } + std::istream& operator>>(std::istream& o, AutoConnectOption& var) { std::string s; @@ -671,6 +677,20 @@ std::ostream& operator<<(std::ostream& o, const AutoConnectOption& var) return o << s; } +std::istream& operator>>(std::istream& o, TracksAutoNamingRule& var) +{ + std::string s; + o >> s; + var = (TracksAutoNamingRule) string_2_enum (s, var); + return o; +} + +std::ostream& operator<<(std::ostream& o, const TracksAutoNamingRule& var) +{ + std::string s = enum_2_string (var); + return o << s; +} + std::istream& operator>>(std::istream& o, MonitorModel& var) { std::string s; diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 1a1d33ca29..e768025d53 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -65,6 +65,7 @@ #include "ardour/control_protocol_manager.h" #include "ardour/data_type.h" #include "ardour/debug.h" +#include "ardour/engine_state_controller.h" #include "ardour/filename_extensions.h" #include "ardour/graph.h" #include "ardour/midiport_manager.h" @@ -358,12 +359,11 @@ Session::Session (AudioEngine &eng, */ if (_is_new && ARDOUR::Profile->get_trx () ) { uint32_t how_many (0); - if (_engine.current_backend()->input_channels () > 0){ - how_many = _engine.current_backend()->input_channels (); - } else { - const string device_name = _engine.current_backend()->device_name (); - how_many = _engine.current_backend()->available_input_channel_count (device_name); - } + + std::vector inputs; + EngineStateController::instance()->get_physical_audio_inputs(inputs); + + how_many = inputs.size(); list > tracks = new_audio_track (1, 1, Normal, 0, how_many, string() ); @@ -813,7 +813,12 @@ Session::auto_connect_master_bus () vector outputs[DataType::num_types]; for (uint32_t i = 0; i < DataType::num_types; ++i) { - _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + + if ( Profile->get_trx() && DataType::Symbol (i) == DataType::AUDIO) { + EngineStateController::instance()->get_physical_audio_outputs(outputs[i]); + } else { + _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + } } for (uint32_t n = 0; n < limit; ++n) { @@ -973,7 +978,13 @@ Session::add_monitor_section () vector outputs[DataType::num_types]; for (uint32_t i = 0; i < DataType::num_types; ++i) { - _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + + if ( Profile->get_trx() && DataType::Symbol (i) == DataType::AUDIO) { + EngineStateController::instance()->get_physical_audio_outputs(outputs[i]); + } else { + _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]); + } + } uint32_t mod = outputs[DataType::AUDIO].size(); @@ -2000,8 +2011,17 @@ Session::auto_connect_route (boost::shared_ptr route, ChanCount& existing vector physinputs; vector physoutputs; - _engine.get_physical_outputs (*t, physoutputs); - _engine.get_physical_inputs (*t, physinputs); + if ( Profile->get_trx() && *t == DataType::AUDIO) { + EngineStateController::instance()->get_physical_audio_outputs(physoutputs); + } else { + _engine.get_physical_outputs (*t, physoutputs); + } + + if ( Profile->get_trx() && *t == DataType::AUDIO) { + EngineStateController::instance()->get_physical_audio_inputs(physinputs); + } else { + _engine.get_physical_inputs (*t, physinputs); + } if (!physinputs.empty() && connect_inputs) { uint32_t nphysical_in = physinputs.size(); @@ -2097,7 +2117,6 @@ Session::auto_connect_route (boost::shared_ptr route, ChanCount& existing void Session::reconnect_existing_routes (bool withLock, bool reconnect_master) { - PBD::stacktrace (cerr, 20); Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); if (withLock) { @@ -2125,8 +2144,8 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master) vector physinputs; vector physoutputs; - _engine.get_physical_outputs (DataType::AUDIO, physoutputs); - _engine.get_physical_inputs (DataType::AUDIO, physinputs); + EngineStateController::instance()->get_physical_audio_outputs(physoutputs); + EngineStateController::instance()->get_physical_audio_inputs(physinputs); uint32_t input_n = 0; uint32_t output_n = 0; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index af5e8841bf..2f6a794f42 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -3512,21 +3512,11 @@ Session::config_changed (std::string p, bool ours) reconnect_ltc_output (); } else if (p == "timecode-generator-offset") { ltc_tx_parse_offset(); - } else if (p == "output-auto-connect") { - if (ARDOUR::Profile->get_trx() ) { - update_output_mode(); - } - } + } set_dirty (); } -void -Session::update_output_mode() -{ - reconnect_existing_routes(true, true); -} - void Session::set_history_depth (uint32_t d) { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 0302289820..ff93378f0a 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -69,6 +69,7 @@ libardour_sources = [ 'element_import_handler.cc', 'element_importer.cc', 'engine_slave.cc', + 'engine_state_controller.cc', 'enums.cc', 'event_type_map.cc', 'export_channel.cc',