debug instrumentation for locate time
[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 #ifdef COMPILER_MSVC
21 #include <io.h> // Microsoft's nearest equivalent to <unistd.h>
22 #include <ardourext/misc.h>
23 #else
24 #include <regex.h>
25 #endif
26
27 #include <glibmm/fileutils.h>
28 #include <glibmm/miscutils.h>
29
30 #include "pbd/error.h"
31
32 #include "ardour/async_midi_port.h"
33 #include "ardour/audio_backend.h"
34 #include "ardour/audio_port.h"
35 #include "ardour/debug.h"
36 #include "ardour/filesystem_paths.h"
37 #include "ardour/midi_port.h"
38 #include "ardour/midiport_manager.h"
39 #include "ardour/port_manager.h"
40 #include "ardour/profile.h"
41 #include "ardour/session.h"
42 #include "ardour/types_convert.h"
43
44 #include "pbd/i18n.h"
45
46 using namespace ARDOUR;
47 using namespace PBD;
48 using std::string;
49 using std::vector;
50
51 PortManager::PortManager ()
52         : ports (new Ports)
53         , _port_remove_in_progress (false)
54         , _port_deletions_pending (8192) /* ick, arbitrary sizing */
55         , midi_info_dirty (true)
56 {
57         load_midi_port_info ();
58 }
59
60 void
61 PortManager::clear_pending_port_deletions ()
62 {
63         Port* p;
64
65         DEBUG_TRACE (DEBUG::Ports, string_compose ("pending port deletions: %1\n", _port_deletions_pending.read_space()));
66
67         while (_port_deletions_pending.read (&p, 1) == 1) {
68                 delete p;
69         }
70 }
71
72 void
73 PortManager::remove_all_ports ()
74 {
75         /* make sure that JACK callbacks that will be invoked as we cleanup
76          * ports know that they have nothing to do.
77          */
78
79         _port_remove_in_progress = true;
80
81         /* process lock MUST be held by caller
82         */
83
84         {
85                 RCUWriter<Ports> writer (ports);
86                 boost::shared_ptr<Ports> ps = writer.get_copy ();
87                 ps->clear ();
88         }
89
90         /* clear dead wood list in RCU */
91
92         ports.flush ();
93
94         /* clear out pending port deletion list. we know this is safe because
95          * the auto connect thread in Session is already dead when this is
96          * done. It doesn't use shared_ptr<Port> anyway.
97          */
98
99         _port_deletions_pending.reset ();
100
101         _port_remove_in_progress = false;
102 }
103
104
105 string
106 PortManager::make_port_name_relative (const string& portname) const
107 {
108         if (!_backend) {
109                 return portname;
110         }
111
112         string::size_type colon = portname.find (':');
113
114         if (colon == string::npos) {
115                 return portname;
116         }
117
118         if (portname.substr (0, colon) == _backend->my_name()) {
119                 return portname.substr (colon+1);
120         }
121
122         return portname;
123 }
124
125 string
126 PortManager::make_port_name_non_relative (const string& portname) const
127 {
128         string str;
129
130         if (portname.find_first_of (':') != string::npos) {
131                 return portname;
132         }
133
134         str  = _backend->my_name();
135         str += ':';
136         str += portname;
137
138         return str;
139 }
140
141 std::string
142 PortManager::get_pretty_name_by_name(const std::string& portname) const
143 {
144         PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
145         if (ph) {
146                 std::string value;
147                 std::string type;
148                 if (0 == _backend->get_port_property (ph,
149                                         "http://jackaudio.org/metadata/pretty-name",
150                                         value, type))
151                 {
152                         return value;
153                 }
154         }
155         return "";
156 }
157
158 bool
159 PortManager::port_is_mine (const string& portname) const
160 {
161         if (!_backend) {
162                 return true;
163         }
164
165         string self = _backend->my_name();
166
167         if (portname.find_first_of (':') != string::npos) {
168                 if (portname.substr (0, self.length ()) != self) {
169                         return false;
170                 }
171         }
172
173         return true;
174 }
175
176 bool
177 PortManager::port_is_physical (const std::string& portname) const
178 {
179         if (!_backend) {
180                 return false;
181         }
182
183         PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
184         if (!ph) {
185                 return false;
186         }
187
188         return _backend->port_is_physical (ph);
189 }
190
191 void
192 PortManager::filter_midi_ports (vector<string>& ports, MidiPortFlags include, MidiPortFlags exclude)
193 {
194         if (!include && !exclude) {
195                 return;
196         }
197
198         for (vector<string>::iterator si = ports.begin(); si != ports.end(); ) {
199
200                 PortManager::MidiPortInformation mpi = midi_port_information (*si);
201
202                 if (mpi.pretty_name.empty()) {
203                         /* no information !!! */
204                         ++si;
205                         continue;
206                 }
207
208                 if (include) {
209                         if ((mpi.properties & include) != include) {
210                                 /* properties do not include requested ones */
211                                 si = ports.erase (si);
212                                 continue;
213                         }
214                 }
215
216                 if (exclude) {
217                         if ((mpi.properties & exclude)) {
218                                 /* properties include ones to avoid */
219                                 si = ports.erase (si);
220                                 continue;
221                         }
222                 }
223
224                 ++si;
225         }
226 }
227
228 void
229 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s, MidiPortFlags include, MidiPortFlags exclude)
230 {
231         if (!_backend) {
232                 s.clear ();
233                 return;
234         }
235         _backend->get_physical_outputs (type, s);
236         filter_midi_ports (s, include, exclude);
237 }
238
239 void
240 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s, MidiPortFlags include, MidiPortFlags exclude)
241 {
242         if (!_backend) {
243                 s.clear ();
244                 return;
245         }
246
247         _backend->get_physical_inputs (type, s);
248         filter_midi_ports (s, include, exclude);
249 }
250
251 ChanCount
252 PortManager::n_physical_outputs () const
253 {
254         if (!_backend) {
255                 return ChanCount::ZERO;
256         }
257
258         return _backend->n_physical_outputs ();
259 }
260
261 ChanCount
262 PortManager::n_physical_inputs () const
263 {
264         if (!_backend) {
265                 return ChanCount::ZERO;
266         }
267         return _backend->n_physical_inputs ();
268 }
269
270 /** @param name Full or short name of port
271  *  @return Corresponding Port or 0.
272  */
273
274 boost::shared_ptr<Port>
275 PortManager::get_port_by_name (const string& portname)
276 {
277         if (!_backend) {
278                 return boost::shared_ptr<Port>();
279         }
280
281         if (!port_is_mine (portname)) {
282                 /* not an ardour port */
283                 return boost::shared_ptr<Port> ();
284         }
285
286         boost::shared_ptr<Ports> pr = ports.reader();
287         std::string rel = make_port_name_relative (portname);
288         Ports::iterator x = pr->find (rel);
289
290         if (x != pr->end()) {
291                 /* its possible that the port was renamed by some 3rd party and
292                    we don't know about it. check for this (the check is quick
293                    and cheap), and if so, rename the port (which will alter
294                    the port map as a side effect).
295                 */
296                 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
297                 if (check != rel) {
298                         x->second->set_name (check);
299                 }
300                 return x->second;
301         }
302
303         return boost::shared_ptr<Port> ();
304 }
305
306 void
307 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
308 {
309         RCUWriter<Ports> writer (ports);
310         boost::shared_ptr<Ports> p = writer.get_copy();
311         Ports::iterator x = p->find (old_relative_name);
312
313         if (x != p->end()) {
314                 boost::shared_ptr<Port> port = x->second;
315                 p->erase (x);
316                 p->insert (make_pair (new_relative_name, port));
317         }
318 }
319
320 int
321 PortManager::get_ports (DataType type, PortList& pl)
322 {
323         boost::shared_ptr<Ports> plist = ports.reader();
324         for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
325                 if (p->second->type() == type) {
326                         pl.push_back (p->second);
327                 }
328         }
329         return pl.size();
330 }
331
332 int
333 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
334 {
335         s.clear();
336
337         if (!_backend) {
338                 return 0;
339         }
340
341         return _backend->get_ports (port_name_pattern, type, flags, s);
342 }
343
344 void
345 PortManager::port_registration_failure (const std::string& portname)
346 {
347         if (!_backend) {
348                 return;
349         }
350
351         string full_portname = _backend->my_name();
352         full_portname += ':';
353         full_portname += portname;
354
355
356         PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
357         string reason;
358
359         if (p) {
360                 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
361         } else {
362                 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);
363         }
364
365         throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
366 }
367
368 struct PortDeleter
369 {
370         void operator() (Port* p) {
371                 AudioEngine::instance()->add_pending_port_deletion (p);
372         }
373 };
374
375 boost::shared_ptr<Port>
376 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async, PortFlags flags)
377 {
378         boost::shared_ptr<Port> newport;
379
380         /* limit the possible flags that can be set */
381
382         flags = PortFlags (flags & (Hidden|Shadow|IsTerminal));
383
384         try {
385                 if (dtype == DataType::AUDIO) {
386                         DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
387                                                                    portname, input));
388                         newport.reset (new AudioPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
389                                        PortDeleter());
390                 } else if (dtype == DataType::MIDI) {
391                         if (async) {
392                                 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
393                                                                            portname, input));
394                                 newport.reset (new AsyncMIDIPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
395                                                PortDeleter());
396                         } else {
397                                 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
398                                                                            portname, input));
399                                 newport.reset (new MidiPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
400                                                PortDeleter());
401                         }
402                 } else {
403                         throw PortRegistrationFailure("unable to create port (unknown type)");
404                 }
405
406                 RCUWriter<Ports> writer (ports);
407                 boost::shared_ptr<Ports> ps = writer.get_copy ();
408                 ps->insert (make_pair (make_port_name_relative (portname), newport));
409
410                 /* writer goes out of scope, forces update */
411
412         }
413
414         catch (PortRegistrationFailure& err) {
415                 throw err;
416         } catch (std::exception& e) {
417                 throw PortRegistrationFailure(string_compose(
418                                 _("unable to create port: %1"), e.what()).c_str());
419         } catch (...) {
420                 throw PortRegistrationFailure("unable to create port (unknown error)");
421         }
422
423         DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
424         return newport;
425 }
426
427 boost::shared_ptr<Port>
428 PortManager::register_input_port (DataType type, const string& portname, bool async, PortFlags extra_flags)
429 {
430         return register_port (type, portname, true, async, extra_flags);
431 }
432
433 boost::shared_ptr<Port>
434 PortManager::register_output_port (DataType type, const string& portname, bool async, PortFlags extra_flags)
435 {
436         return register_port (type, portname, false, async, extra_flags);
437 }
438
439 int
440 PortManager::unregister_port (boost::shared_ptr<Port> port)
441 {
442         /* This is a little subtle. We do not call the backend's port
443          * unregistration code from here. That is left for the Port
444          * destructor. We are trying to drop references to the Port object
445          * here, so that its destructor will run and it will unregister itself.
446          */
447
448         /* caller must hold process lock */
449
450         {
451                 RCUWriter<Ports> writer (ports);
452                 boost::shared_ptr<Ports> ps = writer.get_copy ();
453                 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
454
455                 if (x != ps->end()) {
456                         DEBUG_TRACE (DEBUG::Ports, string_compose ("removing %1 from port map (uc=%2)\n", port->name(), port.use_count()));
457                         ps->erase (x);
458                 }
459
460                 /* writer goes out of scope, forces update */
461         }
462
463         ports.flush ();
464
465         return 0;
466 }
467
468 bool
469 PortManager::connected (const string& port_name)
470 {
471         if (!_backend) {
472                 return false;
473         }
474
475         PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
476
477         if (!handle) {
478                 return false;
479         }
480
481         return _backend->connected (handle);
482 }
483
484 bool
485 PortManager::physically_connected (const string& port_name)
486 {
487         if (!_backend) {
488                 return false;
489         }
490
491         PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
492
493         if (!handle) {
494                 return false;
495         }
496
497         return _backend->physically_connected (handle);
498 }
499
500 int
501 PortManager::get_connections (const string& port_name, std::vector<std::string>& s)
502 {
503         if (!_backend) {
504                 s.clear ();
505                 return 0;
506         }
507
508         PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
509
510         if (!handle) {
511                 s.clear ();
512                 return 0;
513         }
514
515         return _backend->get_connections (handle, s);
516 }
517
518 int
519 PortManager::connect (const string& source, const string& destination)
520 {
521         int ret;
522
523         string s = make_port_name_non_relative (source);
524         string d = make_port_name_non_relative (destination);
525
526         boost::shared_ptr<Port> src = get_port_by_name (s);
527         boost::shared_ptr<Port> dst = get_port_by_name (d);
528
529         if (src) {
530                 ret = src->connect (d);
531         } else if (dst) {
532                 ret = dst->connect (s);
533         } else {
534                 /* neither port is known to us ...hand-off to the PortEngine
535                  */
536                 if (_backend) {
537                         ret = _backend->connect (s, d);
538                 } else {
539                         ret = -1;
540                 }
541         }
542
543         if (ret > 0) {
544                 /* already exists - no error, no warning */
545         } else if (ret < 0) {
546                 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
547                                         source, s, destination, d)
548                       << endmsg;
549         }
550
551         return ret;
552 }
553
554 int
555 PortManager::disconnect (const string& source, const string& destination)
556 {
557         int ret;
558
559         string s = make_port_name_non_relative (source);
560         string d = make_port_name_non_relative (destination);
561
562         boost::shared_ptr<Port> src = get_port_by_name (s);
563         boost::shared_ptr<Port> dst = get_port_by_name (d);
564
565         if (src) {
566                 ret = src->disconnect (d);
567         } else if (dst) {
568                 ret = dst->disconnect (s);
569         } else {
570                 /* neither port is known to us ...hand-off to the PortEngine
571                  */
572                 if (_backend) {
573                         ret = _backend->disconnect (s, d);
574                 } else {
575                         ret = -1;
576                 }
577         }
578         return ret;
579 }
580
581 int
582 PortManager::disconnect (boost::shared_ptr<Port> port)
583 {
584         return port->disconnect_all ();
585 }
586
587 int
588 PortManager::disconnect (std::string const & name)
589 {
590         PortEngine::PortHandle ph = _backend->get_port_by_name (name);
591         if (ph) {
592                 return _backend->disconnect_all (ph);
593         }
594         return -2;
595 }
596
597 int
598 PortManager::reestablish_ports ()
599 {
600         Ports::iterator i;
601
602         boost::shared_ptr<Ports> p = ports.reader ();
603
604         DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
605
606         for (i = p->begin(); i != p->end(); ++i) {
607                 if (i->second->reestablish ()) {
608                         error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
609                         std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
610                         break;
611                 }
612         }
613
614         if (i != p->end()) {
615                 /* failed */
616                 remove_all_ports ();
617                 return -1;
618         }
619
620         return 0;
621 }
622
623 int
624 PortManager::reconnect_ports ()
625 {
626         boost::shared_ptr<Ports> p = ports.reader ();
627
628         if (!Profile->get_trx()) {
629                 /* re-establish connections */
630
631                 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
632
633                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
634                         i->second->reconnect ();
635                 }
636         }
637
638         return 0;
639 }
640
641 void
642 PortManager::connect_callback (const string& a, const string& b, bool conn)
643 {
644         boost::shared_ptr<Port> port_a;
645         boost::shared_ptr<Port> port_b;
646         Ports::iterator x;
647         boost::shared_ptr<Ports> pr = ports.reader ();
648
649         x = pr->find (make_port_name_relative (a));
650         if (x != pr->end()) {
651                 port_a = x->second;
652         }
653
654         x = pr->find (make_port_name_relative (b));
655         if (x != pr->end()) {
656                 port_b = x->second;
657         }
658
659         PortConnectedOrDisconnected (
660                 port_a, a,
661                 port_b, b,
662                 conn
663                 ); /* EMIT SIGNAL */
664 }
665
666 void
667 PortManager::registration_callback ()
668 {
669         if (!_port_remove_in_progress) {
670
671                 {
672                         Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
673                         midi_info_dirty = true;
674                 }
675
676                 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
677         }
678 }
679
680 bool
681 PortManager::can_request_input_monitoring () const
682 {
683         if (!_backend) {
684                 return false;
685         }
686
687         return _backend->can_monitor_input ();
688 }
689
690 void
691 PortManager::request_input_monitoring (const string& name, bool yn) const
692 {
693         if (!_backend) {
694                 return;
695         }
696
697         PortEngine::PortHandle ph = _backend->get_port_by_name (name);
698
699         if (ph) {
700                 _backend->request_input_monitoring (ph, yn);
701         }
702 }
703
704 void
705 PortManager::ensure_input_monitoring (const string& name, bool yn) const
706 {
707         if (!_backend) {
708                 return;
709         }
710
711         PortEngine::PortHandle ph = _backend->get_port_by_name (name);
712
713         if (ph) {
714                 _backend->ensure_input_monitoring (ph, yn);
715         }
716 }
717
718 uint32_t
719 PortManager::port_name_size() const
720 {
721         if (!_backend) {
722                 return 0;
723         }
724
725         return _backend->port_name_size ();
726 }
727
728 string
729 PortManager::my_name() const
730 {
731         if (!_backend) {
732                 return string();
733         }
734
735         return _backend->my_name();
736 }
737
738 int
739 PortManager::graph_order_callback ()
740 {
741         if (!_port_remove_in_progress) {
742                 GraphReordered(); /* EMIT SIGNAL */
743         }
744
745         return 0;
746 }
747
748 void
749 PortManager::cycle_start (pframes_t nframes)
750 {
751         Port::set_global_port_buffer_offset (0);
752         Port::set_cycle_framecnt (nframes);
753
754         _cycle_ports = ports.reader ();
755
756         for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
757                 p->second->cycle_start (nframes);
758         }
759 }
760
761 void
762 PortManager::cycle_end (pframes_t nframes)
763 {
764         for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
765                 p->second->cycle_end (nframes);
766         }
767
768         for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
769                 p->second->flush_buffers (nframes);
770         }
771
772         _cycle_ports.reset ();
773
774         /* we are done */
775 }
776
777 void
778 PortManager::silence (pframes_t nframes, Session *s)
779 {
780         for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
781                 if (s && i->second == s->mtc_output_port ()) {
782                         continue;
783                 }
784                 if (s && i->second == s->midi_clock_output_port ()) {
785                         continue;
786                 }
787                 if (s && i->second == s->ltc_output_port ()) {
788                         continue;
789                 }
790                 if (boost::dynamic_pointer_cast<AsyncMIDIPort>(i->second)) {
791                         continue;
792                 }
793                 if (i->second->sends_output()) {
794                         i->second->get_buffer(nframes).silence(nframes);
795                 }
796         }
797 }
798
799 void
800 PortManager::silence_outputs (pframes_t nframes)
801 {
802         std::vector<std::string> port_names;
803         if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
804                 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
805                         if (!port_is_mine(*p)) {
806                                 continue;
807                         }
808                         PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
809                         if (!ph) {
810                                 continue;
811                         }
812                         void *buf = _backend->get_buffer(ph, nframes);
813                         if (!buf) {
814                                 continue;
815                         }
816                         memset (buf, 0, sizeof(float) * nframes);
817                 }
818         }
819
820         if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
821                 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
822                         if (!port_is_mine(*p)) {
823                                 continue;
824                         }
825                         PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
826                         if (!ph) {
827                                 continue;
828                         }
829                         void *buf = _backend->get_buffer(ph, nframes);
830                         if (!buf) {
831                                 continue;
832                         }
833                         _backend->midi_clear (buf);
834                 }
835         }
836 }
837
838 void
839 PortManager::check_monitoring ()
840 {
841         for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
842
843                 bool x;
844
845                 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
846                         i->second->set_last_monitor (x);
847                         /* XXX I think this is dangerous, due to
848                            a likely mutex in the signal handlers ...
849                         */
850                         i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
851                 }
852         }
853 }
854
855 void
856 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
857 {
858         for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
859
860                 if (i->second->sends_output()) {
861
862                         boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
863                         if (ap) {
864                                 Sample* s = ap->engine_get_whole_audio_buffer ();
865                                 gain_t g = base_gain;
866
867                                 for (pframes_t n = 0; n < nframes; ++n) {
868                                         *s++ *= g;
869                                         g -= gain_step;
870                                 }
871                         }
872                 }
873         }
874 }
875
876 PortEngine&
877 PortManager::port_engine()
878 {
879         assert (_backend);
880         return *_backend;
881 }
882
883 bool
884 PortManager::port_is_control_only (std::string const& name)
885 {
886         static regex_t compiled_pattern;
887         static string pattern;
888
889         if (pattern.empty()) {
890
891                 /* This is a list of regular expressions that match ports
892                  * related to physical MIDI devices that we do not want to
893                  * expose as normal physical ports.
894                  */
895
896                 const char * const control_only_ports[] = {
897                         X_(".*Ableton Push.*"),
898                         X_(".*FaderPort .*"),
899                         X_(".*FaderPort8 .*"),
900                 };
901
902                 pattern = "(";
903                 for (size_t n = 0; n < sizeof (control_only_ports)/sizeof (control_only_ports[0]); ++n) {
904                         if (n > 0) {
905                                 pattern += '|';
906                         }
907                         pattern += control_only_ports[n];
908                 }
909                 pattern += ')';
910
911                 regcomp (&compiled_pattern, pattern.c_str(), REG_EXTENDED|REG_NOSUB);
912         }
913
914         return regexec (&compiled_pattern, name.c_str(), 0, 0, 0) == 0;
915 }
916
917 PortManager::MidiPortInformation
918 PortManager::midi_port_information (std::string const & name)
919 {
920         Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
921
922         fill_midi_port_info_locked ();
923
924         MidiPortInfo::iterator x = midi_port_info.find (name);
925
926         if (x != midi_port_info.end()) {
927                 return x->second;
928         }
929
930         return MidiPortInformation ();
931 }
932
933 void
934 PortManager::get_known_midi_ports (vector<string>& copy)
935 {
936         Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
937
938         fill_midi_port_info_locked ();
939
940         for (MidiPortInfo::const_iterator x = midi_port_info.begin(); x != midi_port_info.end(); ++x) {
941                 copy.push_back (x->first);
942         }
943 }
944
945 void
946 PortManager::get_midi_selection_ports (vector<string>& copy)
947 {
948         Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
949
950         fill_midi_port_info_locked ();
951
952         for (MidiPortInfo::const_iterator x = midi_port_info.begin(); x != midi_port_info.end(); ++x) {
953                 if (x->second.properties & MidiPortSelection) {
954                         copy.push_back (x->first);
955                 }
956         }
957 }
958
959 void
960 PortManager::set_midi_port_pretty_name (string const & port, string const & pretty)
961 {
962         {
963                 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
964
965                 fill_midi_port_info_locked ();
966
967                 MidiPortInfo::iterator x = midi_port_info.find (port);
968                 if (x == midi_port_info.end()) {
969                         return;
970                 }
971                 x->second.pretty_name = pretty;
972         }
973
974         /* push into back end */
975
976         PortEngine::PortHandle ph = _backend->get_port_by_name (port);
977
978         if (ph) {
979                 _backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", pretty, string());
980         }
981
982         MidiPortInfoChanged (); /* EMIT SIGNAL*/
983 }
984
985 void
986 PortManager::add_midi_port_flags (string const & port, MidiPortFlags flags)
987 {
988         bool emit = false;
989
990         {
991                 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
992
993                 fill_midi_port_info_locked ();
994
995                 MidiPortInfo::iterator x = midi_port_info.find (port);
996                 if (x != midi_port_info.end()) {
997                         if ((x->second.properties & flags) != flags) { // at least one missing
998                                 x->second.properties = MidiPortFlags (x->second.properties | flags);
999                                 emit = true;
1000                         }
1001                 }
1002         }
1003
1004         if (emit) {
1005                 if (flags & MidiPortSelection) {
1006                         MidiSelectionPortsChanged (); /* EMIT SIGNAL */
1007                 }
1008
1009                 if (flags != MidiPortSelection) {
1010                         MidiPortInfoChanged (); /* EMIT SIGNAL */
1011                 }
1012
1013                 save_midi_port_info ();
1014         }
1015 }
1016
1017 void
1018 PortManager::remove_midi_port_flags (string const & port, MidiPortFlags flags)
1019 {
1020         bool emit = false;
1021
1022         {
1023                 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
1024
1025                 fill_midi_port_info_locked ();
1026
1027                 MidiPortInfo::iterator x = midi_port_info.find (port);
1028                 if (x != midi_port_info.end()) {
1029                         if (x->second.properties & flags) { // at least one is set
1030                                 x->second.properties = MidiPortFlags (x->second.properties & ~flags);
1031                                 emit = true;
1032                         }
1033                 }
1034         }
1035
1036         if (emit) {
1037                 if (flags & MidiPortSelection) {
1038                         MidiSelectionPortsChanged (); /* EMIT SIGNAL */
1039                 }
1040
1041                 if (flags != MidiPortSelection) {
1042                         MidiPortInfoChanged (); /* EMIT SIGNAL */
1043                 }
1044
1045                 save_midi_port_info ();
1046         }
1047 }
1048
1049 string
1050 PortManager::midi_port_info_file ()
1051 {
1052         return Glib::build_filename (user_config_directory(), X_("midi_port_info"));
1053 }
1054
1055 void
1056 PortManager::save_midi_port_info ()
1057 {
1058         string path = midi_port_info_file ();
1059
1060         XMLNode* root = new XMLNode (X_("MidiPortInfo"));
1061
1062         {
1063                 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
1064
1065                 if (midi_port_info.empty()) {
1066                         delete root;
1067                         return;
1068                 }
1069
1070                 for (MidiPortInfo::iterator i = midi_port_info.begin(); i != midi_port_info.end(); ++i) {
1071                         XMLNode* node = new XMLNode (X_("port"));
1072                         node->set_property (X_("name"), i->first);
1073                         node->set_property (X_("input"), i->second.input);
1074                         node->set_property (X_("properties"), i->second.properties);
1075                         root->add_child_nocopy (*node);
1076                 }
1077         }
1078
1079         XMLTree tree;
1080
1081         tree.set_root (root);
1082
1083         if (!tree.write (path)) {
1084                 error << string_compose (_("Could not save MIDI port info to %1"), path) << endmsg;
1085         }
1086 }
1087
1088 void
1089 PortManager::load_midi_port_info ()
1090 {
1091         string path = midi_port_info_file ();
1092         XMLTree tree;
1093
1094         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1095                 return;
1096         }
1097
1098         if (!tree.read (path)) {
1099                 error << string_compose (_("Cannot load MIDI port info from %1"), path) << endmsg;
1100                 return;
1101         }
1102
1103         midi_port_info.clear ();
1104
1105         for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1106                 MidiPortInformation mpi;
1107                 string name;
1108
1109                 if (!(*i)->get_property (X_("name"), name) ||
1110                     !(*i)->get_property (X_("input"), mpi.input) ||
1111                     !(*i)->get_property (X_("properties"), mpi.properties)) {
1112                         continue;
1113                 }
1114
1115                 midi_port_info.insert (make_pair (name, mpi));
1116         }
1117 }
1118
1119 void
1120 PortManager::fill_midi_port_info ()
1121 {
1122         Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
1123         fill_midi_port_info_locked ();
1124 }
1125
1126 void
1127 PortManager::fill_midi_port_info_locked ()
1128 {
1129         /* MIDI info mutex MUST be held */
1130
1131         if (!midi_info_dirty) {
1132                 return;
1133         }
1134
1135         std::vector<string> ports;
1136
1137         AudioEngine::instance()->get_ports (string(), DataType::MIDI, IsOutput, ports);
1138
1139         for (vector<string>::iterator p = ports.begin(); p != ports.end(); ++p) {
1140
1141                 if (port_is_mine (*p)) {
1142                         continue;
1143                 }
1144
1145                 if (midi_port_info.find (*p) == midi_port_info.end()) {
1146                         MidiPortInformation mpi;
1147                         mpi.pretty_name = *p;
1148                         mpi.input = true;
1149
1150                         if (port_is_control_only (*p)) {
1151                                 mpi.properties = MidiPortFlags (mpi.properties | MidiPortControl);
1152                         }
1153 #ifdef LINUX
1154                         if ((*p.find (X_("Midi Through")) != string::npos ||
1155                              (*p).find (X_("Midi-Through")) != string::npos))
1156                         {
1157                                 mpi.properties = MidiPortFlags (mpi.properties | MidiPortVirtual);
1158                         }
1159 #endif
1160                         midi_port_info.insert (make_pair (*p, mpi));
1161                 }
1162         }
1163
1164         AudioEngine::instance()->get_ports (string(), DataType::MIDI, IsInput, ports);
1165
1166         for (vector<string>::iterator p = ports.begin(); p != ports.end(); ++p) {
1167
1168                 if (port_is_mine (*p)) {
1169                         continue;
1170                 }
1171
1172                 if (midi_port_info.find (*p) == midi_port_info.end()) {
1173                         MidiPortInformation mpi;
1174                         mpi.pretty_name = *p;
1175                         mpi.input = false;
1176
1177                         if (port_is_control_only (*p)) {
1178                                 mpi.properties = MidiPortFlags (mpi.properties | MidiPortControl);
1179                         }
1180 #ifdef LINUX
1181                         if ((*p.find (X_("Midi Through")) != string::npos ||
1182                              (*p).find (X_("Midi-Through")) != string::npos))
1183                         {
1184                                 mpi.properties = MidiPortFlags (mpi.properties | MidiPortVirtual);
1185                         }
1186 #endif
1187                         midi_port_info.insert (make_pair (*p, mpi));
1188                 }
1189         }
1190
1191         /* now push/pull pretty name information between backend and the
1192          * PortManager
1193          */
1194
1195         // rg: I don't understand what this attempts to solve
1196         //
1197         // Naming ports should be left to the backend:
1198         // Ardour cannot associate numeric IDs with corresponding hardware.
1199         // (see also 7dde6c3b)
1200
1201         for (MidiPortInfo::iterator x = midi_port_info.begin(); x != midi_port_info.end(); ++x) {
1202                 PortEngine::PortHandle ph = _backend->get_port_by_name (x->first);
1203
1204                 if (!ph) {
1205                         /* port info saved from some condition where this port
1206                          * existed, but no longer does (i.e. device unplugged
1207                          * at present)
1208                          */
1209                         continue;
1210                 }
1211
1212                 if (!x->second.pretty_name.empty () && x->second.pretty_name != x->first) {
1213                         /* name set in port info ... propagate */
1214                         _backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", x->second.pretty_name, string());
1215                 } else {
1216                         /* check with backend for pre-existing pretty name */
1217                         string value;
1218                         string type;
1219                         if (0 == _backend->get_port_property (ph,
1220                                                               "http://jackaudio.org/metadata/pretty-name",
1221                                                               value, type)) {
1222                                 x->second.pretty_name = value;
1223                         }
1224                 }
1225         }
1226
1227         midi_info_dirty = false;
1228 }