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 <jack/weakjack.h> // so that we can test for new functions at runtime
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/failed_constructor.h"
30 #include "ardour/audioengine.h"
31 #include "ardour/debug.h"
32 #include "ardour/port.h"
33 #include "ardour/port_engine.h"
38 using namespace ARDOUR;
41 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
42 PBD::Signal0<void> Port::PortDrop;
44 bool Port::_connecting_blocked = false;
45 pframes_t Port::_global_port_buffer_offset = 0;
46 pframes_t Port::_cycle_nframes = 0;
48 /* a handy define to shorten what would otherwise be a needlessly verbose
51 #define port_engine AudioEngine::instance()->port_engine()
52 #define port_manager AudioEngine::instance()
54 /** @param n Port short name */
55 Port::Port (std::string const & n, DataType t, PortFlags f)
56 : _port_buffer_offset (0)
59 , _last_monitor (false)
61 _private_playback_latency.min = 0;
62 _private_playback_latency.max = 0;
63 _private_capture_latency.min = 0;
64 _private_capture_latency.max = 0;
66 /* Unfortunately we have to pass the DataType into this constructor so that
67 we can create the right kind of port; aside from this we'll use the
68 virtual function type () to establish type.
71 assert (_name.find_first_of (':') == std::string::npos);
73 if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
74 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
75 throw failed_constructor ();
78 PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
81 /** Port destructor */
91 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
92 port_engine.unregister_port (_port_handle);
97 /** @return true if this port is connected to anything */
99 Port::connected () const
101 return (port_engine.connected (_port_handle) != 0);
105 Port::disconnect_all ()
107 port_engine.disconnect_all (_port_handle);
108 _connections.clear ();
110 /* a cheaper, less hacky way to do boost::shared_from_this() ...
112 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
113 PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
118 /** @param o Port name
119 * @return true if this port is connected to o, otherwise false.
122 Port::connected_to (std::string const & o) const
124 if (!port_engine.connected()) {
128 return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
132 Port::get_connections (std::vector<std::string> & c) const
134 if (!port_engine.connected()) {
135 c.insert (c.end(), _connections.begin(), _connections.end());
139 return port_engine.get_connections (_port_handle, c);
143 Port::connect (std::string const & other)
145 std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
146 std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
150 if (_connecting_blocked) {
154 if (sends_output ()) {
155 r = port_engine.connect (our_name, other_name);
157 r = port_engine.connect (other_name, our_name);
161 _connections.insert (other);
168 Port::disconnect (std::string const & other)
170 std::string const other_fullname = port_manager->make_port_name_non_relative (other);
171 std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
175 if (sends_output ()) {
176 r = port_engine.disconnect (this_fullname, other_fullname);
178 r = port_engine.disconnect (other_fullname, this_fullname);
182 _connections.erase (other);
185 /* a cheaper, less hacky way to do boost::shared_from_this() ...
187 boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
188 boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
190 if (pself && pother) {
191 /* Disconnecting from another Ardour port: need to allow
192 a check on whether this may affect anything that we
195 PostDisconnect (pself, pother); // emit signal
203 Port::connected_to (Port* o) const
205 return connected_to (o->name ());
209 Port::connect (Port* o)
211 return connect (o->name ());
215 Port::disconnect (Port* o)
217 return disconnect (o->name ());
221 Port::request_input_monitoring (bool yn)
223 port_engine.request_input_monitoring (_port_handle, yn);
227 Port::ensure_input_monitoring (bool yn)
229 port_engine.ensure_input_monitoring (_port_handle, yn);
233 Port::monitoring_input () const
236 return port_engine.monitoring_input (_port_handle);
242 _last_monitor = false;
246 Port::cycle_start (pframes_t)
248 _port_buffer_offset = 0;
252 Port::increment_port_buffer_offset (pframes_t nframes)
254 _port_buffer_offset += nframes;
258 Port::set_public_latency_range (LatencyRange& range, bool playback) const
260 /* this sets the visible latency that the rest of the port system
261 sees. because we do latency compensation, all (most) of our visible
262 port latency values are identical.
265 DEBUG_TRACE (DEBUG::Latency,
266 string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
267 name(), range.min, range.max,
268 (playback ? "PLAYBACK" : "CAPTURE")));;
270 port_engine.set_latency_range (_port_handle, playback, range);
274 Port::set_private_latency_range (LatencyRange& range, bool playback)
277 _private_playback_latency = range;
278 DEBUG_TRACE (DEBUG::Latency, string_compose (
279 "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
281 _private_playback_latency.min,
282 _private_playback_latency.max));
284 _private_capture_latency = range;
285 DEBUG_TRACE (DEBUG::Latency, string_compose (
286 "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
288 _private_capture_latency.min,
289 _private_capture_latency.max));
292 /* push to public (port system) location so that everyone else can see it */
294 set_public_latency_range (range, playback);
298 Port::private_latency_range (bool playback) const
301 DEBUG_TRACE (DEBUG::Latency, string_compose (
302 "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
304 _private_playback_latency.min,
305 _private_playback_latency.max));
306 return _private_playback_latency;
308 DEBUG_TRACE (DEBUG::Latency, string_compose (
309 "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
311 _private_playback_latency.min,
312 _private_playback_latency.max));
313 return _private_capture_latency;
318 Port::public_latency_range (bool /*playback*/) const
322 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
324 DEBUG_TRACE (DEBUG::Latency, string_compose (
325 "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
326 name(), r.min, r.max,
327 sends_output() ? "PLAYBACK" : "CAPTURE"));
332 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
334 vector<string> connections;
336 get_connections (connections);
338 if (!connections.empty()) {
340 range.min = ~((pframes_t) 0);
343 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
345 for (vector<string>::const_iterator c = connections.begin();
346 c != connections.end(); ++c) {
350 if (!AudioEngine::instance()->port_is_mine (*c)) {
352 /* port belongs to some other port-system client, use
353 * the port engine to lookup its latency information.
356 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
359 lr = port_engine.get_latency_range (remote_port, playback);
361 DEBUG_TRACE (DEBUG::Latency, string_compose (
362 "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
363 name(), *c, lr.min, lr.max));
365 range.min = min (range.min, lr.min);
366 range.max = max (range.max, lr.max);
371 /* port belongs to this instance of ardour,
372 so look up its latency information
373 internally, because our published/public
374 values already contain our plugin
375 latency compensation.
378 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
380 lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
381 DEBUG_TRACE (DEBUG::Latency, string_compose (
382 "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
383 name(), *c, lr.min, lr.max));
385 range.min = min (range.min, lr.min);
386 range.max = max (range.max, lr.max);
392 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
397 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
403 DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
404 _port_handle = port_engine.register_port (_name, type(), _flags);
406 if (_port_handle == 0) {
407 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
420 /* caller must hold process lock; intended to be used only after reestablish() */
422 for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
431 /** @param n Short port name (no port-system client name) */
433 Port::set_name (std::string const & n)
439 int const r = port_engine.set_port_name (_port_handle, n);
442 AudioEngine::instance()->port_renamed (_name, n);
451 Port::physically_connected () const
453 return port_engine.physically_connected (_port_handle);