19bebd103fe4e3c3d13fb439b1b53f71ccc68585
[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 "pbd/compose.h"
25 #include "pbd/error.h"
26 #include "pbd/failed_constructor.h"
27
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/port.h"
31 #include "ardour/port_engine.h"
32
33 #include "i18n.h"
34
35 using namespace std;
36 using namespace ARDOUR;
37 using namespace PBD;
38
39 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
40 PBD::Signal0<void> Port::PortDrop;
41
42 bool         Port::_connecting_blocked = false;
43 pframes_t    Port::_global_port_buffer_offset = 0;
44 pframes_t    Port::_cycle_nframes = 0;
45 std::string  Port::state_node_name = X_("Port");
46
47 /* a handy define to shorten what would otherwise be a needlessly verbose
48  * repeated phrase
49  */
50 #define port_engine AudioEngine::instance()->port_engine()
51 #define port_manager AudioEngine::instance()
52
53 /** @param n Port short name */
54 Port::Port (std::string const & n, DataType t, PortFlags f)
55         : _port_buffer_offset (0)
56         , _name (n)
57         , _flags (f)
58         , _last_monitor (false)
59 {
60         _private_playback_latency.min = 0;
61         _private_playback_latency.max = 0;
62         _private_capture_latency.min = 0;
63         _private_capture_latency.max = 0;
64
65         /* Unfortunately we have to pass the DataType into this constructor so that
66            we can create the right kind of port; aside from this we'll use the
67            virtual function type () to establish type.
68         */
69
70         assert (_name.find_first_of (':') == std::string::npos);
71
72         if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
73                 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
74                 throw failed_constructor ();
75         }
76         
77         PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
78 }
79
80 /** Port destructor */
81 Port::~Port ()
82 {
83         drop ();
84 }
85
86 void
87 Port::drop ()
88 {
89         if (_port_handle) {
90                 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
91                 port_engine.unregister_port (_port_handle);
92                 _port_handle = 0;
93         }
94 }
95
96 /** @return true if this port is connected to anything */
97 bool
98 Port::connected () const
99 {
100         return (port_engine.connected (_port_handle) != 0);
101 }
102
103 int
104 Port::disconnect_all ()
105 {
106         port_engine.disconnect_all (_port_handle);
107         _connections.clear ();
108
109         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
110          */
111         boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
112         PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
113
114         return 0;
115 }
116
117 /** @param o Port name
118  * @return true if this port is connected to o, otherwise false.
119  */
120 bool
121 Port::connected_to (std::string const & o) const
122 {
123         if (!port_engine.available()) {
124                 return false;
125         }
126
127         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
128 }
129
130 int
131 Port::get_connections (std::vector<std::string> & c) const
132 {
133         if (!port_engine.available()) {
134                 c.insert (c.end(), _connections.begin(), _connections.end());
135                 return c.size();
136         }
137
138         return port_engine.get_connections (_port_handle, c);
139 }
140
141 int
142 Port::connect (std::string const & other)
143 {
144         std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
145         std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
146
147         int r = 0;
148
149         if (_connecting_blocked) {
150                 return r;
151         }
152
153         if (sends_output ()) {
154                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
155                 r = port_engine.connect (our_name, other_name);
156         } else {
157                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
158                 r = port_engine.connect (other_name, our_name);
159         }
160
161         if (r == 0) {
162                 _connections.insert (other);
163         }
164
165         return r;
166 }
167
168 int
169 Port::disconnect (std::string const & other)
170 {
171         std::string const other_fullname = port_manager->make_port_name_non_relative (other);
172         std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
173
174         int r = 0;
175
176         if (sends_output ()) {
177                 r = port_engine.disconnect (this_fullname, other_fullname);
178         } else {
179                 r = port_engine.disconnect (other_fullname, this_fullname);
180         }
181
182         if (r == 0) {
183                 _connections.erase (other);
184         }
185
186         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
187          */
188         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
189         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
190
191         if (pself && pother) {
192                 /* Disconnecting from another Ardour port: need to allow
193                    a check on whether this may affect anything that we
194                    need to know about.
195                 */
196                 PostDisconnect (pself, pother); // emit signal 
197         }
198
199         return r;
200 }
201
202
203 bool
204 Port::connected_to (Port* o) const
205 {
206         return connected_to (o->name ());
207 }
208
209 int
210 Port::connect (Port* o)
211 {
212         return connect (o->name ());
213 }
214
215 int
216 Port::disconnect (Port* o)
217 {
218         return disconnect (o->name ());
219 }
220
221 void
222 Port::request_input_monitoring (bool yn)
223 {
224         port_engine.request_input_monitoring (_port_handle, yn);
225 }
226
227 void
228 Port::ensure_input_monitoring (bool yn)
229 {
230         port_engine.ensure_input_monitoring (_port_handle, yn);
231 }
232
233 bool
234 Port::monitoring_input () const
235 {
236         
237         return port_engine.monitoring_input (_port_handle);
238 }
239
240 void
241 Port::reset ()
242 {
243         _last_monitor = false;
244 }
245
246 void
247 Port::cycle_start (pframes_t)
248 {
249         _port_buffer_offset = 0;
250 }
251
252 void
253 Port::increment_port_buffer_offset (pframes_t nframes)
254 {
255         _port_buffer_offset += nframes;
256 }
257
258 void
259 Port::set_public_latency_range (LatencyRange& range, bool playback) const
260 {
261         /* this sets the visible latency that the rest of the port system
262            sees. because we do latency compensation, all (most) of our visible
263            port latency values are identical.
264         */
265
266         DEBUG_TRACE (DEBUG::Latency,
267                      string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
268                                      name(), range.min, range.max,
269                                      (playback ? "PLAYBACK" : "CAPTURE")));;
270
271         port_engine.set_latency_range (_port_handle, playback, range);
272 }
273
274 void
275 Port::set_private_latency_range (LatencyRange& range, bool playback)
276 {
277         if (playback) {
278                 _private_playback_latency = range;
279                 DEBUG_TRACE (DEBUG::Latency, string_compose (
280                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
281                                      name(),
282                                      _private_playback_latency.min,
283                                      _private_playback_latency.max));
284         } else {
285                 _private_capture_latency = range;
286                 DEBUG_TRACE (DEBUG::Latency, string_compose (
287                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
288                                      name(),
289                                      _private_capture_latency.min,
290                                      _private_capture_latency.max));
291         }
292
293         /* push to public (port system) location so that everyone else can see it */
294
295         set_public_latency_range (range, playback);
296 }
297
298 const LatencyRange&
299 Port::private_latency_range (bool playback) const
300 {
301         if (playback) {
302                 DEBUG_TRACE (DEBUG::Latency, string_compose (
303                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
304                                      name(),
305                                      _private_playback_latency.min,
306                                      _private_playback_latency.max));
307                 return _private_playback_latency;
308         } else {
309                 DEBUG_TRACE (DEBUG::Latency, string_compose (
310                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
311                                      name(),
312                                      _private_playback_latency.min,
313                                      _private_playback_latency.max));
314                 return _private_capture_latency;
315         }
316 }
317
318 LatencyRange
319 Port::public_latency_range (bool /*playback*/) const
320 {
321         LatencyRange r;
322
323         r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
324
325         DEBUG_TRACE (DEBUG::Latency, string_compose (
326                              "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
327                              name(), r.min, r.max,
328                              sends_output() ? "PLAYBACK" : "CAPTURE"));
329         return r;
330 }
331
332 void
333 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
334 {
335         vector<string> connections;
336
337         get_connections (connections);
338
339         if (!connections.empty()) {
340
341                 range.min = ~((pframes_t) 0);
342                 range.max = 0;
343
344                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
345
346                 for (vector<string>::const_iterator c = connections.begin();
347                      c != connections.end(); ++c) {
348
349                         LatencyRange lr;
350
351                         if (!AudioEngine::instance()->port_is_mine (*c)) {
352
353                                 /* port belongs to some other port-system client, use
354                                  * the port engine to lookup its latency information.
355                                  */
356
357                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
358
359                                 if (remote_port) {
360                                         lr = port_engine.get_latency_range (remote_port, playback);
361
362                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
363                                                              "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
364                                                              name(), *c, lr.min, lr.max));
365
366                                         range.min = min (range.min, lr.min);
367                                         range.max = max (range.max, lr.max);
368                                 }
369
370                         } else {
371
372                                 /* port belongs to this instance of ardour,
373                                    so look up its latency information
374                                    internally, because our published/public
375                                    values already contain our plugin
376                                    latency compensation.
377                                 */
378
379                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
380                                 if (remote_port) {
381                                         lr = remote_port->private_latency_range ((playback ? true : false));
382                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
383                                                              "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
384                                                              name(), *c, lr.min, lr.max));
385
386                                         range.min = min (range.min, lr.min);
387                                         range.max = max (range.max, lr.max);
388                                 }
389                         }
390                 }
391
392         } else {
393                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
394                 range.min = 0;
395                 range.max = 0;
396         }
397
398         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
399 }
400
401 int
402 Port::reestablish ()
403 {
404         DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
405         _port_handle = port_engine.register_port (_name, type(), _flags);
406
407         if (_port_handle == 0) {
408                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
409                 return -1;
410         }
411
412         reset ();
413
414         return 0;
415 }
416
417
418 int
419 Port::reconnect ()
420 {
421         /* caller must hold process lock; intended to be used only after reestablish() */
422
423         DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
424
425         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
426                 if (connect (*i)) {
427                         return -1;
428                 }
429         }
430
431         return 0;
432 }
433
434 /** @param n Short port name (no port-system client name) */
435 int
436 Port::set_name (std::string const & n)
437 {
438         if (n == _name) {
439                 return 0;
440         }
441
442         int const r = port_engine.set_port_name (_port_handle, n);
443
444         if (r == 0) {
445                 AudioEngine::instance()->port_renamed (_name, n);
446                 _name = n;
447         }
448
449
450         return r;
451 }
452
453 bool
454 Port::physically_connected () const
455 {
456         return port_engine.physically_connected (_port_handle);
457 }
458
459 XMLNode&
460 Port::get_state () const
461 {
462         XMLNode* root = new XMLNode (state_node_name);
463
464         root->add_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
465
466         if (receives_input()) {
467                 root->add_property (X_("direction"), X_("input"));
468         } else {
469                 root->add_property (X_("direction"), X_("output"));
470         }
471
472         vector<string> c;
473         
474         get_connections (c);
475
476         for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
477                 XMLNode* child = new XMLNode (X_("Connection"));
478                 child->add_property (X_("other"), *i);
479                 root->add_child_nocopy (*child);
480         }
481
482         return *root;
483 }
484
485 int
486 Port::set_state (const XMLNode& node, int)
487 {
488         const XMLProperty* prop;
489
490         if (node.name() != state_node_name) {
491                 return -1;
492         }
493
494         if ((prop = node.property (X_("name"))) != 0) {
495                 set_name (prop->value());
496         }
497
498         const XMLNodeList& children (node.children());
499
500         _connections.clear ();
501
502         for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
503
504                 if ((*c)->name() != X_("Connection")) {
505                         continue;
506                 }
507                 
508                 if ((prop = (*c)->property (X_("other"))) == 0) {
509                         continue;
510                 }
511
512                 _connections.insert (prop->value());
513         }
514
515         return 0;
516 }