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_engine.connected()) {
74 throw failed_constructor ();
77 if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
78 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
79 throw failed_constructor ();
82 PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
85 /** Port destructor */
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.connected()) {
128 /* in some senses, this answer isn't the right one all the time,
129 because we know about our connections and will re-establish
130 them when we reconnect to the port engine.
135 return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
139 Port::get_connections (std::vector<std::string> & c) const
141 return port_engine.get_connections (_port_handle, c);
145 Port::connect (std::string const & other)
147 std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
148 std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
152 if (_connecting_blocked) {
156 if (sends_output ()) {
157 port_engine.connect (our_name, other_name);
159 port_engine.connect (other_name, our_name);
163 _connections.insert (other);
170 Port::disconnect (std::string const & other)
172 std::string const other_fullname = port_manager->make_port_name_non_relative (other);
173 std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
177 if (sends_output ()) {
178 r = port_engine.disconnect (this_fullname, other_fullname);
180 r = port_engine.disconnect (other_fullname, this_fullname);
184 _connections.erase (other);
187 /* a cheaper, less hacky way to do boost::shared_from_this() ...
189 boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
190 boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
192 if (pself && pother) {
193 /* Disconnecting from another Ardour port: need to allow
194 a check on whether this may affect anything that we
197 PostDisconnect (pself, pother); // emit signal
205 Port::connected_to (Port* o) const
207 return connected_to (o->name ());
211 Port::connect (Port* o)
213 return connect (o->name ());
217 Port::disconnect (Port* o)
219 return disconnect (o->name ());
223 Port::request_input_monitoring (bool yn)
225 port_engine.request_input_monitoring (_port_handle, yn);
229 Port::ensure_input_monitoring (bool yn)
231 port_engine.ensure_input_monitoring (_port_handle, yn);
235 Port::monitoring_input () const
238 return port_engine.monitoring_input (_port_handle);
244 _last_monitor = false;
248 Port::cycle_start (pframes_t)
250 _port_buffer_offset = 0;
254 Port::increment_port_buffer_offset (pframes_t nframes)
256 _port_buffer_offset += nframes;
260 Port::set_public_latency_range (LatencyRange& range, bool playback) const
262 /* this sets the visible latency that the rest of the port system
263 sees. because we do latency compensation, all (most) of our visible
264 port latency values are identical.
267 DEBUG_TRACE (DEBUG::Latency,
268 string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
269 name(), range.min, range.max,
270 (playback ? "PLAYBACK" : "CAPTURE")));;
272 port_engine.set_latency_range (_port_handle, playback, range);
276 Port::set_private_latency_range (LatencyRange& range, bool playback)
279 _private_playback_latency = range;
280 DEBUG_TRACE (DEBUG::Latency, string_compose (
281 "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
283 _private_playback_latency.min,
284 _private_playback_latency.max));
286 _private_capture_latency = range;
287 DEBUG_TRACE (DEBUG::Latency, string_compose (
288 "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
290 _private_capture_latency.min,
291 _private_capture_latency.max));
294 /* push to public (port system) location so that everyone else can see it */
296 set_public_latency_range (range, playback);
300 Port::private_latency_range (bool playback) const
303 DEBUG_TRACE (DEBUG::Latency, string_compose (
304 "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
306 _private_playback_latency.min,
307 _private_playback_latency.max));
308 return _private_playback_latency;
310 DEBUG_TRACE (DEBUG::Latency, string_compose (
311 "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
313 _private_playback_latency.min,
314 _private_playback_latency.max));
315 return _private_capture_latency;
320 Port::public_latency_range (bool /*playback*/) const
324 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
326 DEBUG_TRACE (DEBUG::Latency, string_compose (
327 "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
328 name(), r.min, r.max,
329 sends_output() ? "PLAYBACK" : "CAPTURE"));
334 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
336 vector<string> connections;
338 get_connections (connections);
340 if (!connections.empty()) {
342 range.min = ~((jack_nframes_t) 0);
345 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
347 for (vector<string>::const_iterator c = connections.begin();
348 c != connections.end(); ++c) {
352 if (!AudioEngine::instance()->port_is_mine (*c)) {
354 /* port belongs to some other port-system client, use
355 * the port engine to lookup its latency information.
358 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
361 lr = port_engine.get_latency_range (remote_port, playback);
363 DEBUG_TRACE (DEBUG::Latency, string_compose (
364 "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
365 name(), *c, lr.min, lr.max));
367 range.min = min (range.min, lr.min);
368 range.max = max (range.max, lr.max);
373 /* port belongs to this instance of ardour,
374 so look up its latency information
375 internally, because our published/public
376 values already contain our plugin
377 latency compensation.
380 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
382 lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
383 DEBUG_TRACE (DEBUG::Latency, string_compose (
384 "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
385 name(), *c, lr.min, lr.max));
387 range.min = min (range.min, lr.min);
388 range.max = max (range.max, lr.max);
394 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
399 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
405 _port_handle = port_engine.register_port (_name, type(), _flags);
407 if (_port_handle == 0) {
408 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
421 /* caller must hold process lock; intended to be used only after reestablish() */
423 for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
432 /** @param n Short port name (no port-system client name) */
434 Port::set_name (std::string const & n)
440 int const r = port_engine.set_port_name (_port_handle, n);
443 AudioEngine::instance()->port_renamed (_name, n);
452 Port::physically_connected () const
454 return port_engine.physically_connected (_port_handle);