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