From 9ac6bb9befa047a6c349bed02d40da84600b67cc Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 24 Jul 2013 19:29:45 -0400 Subject: part-way through getting the audioengine changes to compile --- libs/ardour/audioengine.cc | 706 +++++++++++++-------------------------------- 1 file changed, 205 insertions(+), 501 deletions(-) (limited to 'libs/ardour/audioengine.cc') diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 25a55b5aaf..1e43c590a0 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -25,11 +25,14 @@ #include #include +#include +#include +#include "pbd/epa.h" +#include "pbd/file_utils.h" #include "pbd/pthread_utils.h" #include "pbd/stacktrace.h" #include "pbd/unknown_type.h" -#include "pbd/epa.h" #include @@ -39,7 +42,9 @@ #include "midi++/manager.h" #include "ardour/audio_port.h" +#include "ardour/audio_backend.h" #include "ardour/audioengine.h" +#include "ardour/backend_search_path.h" #include "ardour/buffer.h" #include "ardour/cycle_timer.h" #include "ardour/internal_send.h" @@ -58,8 +63,9 @@ using namespace PBD; gint AudioEngine::m_meter_exit; AudioEngine* AudioEngine::_instance = 0; -AudioEngine::AudioEngine () - : session_remove_pending (false) +AudioEngine::AudioEngine (const std::string& bcn, const std::string& bsu) + : _backend (0) + , session_remove_pending (false) , session_removal_countdown (-1) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) @@ -70,14 +76,16 @@ AudioEngine::AudioEngine () , port_remove_in_progress (false) , m_meter_thread (0) , _main_thread (0) + , backend_client_name (bcn) + , backend_session_uuid (bsu) { g_atomic_int_set (&m_meter_exit, 0); - - Port::set_engine (this); } AudioEngine::~AudioEngine () { + drop_backend (); + config_connection.disconnect (); { @@ -88,18 +96,38 @@ AudioEngine::~AudioEngine () } AudioEngine* -AudioEngine::create () +AudioEngine::create (const std::string& bcn, const std::string& bsu) { if (_instance) { return _instance; } - return new AudioEngine; + return new AudioEngine (bcn, bsu); } -jack_client_t* -AudioEngine::jack() const +void +AudioEngine::drop_backend () { - return _jack; + if (_backend) { + _backend->stop (); + delete _backend; + _backend = 0; + } +} + +int +AudioEngine::set_backend (const std::string& name) +{ + BackendMap::iterator b = _backends.find (name); + + if (b == _backends.end()) { + return -1; + } + + drop_backend (); + + _backend = b->second; + + return 0; } void @@ -120,70 +148,6 @@ _thread_init_callback (void * /*arg*/) } -int -AudioEngine::start () -{ - GET_PRIVATE_JACK_POINTER_RET (_jack, -1); - - if (!_running) { - - if (!jack_port_type_get_buffer_size) { - warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg; - } - - if (_session) { - BootMessage (_("Connect session to engine")); - _session->set_frame_rate (jack_get_sample_rate (_priv_jack)); - } - - /* a proxy for whether jack_activate() will definitely call the buffer size - * callback. with older versions of JACK, this function symbol will be null. - * this is reliable, but not clean. - */ - - if (!jack_port_type_get_buffer_size) { - jack_bufsize_callback (jack_get_buffer_size (_priv_jack)); - } - - _processed_frames = 0; - last_monitor_check = 0; - - set_jack_callbacks (); - - if (jack_activate (_priv_jack) == 0) { - _running = true; - _has_run = true; - Running(); /* EMIT SIGNAL */ - } else { - // error << _("cannot activate JACK client") << endmsg; - } - } - - return _running ? 0 : -1; -} - -int -AudioEngine::stop (bool forever) -{ - GET_PRIVATE_JACK_POINTER_RET (_jack, -1); - - if (_priv_jack) { - if (forever) { - disconnect_from_jack (); - } else { - jack_deactivate (_priv_jack); - MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */ - Stopped(); /* EMIT SIGNAL */ - } - } - - if (forever) { - stop_metering_thread (); - } - - return _running ? -1 : 0; -} - void AudioEngine::split_cycle (pframes_t offset) @@ -208,7 +172,6 @@ AudioEngine::split_cycle (pframes_t offset) int AudioEngine::process_callback (pframes_t nframes) { - GET_PRIVATE_JACK_POINTER_RET(_jack,0); Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK); PT_TIMING_REF; @@ -436,7 +399,7 @@ AudioEngine::set_session (Session *s) start_metering_thread (); - pframes_t blocksize = jack_get_buffer_size (_jack); + pframes_t blocksize = _backend->get_buffer_size (); /* page in as much of the session process code as we can before we really start running. @@ -484,549 +447,290 @@ AudioEngine::remove_session () remove_all_ports (); } + void -AudioEngine::port_registration_failure (const std::string& portname) +AudioEngine::died () { - GET_PRIVATE_JACK_POINTER (_jack); - string full_portname = jack_client_name; - full_portname += ':'; - full_portname += portname; - - - jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str()); - string reason; + /* called from a signal handler for SIGPIPE */ - if (p) { - reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname); - } else { - reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME); - } + stop_metering_thread (); - throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str()); + _running = false; + _buffer_size = 0; + _frame_rate = 0; } -boost::shared_ptr -AudioEngine::register_port (DataType dtype, const string& portname, bool input) +int +AudioEngine::reset_timebase () { - boost::shared_ptr newport; - - try { - if (dtype == DataType::AUDIO) { - newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput))); - } else if (dtype == DataType::MIDI) { - newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput))); + if (_session) { + if (_session->config.get_jack_time_master()) { + _backend->set_time_master (true); } else { - throw PortRegistrationFailure("unable to create port (unknown type)"); + _backend->set_time_master (false); } - - RCUWriter writer (ports); - boost::shared_ptr ps = writer.get_copy (); - ps->insert (make_pair (make_port_name_relative (portname), newport)); - - /* writer goes out of scope, forces update */ - - return newport; - } - - catch (PortRegistrationFailure& err) { - throw err; - } catch (std::exception& e) { - throw PortRegistrationFailure(string_compose( - _("unable to create port: %1"), e.what()).c_str()); - } catch (...) { - throw PortRegistrationFailure("unable to create port (unknown error)"); } + return 0; } -boost::shared_ptr -AudioEngine::register_input_port (DataType type, const string& portname) -{ - return register_port (type, portname, true); -} -boost::shared_ptr -AudioEngine::register_output_port (DataType type, const string& portname) +void +AudioEngine::destroy () { - return register_port (type, portname, false); + delete _instance; + _instance = 0; } int -AudioEngine::unregister_port (boost::shared_ptr port) +AudioEngine::discover_backends () { - /* caller must hold process lock */ - - if (!_running) { - /* probably happening when the engine has been halted by JACK, - in which case, there is nothing we can do here. - */ - return 0; - } - - { - RCUWriter writer (ports); - boost::shared_ptr ps = writer.get_copy (); - Ports::iterator x = ps->find (make_port_name_relative (port->name())); + vector backend_modules; + AudioBackend* backend; - if (x != ps->end()) { - ps->erase (x); - } + _backends.clear (); - /* writer goes out of scope, forces update */ - } + Glib::PatternSpec so_extension_pattern("*.so"); + Glib::PatternSpec dylib_extension_pattern("*.dylib"); - ports.flush (); + find_matching_files_in_search_path (backend_search_path (), + so_extension_pattern, backend_modules); - return 0; -} + find_matching_files_in_search_path (backend_search_path (), + dylib_extension_pattern, backend_modules); -int -AudioEngine::connect (const string& source, const string& destination) -{ - int ret; + DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string())); - if (!_running) { - if (!_has_run) { - fatal << _("connect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; + for (vector::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) { + if ((backend = backend_discover (*i)) != 0) { + _backends.insert (make_pair (backend->name(), backend)); } } - string s = make_port_name_non_relative (source); - string d = make_port_name_non_relative (destination); - + return _backends.size(); +} - boost::shared_ptr src = get_port_by_name (s); - boost::shared_ptr dst = get_port_by_name (d); +AudioBackend* +AudioEngine::backend_discover (const string& path) +{ + Glib::Module* module = new Glib::Module(path); + AudioBackend* (*dfunc)(void); + void* func = 0; - if (src) { - ret = src->connect (d); - } else if (dst) { - ret = dst->connect (s); - } else { - /* neither port is known to us, and this API isn't intended for use as a general patch bay */ - ret = -1; + if (!module) { + error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path, + Glib::Module::get_last_error()) << endmsg; + delete module; + return 0; } - if (ret > 0) { - /* already exists - no error, no warning */ - } else if (ret < 0) { - error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"), - source, s, destination, d) - << endmsg; + if (!module->get_symbol("backend_factory", func)) { + error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg; + error << Glib::Module::get_last_error() << endmsg; + delete module; + return 0; } - return ret; + dfunc = (AudioBackend* (*)(void))func; + AudioBackend* backend = dfunc(); + + return backend; } +/* BACKEND PROXY WRAPPERS */ + int -AudioEngine::disconnect (const string& source, const string& destination) +AudioEngine::start () { - int ret; - - if (!_running) { - if (!_has_run) { - fatal << _("disconnect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; - } + if (!_backend) { + return -1; } - string s = make_port_name_non_relative (source); - string d = make_port_name_non_relative (destination); - - boost::shared_ptr src = get_port_by_name (s); - boost::shared_ptr dst = get_port_by_name (d); + if (!_running) { - if (src) { - ret = src->disconnect (d); - } else if (dst) { - ret = dst->disconnect (s); - } else { - /* neither port is known to us, and this API isn't intended for use as a general patch bay */ - ret = -1; - } - return ret; -} + if (_session) { + BootMessage (_("Connect session to engine")); + _session->set_frame_rate (_backend->sample_rate()); + } -int -AudioEngine::disconnect (boost::shared_ptr port) -{ - GET_PRIVATE_JACK_POINTER_RET (_jack,-1); + _processed_frames = 0; + last_monitor_check = 0; - if (!_running) { - if (!_has_run) { - fatal << _("disconnect called before engine was started") << endmsg; - /*NOTREACHED*/ + if (_backend->start() == 0) { + _running = true; + _has_run = true; + Running(); /* EMIT SIGNAL */ } else { - return -1; + /* should report error? */ } } - - return port->disconnect_all (); + + return _running ? 0 : -1; } -ARDOUR::framecnt_t -AudioEngine::frame_rate () const +int +AudioEngine::stop () { - GET_PRIVATE_JACK_POINTER_RET (_jack, 0); - if (_frame_rate == 0) { - return (_frame_rate = jack_get_sample_rate (_priv_jack)); - } else { - return _frame_rate; + if (!_backend) { + return 0; } + + return _backend->stop (); } -size_t -AudioEngine::raw_buffer_size (DataType t) -{ - std::map::const_iterator s = _raw_buffer_sizes.find(t); - return (s != _raw_buffer_sizes.end()) ? s->second : 0; -} - -ARDOUR::pframes_t -AudioEngine::frames_per_cycle () const +int +AudioEngine::pause () { - GET_PRIVATE_JACK_POINTER_RET (_jack,0); - if (_buffer_size == 0) { - return jack_get_buffer_size (_jack); - } else { - return _buffer_size; + if (!_backend) { + return 0; } + + return _backend->pause (); } -/** @param name Full or short name of port - * @return Corresponding Port or 0. - */ - -boost::shared_ptr -AudioEngine::get_port_by_name (const string& portname) +int +AudioEngine::freewheel (bool start_stop) { - if (!_running) { - if (!_has_run) { - fatal << _("get_port_by_name() called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - boost::shared_ptr (); - } + if (!_backend) { + return -1; } - if (!port_is_mine (portname)) { - /* not an ardour port */ - return boost::shared_ptr (); - } - - boost::shared_ptr pr = ports.reader(); - std::string rel = make_port_name_relative (portname); - Ports::iterator x = pr->find (rel); + /* _freewheeling will be set when first Freewheel signal occurs */ - if (x != pr->end()) { - /* its possible that the port was renamed by some 3rd party and - we don't know about it. check for this (the check is quick - and cheap), and if so, rename the port (which will alter - the port map as a side effect). - */ - const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port())); - if (check != rel) { - x->second->set_name (check); - } - return x->second; - } - - return boost::shared_ptr (); + return _backend->freewheel (start_stop); } -void -AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name) +float +AudioEngine::get_cpu_load() const { - RCUWriter writer (ports); - boost::shared_ptr p = writer.get_copy(); - Ports::iterator x = p->find (old_relative_name); - - if (x != p->end()) { - boost::shared_ptr port = x->second; - p->erase (x); - p->insert (make_pair (new_relative_name, port)); + if (!_backend) { + return 0.0; } + return _backend->get_cpu_load (); } -const char ** -AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags) +void +AudioEngine::transport_start () { - GET_PRIVATE_JACK_POINTER_RET (_jack,0); - if (!_running) { - if (!_has_run) { - fatal << _("get_ports called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return 0; - } + if (!_backend) { + return; } - return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags); + return _backend->transport_start (); } void -AudioEngine::died () -{ - /* called from a signal handler for SIGPIPE */ - - stop_metering_thread (); - - _running = false; - _buffer_size = 0; - _frame_rate = 0; - _jack = 0; -} - -bool -AudioEngine::can_request_hardware_monitoring () +AudioEngine::transport_stop () { - GET_PRIVATE_JACK_POINTER_RET (_jack,false); - const char ** ports; - - if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) { - return false; + if (!_backend) { + return; } - - free (ports); - - return true; + return _backend->transport_stop (); } -ChanCount -AudioEngine::n_physical (unsigned long flags) const +TransportState +AudioEngine::transport_state () { - ChanCount c; - - GET_PRIVATE_JACK_POINTER_RET (_jack, c); - - const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags); - if (ports == 0) { - return c; + if (!_backend) { + return TransportStopped; } - - for (uint32_t i = 0; ports[i]; ++i) { - if (!strstr (ports[i], "Midi-Through")) { - DataType t (jack_port_type (jack_port_by_name (_jack, ports[i]))); - c.set (t, c.get (t) + 1); - } - } - - free (ports); - - return c; -} - -ChanCount -AudioEngine::n_physical_inputs () const -{ - return n_physical (JackPortIsInput); -} - -ChanCount -AudioEngine::n_physical_outputs () const -{ - return n_physical (JackPortIsOutput); + return _backend->transport_state (); } void -AudioEngine::get_physical (DataType type, unsigned long flags, vector& phy) +AudioEngine::transport_locate (framepos_t pos) { - GET_PRIVATE_JACK_POINTER (_jack); - const char ** ports; - - if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) { + if (!_backend) { return; } + return _backend->transport_locate (pos); +} - if (ports) { - for (uint32_t i = 0; ports[i]; ++i) { - if (strstr (ports[i], "Midi-Through")) { - continue; - } - phy.push_back (ports[i]); - } - free (ports); +framepos_t +AudioEngine::transport_frame() +{ + if (!_backend) { + return 0; } + return _backend->transport_frame (); } -/** Get physical ports for which JackPortIsOutput is set; ie those that correspond to - * a physical input connector. - */ -void -AudioEngine::get_physical_inputs (DataType type, vector& ins) +framecnt_t +AudioEngine::sample_rate () const { - get_physical (type, JackPortIsOutput, ins); + if (!_backend) { + return 0; + } + return _backend->sample_rate (); } -/** Get physical ports for which JackPortIsInput is set; ie those that correspond to - * a physical output connector. - */ -void -AudioEngine::get_physical_outputs (DataType type, vector& outs) +pframes_t +AudioEngine::samples_per_cycle () const { - get_physical (type, JackPortIsInput, outs); + if (!_backend) { + return 0; + } + return _backend->samples_per_cycle (); } - int -AudioEngine::reset_timebase () +AudioEngine::usecs_per_cycle () const { - GET_PRIVATE_JACK_POINTER_RET (_jack, -1); - if (_session) { - if (_session->config.get_jack_time_master()) { - _backend->set_time_master (true); - } else { - _backend->set_time_master (false); - } + if (!_backend) { + return -1; } - return 0; + return _backend->start (); } -void -AudioEngine::remove_all_ports () +size_t +AudioEngine::raw_buffer_size (DataType t) { - /* make sure that JACK callbacks that will be invoked as we cleanup - * ports know that they have nothing to do. - */ - - port_remove_in_progress = true; - - /* process lock MUST be held by caller - */ - - { - RCUWriter writer (ports); - boost::shared_ptr ps = writer.get_copy (); - ps->clear (); + if (!_backend) { + return -1; } - - /* clear dead wood list in RCU */ - - ports.flush (); - - port_remove_in_progress = false; + return _backend->raw_buffer_size (t); } - -string -AudioEngine::make_port_name_relative (string portname) const +pframes_t +AudioEngine::sample_time () { - string::size_type len; - string::size_type n; - - len = portname.length(); - - for (n = 0; n < len; ++n) { - if (portname[n] == ':') { - break; - } - } - - if ((n != len) && (portname.substr (0, n) == jack_client_name)) { - return portname.substr (n+1); + if (!_backend) { + return 0; } - - return portname; + return _backend->sample_time (); } -string -AudioEngine::make_port_name_non_relative (string portname) const +pframes_t +AudioEngine::sample_time_at_cycle_start () { - string str; - - if (portname.find_first_of (':') != string::npos) { - return portname; + if (!_backend) { + return 0; } - - str = jack_client_name; - str += ':'; - str += portname; - - return str; + return _backend->sample_time_at_cycle_start (); } -bool -AudioEngine::port_is_mine (const string& portname) const +pframes_t +AudioEngine::samples_since_cycle_start () { - if (portname.find_first_of (':') != string::npos) { - if (portname.substr (0, jack_client_name.length ()) != jack_client_name) { - return false; - } - } - return true; + if (!_backend) { + return 0; + } + return _backend->samples_since_cycle_start (); } bool -AudioEngine::port_is_physical (const std::string& portname) const -{ - GET_PRIVATE_JACK_POINTER_RET(_jack, false); - - jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str()); - - if (!port) { - return false; - } - - return jack_port_flags (port) & JackPortIsPhysical; -} - -void -AudioEngine::destroy () +AudioEngine::get_sync_offset (pframes_t& offset) const { - delete _instance; - _instance = 0; + if (!_backend) { + return false; + } + return _backend->get_sync_offset (offset); } int -AudioEngine::discover_backends () +AudioEngine::create_process_thread (boost::function func, pthread_t* thr, size_t stacksize) { - vector backend_modules; - AudioBackend* backend; - - Glib::PatternSpec so_extension_pattern("*.so"); - Glib::PatternSpec dylib_extension_pattern("*.dylib"); - - find_matching_files_in_search_path (backend_search_path (), - so_extension_pattern, backend_modules); - - find_matching_files_in_search_path (backend_search_path (), - dylib_extension_pattern, backend_modules); - - DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string())); - - for (vector::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) { - if ((backend = backend_discover (*i)) != 0) { - _backends.insert (make_pair (backend->name(), backend)); - } + if (!_backend) { + return -1; } + return _backend->create_process_thread (func, thr, stacksize); } -AudioBackend* -AudioEngine::backend_discover (string path) -{ - Glib::Module* module = new Glib::Module(path); - AudioBackend* (*dfunc)(void); - void* func = 0; - - if (!module) { - error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path, - Glib::Module::get_last_error()) << endmsg; - delete module; - return 0; - } - - if (!module->get_symbol("backend_factory", func)) { - error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg; - error << Glib::Module::get_last_error() << endmsg; - delete module; - return 0; - } - - dfunc = (AudioBackend* (*)(void))func; - AudioBackend* backend = dfunc(); - - return backend; -} -- cgit v1.2.3