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.
20 #include "pbd/error.h"
22 #include "midi++/manager.h"
24 #include "ardour/port_manager.h"
25 #include "ardour/audio_port.h"
26 #include "ardour/midi_port.h"
30 using namespace ARDOUR;
35 PortManager::PortManager ()
37 , _port_remove_in_progress (false)
42 PortManager::remove_all_ports ()
44 /* make sure that JACK callbacks that will be invoked as we cleanup
45 * ports know that they have nothing to do.
48 _port_remove_in_progress = true;
50 /* process lock MUST be held by caller
54 RCUWriter<Ports> writer (ports);
55 boost::shared_ptr<Ports> ps = writer.get_copy ();
59 /* clear dead wood list in RCU */
63 _port_remove_in_progress = false;
68 PortManager::make_port_name_relative (const string& portname) const
70 string::size_type len;
72 string self = _impl->my_name();
74 len = portname.length();
76 for (n = 0; n < len; ++n) {
77 if (portname[n] == ':') {
82 if ((n != len) && (portname.substr (0, n) == self)) {
83 return portname.substr (n+1);
90 PortManager::make_port_name_non_relative (const string& portname) const
94 if (portname.find_first_of (':') != string::npos) {
98 str = _impl->my_name();
106 PortManager::port_is_mine (const string& portname) const
108 string self = _impl->my_name();
110 if (portname.find_first_of (':') != string::npos) {
111 if (portname.substr (0, self.length ()) != self) {
120 PortManager::port_is_physical (const std::string& portname) const
122 PortEngine::PortHandle ph = _impl->get_port_by_name (portname);
127 return _impl->port_is_physical (ph);
131 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
133 _impl->get_physical_outputs (type, s);
137 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
139 _impl->get_physical_inputs (type, s);
143 PortManager::n_physical_outputs () const
145 return _impl->n_physical_outputs ();
149 PortManager::n_physical_inputs () const
151 return _impl->n_physical_inputs ();
154 /** @param name Full or short name of port
155 * @return Corresponding Port or 0.
158 boost::shared_ptr<Port>
159 PortManager::get_port_by_name (const string& portname)
161 if (!port_is_mine (portname)) {
162 /* not an ardour port */
163 return boost::shared_ptr<Port> ();
166 boost::shared_ptr<Ports> pr = ports.reader();
167 std::string rel = make_port_name_relative (portname);
168 Ports::iterator x = pr->find (rel);
170 if (x != pr->end()) {
171 /* its possible that the port was renamed by some 3rd party and
172 we don't know about it. check for this (the check is quick
173 and cheap), and if so, rename the port (which will alter
174 the port map as a side effect).
176 const std::string check = make_port_name_relative (_impl->get_port_name (x->second->port_handle()));
178 x->second->set_name (check);
183 return boost::shared_ptr<Port> ();
187 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
189 RCUWriter<Ports> writer (ports);
190 boost::shared_ptr<Ports> p = writer.get_copy();
191 Ports::iterator x = p->find (old_relative_name);
194 boost::shared_ptr<Port> port = x->second;
196 p->insert (make_pair (new_relative_name, port));
201 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
203 return _impl->get_ports (port_name_pattern, type, flags, s);
207 PortManager::port_registration_failure (const std::string& portname)
209 string full_portname = _impl->my_name();
210 full_portname += ':';
211 full_portname += portname;
214 PortEngine::PortHandle p = _impl->get_port_by_name (full_portname);
218 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
220 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);
223 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
226 boost::shared_ptr<Port>
227 PortManager::register_port (DataType dtype, const string& portname, bool input)
229 boost::shared_ptr<Port> newport;
232 if (dtype == DataType::AUDIO) {
233 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
234 } else if (dtype == DataType::MIDI) {
235 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
237 throw PortRegistrationFailure("unable to create port (unknown type)");
240 RCUWriter<Ports> writer (ports);
241 boost::shared_ptr<Ports> ps = writer.get_copy ();
242 ps->insert (make_pair (make_port_name_relative (portname), newport));
244 /* writer goes out of scope, forces update */
249 catch (PortRegistrationFailure& err) {
251 } catch (std::exception& e) {
252 throw PortRegistrationFailure(string_compose(
253 _("unable to create port: %1"), e.what()).c_str());
255 throw PortRegistrationFailure("unable to create port (unknown error)");
259 boost::shared_ptr<Port>
260 PortManager::register_input_port (DataType type, const string& portname)
262 return register_port (type, portname, true);
265 boost::shared_ptr<Port>
266 PortManager::register_output_port (DataType type, const string& portname)
268 return register_port (type, portname, false);
272 PortManager::unregister_port (boost::shared_ptr<Port> port)
274 /* caller must hold process lock */
277 RCUWriter<Ports> writer (ports);
278 boost::shared_ptr<Ports> ps = writer.get_copy ();
279 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
281 if (x != ps->end()) {
285 /* writer goes out of scope, forces update */
294 PortManager::connected (const string& port_name)
296 PortEngine::PortHandle handle = _impl->get_port_by_name (port_name);
302 return _impl->connected (handle);
306 PortManager::connect (const string& source, const string& destination)
310 string s = make_port_name_non_relative (source);
311 string d = make_port_name_non_relative (destination);
313 boost::shared_ptr<Port> src = get_port_by_name (s);
314 boost::shared_ptr<Port> dst = get_port_by_name (d);
317 ret = src->connect (d);
319 ret = dst->connect (s);
321 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
326 /* already exists - no error, no warning */
327 } else if (ret < 0) {
328 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
329 source, s, destination, d)
337 PortManager::disconnect (const string& source, const string& destination)
341 string s = make_port_name_non_relative (source);
342 string d = make_port_name_non_relative (destination);
344 boost::shared_ptr<Port> src = get_port_by_name (s);
345 boost::shared_ptr<Port> dst = get_port_by_name (d);
348 ret = src->disconnect (d);
350 ret = dst->disconnect (s);
352 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
359 PortManager::disconnect (boost::shared_ptr<Port> port)
361 return port->disconnect_all ();
365 PortManager::reestablish_ports ()
369 boost::shared_ptr<Ports> p = ports.reader ();
371 for (i = p->begin(); i != p->end(); ++i) {
372 if (i->second->reestablish ()) {
383 MIDI::Manager::instance()->reestablish ();
389 PortManager::reconnect_ports ()
391 boost::shared_ptr<Ports> p = ports.reader ();
393 /* re-establish connections */
395 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
396 i->second->reconnect ();
399 MIDI::Manager::instance()->reconnect ();
405 PortManager::connect_callback (const string& a, const string& b, bool conn)
407 boost::shared_ptr<Port> port_a;
408 boost::shared_ptr<Port> port_b;
410 boost::shared_ptr<Ports> pr = ports.reader ();
412 x = pr->find (make_port_name_relative (a));
413 if (x != pr->end()) {
417 x = pr->find (make_port_name_relative (b));
418 if (x != pr->end()) {
422 PortConnectedOrDisconnected (
430 PortManager::registration_callback ()
432 if (!_port_remove_in_progress) {
433 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
438 PortManager::can_request_input_monitoring () const
440 return _impl->can_monitor_input ();
444 PortManager::request_input_monitoring (const string& name, bool yn) const
446 PortEngine::PortHandle ph = _impl->get_port_by_name (name);
449 _impl->request_input_monitoring (ph, yn);
454 PortManager::ensure_input_monitoring (const string& name, bool yn) const
456 PortEngine::PortHandle ph = _impl->get_port_by_name (name);
459 _impl->ensure_input_monitoring (ph, yn);