Remove unused per-port buffer offset
[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 "pbd/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 PBD::Signal0<void> Port::PortSignalDrop;
42
43 bool         Port::_connecting_blocked = false;
44 pframes_t    Port::_global_port_buffer_offset = 0;
45 pframes_t    Port::_cycle_nframes = 0;
46 double       Port::_speed_ratio = 1.0;
47 std::string  Port::state_node_name = X_("Port");
48 const uint32_t Port::_resampler_quality = 12;
49
50 /* a handy define to shorten what would otherwise be a needlessly verbose
51  * repeated phrase
52  */
53 #define port_engine AudioEngine::instance()->port_engine()
54 #define port_manager AudioEngine::instance()
55
56 /** @param n Port short name */
57 Port::Port (std::string const & n, DataType t, PortFlags f)
58         : _name (n)
59         , _flags (f)
60         , _last_monitor (false)
61 {
62         _private_playback_latency.min = 0;
63         _private_playback_latency.max = 0;
64         _private_capture_latency.min = 0;
65         _private_capture_latency.max = 0;
66
67         /* Unfortunately we have to pass the DataType into this constructor so that
68            we can create the right kind of port; aside from this we'll use the
69            virtual function type () to establish type.
70         */
71
72         assert (_name.find_first_of (':') == std::string::npos);
73
74         if (!port_engine.available ()) {
75                 DEBUG_TRACE (DEBUG::Ports, string_compose ("port-engine n/a postpone registering %1\n", name()));
76                 _port_handle = 0; // created during ::reestablish() later
77         } else 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 ();
80         }
81         DEBUG_TRACE (DEBUG::Ports, string_compose ("registed port %1 handle %2\n", name(), _port_handle));
82
83         PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
84         PortSignalDrop.connect_same_thread (drop_connection, boost::bind (&Port::signal_drop, this));
85         port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection,
86                         boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5));
87 }
88
89 /** Port destructor */
90 Port::~Port ()
91 {
92         drop ();
93 }
94
95
96 std::string
97 Port::pretty_name(bool fallback_to_name) const
98 {
99         if (_port_handle) {
100                 std::string value;
101                 std::string type;
102                 if (0 == port_engine.get_port_property (_port_handle,
103                                         "http://jackaudio.org/metadata/pretty-name",
104                                         value, type))
105                 {
106                         return value;
107                 }
108         }
109         if (fallback_to_name) {
110                 return name ();
111         }
112         return "";
113 }
114
115 bool
116 Port::set_pretty_name(const std::string& n)
117 {
118         if (_port_handle) {
119                 if (0 == port_engine.set_port_property (_port_handle,
120                                         "http://jackaudio.org/metadata/pretty-name", n, ""))
121                 {
122                         return true;
123                 }
124         }
125         return false;
126 }
127
128 void
129 Port::signal_drop ()
130 {
131         engine_connection.disconnect ();
132 }
133
134 void
135 Port::drop ()
136 {
137         if (_port_handle) {
138                 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
139                 port_engine.unregister_port (_port_handle);
140                 _port_handle = 0;
141         }
142 }
143
144 void
145 Port::port_connected_or_disconnected (boost::weak_ptr<Port> w0, boost::weak_ptr<Port> w1, bool con)
146 {
147         if (con) {
148                 /* we're only interested in disconnect */
149                 return;
150         }
151         boost::shared_ptr<Port> p0 = w0.lock ();
152         boost::shared_ptr<Port> p1 = w1.lock ();
153         /* a cheaper, less hacky way to do boost::shared_from_this() ...  */
154         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
155
156         if (p0 == pself) {
157                 PostDisconnect (p0, p1); // emit signal
158         }
159         if (p1 == pself) {
160                 PostDisconnect (p1, p0); // emit signal
161         }
162 }
163
164 /** @return true if this port is connected to anything */
165 bool
166 Port::connected () const
167 {
168         if (_port_handle) {
169                 return (port_engine.connected (_port_handle) != 0);
170         }
171         return false;
172 }
173
174 int
175 Port::disconnect_all ()
176 {
177         if (_port_handle) {
178
179                 std::vector<std::string> connections;
180                 get_connections (connections);
181
182                 port_engine.disconnect_all (_port_handle);
183                 _connections.clear ();
184
185                 /* a cheaper, less hacky way to do boost::shared_from_this() ...
186                  */
187                 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
188                 for (vector<string>::const_iterator c = connections.begin(); c != connections.end() && pself; ++c) {
189                         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (*c);
190                         if (pother) {
191                                 PostDisconnect (pself, pother); // emit signal
192                         }
193                 }
194         }
195
196         return 0;
197 }
198
199 /** @param o Port name
200  * @return true if this port is connected to o, otherwise false.
201  */
202 bool
203 Port::connected_to (std::string const & o) const
204 {
205         if (!_port_handle) {
206                 return false;
207         }
208
209         if (!port_engine.available()) {
210                 return false;
211         }
212
213         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
214 }
215
216 int
217 Port::get_connections (std::vector<std::string> & c) const
218 {
219         if (!port_engine.available()) {
220                 c.insert (c.end(), _connections.begin(), _connections.end());
221                 return c.size();
222         }
223
224         if (_port_handle) {
225                 return port_engine.get_connections (_port_handle, c);
226         }
227
228         return 0;
229 }
230
231 int
232 Port::connect (std::string const & other)
233 {
234         std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
235         std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
236
237         int r = 0;
238
239         if (_connecting_blocked) {
240                 return r;
241         }
242
243         if (sends_output ()) {
244                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
245                 r = port_engine.connect (our_name, other_name);
246         } else {
247                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
248                 r = port_engine.connect (other_name, our_name);
249         }
250
251         if (r == 0) {
252                 _connections.insert (other);
253         }
254
255         return r;
256 }
257
258 int
259 Port::disconnect (std::string const & other)
260 {
261         std::string const other_fullname = port_manager->make_port_name_non_relative (other);
262         std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
263
264         int r = 0;
265
266         if (sends_output ()) {
267                 r = port_engine.disconnect (this_fullname, other_fullname);
268         } else {
269                 r = port_engine.disconnect (other_fullname, this_fullname);
270         }
271
272         if (r == 0) {
273                 _connections.erase (other);
274         }
275
276         /* a cheaper, less hacky way to do boost::shared_from_this() ...  */
277         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
278         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
279
280         if (pself && pother) {
281                 /* Disconnecting from another Ardour port: need to allow
282                    a check on whether this may affect anything that we
283                    need to know about.
284                 */
285                 PostDisconnect (pself, pother); // emit signal
286         }
287
288         return r;
289 }
290
291
292 bool
293 Port::connected_to (Port* o) const
294 {
295         return connected_to (o->name ());
296 }
297
298 int
299 Port::connect (Port* o)
300 {
301         return connect (o->name ());
302 }
303
304 int
305 Port::disconnect (Port* o)
306 {
307         return disconnect (o->name ());
308 }
309
310 void
311 Port::request_input_monitoring (bool yn)
312 {
313         if (_port_handle) {
314                 port_engine.request_input_monitoring (_port_handle, yn);
315         }
316 }
317
318 void
319 Port::ensure_input_monitoring (bool yn)
320 {
321         if (_port_handle) {
322                 port_engine.ensure_input_monitoring (_port_handle, yn);
323         }
324 }
325
326 bool
327 Port::monitoring_input () const
328 {
329         if (_port_handle) {
330                 return port_engine.monitoring_input (_port_handle);
331         }
332         return false;
333 }
334
335 void
336 Port::reset ()
337 {
338         _last_monitor = false;
339 }
340
341 void
342 Port::cycle_start (pframes_t)
343 {
344 }
345
346 void
347 Port::set_public_latency_range (LatencyRange const& range, bool playback) const
348 {
349         /* this sets the visible latency that the rest of the port system
350            sees. because we do latency compensation, all (most) of our visible
351            port latency values are identical.
352         */
353
354         DEBUG_TRACE (DEBUG::Latency,
355                      string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
356                                      name(), range.min, range.max,
357                                      (playback ? "PLAYBACK" : "CAPTURE")));;
358
359         if (_port_handle) {
360                 LatencyRange r (range);
361                 if (externally_connected ()) {
362 #if 0
363                         r.min *= _speed_ratio;
364                         r.max *= _speed_ratio;
365 #endif
366                         r.min += (_resampler_quality - 1);
367                         r.max += (_resampler_quality - 1);
368                 }
369                 port_engine.set_latency_range (_port_handle, playback, r);
370         }
371 }
372
373 void
374 Port::set_private_latency_range (LatencyRange& range, bool playback)
375 {
376         if (playback) {
377                 _private_playback_latency = range;
378                 DEBUG_TRACE (DEBUG::Latency, string_compose (
379                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
380                                      name(),
381                                      _private_playback_latency.min,
382                                      _private_playback_latency.max));
383         } else {
384                 _private_capture_latency = range;
385                 DEBUG_TRACE (DEBUG::Latency, string_compose (
386                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
387                                      name(),
388                                      _private_capture_latency.min,
389                                      _private_capture_latency.max));
390         }
391
392         /* push to public (port system) location so that everyone else can see it */
393
394         set_public_latency_range (range, playback);
395 }
396
397 const LatencyRange&
398 Port::private_latency_range (bool playback) const
399 {
400         if (playback) {
401                 DEBUG_TRACE (DEBUG::Latency, string_compose (
402                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
403                                      name(),
404                                      _private_playback_latency.min,
405                                      _private_playback_latency.max));
406                 return _private_playback_latency;
407         } else {
408                 DEBUG_TRACE (DEBUG::Latency, string_compose (
409                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
410                                      name(),
411                                      _private_playback_latency.min,
412                                      _private_playback_latency.max));
413                 return _private_capture_latency;
414         }
415 }
416
417 LatencyRange
418 Port::public_latency_range (bool /*playback*/) const
419 {
420         LatencyRange r;
421
422
423         if (_port_handle) {
424                 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
425                 if (externally_connected ()) {
426 #if 0
427                         r.min /= _speed_ratio;
428                         r.max /= _speed_ratio;
429 #endif
430                         r.min += (_resampler_quality - 1);
431                         r.max += (_resampler_quality - 1);
432                 }
433
434                 DEBUG_TRACE (DEBUG::Latency, string_compose (
435                                      "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
436                                      name(), r.min, r.max,
437                                      sends_output() ? "PLAYBACK" : "CAPTURE"));
438         }
439
440         return r;
441 }
442
443 void
444 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
445 {
446         vector<string> connections;
447
448         get_connections (connections);
449
450         if (!connections.empty()) {
451
452                 range.min = ~((pframes_t) 0);
453                 range.max = 0;
454
455                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
456
457                 for (vector<string>::const_iterator c = connections.begin();
458                                 c != connections.end(); ++c) {
459
460                         LatencyRange lr;
461
462                         if (!AudioEngine::instance()->port_is_mine (*c)) {
463
464                                 /* port belongs to some other port-system client, use
465                                  * the port engine to lookup its latency information.
466                                  */
467
468                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
469
470                                 if (remote_port) {
471                                         lr = port_engine.get_latency_range (remote_port, playback);
472                                         if (externally_connected ()) {
473 #if 0
474                                                 lr.min /= _speed_ratio;
475                                                 lr.max /= _speed_ratio;
476 #endif
477                                                 lr.min += (_resampler_quality - 1);
478                                                 lr.max += (_resampler_quality - 1);
479                                         }
480
481                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
482                                                                 "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
483                                                                 name(), *c, lr.min, lr.max));
484
485                                         range.min = min (range.min, lr.min);
486                                         range.max = max (range.max, lr.max);
487                                 }
488
489                         } else {
490
491                                 /* port belongs to this instance of ardour,
492                                          so look up its latency information
493                                          internally, because our published/public
494                                          values already contain our plugin
495                                          latency compensation.
496                                          */
497
498                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
499                                 if (remote_port) {
500                                         lr = remote_port->private_latency_range ((playback ? true : false));
501                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
502                                                                 "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
503                                                                 name(), *c, lr.min, lr.max));
504
505                                         range.min = min (range.min, lr.min);
506                                         range.max = max (range.max, lr.max);
507                                 }
508                         }
509                 }
510
511         } else {
512                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
513                 range.min = 0;
514                 range.max = 0;
515         }
516
517         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
518 }
519
520 int
521 Port::reestablish ()
522 {
523         DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
524         _port_handle = port_engine.register_port (_name, type(), _flags);
525
526         if (_port_handle == 0) {
527                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
528                 return -1;
529         }
530
531         DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reestablish %1 handle %2\n", name(), _port_handle));
532
533         reset ();
534
535         port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection,
536                         boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5));
537         return 0;
538 }
539
540
541 int
542 Port::reconnect ()
543 {
544         /* caller must hold process lock; intended to be used only after reestablish() */
545
546         DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
547
548         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
549                 if (connect (*i)) {
550                         return -1;
551                 }
552         }
553
554         return 0;
555 }
556
557 /** @param n Short port name (no port-system client name) */
558 int
559 Port::set_name (std::string const & n)
560 {
561         if (n == _name || !_port_handle) {
562                 return 0;
563         }
564
565         int const r = port_engine.set_port_name (_port_handle, n);
566
567         if (r == 0) {
568                 AudioEngine::instance()->port_renamed (_name, n);
569                 _name = n;
570         }
571
572
573         return r;
574 }
575
576 bool
577 Port::physically_connected () const
578 {
579         if (!_port_handle) {
580                 return false;
581         }
582
583         return port_engine.physically_connected (_port_handle);
584 }
585
586 bool
587 Port::externally_connected () const
588 {
589         if (!_port_handle) {
590                 return false;
591         }
592
593         // TODO: When used with JACK, check if this port
594         // is connected to any non-ardour ports.
595
596         return port_engine.physically_connected (_port_handle);
597 }
598
599 XMLNode&
600 Port::get_state () const
601 {
602         XMLNode* root = new XMLNode (state_node_name);
603
604         root->set_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
605
606         if (receives_input()) {
607                 root->set_property (X_("direction"), X_("input"));
608         } else {
609                 root->set_property (X_("direction"), X_("output"));
610         }
611
612         vector<string> c;
613
614         get_connections (c);
615
616         for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
617                 XMLNode* child = new XMLNode (X_("Connection"));
618                 child->set_property (X_("other"), *i);
619                 root->add_child_nocopy (*child);
620         }
621
622         return *root;
623 }
624
625 int
626 Port::set_state (const XMLNode& node, int)
627 {
628         if (node.name() != state_node_name) {
629                 return -1;
630         }
631
632         std::string str;
633         if (node.get_property (X_("name"), str)) {
634                 set_name (str);
635         }
636
637         const XMLNodeList& children (node.children());
638
639         _connections.clear ();
640
641         for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
642
643                 if ((*c)->name() != X_("Connection")) {
644                         continue;
645                 }
646
647                 if (!(*c)->get_property (X_("other"), str)) {
648                         continue;
649                 }
650
651                 _connections.insert (str);
652         }
653
654         return 0;
655 }
656
657 /*static*/ void
658 Port::set_speed_ratio (double s) {
659         /* see VMResampler::set_rratio() for min/max range */
660         _speed_ratio = std::min (16.0, std::max (0.5, s));
661 }
662
663 /*static*/ void
664 Port::set_cycle_samplecnt (pframes_t n) {
665         _cycle_nframes = floor (n * _speed_ratio);
666 }