Merge branch 'master' into audioengine
[ardour.git] / libs / ardour / port.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <jack/weakjack.h> // so that we can test for new functions at runtime
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/failed_constructor.h"
29
30 #include "ardour/audioengine.h"
31 #include "ardour/debug.h"
32 #include "ardour/port.h"
33 #include "ardour/port_engine.h"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40
41 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
42 PBD::Signal0<void> Port::PortDrop;
43
44 bool         Port::_connecting_blocked = false;
45 pframes_t    Port::_global_port_buffer_offset = 0;
46 pframes_t    Port::_cycle_nframes = 0;
47
48 /* a handy define to shorten what would otherwise be a needlessly verbose
49  * repeated phrase
50  */
51 #define port_engine AudioEngine::instance()->port_engine()
52 #define port_manager AudioEngine::instance()
53
54 /** @param n Port short name */
55 Port::Port (std::string const & n, DataType t, PortFlags f)
56         : _port_buffer_offset (0)
57         , _name (n)
58         , _flags (f)
59         , _last_monitor (false)
60 {
61         _private_playback_latency.min = 0;
62         _private_playback_latency.max = 0;
63         _private_capture_latency.min = 0;
64         _private_capture_latency.max = 0;
65
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.
69         */
70
71         assert (_name.find_first_of (':') == std::string::npos);
72
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 ();
76         }
77         
78         PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
79 }
80
81 /** Port destructor */
82 Port::~Port ()
83 {
84         drop ();
85 }
86
87 void
88 Port::drop ()
89 {
90         if (_port_handle) {
91                 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
92                 port_engine.unregister_port (_port_handle);
93                 _port_handle = 0;
94         }
95 }
96
97 /** @return true if this port is connected to anything */
98 bool
99 Port::connected () const
100 {
101         return (port_engine.connected (_port_handle) != 0);
102 }
103
104 int
105 Port::disconnect_all ()
106 {
107         port_engine.disconnect_all (_port_handle);
108         _connections.clear ();
109
110         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
111          */
112         boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
113         PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
114
115         return 0;
116 }
117
118 /** @param o Port name
119  * @return true if this port is connected to o, otherwise false.
120  */
121 bool
122 Port::connected_to (std::string const & o) const
123 {
124         if (!port_engine.connected()) {
125                 return false;
126         }
127
128         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
129 }
130
131 int
132 Port::get_connections (std::vector<std::string> & c) const
133 {
134         if (!port_engine.connected()) {
135                 c.insert (c.end(), _connections.begin(), _connections.end());
136                 return c.size();
137         }
138
139         return port_engine.get_connections (_port_handle, c);
140 }
141
142 int
143 Port::connect (std::string const & other)
144 {
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);
147
148         int r = 0;
149
150         if (_connecting_blocked) {
151                 return r;
152         }
153
154         if (sends_output ()) {
155                 r = port_engine.connect (our_name, other_name);
156         } else {
157                 r = port_engine.connect (other_name, our_name);
158         }
159
160         if (r == 0) {
161                 _connections.insert (other);
162         }
163
164         return r;
165 }
166
167 int
168 Port::disconnect (std::string const & other)
169 {
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);
172
173         int r = 0;
174
175         if (sends_output ()) {
176                 r = port_engine.disconnect (this_fullname, other_fullname);
177         } else {
178                 r = port_engine.disconnect (other_fullname, this_fullname);
179         }
180
181         if (r == 0) {
182                 _connections.erase (other);
183         }
184
185         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
186          */
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);
189
190         if (pself && pother) {
191                 /* Disconnecting from another Ardour port: need to allow
192                    a check on whether this may affect anything that we
193                    need to know about.
194                 */
195                 PostDisconnect (pself, pother); // emit signal 
196         }
197
198         return r;
199 }
200
201
202 bool
203 Port::connected_to (Port* o) const
204 {
205         return connected_to (o->name ());
206 }
207
208 int
209 Port::connect (Port* o)
210 {
211         return connect (o->name ());
212 }
213
214 int
215 Port::disconnect (Port* o)
216 {
217         return disconnect (o->name ());
218 }
219
220 void
221 Port::request_input_monitoring (bool yn)
222 {
223         port_engine.request_input_monitoring (_port_handle, yn);
224 }
225
226 void
227 Port::ensure_input_monitoring (bool yn)
228 {
229         port_engine.ensure_input_monitoring (_port_handle, yn);
230 }
231
232 bool
233 Port::monitoring_input () const
234 {
235         
236         return port_engine.monitoring_input (_port_handle);
237 }
238
239 void
240 Port::reset ()
241 {
242         _last_monitor = false;
243 }
244
245 void
246 Port::cycle_start (pframes_t)
247 {
248         _port_buffer_offset = 0;
249 }
250
251 void
252 Port::increment_port_buffer_offset (pframes_t nframes)
253 {
254         _port_buffer_offset += nframes;
255 }
256
257 void
258 Port::set_public_latency_range (LatencyRange& range, bool playback) const
259 {
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.
263         */
264
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")));;
269
270         port_engine.set_latency_range (_port_handle, playback, range);
271 }
272
273 void
274 Port::set_private_latency_range (LatencyRange& range, bool playback)
275 {
276         if (playback) {
277                 _private_playback_latency = range;
278                 DEBUG_TRACE (DEBUG::Latency, string_compose (
279                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
280                                      name(),
281                                      _private_playback_latency.min,
282                                      _private_playback_latency.max));
283         } else {
284                 _private_capture_latency = range;
285                 DEBUG_TRACE (DEBUG::Latency, string_compose (
286                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
287                                      name(),
288                                      _private_capture_latency.min,
289                                      _private_capture_latency.max));
290         }
291
292         /* push to public (port system) location so that everyone else can see it */
293
294         set_public_latency_range (range, playback);
295 }
296
297 const LatencyRange&
298 Port::private_latency_range (bool playback) const
299 {
300         if (playback) {
301                 DEBUG_TRACE (DEBUG::Latency, string_compose (
302                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
303                                      name(),
304                                      _private_playback_latency.min,
305                                      _private_playback_latency.max));
306                 return _private_playback_latency;
307         } else {
308                 DEBUG_TRACE (DEBUG::Latency, string_compose (
309                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
310                                      name(),
311                                      _private_playback_latency.min,
312                                      _private_playback_latency.max));
313                 return _private_capture_latency;
314         }
315 }
316
317 LatencyRange
318 Port::public_latency_range (bool /*playback*/) const
319 {
320         LatencyRange r;
321
322         r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
323
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"));
328         return r;
329 }
330
331 void
332 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
333 {
334         vector<string> connections;
335
336         get_connections (connections);
337
338         if (!connections.empty()) {
339
340                 range.min = ~((pframes_t) 0);
341                 range.max = 0;
342
343                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
344
345                 for (vector<string>::const_iterator c = connections.begin();
346                      c != connections.end(); ++c) {
347
348                         LatencyRange lr;
349
350                         if (!AudioEngine::instance()->port_is_mine (*c)) {
351
352                                 /* port belongs to some other port-system client, use
353                                  * the port engine to lookup its latency information.
354                                  */
355
356                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
357
358                                 if (remote_port) {
359                                         lr = port_engine.get_latency_range (remote_port, playback);
360
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));
364
365                                         range.min = min (range.min, lr.min);
366                                         range.max = max (range.max, lr.max);
367                                 }
368
369                         } else {
370
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.
376                                 */
377
378                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
379                                 if (remote_port) {
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));
384
385                                         range.min = min (range.min, lr.min);
386                                         range.max = max (range.max, lr.max);
387                                 }
388                         }
389                 }
390
391         } else {
392                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
393                 range.min = 0;
394                 range.max = 0;
395         }
396
397         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
398 }
399
400 int
401 Port::reestablish ()
402 {
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);
405
406         if (_port_handle == 0) {
407                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
408                 return -1;
409         }
410
411         reset ();
412
413         return 0;
414 }
415
416
417 int
418 Port::reconnect ()
419 {
420         /* caller must hold process lock; intended to be used only after reestablish() */
421
422         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
423                 if (connect (*i)) {
424                         return -1;
425                 }
426         }
427
428         return 0;
429 }
430
431 /** @param n Short port name (no port-system client name) */
432 int
433 Port::set_name (std::string const & n)
434 {
435         if (n == _name) {
436                 return 0;
437         }
438
439         int const r = port_engine.set_port_name (_port_handle, n);
440
441         if (r == 0) {
442                 AudioEngine::instance()->port_renamed (_name, n);
443                 _name = n;
444         }
445
446
447         return r;
448 }
449
450 bool
451 Port::physically_connected () const
452 {
453         return port_engine.physically_connected (_port_handle);
454 }
455