diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 3288009721..90e4c54635 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -95,6 +95,7 @@ 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" @@ -283,7 +284,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) /* handle Audio/MIDI setup when session requires it */ - ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_tracks_control_panel, this, _1)); + ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_engine_setup, this, _1)); /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */ @@ -389,7 +390,15 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets)); + // start the engine: + // initialize engin state controller + EngineStateController::instance(); + + // attach to the engine signals attach_to_engine (); + + // start the engine pushing state from the state controller + EngineStateController::instance()->push_current_state_to_backend(true); } GlobalPortMatrixWindow* @@ -426,7 +435,7 @@ ARDOUR_UI::engine_running () update_disk_space (); update_cpu_load (); - update_sample_rate (AudioEngine::instance()->sample_rate()); + update_sample_rate (EngineStateController::instance()->get_current_sample_rate() ); update_timecode_format (); } @@ -1152,7 +1161,7 @@ ARDOUR_UI::update_sample_rate (framecnt_t) } else { - framecnt_t rate = AudioEngine::instance()->sample_rate(); + framecnt_t rate = EngineStateController::instance()->get_current_sample_rate(); if (rate == 0) { /* no sample rate available */ @@ -4392,19 +4401,9 @@ ARDOUR_UI::reset_route_peak_display (Route* route) #define dbg_msg(a) MessageDialog(a, PROGRAM_NAME).run(); int -ARDOUR_UI::do_tracks_control_panel (uint32_t desired_sample_rate) +ARDOUR_UI::do_engine_setup (framecnt_t desired_sample_rate) { - tracks_control_panel->set_desired_sample_rate (desired_sample_rate); - tracks_control_panel->set_position (WIN_POS_CENTER); - - switch (tracks_control_panel->run()) { - case Gtk::RESPONSE_OK: - return 0; - case Gtk::RESPONSE_APPLY: - return 0; - default: - break; - } + ARDOUR::EngineStateController::instance()->set_desired_sample_rate (desired_sample_rate); - return -1; + return 0; } diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 3912470efe..eca63e3f2b 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -758,7 +758,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr std::string _announce_string; void check_announcements (); - int do_tracks_control_panel(uint32_t); + int do_engine_setup(ARDOUR::framecnt_t desired_sample_rate); }; #endif /* __ardour_gui_h__ */ diff --git a/gtk2_ardour/engine_state_controller.cc b/gtk2_ardour/engine_state_controller.cc new file mode 100644 index 0000000000..5715419ee6 --- /dev/null +++ b/gtk2_ardour/engine_state_controller.cc @@ -0,0 +1,544 @@ +// +// engine_state_controller.cpp +// Tracks +// +// Created by Grygorii Zharun on 4/30/14. +// Copyright (c) 2014 Waves. All rights reserved. +// + +#include "engine_state_controller.h" + +#include "ardour_ui.h" +#include "ardour/audioengine.h" +#include "pbd/error.h" +#include "i18n.h" +#include "gui_thread.h" + +using namespace ARDOUR; +using namespace PBD; + +namespace { + + struct DevicePredicate + { + DevicePredicate(const std::string& device_name) + : _device_name(device_name) + {} + + bool operator()(const AudioBackend::DeviceStatus& rhs) + { + return _device_name == rhs.name; + } + + private: + std::string _device_name; + }; +} + +EngineStateController* +EngineStateController::instance() +{ + static EngineStateController instance; + return &instance; +} + + +EngineStateController::EngineStateController() +: _current_state() +, _last_used_real_device("") +, _desired_sample_rate(0) +, _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()); + + /* Subscribe for udpates from AudioEngine */ + AudioEngine::instance()->BufferSizeChanged.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()); + + _deserialize_and_load_states(); + _set_last_active_state_as_current(); + + // now push the sate to the backend + push_current_state_to_backend(false); +} + + +EngineStateController::~EngineStateController() +{ + +} + + +void +EngineStateController::_deserialize_and_load_states() +{ + +} + + +void +EngineStateController::_serialize_and_save_current_state() +{ + // **** add code to save the state list to the file **** +} + + +void +EngineStateController::_set_last_active_state_as_current() +{ + // if we have no saved state load default values + if (!_states.empty() ) { + } else { + _current_state = boost::shared_ptr(new State() ); + + std::vector backends = AudioEngine::instance()->available_backends(); + + if (!backends.empty() ) + { + + if (set_new_backend_as_current(backends.front()->name ) ) { + _current_state->device_name = "None"; + _validate_current_device_state(); + _states.push_front(_current_state); + } else { + std::cerr << "\tfailed to set backend [" << backends.front()->name << "]\n"; + } + } + + } +} + + +void +EngineStateController::_validate_current_device_state() +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + // check if device parameters from the state record are still valid + // validate sample rate + std::vector sample_rates = backend->available_sample_rates (_current_state->device_name); + + // check if session desired sample rate (if it's set) could be used with this device + if (_desired_sample_rate != 0) { + std::vector::iterator sr_iter = std::find (sample_rates.begin(), sample_rates.end(), (float)_desired_sample_rate); + + if (sr_iter != sample_rates.end() ) { + _current_state->sample_rate = _desired_sample_rate; + } else { + _current_state->sample_rate = backend->default_sample_rate(); + } + + } else { + // check if current sample rate is supported because we have no session desired sample rate value + std::vector::iterator sr_iter = std::find (sample_rates.begin(), sample_rates.end(), (float)_current_state->sample_rate); + // switch to default if current sample rate is not supported + if (sr_iter == sample_rates.end() ) { + + _current_state->sample_rate = backend->default_sample_rate(); + } + } + + // validate buffer size + std::vector buffer_sizes = backend->available_buffer_sizes (_current_state->device_name); + // check if buffer size is supported + std::vector::iterator bs_iter = std::find (buffer_sizes.begin(), buffer_sizes.end(), _current_state->buffer_size); + // switch to default if not supported + if (bs_iter == buffer_sizes.end() ) { + _current_state->buffer_size = backend->default_buffer_size (); + } +} + + +const std::string& +EngineStateController::get_current_backend_name() const +{ + return _current_state->backend_name; +} + + +const std::string& +EngineStateController::get_current_device_name() const +{ + return _current_state->device_name; +} + + +void +EngineStateController::available_backends(std::vector& available_backends) +{ + available_backends = AudioEngine::instance()->available_backends(); +} + + +void +EngineStateController::enumerate_devices (std::vector& device_vector) const +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + device_vector = backend->enumerate_devices(); +} + + +framecnt_t +EngineStateController::get_current_sample_rate() const +{ + return _current_state->sample_rate; +} + + +framecnt_t +EngineStateController::get_default_sample_rate() const +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + return backend->default_sample_rate(); +} + + +void +EngineStateController::available_sample_rates_for_current_device(std::vector& sample_rates) const +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + sample_rates = backend->available_sample_rates (_current_state->device_name); +} + + +uint32_t +EngineStateController::get_current_buffer_size() const +{ + return _current_state->buffer_size; +} + + +uint32_t +EngineStateController::get_default_buffer_size() const +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + return backend->default_buffer_size(); +} + + +void +EngineStateController::available_buffer_sizes_for_current_device(std::vector& buffer_sizes) const +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + buffer_sizes = backend->available_buffer_sizes (_current_state->device_name); +} + + +bool +EngineStateController::set_new_backend_as_current(const std::string& backend_name) +{ + if (backend_name == AudioEngine::instance()->current_backend_name () ) { + return true; + } + + boost::shared_ptr backend = AudioEngine::instance()->set_backend (backend_name, "ardour", ""); + if (backend) + { + StateList::iterator found_state_iter = find_if (_states.begin(), _states.end(), + State::StatePredicate(backend_name, "None") ); + + if (found_state_iter != _states.end() ) { + // we found a record for new engine with None device - switch to it + _current_state = *found_state_iter; + + } else { + // create new record for this engine with default device + _current_state = boost::shared_ptr(new State() ); + _current_state->backend_name = backend_name; + _current_state->device_name = "None"; + _validate_current_device_state(); + _states.push_front(_current_state); + } + + + return true; + } + + return false; +} + + +bool +EngineStateController::set_new_current_device_in_controller(const std::string& device_name) +{ + if (_current_state->device_name == device_name) { + return true; + } + + _last_used_real_device.clear(); + + if (device_name != "None") { + _last_used_real_device = device_name; + } + + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + std::vector device_vector = backend->enumerate_devices(); + + // validate the device + std::vector::iterator device_iter; + device_iter = std::find_if (device_vector.begin(), device_vector.end(), DevicePredicate(device_name) ); + + // device is available + if (device_iter != device_vector.end() ) { + + // look through state list and find the record for this device and current engine + StateList::iterator found_state_iter = find_if (_states.begin(), _states.end(), + State::StatePredicate(backend->name(), device_name) ); + + if (found_state_iter != _states.end() ) + { + // we found a record for current engine and provided device name - switch to it + _current_state = *found_state_iter; + _validate_current_device_state(); + + } else { + + // the record is not found, create new one + _current_state = boost::shared_ptr(new State() ); + + _current_state->backend_name = backend->name(); + _current_state->device_name = device_name; + _validate_current_device_state(); + _states.push_front(_current_state); + } + + return true; + } + + // device is not supported by current backend + return false; +} + + + +bool +EngineStateController::set_new_sample_rate_in_controller(framecnt_t sample_rate) +{ + if (_current_state->sample_rate == sample_rate) { + return true; + } + + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + std::vector sample_rates = backend->available_sample_rates (_current_state->device_name); + std::vector::iterator iter = std::find (sample_rates.begin(), sample_rates.end(), (float)sample_rate); + + if (iter != sample_rates.end() ) { + _current_state->sample_rate = sample_rate; + return true; + } + + return false; +} + + + + +bool +EngineStateController::set_new_buffer_size_in_controller(pframes_t buffer_size) +{ + if (_current_state->buffer_size == buffer_size) { + return true; + } + + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + std::vector buffer_sizes = backend->available_buffer_sizes (_current_state->device_name); + std::vector::iterator iter = std::find (buffer_sizes.begin(), buffer_sizes.end(), buffer_size); + + if (iter != buffer_sizes.end() ) { + _current_state->buffer_size = buffer_size; + return true; + } + + return false; +} + + +void +EngineStateController::_on_sample_rate_change(framecnt_t new_sample_rate) +{ + set_new_sample_rate_in_controller(new_sample_rate); + + SampleRateChanged(new_sample_rate); // emit a signal +} + + +void +EngineStateController::_on_buffer_size_change(pframes_t new_buffer_size) +{ + set_new_buffer_size_in_controller(new_buffer_size); + + BufferSizeChanged(new_buffer_size); // emit a signal +} + + +void +EngineStateController::_on_device_list_change() +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + assert(backend); + + std::vector device_vector = backend->enumerate_devices(); + + // find out out if current device is still available if it's not None + if (_current_state->device_name != "None") + { + std::vector::iterator device_iter; + device_iter = std::find_if (device_vector.begin(), device_vector.end(), DevicePredicate(_current_state->device_name) ); + + // if current device is not available any more - switch to None device + if (device_iter == device_vector.end() ) { + + StateList::iterator found_state_iter = find_if (_states.begin(), _states.end(), + State::StatePredicate(_current_state->backend_name, "None") ); + + if (found_state_iter != _states.end() ) { + // found the record - switch to it + _current_state = *found_state_iter; + } else { + // create new record for this engine with default device + _current_state = boost::shared_ptr(new State() ); + _current_state->backend_name = backend->name(); + _current_state->device_name = "None"; + _validate_current_device_state(); + _states.push_front(_current_state); + } + + push_current_state_to_backend(false); + } + } else { + // if the device which was active before is available now - switch to it + + std::vector::iterator device_iter; + device_iter = std::find_if (device_vector.begin(), device_vector.end(), DevicePredicate(_last_used_real_device) ); + + if (device_iter != device_vector.end() ) { + StateList::iterator found_state_iter = find_if (_states.begin(), _states.end(), + State::StatePredicate(_current_state->backend_name, + _last_used_real_device) ); + + if (found_state_iter != _states.end() ) { + _current_state = *found_state_iter; + _validate_current_device_state(); + + push_current_state_to_backend(false); + } + } + + } + + DeviceListChanged(); // emit a signal +} + + +void +EngineStateController::_on_engine_running () +{ +} + + +void +EngineStateController::_on_engine_stopped () +{ +} + +bool +EngineStateController::push_current_state_to_backend(bool start) +{ + boost::shared_ptr backend = AudioEngine::instance()->current_backend(); + + if (!backend) { + return false; + } + + // check if anything changed + bool state_changed = (_current_state->device_name != backend->device_name() ) || + (_current_state->sample_rate != backend->sample_rate() ) || + (_current_state->buffer_size != backend->buffer_size() ); + + bool was_running = AudioEngine::instance()->running(); + + if (state_changed) { + + if (was_running) { + if (ARDOUR_UI::instance()->disconnect_from_engine () ) { + return false; + } + } + + if ((_current_state->device_name != backend->device_name()) && backend->set_device_name (_current_state->device_name)) { + error << string_compose (_("Cannot set device name to %1"), get_current_device_name()) << endmsg; + } + + if (backend->set_sample_rate (_current_state->sample_rate )) { + error << string_compose (_("Cannot set sample rate to %1"), get_current_sample_rate()) << endmsg; + } + + if (backend->set_buffer_size (_current_state->buffer_size )) { + error << string_compose (_("Cannot set buffer size to %1"), get_current_buffer_size()) << endmsg; + } + + //if (backend->set_input_channels (get_input_channels())) { + // error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg; + // return -1; + //} + + //if (backend->set_output_channels (get_output_channels())) { + // error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg; + // return -1; + //} + + //if (backend->set_systemic_input_latency (get_input_latency())) { + // error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg; + // return -1; + //} + + //if (backend->set_systemic_output_latency (get_output_latency())) { + // error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg; + // return -1; + //} + } + + _serialize_and_save_current_state(); + + if(start || (was_running && state_changed) ) { + if (ARDOUR_UI::instance()->reconnect_to_engine () ) { + return false; + } + } + + return true; +} + + +void +EngineStateController::set_desired_sample_rate(framecnt_t session_desired_sr) +{ + if (session_desired_sr == 0 || session_desired_sr == _desired_sample_rate) { + return; + } + + _desired_sample_rate = session_desired_sr; + _validate_current_device_state(); + + // if we swithced to new desired sample rate successfuly - push the new state to the backend + if (_current_state->sample_rate == session_desired_sr) { + push_current_state_to_backend(false); + } +} + diff --git a/gtk2_ardour/engine_state_controller.h b/gtk2_ardour/engine_state_controller.h new file mode 100644 index 0000000000..c65ffd0107 --- /dev/null +++ b/gtk2_ardour/engine_state_controller.h @@ -0,0 +1,172 @@ +// +// engine_state_controller.h +// Tracks +// +// Created by Grygorii Zharun on 4/30/14. +// Copyright (c) 2014 Waves. All rights reserved. +// + +#ifndef __gtk2_ardour__engine_state_controller__ +#define __gtk2_ardour__engine_state_controller__ + +#include + +#include "ardour/types.h" +#include "ardour/audio_backend.h" + +namespace ARDOUR { + +class AudioBackendInfo; + +class EngineStateController +{ +public: + static EngineStateController* instance(); + + //Interfaces + void available_backends(std::vector&); + + const std::string& get_current_backend_name() const; + + const std::string& get_current_device_name() const; + void change_current_device_to(const std::string&) const; + void enumerate_devices (std::vector&) const; + + ARDOUR::framecnt_t get_current_sample_rate() const; + ARDOUR::framecnt_t get_default_sample_rate() const; + void available_sample_rates_for_current_device(std::vector&) const; + + ARDOUR::pframes_t get_current_buffer_size() const; + ARDOUR::pframes_t get_default_buffer_size() const; + void available_buffer_sizes_for_current_device(std::vector&) const; + + 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 + // NOTE: Use push_state_to_backend() method to update backend with the most recent controller state + bool set_new_current_device_in_controller(const std::string& device_name); + bool set_new_sample_rate_in_controller(framecnt_t); + bool set_new_buffer_size_in_controller(pframes_t); + + + // push current controller state to backend + bool push_current_state_to_backend(bool); + // switch engine to new backend + bool set_new_backend_as_current(const std::string&); + // switch backend to session sample rate + void set_desired_sample_rate(framecnt_t); + + + //SIGNALS + /* this signal is emitted if the sample rate changes */ + PBD::Signal1 SampleRateChanged; + + /* this signal is emitted if the buffer size changes */ + PBD::Signal1 BufferSizeChanged; + + /* this signal is emitted if the device list changes */ + PBD::Signal0 DeviceListChanged; + +private: + + EngineStateController(); // singleton + ~EngineStateController(); // singleton + EngineStateController(const EngineStateController& ); // prohibited + EngineStateController& operator=(const EngineStateController&); // prohibited + + // data types: + struct State { + std::string backend_name; + std::string device_name; + ARDOUR::framecnt_t sample_rate; + ARDOUR::pframes_t buffer_size; + uint32_t input_latency; + uint32_t output_latency; + uint32_t input_channels; + uint32_t output_channels; + bool active; + std::string midi_option; + + State() + : input_latency (0) + , output_latency (0) + , input_channels (0) + , output_channels (0) + , active (false) + { + } + + bool operator==(const State& rhs) + { + return (backend_name == rhs.backend_name) && (device_name == rhs.device_name); + } + + // predicates for search + struct StatePredicate + { + StatePredicate(const std::string& backend_name, const std::string& device_name) + : _backend_name (backend_name) + , _device_name (device_name) + {} + + bool operator()(boost::shared_ptr rhs) + { + return (_backend_name == rhs->backend_name) && (_device_name == rhs->device_name); + } + + private: + std::string _backend_name; + std::string _device_name; + }; + }; + + typedef boost::shared_ptr StatePtr; + typedef std::list StateList; + + // state control methods//////////////// + void _deserialize_and_load_states(); + void _serialize_and_save_current_state(); + // sets last active state as current state + // if no last active state found it loads default state + void _set_last_active_state_as_current(); + //////////////////////////////////////// + + // internal helper functions//////////// + // make sure that current device parameters are supported and fit session requirements + void _validate_current_device_state(); + //////////////////////////////////////// + + //////////////////////////////////////// + // callbacks + void _on_engine_running(); + void _on_engine_halted(const char*); + 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(); + //////////////////////////////////////// + + //////////////////////////////////////// + // attributes + StatePtr _current_state; + // list of system states + StateList _states; + + // last active non-default (real) device + std::string _last_used_real_device; + + ARDOUR::framecnt_t _desired_sample_rate; + bool _have_control; + + // Engine connections stuff + PBD::ScopedConnectionList update_connections; + PBD::ScopedConnection running_connection; + PBD::ScopedConnection halt_connection; + PBD::ScopedConnection stopped_connection; + +}; + +} // namespace ARDOUR + +#endif /* defined(__gtk2_ardour__engine_state_controller__) */ diff --git a/gtk2_ardour/session_dialog.logic.cc b/gtk2_ardour/session_dialog.logic.cc index 96bbcd8da8..86b441045e 100644 --- a/gtk2_ardour/session_dialog.logic.cc +++ b/gtk2_ardour/session_dialog.logic.cc @@ -28,6 +28,8 @@ #include +#include "engine_state_controller.h" + #include "pbd/failed_constructor.h" #include "pbd/file_utils.h" #include "pbd/replace_all.h" @@ -213,15 +215,11 @@ SessionDialog::on_new_session (WavesButton*) void SessionDialog::redisplay_system_configuration () { - // Temp solution: - TracksControlPanel* panel = dynamic_cast(_system_configuration_dialog.get(false)); - if (panel) { - _session_details_label.set_text(string_compose (_("%1\n\n\n\n%2"), - panel->get_device_name(), - panel->get_sample_rate())); - } else { - _session_details_label.set_text(""); - } + ARDOUR::EngineStateController* eng_controller (ARDOUR::EngineStateController::instance() ); + + _session_details_label.set_text(string_compose (_("%1\n\n\n\n%2"), + eng_controller->get_current_device_name(), + eng_controller->get_current_sample_rate())); } int diff --git a/gtk2_ardour/tracks_control_panel.cc b/gtk2_ardour/tracks_control_panel.cc index cd77822959..8404b07bc1 100644 --- a/gtk2_ardour/tracks_control_panel.cc +++ b/gtk2_ardour/tracks_control_panel.cc @@ -53,7 +53,6 @@ //#include "utils.h" #include "i18n.h" -using namespace std; using namespace Gtk; using namespace Gtkmm2ext; using namespace PBD; diff --git a/gtk2_ardour/tracks_control_panel.h b/gtk2_ardour/tracks_control_panel.h index bc04668166..c144418a7a 100644 --- a/gtk2_ardour/tracks_control_panel.h +++ b/gtk2_ardour/tracks_control_panel.h @@ -24,6 +24,8 @@ #include #include +#include "ardour/types.h" + #include #include "pbd/signals.h" diff --git a/gtk2_ardour/tracks_control_panel.logic.cc b/gtk2_ardour/tracks_control_panel.logic.cc index 76e1582eab..11d128247d 100644 --- a/gtk2_ardour/tracks_control_panel.logic.cc +++ b/gtk2_ardour/tracks_control_panel.logic.cc @@ -23,8 +23,7 @@ #include -#include "ardour/audio_backend.h" -#include "ardour/audioengine.h" +#include "engine_state_controller.h" #include "ardour/rc_configuration.h" #include "device_connection_control.h" #include "ardour_ui.h" @@ -33,7 +32,7 @@ #include "i18n.h" #include "pbd/convert.h" -using namespace std; +using namespace ARDOUR; using namespace Gtk; using namespace Gtkmm2ext; using namespace PBD; @@ -56,13 +55,14 @@ TracksControlPanel::init () _multi_out_button.signal_clicked.connect(sigc::mem_fun (*this, &TracksControlPanel::on_multi_out)); _stereo_out_button.signal_clicked.connect(sigc::mem_fun (*this, &TracksControlPanel::on_stereo_out)); - ARDOUR::AudioEngine::instance ()->Running.connect (running_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_running, this), gui_context()); - ARDOUR::AudioEngine::instance ()->Stopped.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_stopped, this), gui_context()); - ARDOUR::AudioEngine::instance ()->Halted.connect (stopped_connection, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::engine_stopped, this), gui_context()); + + 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()); /* Subscribe for udpates from AudioEngine */ - ARDOUR::AudioEngine::instance()->BufferSizeChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::update_current_buffer_size, this, _1), gui_context()); - ARDOUR::AudioEngine::instance()->DeviceListChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::update_device_list, this), gui_context()); + EngineStateController::instance()->BufferSizeChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::populate_buffer_size_combo, this), gui_context()); + EngineStateController::instance()->DeviceListChanged.connect (update_connections, MISSING_INVALIDATOR, boost::bind (&TracksControlPanel::populate_device_combo, this), gui_context()); _engine_combo.signal_changed().connect (sigc::mem_fun (*this, &TracksControlPanel::engine_changed)); _device_combo.signal_changed().connect (sigc::mem_fun (*this, &TracksControlPanel::device_changed)); @@ -70,9 +70,9 @@ TracksControlPanel::init () _buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &TracksControlPanel::buffer_size_changed)); populate_engine_combo (); + populate_output_mode(); + _audio_settings_tab_button.set_active(true); - _multi_out_button.set_active(ARDOUR::Config->get_output_auto_connect() & ARDOUR::AutoConnectPhysical); - _stereo_out_button.set_active(ARDOUR::Config->get_output_auto_connect() & ARDOUR::AutoConnectMaster); } DeviceConnectionControl& TracksControlPanel::add_device_capture_control(std::string device_capture_name, bool active, uint16_t capture_number, std::string track_name) @@ -115,14 +115,15 @@ TracksControlPanel::populate_engine_combo() } std::vector strings; - vector backends = ARDOUR::AudioEngine::instance()->available_backends(); + std::vector backends; + EngineStateController::instance()->available_backends(backends); if (backends.empty()) { MessageDialog msg (string_compose (_("No audio/MIDI backends detected. %1 cannot run\n\n(This is a build/packaging/system error. It should never happen.)"), PROGRAM_NAME)); msg.run (); throw failed_constructor (); } - for (vector::const_iterator b = backends.begin(); b != backends.end(); ++b) { + for (std::vector::const_iterator b = backends.begin(); b != backends.end(); ++b) { strings.push_back ((*b)->name); } @@ -135,20 +136,19 @@ TracksControlPanel::populate_engine_combo() if (!strings.empty() ) { - _engine_combo.set_active_text (strings.front()); + _engine_combo.set_active_text (EngineStateController::instance()->get_current_backend_name() ); } } void TracksControlPanel::populate_device_combo() { - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - assert (backend); + std::vector all_devices; + EngineStateController::instance()->enumerate_devices (all_devices); - vector all_devices = backend->enumerate_devices (); - vector available_devices; + std::vector available_devices; - for (vector::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) { + for (std::vector::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) { available_devices.push_back (i->name); } @@ -160,7 +160,7 @@ TracksControlPanel::populate_device_combo() } if(!available_devices.empty() ) { - _device_combo.set_active_text (available_devices.front() ); + _device_combo.set_active_text (EngineStateController::instance()->get_current_device_name() ); } } @@ -168,14 +168,11 @@ TracksControlPanel::populate_device_combo() void TracksControlPanel::populate_sample_rate_combo() { - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - assert (backend); - std::string device_name = _device_combo.get_active_text (); + std::vector sample_rates; + EngineStateController::instance()->available_sample_rates_for_current_device(sample_rates); + std::vector s; - vector sr; - - sr = backend->available_sample_rates (device_name); - for (vector::const_iterator x = sr.begin(); x != sr.end(); ++x) { + for (std::vector::const_iterator x = sample_rates.begin(); x != sample_rates.end(); ++x) { s.push_back (rate_as_string (*x)); } @@ -187,12 +184,8 @@ TracksControlPanel::populate_sample_rate_combo() } if (!s.empty() ) { - std::string active_sr = rate_as_string((_desired_sample_rate != 0) ? - _desired_sample_rate : - backend->default_sample_rate()); - if (std::find(s.begin(), s.end(), active_sr) == s.end()) { - active_sr = s.front(); - } + std::string active_sr = rate_as_string(EngineStateController::instance()->get_current_sample_rate() ); + _sample_rate_combo.set_active_text(active_sr); } } @@ -200,14 +193,11 @@ TracksControlPanel::populate_sample_rate_combo() void TracksControlPanel::populate_buffer_size_combo() { - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - assert (backend); - std::string device_name = _device_combo.get_active_text (); - std::vector s; - std::vector bs; + std::vector s; + std::vector buffer_sizes; - bs = backend->available_buffer_sizes(device_name); - for (std::vector::const_iterator x = bs.begin(); x != bs.end(); ++x) { + EngineStateController::instance()->available_buffer_sizes_for_current_device(buffer_sizes); + for (std::vector::const_iterator x = buffer_sizes.begin(); x != buffer_sizes.end(); ++x) { s.push_back (bufsize_as_string (*x)); } @@ -219,20 +209,25 @@ TracksControlPanel::populate_buffer_size_combo() } if (!s.empty() ) { - std::string active_bs = bufsize_as_string(backend->default_buffer_size()); - if (std::find(s.begin(), s.end(), active_bs) == s.end() ) { - active_bs = s.front(); - } + std::string active_bs = bufsize_as_string(EngineStateController::instance()->get_current_buffer_size()); _buffer_size_combo.set_active_text(active_bs); } } +void +TracksControlPanel::populate_output_mode() +{ + _multi_out_button.set_active(Config->get_output_auto_connect() & AutoConnectPhysical); + _stereo_out_button.set_active(Config->get_output_auto_connect() & AutoConnectMaster); +} + 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; @@ -249,6 +244,7 @@ TracksControlPanel::on_control_panel(WavesButton*) add_midi_capture_control (name, active); add_midi_playback_control (active); +*/ } void TracksControlPanel::engine_changed () @@ -257,17 +253,16 @@ void TracksControlPanel::engine_changed () return; } - string backend_name = _engine_combo.get_active_text(); - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""); - if (!backend) + std::string backend_name = _engine_combo.get_active_text(); + + if ( EngineStateController::instance()->set_new_backend_as_current (backend_name) ) { - std::cerr << "\tfailed to set backend [" << backend_name << "]\n"; - return; + _have_control = EngineStateController::instance()->is_setup_required (); + populate_device_combo(); + return; } - - _have_control = ARDOUR::AudioEngine::instance()->setup_required (); - - populate_device_combo(); + + std::cerr << "\tfailed to set backend [" << backend_name << "]\n"; } void TracksControlPanel::device_changed () @@ -275,14 +270,23 @@ void TracksControlPanel::device_changed () if (_ignore_changes) { return; } - - std::string newDevice = _device_combo.get_active_text(); - if (newDevice != "None") { - _current_device = newDevice; + + std::string device_name = _device_combo.get_active_text (); + if (EngineStateController::instance()->set_new_current_device_in_controller(device_name) ) + { + populate_buffer_size_combo(); + populate_sample_rate_combo(); + return; } - populate_buffer_size_combo(); - populate_sample_rate_combo(); + { + // set _ignore_changes flag to ignore changes in combo-box callbacks + PBD::Unwinder protect_ignore_changes (_ignore_changes, _ignore_changes + 1); + // restore previous device name in combo box + _device_combo.set_active_text (EngineStateController::instance()->get_current_device_name() ); + } + + MessageDialog( _("Selected device is not available for current engine"), PROGRAM_NAME).run(); } void @@ -292,7 +296,22 @@ TracksControlPanel::buffer_size_changed() return; } - show_buffer_duration(); + pframes_t new_buffer_size = get_buffer_size(); + if (EngineStateController::instance()->set_new_buffer_size_in_controller(new_buffer_size) ) + { + show_buffer_duration(); + return; + } + + { + // set _ignore_changes flag to ignore changes in combo-box callbacks + PBD::Unwinder protect_ignore_changes (_ignore_changes, _ignore_changes + 1); + // restore previous buffer size value in combo box + std::string buffer_size_str = bufsize_as_string (EngineStateController::instance()->get_current_buffer_size() ); + _buffer_size_combo.set_active_text(buffer_size_str); + } + + MessageDialog( _("Buffer size set to the value which is not supported"), PROGRAM_NAME).run(); } void @@ -302,129 +321,31 @@ TracksControlPanel::sample_rate_changed() return; } - show_buffer_duration(); -} - -void -TracksControlPanel::update_current_buffer_size (uint32_t new_buffer_size) -{ - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - assert (backend); - - std::string new_buffer_size_str = bufsize_as_string(new_buffer_size); - - /* check if new buffer size value is no the same as already set in combobox */ - if ( new_buffer_size_str != _buffer_size_combo.get_active_text() ) { - vector s; - vector bs; - std::string device_name = _device_combo.get_active_text (); - bs = backend->available_buffer_sizes(device_name); - - for (vector::const_iterator x = bs.begin(); x != bs.end(); ++x) { - s.push_back (bufsize_as_string (*x) ); - } - - { - // set _ignore_changes flag to ignore changes in combo-box callbacks - PBD::Unwinder protect_ignore_changes (_ignore_changes, _ignore_changes + 1); - set_popdown_strings (_buffer_size_combo, s); - _buffer_size_combo.set_sensitive (s.size() > 1); - } - - if (!s.empty() ) { - if (std::find(s.begin(), s.end(), new_buffer_size_str) == s.end() ) { - _buffer_size_combo.set_active_text (new_buffer_size_str ); - } else { - MessageDialog( _("Buffer size changed to the value which is not supported"), PROGRAM_NAME).run(); - } - } + framecnt_t new_sample_rate = get_sample_rate (); + if (EngineStateController::instance()->set_new_sample_rate_in_controller(new_sample_rate) ) + { + show_buffer_duration(); + return; } -} - - -void -TracksControlPanel::update_device_list () -{ - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - assert (backend); - - /* now fill out devices, mark sample rates, buffer sizes insensitive */ - - vector all_devices = backend->enumerate_devices (); - - vector available_devices; - - for (vector::const_iterator i = all_devices.begin(); i != all_devices.end(); ++i) { - available_devices.push_back (i->name); - } - - if (!available_devices.empty()) { - - /* Now get current device name */ - std::string current_active_device = _device_combo.get_active_text (); - - /* If previous device is available again we should switch to it from "None" */ - std::string newDevice; - if (current_active_device == "None" && !_current_device.empty() ){ - newDevice = _current_device; - } else { - newDevice = current_active_device; - } - - bool deviceFound(false); - { - // set _ignore_changes flag to ignore changes in combo-box callbacks - PBD::Unwinder protect_ignore_changes (_ignore_changes, _ignore_changes + 1); - set_popdown_strings (_device_combo, available_devices); - _device_combo.set_sensitive (available_devices.size() > 1); - - for (vector::const_iterator i = available_devices.begin(); i != available_devices.end(); ++i) { - if (newDevice == *i) { - deviceFound = true; - break; - } - } - } - - if (deviceFound) { - switch_to_device(newDevice); - - } else if (current_active_device != "None") { - switch_to_device("None"); - MessageDialog( _("Current device is not available! Switched to NONE device."), PROGRAM_NAME).run(); - } - } -} - - -void -TracksControlPanel::switch_to_device(const std::string& device_name) -{ - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); { - // set _ignore_changes flag to ignore changes in combo-box callbacks - PBD::Unwinder protect_ignore_changes (_ignore_changes, _ignore_changes + 1); - _device_combo.set_active_text(device_name); - } - - if (backend->device_name() != device_name) { - - // push state to backend, but do not start unless it was running - push_state_to_backend (false); + // set _ignore_changes flag to ignore changes in combo-box callbacks + PBD::Unwinder protect_ignore_changes (_ignore_changes, _ignore_changes + 1); + // restore previous buffer size value in combo box + std::string sample_rate_str = rate_as_string (EngineStateController::instance()->get_current_sample_rate() ); + _sample_rate_combo.set_active_text(sample_rate_str); } + + MessageDialog( _("Sample rate set to the value which is not supported"), PROGRAM_NAME).run(); } void TracksControlPanel::engine_running () { - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - assert (backend); + _buffer_size_combo.set_active_text (bufsize_as_string (EngineStateController::instance()->get_current_buffer_size() ) ); - _buffer_size_combo.set_active_text (bufsize_as_string (backend->buffer_size())); - - _sample_rate_combo.set_active_text (rate_as_string (backend->sample_rate())); + _sample_rate_combo.set_active_text (rate_as_string (EngineStateController::instance()->get_current_sample_rate() ) ); _buffer_size_combo.set_sensitive (true); _sample_rate_combo.set_sensitive (true); @@ -476,11 +397,11 @@ TracksControlPanel::on_session_settings (WavesButton*) void TracksControlPanel::on_multi_out (WavesButton*) { - if (ARDOUR::Config->get_output_auto_connect() & ARDOUR::AutoConnectPhysical) { + if (Config->get_output_auto_connect() & AutoConnectPhysical) { return; } - ARDOUR::Config->set_output_auto_connect(ARDOUR::AutoConnectPhysical); + Config->set_output_auto_connect(AutoConnectPhysical); _stereo_out_button.set_active(false); _multi_out_button.set_active(true); } @@ -490,11 +411,11 @@ void TracksControlPanel::on_stereo_out (WavesButton*) { - if (ARDOUR::Config->get_output_auto_connect() & ARDOUR::AutoConnectMaster) { + if (Config->get_output_auto_connect() & AutoConnectMaster) { return; } - ARDOUR::Config->set_output_auto_connect(ARDOUR::AutoConnectMaster); + Config->set_output_auto_connect(AutoConnectMaster); _multi_out_button.set_active(false); _stereo_out_button.set_active(true); } @@ -503,7 +424,7 @@ void TracksControlPanel::on_ok (WavesButton*) { hide(); - push_state_to_backend (true); + EngineStateController::instance()->push_current_state_to_backend(true); response(Gtk::RESPONSE_OK); } @@ -519,7 +440,7 @@ TracksControlPanel::on_cancel (WavesButton*) void TracksControlPanel::on_apply (WavesButton*) { - push_state_to_backend (true); + EngineStateController::instance()->push_current_state_to_backend(true); response(Gtk::RESPONSE_APPLY); } @@ -563,62 +484,8 @@ TracksControlPanel::bufsize_as_string (uint32_t sz) return buf; } -void -TracksControlPanel::set_desired_sample_rate (uint32_t sr) - { - _desired_sample_rate = sr; - std::string active_sr = rate_as_string(_desired_sample_rate); - std::string prev_selected = _sample_rate_combo.get_active_text(); - _sample_rate_combo.set_active_text(active_sr); - active_sr = _sample_rate_combo.get_active_text(); - if (active_sr.empty()) { - _sample_rate_combo.set_active_text(prev_selected); - } - } -XMLNode& -TracksControlPanel::get_state () -{ - return *new XMLNode ("TracksPreferences");// !!!!!!!!!!!!!!! - /* - XMLNode* root = new XMLNode ("TracksPreferences"); - std::string path; - - if (!states.empty()) { - XMLNode* state_nodes = new XMLNode ("EngineStates"); - - for (StateList::const_iterator i = states.begin(); i != states.end(); ++i) { - - XMLNode* node = new XMLNode ("State"); - - node->add_property ("backend", (*i).backend); - node->add_property ("driver", (*i).driver); - node->add_property ("device", (*i).device); - node->add_property ("sample-rate", (*i).sample_rate); - node->add_property ("buffer-size", (*i).buffer_size); - node->add_property ("input-latency", (*i).input_latency); - node->add_property ("output-latency", (*i).output_latency); - node->add_property ("input-channels", (*i).input_channels); - node->add_property ("output-channels", (*i).output_channels); - node->add_property ("active", (*i).active ? "yes" : "no"); - node->add_property ("midi-option", (*i).midi_option); - - state_nodes->add_child_nocopy (*node); - } - - root->add_child_nocopy (*state_nodes); - } - - return *root; - */ -} - -void -TracksControlPanel::set_state (const XMLNode& root) -{ -} - -float +framecnt_t TracksControlPanel::get_sample_rate () const { float r = atof (_sample_rate_combo.get_active_text ()); @@ -631,10 +498,10 @@ TracksControlPanel::get_sample_rate () const return r; } -uint32_t TracksControlPanel::get_buffer_size() const +pframes_t TracksControlPanel::get_buffer_size() const { - string bs_text = _buffer_size_combo.get_active_text (); - uint32_t samples = atoi (bs_text); /* will ignore trailing text */ + std::string bs_text = _buffer_size_combo.get_active_text (); + pframes_t samples = atoi (bs_text); /* will ignore trailing text */ return samples; } @@ -648,63 +515,3 @@ TracksControlPanel::show_buffer_duration () latency, latency, 2*latency); _latency_label.set_text (buf); } - -int -TracksControlPanel::push_state_to_backend (bool start) -{ - boost::shared_ptr backend = ARDOUR::AudioEngine::instance()->current_backend(); - - if (!backend) { - return 0; - } - - bool was_running = ARDOUR::AudioEngine::instance()->running(); - if (was_running) { - if (ARDOUR_UI::instance()->disconnect_from_engine ()) { - return -1; - } - } - - if ((get_device_name() != backend->device_name()) && backend->set_device_name (get_device_name())) { - error << string_compose (_("Cannot set device name to %1"), get_device_name()) << endmsg; - return -1; - } - - if (backend->set_sample_rate (get_sample_rate())) { - error << string_compose (_("Cannot set sample rate to %1"), get_sample_rate()) << endmsg; - return -1; - } - - if (backend->set_buffer_size (get_buffer_size())) { - error << string_compose (_("Cannot set buffer size to %1"), get_buffer_size()) << endmsg; - return -1; - } - - //if (backend->set_input_channels (get_input_channels())) { - // error << string_compose (_("Cannot set input channels to %1"), get_input_channels()) << endmsg; - // return -1; - //} - - //if (backend->set_output_channels (get_output_channels())) { - // error << string_compose (_("Cannot set output channels to %1"), get_output_channels()) << endmsg; - // return -1; - //} - - //if (backend->set_systemic_input_latency (get_input_latency())) { - // error << string_compose (_("Cannot set input latency to %1"), get_input_latency()) << endmsg; - // return -1; - //} - - //if (backend->set_systemic_output_latency (get_output_latency())) { - // error << string_compose (_("Cannot set output latency to %1"), get_output_latency()) << endmsg; - // return -1; - //} - - if(start || was_running) - { - //dbg_msg("ARDOUR_UI::instance()->reconnect_to_engine ()"); - ARDOUR_UI::instance()->reconnect_to_engine (); - //dbg_msg("Done"); - } - return 0; -} diff --git a/gtk2_ardour/tracks_control_panel.logic.h b/gtk2_ardour/tracks_control_panel.logic.h index 2333be96d6..fba56cd922 100644 --- a/gtk2_ardour/tracks_control_panel.logic.h +++ b/gtk2_ardour/tracks_control_panel.logic.h @@ -16,17 +16,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + // class TracksControlPanel : public WavesDialog { public: - void set_desired_sample_rate (uint32_t sr); - XMLNode& get_state (); - - void update_current_buffer_size (uint32_t new_buffer_size); - void update_device_list (); - void switch_to_device(const std::string& device_name); - - float get_sample_rate() const; - std::string get_device_name() const { return _device_combo.get_active_text (); }; private: // data types: @@ -101,16 +93,17 @@ void populate_device_combo (); void populate_sample_rate_combo (); void populate_buffer_size_combo (); + void populate_output_mode (); std::string bufsize_as_string (uint32_t sz); - void set_state (const XMLNode&); - int push_state_to_backend (bool start); - uint32_t get_buffer_size () const; - uint32_t get_input_channels () const { return 0; }; - uint32_t get_output_channels () const { return 0; }; - uint32_t get_input_latency () const { return 0; }; - uint32_t get_output_latency () const { return 0; }; + std::string get_device_name() const { return _device_combo.get_active_text (); }; + ARDOUR::framecnt_t get_sample_rate() const; + ARDOUR::pframes_t get_buffer_size () const; + uint32_t get_input_channels () const { return 0; }; + uint32_t get_output_channels () const { return 0; }; + uint32_t get_input_latency () const { return 0; }; + uint32_t get_output_latency () const { return 0; }; void show_buffer_duration (); //}; diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 35c99fbb25..5d209d8ce1 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -94,6 +94,7 @@ 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',