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