avoid redundant IO port reconnections in Tracks runtime case
[ardour.git] / libs / ardour / port_manager.cc
1 /*
2     Copyright (C) 2013 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 #include "pbd/error.h"
21
22 #include "ardour/async_midi_port.h"
23 #include "ardour/audio_backend.h"
24 #include "ardour/audio_port.h"
25 #include "ardour/debug.h"
26 #include "ardour/midi_port.h"
27 #include "ardour/midiport_manager.h"
28 #include "ardour/port_manager.h"
29
30 #include "i18n.h"
31
32 using namespace ARDOUR;
33 using namespace PBD;
34 using std::string;
35 using std::vector;
36
37 PortManager::PortManager ()
38         : ports (new Ports)
39         , _port_remove_in_progress (false)
40 {
41 }
42
43 void
44 PortManager::remove_all_ports ()
45 {
46         /* make sure that JACK callbacks that will be invoked as we cleanup
47          * ports know that they have nothing to do.
48          */
49
50         _port_remove_in_progress = true;
51
52         /* process lock MUST be held by caller
53         */
54
55         {
56                 RCUWriter<Ports> writer (ports);
57                 boost::shared_ptr<Ports> ps = writer.get_copy ();
58                 ps->clear ();
59         }
60
61         /* clear dead wood list in RCU */
62
63         ports.flush ();
64
65         _port_remove_in_progress = false;
66 }
67
68
69 string
70 PortManager::make_port_name_relative (const string& portname) const
71 {
72         if (!_backend) {
73                 return portname;
74         }
75
76         string::size_type len;
77         string::size_type n;
78         string self = _backend->my_name();
79
80         len = portname.length();
81
82         for (n = 0; n < len; ++n) {
83                 if (portname[n] == ':') {
84                         break;
85                 }
86         }
87
88         if ((n != len) && (portname.substr (0, n) == self)) {
89                 return portname.substr (n+1);
90         }
91
92         return portname;
93 }
94
95 string
96 PortManager::make_port_name_non_relative (const string& portname) const
97 {
98         string str;
99
100         if (portname.find_first_of (':') != string::npos) {
101                 return portname;
102         }
103
104         str  = _backend->my_name();
105         str += ':';
106         str += portname;
107
108         return str;
109 }
110
111 std::string
112 PortManager::get_pretty_name_by_name(const std::string& portname) const
113 {
114         PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
115         if (ph) {
116                 std::string value;
117                 std::string type;
118                 if (0 == _backend->get_port_property (ph,
119                                         "http://jackaudio.org/metadata/pretty-name",
120                                         value, type))
121                 {
122                         return value;
123                 }
124         }
125         return "";
126 }
127
128 bool
129 PortManager::port_is_mine (const string& portname) const
130 {
131         if (!_backend) {
132                 return true;
133         }
134
135         string self = _backend->my_name();
136
137         if (portname.find_first_of (':') != string::npos) {
138                 if (portname.substr (0, self.length ()) != self) {
139                         return false;
140                 }
141         }
142
143         return true;
144 }
145
146 bool
147 PortManager::port_is_physical (const std::string& portname) const
148 {
149         if (!_backend) {
150                 return false;
151         }
152
153         PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
154         if (!ph) {
155                 return false;
156         }
157
158         return _backend->port_is_physical (ph);
159 }
160
161 void
162 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
163 {
164         if (!_backend) {
165                 return;
166         }
167         _backend->get_physical_outputs (type, s);
168 }
169  
170 void
171 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
172 {
173         if (!_backend) {
174                 return;
175         }
176
177         _backend->get_physical_inputs (type, s);
178 }
179  
180 ChanCount
181 PortManager::n_physical_outputs () const
182 {
183         if (!_backend) {
184                 return ChanCount::ZERO;
185         }
186
187         return _backend->n_physical_outputs ();
188 }
189  
190 ChanCount
191 PortManager::n_physical_inputs () const
192 {
193         if (!_backend) {
194                 return ChanCount::ZERO;
195         }
196         return _backend->n_physical_inputs ();
197 }
198
199 /** @param name Full or short name of port
200  *  @return Corresponding Port or 0.
201  */
202
203 boost::shared_ptr<Port>
204 PortManager::get_port_by_name (const string& portname)
205 {
206         if (!_backend) {
207                 return boost::shared_ptr<Port>();
208         }
209
210         if (!port_is_mine (portname)) {
211                 /* not an ardour port */
212                 return boost::shared_ptr<Port> ();
213         }
214
215         boost::shared_ptr<Ports> pr = ports.reader();
216         std::string rel = make_port_name_relative (portname);
217         Ports::iterator x = pr->find (rel);
218
219         if (x != pr->end()) {
220                 /* its possible that the port was renamed by some 3rd party and
221                    we don't know about it. check for this (the check is quick
222                    and cheap), and if so, rename the port (which will alter
223                    the port map as a side effect).
224                 */
225                 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
226                 if (check != rel) {
227                         x->second->set_name (check);
228                 }
229                 return x->second;
230         }
231
232         return boost::shared_ptr<Port> ();
233 }
234
235 void
236 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
237 {
238         RCUWriter<Ports> writer (ports);
239         boost::shared_ptr<Ports> p = writer.get_copy();
240         Ports::iterator x = p->find (old_relative_name);
241         
242         if (x != p->end()) {
243                 boost::shared_ptr<Port> port = x->second;
244                 p->erase (x);
245                 p->insert (make_pair (new_relative_name, port));
246         }
247 }
248
249 int
250 PortManager::get_ports (DataType type, PortList& pl)
251 {
252         boost::shared_ptr<Ports> plist = ports.reader();
253         for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
254                 if (p->second->type() == type) {
255                         pl.push_back (p->second);
256                 }
257         }
258         return pl.size();
259 }
260
261 int
262 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
263 {
264         s.clear();
265
266         if (!_backend) {
267                 return 0;
268         }
269
270         return _backend->get_ports (port_name_pattern, type, flags, s);
271 }
272
273 void
274 PortManager::port_registration_failure (const std::string& portname)
275 {
276         if (!_backend) {
277                 return;
278         }
279
280         string full_portname = _backend->my_name();
281         full_portname += ':';
282         full_portname += portname;
283
284
285         PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
286         string reason;
287
288         if (p) {
289                 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
290         } else {
291                 reason = string_compose (_("No more ports are available. You will need to stop %1 and restart with more ports if you need this many tracks."), PROGRAM_NAME);
292         }
293
294         throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
295 }
296
297 boost::shared_ptr<Port>
298 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
299 {
300         boost::shared_ptr<Port> newport;
301
302         try {
303                 if (dtype == DataType::AUDIO) {
304                         DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
305                                                                    portname, input));
306                         newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
307                 } else if (dtype == DataType::MIDI) {
308                         if (async) {
309                                 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
310                                                                            portname, input));
311                                 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
312                         } else {
313                                 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
314                                                                            portname, input));
315                                 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
316                         }
317                 } else {
318                         throw PortRegistrationFailure("unable to create port (unknown type)");
319                 }
320
321                 RCUWriter<Ports> writer (ports);
322                 boost::shared_ptr<Ports> ps = writer.get_copy ();
323                 ps->insert (make_pair (make_port_name_relative (portname), newport));
324
325                 /* writer goes out of scope, forces update */
326
327         }
328
329         catch (PortRegistrationFailure& err) {
330                 throw err;
331         } catch (std::exception& e) {
332                 throw PortRegistrationFailure(string_compose(
333                                 _("unable to create port: %1"), e.what()).c_str());
334         } catch (...) {
335                 throw PortRegistrationFailure("unable to create port (unknown error)");
336         }
337
338         DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
339         return newport;
340 }
341
342 boost::shared_ptr<Port>
343 PortManager::register_input_port (DataType type, const string& portname, bool async)
344 {
345         return register_port (type, portname, true, async);
346 }
347
348 boost::shared_ptr<Port>
349 PortManager::register_output_port (DataType type, const string& portname, bool async)
350 {
351         return register_port (type, portname, false, async);
352 }
353
354 int
355 PortManager::unregister_port (boost::shared_ptr<Port> port)
356 {
357         /* caller must hold process lock */
358
359         {
360                 RCUWriter<Ports> writer (ports);
361                 boost::shared_ptr<Ports> ps = writer.get_copy ();
362                 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
363
364                 if (x != ps->end()) {
365                         ps->erase (x);
366                 }
367
368                 /* writer goes out of scope, forces update */
369         }
370
371         ports.flush ();
372
373         return 0;
374 }
375
376 bool
377 PortManager::connected (const string& port_name)
378 {
379         if (!_backend) {
380                 return false;
381         }
382
383         PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
384
385         if (!handle) {
386                 return false;
387         }
388
389         return _backend->connected (handle);
390 }
391
392 int
393 PortManager::connect (const string& source, const string& destination)
394 {
395         int ret;
396
397         string s = make_port_name_non_relative (source);
398         string d = make_port_name_non_relative (destination);
399
400         boost::shared_ptr<Port> src = get_port_by_name (s);
401         boost::shared_ptr<Port> dst = get_port_by_name (d);
402
403         if (src) {
404                 ret = src->connect (d);
405         } else if (dst) {
406                 ret = dst->connect (s);
407         } else {
408                 /* neither port is known to us ...hand-off to the PortEngine
409                  */
410                 if (_backend) {
411                         ret = _backend->connect (s, d);
412                 } else {
413                         ret = -1;
414                 }
415         }
416
417         if (ret > 0) {
418                 /* already exists - no error, no warning */
419         } else if (ret < 0) {
420                 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
421                                         source, s, destination, d)
422                       << endmsg;
423         }
424
425         return ret;
426 }
427
428 int
429 PortManager::disconnect (const string& source, const string& destination)
430 {
431         int ret;
432
433         string s = make_port_name_non_relative (source);
434         string d = make_port_name_non_relative (destination);
435
436         boost::shared_ptr<Port> src = get_port_by_name (s);
437         boost::shared_ptr<Port> dst = get_port_by_name (d);
438
439         if (src) {
440                 ret = src->disconnect (d);
441         } else if (dst) {
442                 ret = dst->disconnect (s);
443         } else {
444                 /* neither port is known to us ...hand-off to the PortEngine
445                  */
446                 if (_backend) {
447                         ret = _backend->disconnect (s, d);
448                 } else {
449                         ret = -1;
450                 }
451         }
452         return ret;
453 }
454
455 int
456 PortManager::disconnect (boost::shared_ptr<Port> port)
457 {
458         return port->disconnect_all ();
459 }
460
461 int
462 PortManager::reestablish_ports ()
463 {
464         Ports::iterator i;
465
466         boost::shared_ptr<Ports> p = ports.reader ();
467
468         DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
469
470         for (i = p->begin(); i != p->end(); ++i) {
471                 if (i->second->reestablish ()) {
472                         error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
473                         std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
474                         break;
475                 }
476         }
477
478         if (i != p->end()) {
479                 /* failed */
480                 remove_all_ports ();
481                 return -1;
482         }
483
484         return 0;
485 }
486
487 int
488 PortManager::reconnect_ports ()
489 {
490         boost::shared_ptr<Ports> p = ports.reader ();
491
492         if (!Profile->get_trx()) {
493                 /* re-establish connections */
494                 
495                 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
496                 
497                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
498                         i->second->reconnect ();
499                 }
500         }
501
502         return 0;
503 }
504
505 void
506 PortManager::connect_callback (const string& a, const string& b, bool conn)
507 {
508         boost::shared_ptr<Port> port_a;
509         boost::shared_ptr<Port> port_b;
510         Ports::iterator x;
511         boost::shared_ptr<Ports> pr = ports.reader ();
512
513         x = pr->find (make_port_name_relative (a));
514         if (x != pr->end()) {
515                 port_a = x->second;
516         }
517
518         x = pr->find (make_port_name_relative (b));
519         if (x != pr->end()) {
520                 port_b = x->second;
521         }
522
523         PortConnectedOrDisconnected (
524                 port_a, a,
525                 port_b, b,
526                 conn
527                 ); /* EMIT SIGNAL */
528 }       
529
530 void
531 PortManager::registration_callback ()
532 {
533         if (!_port_remove_in_progress) {
534                 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
535         }
536 }
537
538 bool
539 PortManager::can_request_input_monitoring () const
540 {
541         if (!_backend) {
542                 return false;
543         }
544
545         return _backend->can_monitor_input ();
546 }
547  
548 void
549 PortManager::request_input_monitoring (const string& name, bool yn) const
550 {
551         if (!_backend) {
552                 return;
553         }
554
555         PortEngine::PortHandle ph = _backend->get_port_by_name (name);
556
557         if (ph) {
558                 _backend->request_input_monitoring (ph, yn);
559         }
560 }
561  
562 void
563 PortManager::ensure_input_monitoring (const string& name, bool yn) const
564 {
565         if (!_backend) {
566                 return;
567         }
568
569         PortEngine::PortHandle ph = _backend->get_port_by_name (name);
570
571         if (ph) {
572                 _backend->ensure_input_monitoring (ph, yn);
573         }
574 }
575
576 uint32_t
577 PortManager::port_name_size() const
578 {
579         if (!_backend) {
580                 return 0;
581         }
582         
583         return _backend->port_name_size ();
584 }
585
586 string
587 PortManager::my_name() const
588 {
589         if (!_backend) {
590                 return string();
591         }
592         
593         return _backend->my_name();
594 }
595
596 int
597 PortManager::graph_order_callback ()
598 {
599         if (!_port_remove_in_progress) {
600                 GraphReordered(); /* EMIT SIGNAL */
601         }
602
603         return 0;
604 }
605
606 void
607 PortManager::cycle_start (pframes_t nframes)
608 {
609         Port::set_global_port_buffer_offset (0);
610         Port::set_cycle_framecnt (nframes);
611
612         _cycle_ports = ports.reader ();
613
614         for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
615                 p->second->cycle_start (nframes);
616         }
617 }
618
619 void
620 PortManager::cycle_end (pframes_t nframes)
621 {
622         for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
623                 p->second->cycle_end (nframes);
624         }
625
626         for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
627                 p->second->flush_buffers (nframes);
628         }
629
630         _cycle_ports.reset ();
631
632         /* we are done */
633 }
634
635 void
636 PortManager::silence (pframes_t nframes)
637 {
638         for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
639                 if (i->second->sends_output()) {
640                         i->second->get_buffer(nframes).silence(nframes);
641                 }
642         }
643 }
644
645 void
646 PortManager::silence_outputs (pframes_t nframes)
647 {
648         std::vector<std::string> port_names;
649         if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
650                 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
651                         if (!port_is_mine(*p)) {
652                                 continue;
653                         }
654                         PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
655                         if (!ph) {
656                                 continue;
657                         }
658                         void *buf = _backend->get_buffer(ph, nframes);
659                         if (!buf) {
660                                 continue;
661                         }
662                         memset (buf, 0, sizeof(float) * nframes);
663                 }
664         }
665
666         if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
667                 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
668                         if (!port_is_mine(*p)) {
669                                 continue;
670                         }
671                         PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
672                         if (!ph) {
673                                 continue;
674                         }
675                         void *buf = _backend->get_buffer(ph, nframes);
676                         if (!buf) {
677                                 continue;
678                         }
679                         _backend->midi_clear (buf);
680                 }
681         }
682 }
683
684 void
685 PortManager::check_monitoring ()
686 {
687         for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
688                 
689                 bool x;
690                 
691                 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
692                         i->second->set_last_monitor (x);
693                         /* XXX I think this is dangerous, due to
694                            a likely mutex in the signal handlers ...
695                         */
696                         i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
697                 }
698         }
699 }
700
701 void
702 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
703 {
704         for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
705                 
706                 if (i->second->sends_output()) {
707                         
708                         boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
709                         if (ap) {
710                                 Sample* s = ap->engine_get_whole_audio_buffer ();
711                                 gain_t g = base_gain;
712                                 
713                                 for (pframes_t n = 0; n < nframes; ++n) {
714                                         *s++ *= g;
715                                         g -= gain_step;
716                                 }
717                         }
718                 }
719         }
720 }
721
722 PortEngine&
723 PortManager::port_engine()
724 {
725         assert (_backend);
726         return *_backend;
727 }