2 Copyright (C) 2013 Paul Davis
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.
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.
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.
21 #include <io.h> // Microsoft's nearest equivalent to <unistd.h>
22 #include <ardourext/misc.h>
27 #include <glibmm/fileutils.h>
28 #include <glibmm/miscutils.h>
30 #include "pbd/convert.h"
31 #include "pbd/error.h"
33 #include "ardour/async_midi_port.h"
34 #include "ardour/audio_backend.h"
35 #include "ardour/audio_port.h"
36 #include "ardour/debug.h"
37 #include "ardour/filesystem_paths.h"
38 #include "ardour/midi_port.h"
39 #include "ardour/midiport_manager.h"
40 #include "ardour/port_manager.h"
41 #include "ardour/profile.h"
42 #include "ardour/session.h"
46 using namespace ARDOUR;
51 PortManager::PortManager ()
53 , _port_remove_in_progress (false)
54 , _port_deletions_pending (8192) /* ick, arbitrary sizing */
55 , midi_info_dirty (true)
57 load_midi_port_info ();
61 PortManager::clear_pending_port_deletions ()
65 DEBUG_TRACE (DEBUG::Ports, string_compose ("pending port deletions: %1\n", _port_deletions_pending.read_space()));
67 while (_port_deletions_pending.read (&p, 1) == 1) {
73 PortManager::remove_all_ports ()
75 /* make sure that JACK callbacks that will be invoked as we cleanup
76 * ports know that they have nothing to do.
79 _port_remove_in_progress = true;
81 /* process lock MUST be held by caller
85 RCUWriter<Ports> writer (ports);
86 boost::shared_ptr<Ports> ps = writer.get_copy ();
90 /* clear dead wood list in RCU */
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.
99 _port_deletions_pending.reset ();
101 _port_remove_in_progress = false;
106 PortManager::make_port_name_relative (const string& portname) const
112 string::size_type colon = portname.find (':');
114 if (colon == string::npos) {
118 if (portname.substr (0, colon) == _backend->my_name()) {
119 return portname.substr (colon+1);
126 PortManager::make_port_name_non_relative (const string& portname) const
130 if (portname.find_first_of (':') != string::npos) {
134 str = _backend->my_name();
142 PortManager::get_pretty_name_by_name(const std::string& portname) const
144 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
148 if (0 == _backend->get_port_property (ph,
149 "http://jackaudio.org/metadata/pretty-name",
159 PortManager::port_is_mine (const string& portname) const
165 string self = _backend->my_name();
167 if (portname.find_first_of (':') != string::npos) {
168 if (portname.substr (0, self.length ()) != self) {
177 PortManager::port_is_physical (const std::string& portname) const
183 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
188 return _backend->port_is_physical (ph);
192 PortManager::filter_midi_ports (vector<string>& ports, MidiPortFlags include, MidiPortFlags exclude)
194 if (!include && !exclude) {
198 for (vector<string>::iterator si = ports.begin(); si != ports.end(); ) {
200 PortManager::MidiPortInformation mpi = midi_port_information (*si);
202 if (mpi.pretty_name.empty()) {
203 /* no information !!! */
209 if ((mpi.properties & include) != include) {
210 /* properties do not include requested ones */
211 si = ports.erase (si);
217 if ((mpi.properties & exclude)) {
218 /* properties include ones to avoid */
219 si = ports.erase (si);
229 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s, MidiPortFlags include, MidiPortFlags exclude)
235 _backend->get_physical_outputs (type, s);
236 filter_midi_ports (s, include, exclude);
240 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s, MidiPortFlags include, MidiPortFlags exclude)
247 _backend->get_physical_inputs (type, s);
248 filter_midi_ports (s, include, exclude);
252 PortManager::n_physical_outputs () const
255 return ChanCount::ZERO;
258 return _backend->n_physical_outputs ();
262 PortManager::n_physical_inputs () const
265 return ChanCount::ZERO;
267 return _backend->n_physical_inputs ();
270 /** @param name Full or short name of port
271 * @return Corresponding Port or 0.
274 boost::shared_ptr<Port>
275 PortManager::get_port_by_name (const string& portname)
278 return boost::shared_ptr<Port>();
281 if (!port_is_mine (portname)) {
282 /* not an ardour port */
283 return boost::shared_ptr<Port> ();
286 boost::shared_ptr<Ports> pr = ports.reader();
287 std::string rel = make_port_name_relative (portname);
288 Ports::iterator x = pr->find (rel);
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).
296 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
298 x->second->set_name (check);
303 return boost::shared_ptr<Port> ();
307 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
309 RCUWriter<Ports> writer (ports);
310 boost::shared_ptr<Ports> p = writer.get_copy();
311 Ports::iterator x = p->find (old_relative_name);
314 boost::shared_ptr<Port> port = x->second;
316 p->insert (make_pair (new_relative_name, port));
321 PortManager::get_ports (DataType type, PortList& pl)
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);
333 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
341 return _backend->get_ports (port_name_pattern, type, flags, s);
345 PortManager::port_registration_failure (const std::string& portname)
351 string full_portname = _backend->my_name();
352 full_portname += ':';
353 full_portname += portname;
356 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
360 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
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);
365 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
370 void operator() (Port* p) {
371 AudioEngine::instance()->add_pending_port_deletion (p);
375 boost::shared_ptr<Port>
376 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async, PortFlags flags)
378 boost::shared_ptr<Port> newport;
380 /* limit the possible flags that can be set */
382 flags = PortFlags (flags & (Hidden|Shadow|IsTerminal));
385 if (dtype == DataType::AUDIO) {
386 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
388 newport.reset (new AudioPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
390 } else if (dtype == DataType::MIDI) {
392 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
394 newport.reset (new AsyncMIDIPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
397 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
399 newport.reset (new MidiPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)),
403 throw PortRegistrationFailure("unable to create port (unknown type)");
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));
410 /* writer goes out of scope, forces update */
414 catch (PortRegistrationFailure& err) {
416 } catch (std::exception& e) {
417 throw PortRegistrationFailure(string_compose(
418 _("unable to create port: %1"), e.what()).c_str());
420 throw PortRegistrationFailure("unable to create port (unknown error)");
423 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
427 boost::shared_ptr<Port>
428 PortManager::register_input_port (DataType type, const string& portname, bool async, PortFlags extra_flags)
430 return register_port (type, portname, true, async, extra_flags);
433 boost::shared_ptr<Port>
434 PortManager::register_output_port (DataType type, const string& portname, bool async, PortFlags extra_flags)
436 return register_port (type, portname, false, async, extra_flags);
440 PortManager::unregister_port (boost::shared_ptr<Port> port)
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.
448 /* caller must hold process lock */
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()));
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()));
460 /* writer goes out of scope, forces update */
469 PortManager::connected (const string& port_name)
475 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
481 return _backend->connected (handle);
485 PortManager::physically_connected (const string& port_name)
491 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
497 return _backend->physically_connected (handle);
501 PortManager::get_connections (const string& port_name, std::vector<std::string>& s)
508 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
515 return _backend->get_connections (handle, s);
519 PortManager::connect (const string& source, const string& destination)
523 string s = make_port_name_non_relative (source);
524 string d = make_port_name_non_relative (destination);
526 boost::shared_ptr<Port> src = get_port_by_name (s);
527 boost::shared_ptr<Port> dst = get_port_by_name (d);
530 ret = src->connect (d);
532 ret = dst->connect (s);
534 /* neither port is known to us ...hand-off to the PortEngine
537 ret = _backend->connect (s, d);
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)
555 PortManager::disconnect (const string& source, const string& destination)
559 string s = make_port_name_non_relative (source);
560 string d = make_port_name_non_relative (destination);
562 boost::shared_ptr<Port> src = get_port_by_name (s);
563 boost::shared_ptr<Port> dst = get_port_by_name (d);
566 ret = src->disconnect (d);
568 ret = dst->disconnect (s);
570 /* neither port is known to us ...hand-off to the PortEngine
573 ret = _backend->disconnect (s, d);
582 PortManager::disconnect (boost::shared_ptr<Port> port)
584 return port->disconnect_all ();
588 PortManager::disconnect (std::string const & name)
590 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
592 return _backend->disconnect_all (ph);
598 PortManager::reestablish_ports ()
602 boost::shared_ptr<Ports> p = ports.reader ();
604 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
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;
624 PortManager::reconnect_ports ()
626 boost::shared_ptr<Ports> p = ports.reader ();
628 if (!Profile->get_trx()) {
629 /* re-establish connections */
631 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
633 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
634 i->second->reconnect ();
642 PortManager::connect_callback (const string& a, const string& b, bool conn)
644 boost::shared_ptr<Port> port_a;
645 boost::shared_ptr<Port> port_b;
647 boost::shared_ptr<Ports> pr = ports.reader ();
649 x = pr->find (make_port_name_relative (a));
650 if (x != pr->end()) {
654 x = pr->find (make_port_name_relative (b));
655 if (x != pr->end()) {
659 PortConnectedOrDisconnected (
667 PortManager::registration_callback ()
669 if (!_port_remove_in_progress) {
672 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
673 midi_info_dirty = true;
676 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
681 PortManager::can_request_input_monitoring () const
687 return _backend->can_monitor_input ();
691 PortManager::request_input_monitoring (const string& name, bool yn) const
697 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
700 _backend->request_input_monitoring (ph, yn);
705 PortManager::ensure_input_monitoring (const string& name, bool yn) const
711 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
714 _backend->ensure_input_monitoring (ph, yn);
719 PortManager::port_name_size() const
725 return _backend->port_name_size ();
729 PortManager::my_name() const
735 return _backend->my_name();
739 PortManager::graph_order_callback ()
741 if (!_port_remove_in_progress) {
742 GraphReordered(); /* EMIT SIGNAL */
749 PortManager::cycle_start (pframes_t nframes)
751 Port::set_global_port_buffer_offset (0);
752 Port::set_cycle_framecnt (nframes);
754 _cycle_ports = ports.reader ();
756 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
757 p->second->cycle_start (nframes);
762 PortManager::cycle_end (pframes_t nframes)
764 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
765 p->second->cycle_end (nframes);
768 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
769 p->second->flush_buffers (nframes);
772 _cycle_ports.reset ();
778 PortManager::silence (pframes_t nframes, Session *s)
780 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
781 if (s && i->second == s->mtc_output_port ()) {
784 if (s && i->second == s->midi_clock_output_port ()) {
787 if (s && i->second == s->ltc_output_port ()) {
790 if (boost::dynamic_pointer_cast<AsyncMIDIPort>(i->second)) {
793 if (i->second->sends_output()) {
794 i->second->get_buffer(nframes).silence(nframes);
800 PortManager::silence_outputs (pframes_t nframes)
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)) {
808 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
812 void *buf = _backend->get_buffer(ph, nframes);
816 memset (buf, 0, sizeof(float) * nframes);
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)) {
825 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
829 void *buf = _backend->get_buffer(ph, nframes);
833 _backend->midi_clear (buf);
839 PortManager::check_monitoring ()
841 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
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 ...
850 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
856 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
858 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
860 if (i->second->sends_output()) {
862 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
864 Sample* s = ap->engine_get_whole_audio_buffer ();
865 gain_t g = base_gain;
867 for (pframes_t n = 0; n < nframes; ++n) {
877 PortManager::port_engine()
884 PortManager::port_is_control_only (std::string const& name)
886 static regex_t compiled_pattern;
887 static string pattern;
889 if (pattern.empty()) {
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.
896 const char * const control_only_ports[] = {
897 X_(".*Ableton Push.*"),
898 X_(".*FaderPort .*"),
902 for (size_t n = 0; n < sizeof (control_only_ports)/sizeof (control_only_ports[0]); ++n) {
906 pattern += control_only_ports[n];
910 regcomp (&compiled_pattern, pattern.c_str(), REG_EXTENDED|REG_NOSUB);
913 return regexec (&compiled_pattern, name.c_str(), 0, 0, 0) == 0;
916 PortManager::MidiPortInformation
917 PortManager::midi_port_information (std::string const & name)
919 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
921 fill_midi_port_info_locked ();
923 MidiPortInfo::iterator x = midi_port_info.find (name);
925 if (x != midi_port_info.end()) {
929 return MidiPortInformation ();
933 PortManager::get_known_midi_ports (vector<string>& copy)
935 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
937 fill_midi_port_info_locked ();
939 for (MidiPortInfo::const_iterator x = midi_port_info.begin(); x != midi_port_info.end(); ++x) {
940 copy.push_back (x->first);
945 PortManager::get_midi_selection_ports (vector<string>& copy)
947 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
949 fill_midi_port_info_locked ();
951 for (MidiPortInfo::const_iterator x = midi_port_info.begin(); x != midi_port_info.end(); ++x) {
952 if (x->second.properties & MidiPortSelection) {
953 copy.push_back (x->first);
959 PortManager::set_midi_port_pretty_name (string const & port, string const & pretty)
962 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
964 fill_midi_port_info_locked ();
966 MidiPortInfo::iterator x = midi_port_info.find (port);
967 if (x == midi_port_info.end()) {
970 x->second.pretty_name = pretty;
973 /* push into back end */
975 PortEngine::PortHandle ph = _backend->get_port_by_name (port);
978 _backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", pretty, string());
981 MidiPortInfoChanged (); /* EMIT SIGNAL*/
985 PortManager::add_midi_port_flags (string const & port, MidiPortFlags flags)
990 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
992 fill_midi_port_info_locked ();
994 MidiPortInfo::iterator x = midi_port_info.find (port);
995 if (x != midi_port_info.end()) {
996 if ((x->second.properties & flags) != flags) { // at least one missing
997 x->second.properties = MidiPortFlags (x->second.properties | flags);
1004 if (flags & MidiPortSelection) {
1005 MidiSelectionPortsChanged (); /* EMIT SIGNAL */
1008 if (flags != MidiPortSelection) {
1009 MidiPortInfoChanged (); /* EMIT SIGNAL */
1012 save_midi_port_info ();
1017 PortManager::remove_midi_port_flags (string const & port, MidiPortFlags flags)
1022 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
1024 fill_midi_port_info_locked ();
1026 MidiPortInfo::iterator x = midi_port_info.find (port);
1027 if (x != midi_port_info.end()) {
1028 if (x->second.properties & flags) { // at least one is set
1029 x->second.properties = MidiPortFlags (x->second.properties & ~flags);
1036 if (flags & MidiPortSelection) {
1037 MidiSelectionPortsChanged (); /* EMIT SIGNAL */
1040 if (flags != MidiPortSelection) {
1041 MidiPortInfoChanged (); /* EMIT SIGNAL */
1044 save_midi_port_info ();
1049 PortManager::midi_port_info_file ()
1051 return Glib::build_filename (user_config_directory(), X_("midi_port_info"));
1055 PortManager::save_midi_port_info ()
1057 string path = midi_port_info_file ();
1059 XMLNode* root = new XMLNode (X_("MidiPortInfo"));
1062 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
1064 if (midi_port_info.empty()) {
1069 for (MidiPortInfo::iterator i = midi_port_info.begin(); i != midi_port_info.end(); ++i) {
1070 XMLNode* node = new XMLNode (X_("port"));
1071 node->add_property (X_("name"), i->first);
1072 node->add_property (X_("input"), i->second.input ? X_("yes") : X_("no"));
1073 node->add_property (X_("properties"), enum_2_string (i->second.properties));
1074 root->add_child_nocopy (*node);
1080 tree.set_root (root);
1082 if (!tree.write (path)) {
1083 error << string_compose (_("Could not save MIDI port info to %1"), path) << endmsg;
1088 PortManager::load_midi_port_info ()
1090 string path = midi_port_info_file ();
1093 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1097 if (!tree.read (path)) {
1098 error << string_compose (_("Cannot load MIDI port info from %1"), path) << endmsg;
1102 midi_port_info.clear ();
1104 for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
1105 XMLProperty const* prop;
1106 MidiPortInformation mpi;
1109 if ((prop = (*i)->property (X_("name"))) == 0) {
1113 name = prop->value ();
1115 if ((prop = (*i)->property (X_("input"))) == 0) {
1118 mpi.input = string_is_affirmative (prop->value());
1120 if ((prop = (*i)->property (X_("properties"))) == 0) {
1124 mpi.properties = (MidiPortFlags) string_2_enum (prop->value(), mpi.properties);
1126 midi_port_info.insert (make_pair (name, mpi));
1131 PortManager::fill_midi_port_info ()
1133 Glib::Threads::Mutex::Lock lm (midi_port_info_mutex);
1134 fill_midi_port_info_locked ();
1138 PortManager::fill_midi_port_info_locked ()
1140 /* MIDI info mutex MUST be held */
1142 if (!midi_info_dirty) {
1146 std::vector<string> ports;
1148 AudioEngine::instance()->get_ports (string(), DataType::MIDI, IsOutput, ports);
1150 for (vector<string>::iterator p = ports.begin(); p != ports.end(); ++p) {
1152 if (port_is_mine (*p)) {
1156 if (midi_port_info.find (*p) == midi_port_info.end()) {
1157 MidiPortInformation mpi;
1158 mpi.pretty_name = *p;
1161 if (port_is_control_only (*p)) {
1162 mpi.properties = MidiPortFlags (mpi.properties | MidiPortControl);
1165 if ((*p.find (X_("Midi Through")) != string::npos ||
1166 (*p).find (X_("Midi-Through")) != string::npos))
1168 mpi.properties = MidiPortFlags (mpi.properties | MidiPortVirtual);
1171 midi_port_info.insert (make_pair (*p, mpi));
1175 AudioEngine::instance()->get_ports (string(), DataType::MIDI, IsInput, ports);
1177 for (vector<string>::iterator p = ports.begin(); p != ports.end(); ++p) {
1179 if (port_is_mine (*p)) {
1183 if (midi_port_info.find (*p) == midi_port_info.end()) {
1184 MidiPortInformation mpi;
1185 mpi.pretty_name = *p;
1188 if (port_is_control_only (*p)) {
1189 mpi.properties = MidiPortFlags (mpi.properties | MidiPortControl);
1192 if ((*p.find (X_("Midi Through")) != string::npos ||
1193 (*p).find (X_("Midi-Through")) != string::npos))
1195 mpi.properties = MidiPortFlags (mpi.properties | MidiPortVirtual);
1198 midi_port_info.insert (make_pair (*p, mpi));
1202 /* now push/pull pretty name information between backend and the
1206 for (MidiPortInfo::iterator x = midi_port_info.begin(); x != midi_port_info.end(); ++x) {
1207 PortEngine::PortHandle ph = _backend->get_port_by_name (x->first);
1209 if (x->second.pretty_name != x->first) {
1210 /* name set in port info ... propagate */
1211 _backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", x->second.pretty_name, string());
1213 /* check with backend for pre-existing pretty name */
1217 if (0 == _backend->get_port_property (ph,
1218 "http://jackaudio.org/metadata/pretty-name",
1220 x->second.pretty_name = value;
1226 midi_info_dirty = false;