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