X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fport.cc;h=ec67e9c0af76e866eedb3ecdaf51de6dd57d2ba9;hb=db674ac8b676bb3412422bb784abd35ca9a19930;hp=bc5d26fb805431059246f5f29dd46c820ea125d0;hpb=0da34e65e3470b1c2298ddf571df6356d0d42bd8;p=ardour.git diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index bc5d26fb80..ec67e9c0af 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -21,10 +21,6 @@ #include "libardour-config.h" #endif -#ifndef PLATFORM_WINDOWS -#include // so that we can test for new functions at runtime -#endif - #include "pbd/compose.h" #include "pbd/error.h" #include "pbd/failed_constructor.h" @@ -34,7 +30,7 @@ #include "ardour/port.h" #include "ardour/port_engine.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -42,11 +38,14 @@ using namespace PBD; PBD::Signal2, boost::shared_ptr > Port::PostDisconnect; PBD::Signal0 Port::PortDrop; +PBD::Signal0 Port::PortSignalDrop; bool Port::_connecting_blocked = false; pframes_t Port::_global_port_buffer_offset = 0; pframes_t Port::_cycle_nframes = 0; +double Port::_speed_ratio = 1.0; std::string Port::state_node_name = X_("Port"); +const uint32_t Port::_resampler_quality = 12; /* a handy define to shorten what would otherwise be a needlessly verbose * repeated phrase @@ -56,10 +55,9 @@ std::string Port::state_node_name = X_("Port"); /** @param n Port short name */ Port::Port (std::string const & n, DataType t, PortFlags f) - : _port_buffer_offset (0) - , _name (n) + : _name (n) , _flags (f) - , _last_monitor (false) + , _last_monitor (false) { _private_playback_latency.min = 0; _private_playback_latency.max = 0; @@ -73,12 +71,19 @@ Port::Port (std::string const & n, DataType t, PortFlags f) assert (_name.find_first_of (':') == std::string::npos); - if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) { + if (!port_engine.available ()) { + DEBUG_TRACE (DEBUG::Ports, string_compose ("port-engine n/a postpone registering %1\n", name())); + _port_handle = 0; // created during ::reestablish() later + } else if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) { cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n"; throw failed_constructor (); } - + DEBUG_TRACE (DEBUG::Ports, string_compose ("registed port %1 handle %2\n", name(), _port_handle)); + PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this)); + PortSignalDrop.connect_same_thread (drop_connection, boost::bind (&Port::signal_drop, this)); + port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection, + boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5)); } /** Port destructor */ @@ -87,6 +92,45 @@ Port::~Port () drop (); } + +std::string +Port::pretty_name(bool fallback_to_name) const +{ + if (_port_handle) { + std::string value; + std::string type; + if (0 == port_engine.get_port_property (_port_handle, + "http://jackaudio.org/metadata/pretty-name", + value, type)) + { + return value; + } + } + if (fallback_to_name) { + return name (); + } + return ""; +} + +bool +Port::set_pretty_name(const std::string& n) +{ + if (_port_handle) { + if (0 == port_engine.set_port_property (_port_handle, + "http://jackaudio.org/metadata/pretty-name", n, "")) + { + return true; + } + } + return false; +} + +void +Port::signal_drop () +{ + engine_connection.disconnect (); +} + void Port::drop () { @@ -97,23 +141,57 @@ Port::drop () } } +void +Port::port_connected_or_disconnected (boost::weak_ptr w0, boost::weak_ptr w1, bool con) +{ + if (con) { + /* we're only interested in disconnect */ + return; + } + boost::shared_ptr p0 = w0.lock (); + boost::shared_ptr p1 = w1.lock (); + /* a cheaper, less hacky way to do boost::shared_from_this() ... */ + boost::shared_ptr pself = AudioEngine::instance()->get_port_by_name (name()); + + if (p0 == pself) { + PostDisconnect (p0, p1); // emit signal + } + if (p1 == pself) { + PostDisconnect (p1, p0); // emit signal + } +} + /** @return true if this port is connected to anything */ bool Port::connected () const { - return (port_engine.connected (_port_handle) != 0); + if (_port_handle) { + return (port_engine.connected (_port_handle) != 0); + } + return false; } int Port::disconnect_all () { - port_engine.disconnect_all (_port_handle); - _connections.clear (); + if (_port_handle) { + + std::vector connections; + get_connections (connections); - /* a cheaper, less hacky way to do boost::shared_from_this() ... - */ - boost::shared_ptr pself = port_manager->get_port_by_name (name()); - PostDisconnect (pself, boost::shared_ptr()); // emit signal + port_engine.disconnect_all (_port_handle); + _connections.clear (); + + /* a cheaper, less hacky way to do boost::shared_from_this() ... + */ + boost::shared_ptr pself = port_manager->get_port_by_name (name()); + for (vector::const_iterator c = connections.begin(); c != connections.end() && pself; ++c) { + boost::shared_ptr pother = AudioEngine::instance()->get_port_by_name (*c); + if (pother) { + PostDisconnect (pself, pother); // emit signal + } + } + } return 0; } @@ -124,6 +202,10 @@ Port::disconnect_all () bool Port::connected_to (std::string const & o) const { + if (!_port_handle) { + return false; + } + if (!port_engine.available()) { return false; } @@ -139,7 +221,11 @@ Port::get_connections (std::vector & c) const return c.size(); } - return port_engine.get_connections (_port_handle, c); + if (_port_handle) { + return port_engine.get_connections (_port_handle, c); + } + + return 0; } int @@ -187,8 +273,7 @@ Port::disconnect (std::string const & other) _connections.erase (other); } - /* a cheaper, less hacky way to do boost::shared_from_this() ... - */ + /* a cheaper, less hacky way to do boost::shared_from_this() ... */ boost::shared_ptr pself = AudioEngine::instance()->get_port_by_name (name()); boost::shared_ptr pother = AudioEngine::instance()->get_port_by_name (other); @@ -197,7 +282,7 @@ Port::disconnect (std::string const & other) a check on whether this may affect anything that we need to know about. */ - PostDisconnect (pself, pother); // emit signal + PostDisconnect (pself, pother); // emit signal } return r; @@ -225,20 +310,26 @@ Port::disconnect (Port* o) void Port::request_input_monitoring (bool yn) { - port_engine.request_input_monitoring (_port_handle, yn); + if (_port_handle) { + port_engine.request_input_monitoring (_port_handle, yn); + } } void Port::ensure_input_monitoring (bool yn) { - port_engine.ensure_input_monitoring (_port_handle, yn); + if (_port_handle) { + port_engine.ensure_input_monitoring (_port_handle, yn); + } } bool Port::monitoring_input () const { - - return port_engine.monitoring_input (_port_handle); + if (_port_handle) { + return port_engine.monitoring_input (_port_handle); + } + return false; } void @@ -250,17 +341,10 @@ Port::reset () void Port::cycle_start (pframes_t) { - _port_buffer_offset = 0; -} - -void -Port::increment_port_buffer_offset (pframes_t nframes) -{ - _port_buffer_offset += nframes; } void -Port::set_public_latency_range (LatencyRange& range, bool playback) const +Port::set_public_latency_range (LatencyRange const& range, bool playback) const { /* this sets the visible latency that the rest of the port system sees. because we do latency compensation, all (most) of our visible @@ -272,7 +356,18 @@ Port::set_public_latency_range (LatencyRange& range, bool playback) const name(), range.min, range.max, (playback ? "PLAYBACK" : "CAPTURE")));; - port_engine.set_latency_range (_port_handle, playback, range); + if (_port_handle) { + LatencyRange r (range); + if (externally_connected ()) { +#if 0 + r.min *= _speed_ratio; + r.max *= _speed_ratio; +#endif + r.min += (_resampler_quality - 1); + r.max += (_resampler_quality - 1); + } + port_engine.set_latency_range (_port_handle, playback, r); + } } void @@ -324,12 +419,24 @@ Port::public_latency_range (bool /*playback*/) const { LatencyRange r; - r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false); - DEBUG_TRACE (DEBUG::Latency, string_compose ( - "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n", - name(), r.min, r.max, - sends_output() ? "PLAYBACK" : "CAPTURE")); + if (_port_handle) { + r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false); + if (externally_connected ()) { +#if 0 + r.min /= _speed_ratio; + r.max /= _speed_ratio; +#endif + r.min += (_resampler_quality - 1); + r.max += (_resampler_quality - 1); + } + + DEBUG_TRACE (DEBUG::Latency, string_compose ( + "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n", + name(), r.min, r.max, + sends_output() ? "PLAYBACK" : "CAPTURE")); + } + return r; } @@ -348,49 +455,57 @@ Port::get_connected_latency_range (LatencyRange& range, bool playback) const DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size())); for (vector::const_iterator c = connections.begin(); - c != connections.end(); ++c) { + c != connections.end(); ++c) { - LatencyRange lr; + LatencyRange lr; - if (!AudioEngine::instance()->port_is_mine (*c)) { + if (!AudioEngine::instance()->port_is_mine (*c)) { - /* port belongs to some other port-system client, use - * the port engine to lookup its latency information. - */ + /* port belongs to some other port-system client, use + * the port engine to lookup its latency information. + */ PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c); - if (remote_port) { - lr = port_engine.get_latency_range (remote_port, playback); + if (remote_port) { + lr = port_engine.get_latency_range (remote_port, playback); + if (externally_connected ()) { +#if 0 + lr.min /= _speed_ratio; + lr.max /= _speed_ratio; +#endif + lr.min += (_resampler_quality - 1); + lr.max += (_resampler_quality - 1); + } - DEBUG_TRACE (DEBUG::Latency, string_compose ( - "\t%1 <-> %2 : latter has latency range %3 .. %4\n", - name(), *c, lr.min, lr.max)); + DEBUG_TRACE (DEBUG::Latency, string_compose ( + "\t%1 <-> %2 : latter has latency range %3 .. %4\n", + name(), *c, lr.min, lr.max)); - range.min = min (range.min, lr.min); - range.max = max (range.max, lr.max); - } + range.min = min (range.min, lr.min); + range.max = max (range.max, lr.max); + } } else { - /* port belongs to this instance of ardour, - so look up its latency information - internally, because our published/public - values already contain our plugin - latency compensation. - */ - - boost::shared_ptr remote_port = AudioEngine::instance()->get_port_by_name (*c); - if (remote_port) { - lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency)); - DEBUG_TRACE (DEBUG::Latency, string_compose ( - "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n", - name(), *c, lr.min, lr.max)); - - range.min = min (range.min, lr.min); - range.max = max (range.max, lr.max); - } - } + /* port belongs to this instance of ardour, + so look up its latency information + internally, because our published/public + values already contain our plugin + latency compensation. + */ + + boost::shared_ptr remote_port = AudioEngine::instance()->get_port_by_name (*c); + if (remote_port) { + lr = remote_port->private_latency_range ((playback ? true : false)); + DEBUG_TRACE (DEBUG::Latency, string_compose ( + "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n", + name(), *c, lr.min, lr.max)); + + range.min = min (range.min, lr.min); + range.max = max (range.max, lr.max); + } + } } } else { @@ -399,7 +514,7 @@ Port::get_connected_latency_range (LatencyRange& range, bool playback) const range.max = 0; } - DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max)); + DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max)); } int @@ -413,8 +528,12 @@ Port::reestablish () return -1; } + DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reestablish %1 handle %2\n", name(), _port_handle)); + reset (); + port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection, + boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5)); return 0; } @@ -439,7 +558,7 @@ Port::reconnect () int Port::set_name (std::string const & n) { - if (n == _name) { + if (n == _name || !_port_handle) { return 0; } @@ -457,6 +576,23 @@ Port::set_name (std::string const & n) bool Port::physically_connected () const { + if (!_port_handle) { + return false; + } + + return port_engine.physically_connected (_port_handle); +} + +bool +Port::externally_connected () const +{ + if (!_port_handle) { + return false; + } + + // TODO: When used with JACK, check if this port + // is connected to any non-ardour ports. + return port_engine.physically_connected (_port_handle); } @@ -465,21 +601,21 @@ Port::get_state () const { XMLNode* root = new XMLNode (state_node_name); - root->add_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name())); + root->set_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name())); if (receives_input()) { - root->add_property (X_("direction"), X_("input")); + root->set_property (X_("direction"), X_("input")); } else { - root->add_property (X_("direction"), X_("output")); + root->set_property (X_("direction"), X_("output")); } vector c; - + get_connections (c); for (vector::const_iterator i = c.begin(); i != c.end(); ++i) { XMLNode* child = new XMLNode (X_("Connection")); - child->add_property (X_("other"), *i); + child->set_property (X_("other"), *i); root->add_child_nocopy (*child); } @@ -489,14 +625,13 @@ Port::get_state () const int Port::set_state (const XMLNode& node, int) { - const XMLProperty* prop; - if (node.name() != state_node_name) { return -1; } - if ((prop = node.property (X_("name"))) != 0) { - set_name (prop->value()); + std::string str; + if (node.get_property (X_("name"), str)) { + set_name (str); } const XMLNodeList& children (node.children()); @@ -508,13 +643,24 @@ Port::set_state (const XMLNode& node, int) if ((*c)->name() != X_("Connection")) { continue; } - - if ((prop = (*c)->property (X_("other"))) == 0) { + + if (!(*c)->get_property (X_("other"), str)) { continue; } - _connections.insert (prop->value()); + _connections.insert (str); } return 0; } + +/*static*/ void +Port::set_speed_ratio (double s) { + /* see VMResampler::set_rratio() for min/max range */ + _speed_ratio = std::min (16.0, std::max (0.5, s)); +} + +/*static*/ void +Port::set_cycle_samplecnt (pframes_t n) { + _cycle_nframes = floor (n * _speed_ratio); +}