globally remove all trailing whitespace from ardour code base.
[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
87 std::string
88 Port::pretty_name(bool fallback_to_name) const
89 {
90         if (_port_handle) {
91                 std::string value;
92                 std::string type;
93                 if (0 == port_engine.get_port_property (_port_handle,
94                                         "http://jackaudio.org/metadata/pretty-name",
95                                         value, type))
96                 {
97                         return value;
98                 }
99         }
100         if (fallback_to_name) {
101                 return name ();
102         }
103         return "";
104 }
105
106 void
107 Port::drop ()
108 {
109         if (_port_handle) {
110                 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
111                 port_engine.unregister_port (_port_handle);
112                 _port_handle = 0;
113         }
114 }
115
116 /** @return true if this port is connected to anything */
117 bool
118 Port::connected () const
119 {
120         if (_port_handle) {
121                 return (port_engine.connected (_port_handle) != 0);
122         }
123         return false;
124 }
125
126 int
127 Port::disconnect_all ()
128 {
129         if (_port_handle) {
130                 
131                 port_engine.disconnect_all (_port_handle);
132                 _connections.clear ();
133                 
134                 /* a cheaper, less hacky way to do boost::shared_from_this() ...
135                  */
136                 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
137                 PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
138         }
139
140         return 0;
141 }
142
143 /** @param o Port name
144  * @return true if this port is connected to o, otherwise false.
145  */
146 bool
147 Port::connected_to (std::string const & o) const
148 {
149         if (!_port_handle) {
150                 return false;
151         }
152
153         if (!port_engine.available()) {
154                 return false;
155         }
156
157         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
158 }
159
160 int
161 Port::get_connections (std::vector<std::string> & c) const
162 {
163         if (!port_engine.available()) {
164                 c.insert (c.end(), _connections.begin(), _connections.end());
165                 return c.size();
166         }
167
168         if (_port_handle) {
169                 return port_engine.get_connections (_port_handle, c);
170         }
171
172         return 0;
173 }
174
175 int
176 Port::connect (std::string const & other)
177 {
178         std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
179         std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
180
181         int r = 0;
182
183         if (_connecting_blocked) {
184                 return r;
185         }
186
187         if (sends_output ()) {
188                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
189                 r = port_engine.connect (our_name, other_name);
190         } else {
191                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
192                 r = port_engine.connect (other_name, our_name);
193         }
194
195         if (r == 0) {
196                 _connections.insert (other);
197         }
198
199         return r;
200 }
201
202 int
203 Port::disconnect (std::string const & other)
204 {
205         std::string const other_fullname = port_manager->make_port_name_non_relative (other);
206         std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
207
208         int r = 0;
209
210         if (sends_output ()) {
211                 r = port_engine.disconnect (this_fullname, other_fullname);
212         } else {
213                 r = port_engine.disconnect (other_fullname, this_fullname);
214         }
215
216         if (r == 0) {
217                 _connections.erase (other);
218         }
219
220         /* a cheaper, less hacky way to do boost::shared_from_this() ...
221          */
222         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
223         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
224
225         if (pself && pother) {
226                 /* Disconnecting from another Ardour port: need to allow
227                    a check on whether this may affect anything that we
228                    need to know about.
229                 */
230                 PostDisconnect (pself, pother); // emit signal
231         }
232
233         return r;
234 }
235
236
237 bool
238 Port::connected_to (Port* o) const
239 {
240         return connected_to (o->name ());
241 }
242
243 int
244 Port::connect (Port* o)
245 {
246         return connect (o->name ());
247 }
248
249 int
250 Port::disconnect (Port* o)
251 {
252         return disconnect (o->name ());
253 }
254
255 void
256 Port::request_input_monitoring (bool yn)
257 {
258         if (_port_handle) {
259                 port_engine.request_input_monitoring (_port_handle, yn);
260         }
261 }
262
263 void
264 Port::ensure_input_monitoring (bool yn)
265 {
266         if (_port_handle) {
267                 port_engine.ensure_input_monitoring (_port_handle, yn);
268         }
269 }
270
271 bool
272 Port::monitoring_input () const
273 {
274         if (_port_handle) {
275                 return port_engine.monitoring_input (_port_handle);
276         }
277         return false;
278 }
279
280 void
281 Port::reset ()
282 {
283         _last_monitor = false;
284 }
285
286 void
287 Port::cycle_start (pframes_t)
288 {
289         _port_buffer_offset = 0;
290 }
291
292 void
293 Port::increment_port_buffer_offset (pframes_t nframes)
294 {
295         _port_buffer_offset += nframes;
296 }
297
298 void
299 Port::set_public_latency_range (LatencyRange& range, bool playback) const
300 {
301         /* this sets the visible latency that the rest of the port system
302            sees. because we do latency compensation, all (most) of our visible
303            port latency values are identical.
304         */
305
306         DEBUG_TRACE (DEBUG::Latency,
307                      string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
308                                      name(), range.min, range.max,
309                                      (playback ? "PLAYBACK" : "CAPTURE")));;
310
311         if (_port_handle) {
312                 port_engine.set_latency_range (_port_handle, playback, range);
313         }
314 }
315
316 void
317 Port::set_private_latency_range (LatencyRange& range, bool playback)
318 {
319         if (playback) {
320                 _private_playback_latency = range;
321                 DEBUG_TRACE (DEBUG::Latency, string_compose (
322                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
323                                      name(),
324                                      _private_playback_latency.min,
325                                      _private_playback_latency.max));
326         } else {
327                 _private_capture_latency = range;
328                 DEBUG_TRACE (DEBUG::Latency, string_compose (
329                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
330                                      name(),
331                                      _private_capture_latency.min,
332                                      _private_capture_latency.max));
333         }
334
335         /* push to public (port system) location so that everyone else can see it */
336
337         set_public_latency_range (range, playback);
338 }
339
340 const LatencyRange&
341 Port::private_latency_range (bool playback) const
342 {
343         if (playback) {
344                 DEBUG_TRACE (DEBUG::Latency, string_compose (
345                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
346                                      name(),
347                                      _private_playback_latency.min,
348                                      _private_playback_latency.max));
349                 return _private_playback_latency;
350         } else {
351                 DEBUG_TRACE (DEBUG::Latency, string_compose (
352                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
353                                      name(),
354                                      _private_playback_latency.min,
355                                      _private_playback_latency.max));
356                 return _private_capture_latency;
357         }
358 }
359
360 LatencyRange
361 Port::public_latency_range (bool /*playback*/) const
362 {
363         LatencyRange r;
364
365
366         if (_port_handle) {
367                 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
368                 
369                 DEBUG_TRACE (DEBUG::Latency, string_compose (
370                                      "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
371                                      name(), r.min, r.max,
372                                      sends_output() ? "PLAYBACK" : "CAPTURE"));
373         }
374
375         return r;
376 }
377
378 void
379 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
380 {
381         vector<string> connections;
382
383         get_connections (connections);
384
385         if (!connections.empty()) {
386
387                 range.min = ~((pframes_t) 0);
388                 range.max = 0;
389
390                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
391
392                 for (vector<string>::const_iterator c = connections.begin();
393                      c != connections.end(); ++c) {
394
395                         LatencyRange lr;
396
397                         if (!AudioEngine::instance()->port_is_mine (*c)) {
398
399                                 /* port belongs to some other port-system client, use
400                                  * the port engine to lookup its latency information.
401                                  */
402
403                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
404
405                                 if (remote_port) {
406                                         lr = port_engine.get_latency_range (remote_port, playback);
407
408                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
409                                                              "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
410                                                              name(), *c, lr.min, lr.max));
411
412                                         range.min = min (range.min, lr.min);
413                                         range.max = max (range.max, lr.max);
414                                 }
415
416                         } else {
417
418                                 /* port belongs to this instance of ardour,
419                                    so look up its latency information
420                                    internally, because our published/public
421                                    values already contain our plugin
422                                    latency compensation.
423                                 */
424
425                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
426                                 if (remote_port) {
427                                         lr = remote_port->private_latency_range ((playback ? true : false));
428                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
429                                                              "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
430                                                              name(), *c, lr.min, lr.max));
431
432                                         range.min = min (range.min, lr.min);
433                                         range.max = max (range.max, lr.max);
434                                 }
435                         }
436                 }
437
438         } else {
439                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
440                 range.min = 0;
441                 range.max = 0;
442         }
443
444         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
445 }
446
447 int
448 Port::reestablish ()
449 {
450         DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
451         _port_handle = port_engine.register_port (_name, type(), _flags);
452
453         if (_port_handle == 0) {
454                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
455                 return -1;
456         }
457
458         reset ();
459
460         return 0;
461 }
462
463
464 int
465 Port::reconnect ()
466 {
467         /* caller must hold process lock; intended to be used only after reestablish() */
468
469         DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
470
471         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
472                 if (connect (*i)) {
473                         return -1;
474                 }
475         }
476
477         return 0;
478 }
479
480 /** @param n Short port name (no port-system client name) */
481 int
482 Port::set_name (std::string const & n)
483 {
484         if (n == _name || !_port_handle) {
485                 return 0;
486         }
487
488         int const r = port_engine.set_port_name (_port_handle, n);
489
490         if (r == 0) {
491                 AudioEngine::instance()->port_renamed (_name, n);
492                 _name = n;
493         }
494
495
496         return r;
497 }
498
499 bool
500 Port::physically_connected () const
501 {
502         if (!_port_handle) {
503                 return false;
504         }
505
506         return port_engine.physically_connected (_port_handle);
507 }
508
509 XMLNode&
510 Port::get_state () const
511 {
512         XMLNode* root = new XMLNode (state_node_name);
513
514         root->add_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
515
516         if (receives_input()) {
517                 root->add_property (X_("direction"), X_("input"));
518         } else {
519                 root->add_property (X_("direction"), X_("output"));
520         }
521
522         vector<string> c;
523         
524         get_connections (c);
525
526         for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
527                 XMLNode* child = new XMLNode (X_("Connection"));
528                 child->add_property (X_("other"), *i);
529                 root->add_child_nocopy (*child);
530         }
531
532         return *root;
533 }
534
535 int
536 Port::set_state (const XMLNode& node, int)
537 {
538         const XMLProperty* prop;
539
540         if (node.name() != state_node_name) {
541                 return -1;
542         }
543
544         if ((prop = node.property (X_("name"))) != 0) {
545                 set_name (prop->value());
546         }
547
548         const XMLNodeList& children (node.children());
549
550         _connections.clear ();
551
552         for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
553
554                 if ((*c)->name() != X_("Connection")) {
555                         continue;
556                 }
557                 
558                 if ((prop = (*c)->property (X_("other"))) == 0) {
559                         continue;
560                 }
561
562                 _connections.insert (prop->value());
563         }
564
565         return 0;
566 }