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 port_engine.unregister_port (_port_handle);
96 /** @return true if this port is connected to anything */
98 Port::connected () const
100 return (port_engine.connected (_port_handle) != 0);
104 Port::disconnect_all ()
106 port_engine.disconnect_all (_port_handle);
107 _connections.clear ();
109 /* a cheaper, less hacky way to do boost::shared_from_this() ...
111 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
112 PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
117 /** @param o Port name
118 * @return true if this port is connected to o, otherwise false.
121 Port::connected_to (std::string const & o) const
123 return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
127 Port::get_connections (std::vector<std::string> & c) const
129 return port_engine.get_connections (_port_handle, c);
133 Port::connect (std::string const & other)
135 std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
136 std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
140 if (_connecting_blocked) {
144 if (sends_output ()) {
145 port_engine.connect (our_name, other_name);
147 port_engine.connect (other_name, our_name);
151 _connections.insert (other);
158 Port::disconnect (std::string const & other)
160 std::string const other_fullname = port_manager->make_port_name_non_relative (other);
161 std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
165 if (sends_output ()) {
166 r = port_engine.disconnect (this_fullname, other_fullname);
168 r = port_engine.disconnect (other_fullname, this_fullname);
172 _connections.erase (other);
175 /* a cheaper, less hacky way to do boost::shared_from_this() ...
177 boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
178 boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
180 if (pself && pother) {
181 /* Disconnecting from another Ardour port: need to allow
182 a check on whether this may affect anything that we
185 PostDisconnect (pself, pother); // emit signal
193 Port::connected_to (Port* o) const
195 return connected_to (o->name ());
199 Port::connect (Port* o)
201 return connect (o->name ());
205 Port::disconnect (Port* o)
207 return disconnect (o->name ());
211 Port::request_input_monitoring (bool yn)
213 port_engine.request_input_monitoring (_port_handle, yn);
217 Port::ensure_input_monitoring (bool yn)
219 port_engine.ensure_input_monitoring (_port_handle, yn);
223 Port::monitoring_input () const
226 return port_engine.monitoring_input (_port_handle);
232 _last_monitor = false;
236 Port::cycle_start (pframes_t)
238 _port_buffer_offset = 0;
242 Port::increment_port_buffer_offset (pframes_t nframes)
244 _port_buffer_offset += nframes;
248 Port::set_public_latency_range (LatencyRange& range, bool playback) const
250 /* this sets the visible latency that the rest of the port system
251 sees. because we do latency compensation, all (most) of our visible
252 port latency values are identical.
255 DEBUG_TRACE (DEBUG::Latency,
256 string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
257 name(), range.min, range.max,
258 (playback ? "PLAYBACK" : "CAPTURE")));;
260 port_engine.set_latency_range (_port_handle, playback, range);
264 Port::set_private_latency_range (LatencyRange& range, bool playback)
267 _private_playback_latency = range;
268 DEBUG_TRACE (DEBUG::Latency, string_compose (
269 "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
271 _private_playback_latency.min,
272 _private_playback_latency.max));
274 _private_capture_latency = range;
275 DEBUG_TRACE (DEBUG::Latency, string_compose (
276 "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
278 _private_capture_latency.min,
279 _private_capture_latency.max));
282 /* push to public (port system) location so that everyone else can see it */
284 set_public_latency_range (range, playback);
288 Port::private_latency_range (bool playback) const
291 DEBUG_TRACE (DEBUG::Latency, string_compose (
292 "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
294 _private_playback_latency.min,
295 _private_playback_latency.max));
296 return _private_playback_latency;
298 DEBUG_TRACE (DEBUG::Latency, string_compose (
299 "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
301 _private_playback_latency.min,
302 _private_playback_latency.max));
303 return _private_capture_latency;
308 Port::public_latency_range (bool /*playback*/) const
312 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
314 DEBUG_TRACE (DEBUG::Latency, string_compose (
315 "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
316 name(), r.min, r.max,
317 sends_output() ? "PLAYBACK" : "CAPTURE"));
322 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
324 vector<string> connections;
326 get_connections (connections);
328 if (!connections.empty()) {
330 range.min = ~((jack_nframes_t) 0);
333 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
335 for (vector<string>::const_iterator c = connections.begin();
336 c != connections.end(); ++c) {
340 if (!AudioEngine::instance()->port_is_mine (*c)) {
342 /* port belongs to some other port-system client, use
343 * the port engine to lookup its latency information.
346 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
349 lr = port_engine.get_latency_range (remote_port, playback);
351 DEBUG_TRACE (DEBUG::Latency, string_compose (
352 "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
353 name(), *c, lr.min, lr.max));
355 range.min = min (range.min, lr.min);
356 range.max = max (range.max, lr.max);
361 /* port belongs to this instance of ardour,
362 so look up its latency information
363 internally, because our published/public
364 values already contain our plugin
365 latency compensation.
368 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
370 lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
371 DEBUG_TRACE (DEBUG::Latency, string_compose (
372 "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
373 name(), *c, lr.min, lr.max));
375 range.min = min (range.min, lr.min);
376 range.max = max (range.max, lr.max);
382 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
387 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
393 DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
394 _port_handle = port_engine.register_port (_name, type(), _flags);
396 if (_port_handle == 0) {
397 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
410 /* caller must hold process lock; intended to be used only after reestablish() */
412 for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
421 /** @param n Short port name (no port-system client name) */
423 Port::set_name (std::string const & n)
429 int const r = port_engine.set_port_name (_port_handle, n);
432 AudioEngine::instance()->port_renamed (_name, n);
441 Port::physically_connected () const
443 return port_engine.physically_connected (_port_handle);