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 #ifndef PLATFORM_WINDOWS
25 #include <jack/weakjack.h> // so that we can test for new functions at runtime
28 #include "pbd/compose.h"
29 #include "pbd/error.h"
30 #include "pbd/failed_constructor.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/debug.h"
34 #include "ardour/port.h"
35 #include "ardour/port_engine.h"
40 using namespace ARDOUR;
43 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
44 PBD::Signal0<void> Port::PortDrop;
46 bool Port::_connecting_blocked = false;
47 pframes_t Port::_global_port_buffer_offset = 0;
48 pframes_t Port::_cycle_nframes = 0;
49 std::string Port::state_node_name = X_("Port");
51 /* a handy define to shorten what would otherwise be a needlessly verbose
54 #define port_engine AudioEngine::instance()->port_engine()
55 #define port_manager AudioEngine::instance()
57 /** @param n Port short name */
58 Port::Port (std::string const & n, DataType t, PortFlags f)
59 : _port_buffer_offset (0)
62 , _last_monitor (false)
64 _private_playback_latency.min = 0;
65 _private_playback_latency.max = 0;
66 _private_capture_latency.min = 0;
67 _private_capture_latency.max = 0;
69 /* Unfortunately we have to pass the DataType into this constructor so that
70 we can create the right kind of port; aside from this we'll use the
71 virtual function type () to establish type.
74 assert (_name.find_first_of (':') == std::string::npos);
76 if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
77 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
78 throw failed_constructor ();
81 PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
84 /** Port destructor */
94 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
95 port_engine.unregister_port (_port_handle);
100 /** @return true if this port is connected to anything */
102 Port::connected () const
104 return (port_engine.connected (_port_handle) != 0);
108 Port::disconnect_all ()
110 port_engine.disconnect_all (_port_handle);
111 _connections.clear ();
113 /* a cheaper, less hacky way to do boost::shared_from_this() ...
115 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
116 PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
121 /** @param o Port name
122 * @return true if this port is connected to o, otherwise false.
125 Port::connected_to (std::string const & o) const
127 if (!port_engine.available()) {
131 return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
135 Port::get_connections (std::vector<std::string> & c) const
137 if (!port_engine.available()) {
138 c.insert (c.end(), _connections.begin(), _connections.end());
142 return port_engine.get_connections (_port_handle, c);
146 Port::connect (std::string const & other)
148 std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
149 std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
153 if (_connecting_blocked) {
157 if (sends_output ()) {
158 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
159 r = port_engine.connect (our_name, other_name);
161 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
162 r = port_engine.connect (other_name, our_name);
166 _connections.insert (other);
173 Port::disconnect (std::string const & other)
175 std::string const other_fullname = port_manager->make_port_name_non_relative (other);
176 std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
180 if (sends_output ()) {
181 r = port_engine.disconnect (this_fullname, other_fullname);
183 r = port_engine.disconnect (other_fullname, this_fullname);
187 _connections.erase (other);
190 /* a cheaper, less hacky way to do boost::shared_from_this() ...
192 boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
193 boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
195 if (pself && pother) {
196 /* Disconnecting from another Ardour port: need to allow
197 a check on whether this may affect anything that we
200 PostDisconnect (pself, pother); // emit signal
208 Port::connected_to (Port* o) const
210 return connected_to (o->name ());
214 Port::connect (Port* o)
216 return connect (o->name ());
220 Port::disconnect (Port* o)
222 return disconnect (o->name ());
226 Port::request_input_monitoring (bool yn)
228 port_engine.request_input_monitoring (_port_handle, yn);
232 Port::ensure_input_monitoring (bool yn)
234 port_engine.ensure_input_monitoring (_port_handle, yn);
238 Port::monitoring_input () const
241 return port_engine.monitoring_input (_port_handle);
247 _last_monitor = false;
251 Port::cycle_start (pframes_t)
253 _port_buffer_offset = 0;
257 Port::increment_port_buffer_offset (pframes_t nframes)
259 _port_buffer_offset += nframes;
263 Port::set_public_latency_range (LatencyRange& range, bool playback) const
265 /* this sets the visible latency that the rest of the port system
266 sees. because we do latency compensation, all (most) of our visible
267 port latency values are identical.
270 DEBUG_TRACE (DEBUG::Latency,
271 string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
272 name(), range.min, range.max,
273 (playback ? "PLAYBACK" : "CAPTURE")));;
275 port_engine.set_latency_range (_port_handle, playback, range);
279 Port::set_private_latency_range (LatencyRange& range, bool playback)
282 _private_playback_latency = range;
283 DEBUG_TRACE (DEBUG::Latency, string_compose (
284 "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
286 _private_playback_latency.min,
287 _private_playback_latency.max));
289 _private_capture_latency = range;
290 DEBUG_TRACE (DEBUG::Latency, string_compose (
291 "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
293 _private_capture_latency.min,
294 _private_capture_latency.max));
297 /* push to public (port system) location so that everyone else can see it */
299 set_public_latency_range (range, playback);
303 Port::private_latency_range (bool playback) const
306 DEBUG_TRACE (DEBUG::Latency, string_compose (
307 "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
309 _private_playback_latency.min,
310 _private_playback_latency.max));
311 return _private_playback_latency;
313 DEBUG_TRACE (DEBUG::Latency, string_compose (
314 "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
316 _private_playback_latency.min,
317 _private_playback_latency.max));
318 return _private_capture_latency;
323 Port::public_latency_range (bool /*playback*/) const
327 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
329 DEBUG_TRACE (DEBUG::Latency, string_compose (
330 "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
331 name(), r.min, r.max,
332 sends_output() ? "PLAYBACK" : "CAPTURE"));
337 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
339 vector<string> connections;
341 get_connections (connections);
343 if (!connections.empty()) {
345 range.min = ~((pframes_t) 0);
348 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
350 for (vector<string>::const_iterator c = connections.begin();
351 c != connections.end(); ++c) {
355 if (!AudioEngine::instance()->port_is_mine (*c)) {
357 /* port belongs to some other port-system client, use
358 * the port engine to lookup its latency information.
361 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
364 lr = port_engine.get_latency_range (remote_port, playback);
366 DEBUG_TRACE (DEBUG::Latency, string_compose (
367 "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
368 name(), *c, lr.min, lr.max));
370 range.min = min (range.min, lr.min);
371 range.max = max (range.max, lr.max);
376 /* port belongs to this instance of ardour,
377 so look up its latency information
378 internally, because our published/public
379 values already contain our plugin
380 latency compensation.
383 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
385 lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
386 DEBUG_TRACE (DEBUG::Latency, string_compose (
387 "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
388 name(), *c, lr.min, lr.max));
390 range.min = min (range.min, lr.min);
391 range.max = max (range.max, lr.max);
397 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
402 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
408 DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
409 _port_handle = port_engine.register_port (_name, type(), _flags);
411 if (_port_handle == 0) {
412 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
425 /* caller must hold process lock; intended to be used only after reestablish() */
427 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
429 for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
438 /** @param n Short port name (no port-system client name) */
440 Port::set_name (std::string const & n)
446 int const r = port_engine.set_port_name (_port_handle, n);
449 AudioEngine::instance()->port_renamed (_name, n);
458 Port::physically_connected () const
460 return port_engine.physically_connected (_port_handle);
464 Port::get_state () const
466 XMLNode* root = new XMLNode (state_node_name);
468 root->add_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
470 if (receives_input()) {
471 root->add_property (X_("direction"), X_("input"));
473 root->add_property (X_("direction"), X_("output"));
480 for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
481 XMLNode* child = new XMLNode (X_("Connection"));
482 child->add_property (X_("other"), *i);
483 root->add_child_nocopy (*child);
490 Port::set_state (const XMLNode& node, int)
492 const XMLProperty* prop;
494 if (node.name() != state_node_name) {
498 if ((prop = node.property (X_("name"))) != 0) {
499 set_name (prop->value());
502 const XMLNodeList& children (node.children());
504 _connections.clear ();
506 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
508 if ((*c)->name() != X_("Connection")) {
512 if ((prop = (*c)->property (X_("other"))) == 0) {
516 _connections.insert (prop->value());