2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "libardour-config.h"
24 #include "pbd/compose.h"
25 #include "pbd/error.h"
26 #include "pbd/failed_constructor.h"
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/port.h"
31 #include "ardour/port_engine.h"
36 using namespace ARDOUR;
39 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
40 PBD::Signal0<void> Port::PortDrop;
42 bool Port::_connecting_blocked = false;
43 pframes_t Port::_global_port_buffer_offset = 0;
44 pframes_t Port::_cycle_nframes = 0;
45 std::string Port::state_node_name = X_("Port");
47 /* a handy define to shorten what would otherwise be a needlessly verbose
50 #define port_engine AudioEngine::instance()->port_engine()
51 #define port_manager AudioEngine::instance()
53 /** @param n Port short name */
54 Port::Port (std::string const & n, DataType t, PortFlags f)
55 : _port_buffer_offset (0)
58 , _last_monitor (false)
60 _private_playback_latency.min = 0;
61 _private_playback_latency.max = 0;
62 _private_capture_latency.min = 0;
63 _private_capture_latency.max = 0;
65 /* Unfortunately we have to pass the DataType into this constructor so that
66 we can create the right kind of port; aside from this we'll use the
67 virtual function type () to establish type.
70 assert (_name.find_first_of (':') == std::string::npos);
72 if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
73 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
74 throw failed_constructor ();
77 PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
80 /** Port destructor */
88 Port::pretty_name(bool fallback_to_name) const
93 if (0 == port_engine.get_port_property (_port_handle,
94 "http://jackaudio.org/metadata/pretty-name",
100 if (fallback_to_name) {
110 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
111 port_engine.unregister_port (_port_handle);
116 /** @return true if this port is connected to anything */
118 Port::connected () const
121 return (port_engine.connected (_port_handle) != 0);
127 Port::disconnect_all ()
131 std::vector<std::string> connections;
132 get_connections (connections);
134 port_engine.disconnect_all (_port_handle);
135 _connections.clear ();
137 /* a cheaper, less hacky way to do boost::shared_from_this() ...
139 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
140 for (vector<string>::const_iterator c = connections.begin(); c != connections.end() && pself; ++c) {
141 boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (*c);
143 PostDisconnect (pself, pother); // emit signal
151 /** @param o Port name
152 * @return true if this port is connected to o, otherwise false.
155 Port::connected_to (std::string const & o) const
161 if (!port_engine.available()) {
165 return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
169 Port::get_connections (std::vector<std::string> & c) const
171 if (!port_engine.available()) {
172 c.insert (c.end(), _connections.begin(), _connections.end());
177 return port_engine.get_connections (_port_handle, c);
184 Port::connect (std::string const & other)
186 std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
187 std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
191 if (_connecting_blocked) {
195 if (sends_output ()) {
196 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
197 r = port_engine.connect (our_name, other_name);
199 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
200 r = port_engine.connect (other_name, our_name);
204 _connections.insert (other);
211 Port::disconnect (std::string const & other)
213 std::string const other_fullname = port_manager->make_port_name_non_relative (other);
214 std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
218 if (sends_output ()) {
219 r = port_engine.disconnect (this_fullname, other_fullname);
221 r = port_engine.disconnect (other_fullname, this_fullname);
225 _connections.erase (other);
228 /* a cheaper, less hacky way to do boost::shared_from_this() ...
230 boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
231 boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
233 if (pself && pother) {
234 /* Disconnecting from another Ardour port: need to allow
235 a check on whether this may affect anything that we
238 PostDisconnect (pself, pother); // emit signal
246 Port::connected_to (Port* o) const
248 return connected_to (o->name ());
252 Port::connect (Port* o)
254 return connect (o->name ());
258 Port::disconnect (Port* o)
260 return disconnect (o->name ());
264 Port::request_input_monitoring (bool yn)
267 port_engine.request_input_monitoring (_port_handle, yn);
272 Port::ensure_input_monitoring (bool yn)
275 port_engine.ensure_input_monitoring (_port_handle, yn);
280 Port::monitoring_input () const
283 return port_engine.monitoring_input (_port_handle);
291 _last_monitor = false;
295 Port::cycle_start (pframes_t)
297 _port_buffer_offset = 0;
301 Port::increment_port_buffer_offset (pframes_t nframes)
303 _port_buffer_offset += nframes;
307 Port::set_public_latency_range (LatencyRange& range, bool playback) const
309 /* this sets the visible latency that the rest of the port system
310 sees. because we do latency compensation, all (most) of our visible
311 port latency values are identical.
314 DEBUG_TRACE (DEBUG::Latency,
315 string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
316 name(), range.min, range.max,
317 (playback ? "PLAYBACK" : "CAPTURE")));;
320 port_engine.set_latency_range (_port_handle, playback, range);
325 Port::set_private_latency_range (LatencyRange& range, bool playback)
328 _private_playback_latency = range;
329 DEBUG_TRACE (DEBUG::Latency, string_compose (
330 "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
332 _private_playback_latency.min,
333 _private_playback_latency.max));
335 _private_capture_latency = range;
336 DEBUG_TRACE (DEBUG::Latency, string_compose (
337 "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
339 _private_capture_latency.min,
340 _private_capture_latency.max));
343 /* push to public (port system) location so that everyone else can see it */
345 set_public_latency_range (range, playback);
349 Port::private_latency_range (bool playback) const
352 DEBUG_TRACE (DEBUG::Latency, string_compose (
353 "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
355 _private_playback_latency.min,
356 _private_playback_latency.max));
357 return _private_playback_latency;
359 DEBUG_TRACE (DEBUG::Latency, string_compose (
360 "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
362 _private_playback_latency.min,
363 _private_playback_latency.max));
364 return _private_capture_latency;
369 Port::public_latency_range (bool /*playback*/) const
375 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
377 DEBUG_TRACE (DEBUG::Latency, string_compose (
378 "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
379 name(), r.min, r.max,
380 sends_output() ? "PLAYBACK" : "CAPTURE"));
387 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
389 vector<string> connections;
391 get_connections (connections);
393 if (!connections.empty()) {
395 range.min = ~((pframes_t) 0);
398 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
400 for (vector<string>::const_iterator c = connections.begin();
401 c != connections.end(); ++c) {
405 if (!AudioEngine::instance()->port_is_mine (*c)) {
407 /* port belongs to some other port-system client, use
408 * the port engine to lookup its latency information.
411 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
414 lr = port_engine.get_latency_range (remote_port, playback);
416 DEBUG_TRACE (DEBUG::Latency, string_compose (
417 "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
418 name(), *c, lr.min, lr.max));
420 range.min = min (range.min, lr.min);
421 range.max = max (range.max, lr.max);
426 /* port belongs to this instance of ardour,
427 so look up its latency information
428 internally, because our published/public
429 values already contain our plugin
430 latency compensation.
433 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
435 lr = remote_port->private_latency_range ((playback ? true : false));
436 DEBUG_TRACE (DEBUG::Latency, string_compose (
437 "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
438 name(), *c, lr.min, lr.max));
440 range.min = min (range.min, lr.min);
441 range.max = max (range.max, lr.max);
447 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
452 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
458 DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
459 _port_handle = port_engine.register_port (_name, type(), _flags);
461 if (_port_handle == 0) {
462 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
475 /* caller must hold process lock; intended to be used only after reestablish() */
477 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
479 for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
488 /** @param n Short port name (no port-system client name) */
490 Port::set_name (std::string const & n)
492 if (n == _name || !_port_handle) {
496 int const r = port_engine.set_port_name (_port_handle, n);
499 AudioEngine::instance()->port_renamed (_name, n);
508 Port::physically_connected () const
514 return port_engine.physically_connected (_port_handle);
518 Port::get_state () const
520 XMLNode* root = new XMLNode (state_node_name);
522 root->add_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
524 if (receives_input()) {
525 root->add_property (X_("direction"), X_("input"));
527 root->add_property (X_("direction"), X_("output"));
534 for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
535 XMLNode* child = new XMLNode (X_("Connection"));
536 child->add_property (X_("other"), *i);
537 root->add_child_nocopy (*child);
544 Port::set_state (const XMLNode& node, int)
546 const XMLProperty* prop;
548 if (node.name() != state_node_name) {
552 if ((prop = node.property (X_("name"))) != 0) {
553 set_name (prop->value());
556 const XMLNodeList& children (node.children());
558 _connections.clear ();
560 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
562 if ((*c)->name() != X_("Connection")) {
566 if ((prop = (*c)->property (X_("other"))) == 0) {
570 _connections.insert (prop->value());