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 "ardour/async_midi_port.h"
23 #include "ardour/audio_backend.h"
24 #include "ardour/audio_port.h"
25 #include "ardour/debug.h"
26 #include "ardour/midi_port.h"
27 #include "ardour/midiport_manager.h"
28 #include "ardour/port_manager.h"
29 #include "ardour/profile.h"
33 using namespace ARDOUR;
38 PortManager::PortManager ()
40 , _port_remove_in_progress (false)
45 PortManager::remove_all_ports ()
47 /* make sure that JACK callbacks that will be invoked as we cleanup
48 * ports know that they have nothing to do.
51 _port_remove_in_progress = true;
53 /* process lock MUST be held by caller
57 RCUWriter<Ports> writer (ports);
58 boost::shared_ptr<Ports> ps = writer.get_copy ();
62 /* clear dead wood list in RCU */
66 _port_remove_in_progress = false;
71 PortManager::make_port_name_relative (const string& portname) const
77 string::size_type len;
79 string self = _backend->my_name();
81 len = portname.length();
83 for (n = 0; n < len; ++n) {
84 if (portname[n] == ':') {
89 if ((n != len) && (portname.substr (0, n) == self)) {
90 return portname.substr (n+1);
97 PortManager::make_port_name_non_relative (const string& portname) const
101 if (portname.find_first_of (':') != string::npos) {
105 str = _backend->my_name();
113 PortManager::get_pretty_name_by_name(const std::string& portname) const
115 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
119 if (0 == _backend->get_port_property (ph,
120 "http://jackaudio.org/metadata/pretty-name",
130 PortManager::port_is_mine (const string& portname) const
136 string self = _backend->my_name();
138 if (portname.find_first_of (':') != string::npos) {
139 if (portname.substr (0, self.length ()) != self) {
148 PortManager::port_is_physical (const std::string& portname) const
154 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
159 return _backend->port_is_physical (ph);
163 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
168 _backend->get_physical_outputs (type, s);
172 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
178 _backend->get_physical_inputs (type, s);
182 PortManager::n_physical_outputs () const
185 return ChanCount::ZERO;
188 return _backend->n_physical_outputs ();
192 PortManager::n_physical_inputs () const
195 return ChanCount::ZERO;
197 return _backend->n_physical_inputs ();
200 /** @param name Full or short name of port
201 * @return Corresponding Port or 0.
204 boost::shared_ptr<Port>
205 PortManager::get_port_by_name (const string& portname)
208 return boost::shared_ptr<Port>();
211 if (!port_is_mine (portname)) {
212 /* not an ardour port */
213 return boost::shared_ptr<Port> ();
216 boost::shared_ptr<Ports> pr = ports.reader();
217 std::string rel = make_port_name_relative (portname);
218 Ports::iterator x = pr->find (rel);
220 if (x != pr->end()) {
221 /* its possible that the port was renamed by some 3rd party and
222 we don't know about it. check for this (the check is quick
223 and cheap), and if so, rename the port (which will alter
224 the port map as a side effect).
226 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
228 x->second->set_name (check);
233 return boost::shared_ptr<Port> ();
237 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
239 RCUWriter<Ports> writer (ports);
240 boost::shared_ptr<Ports> p = writer.get_copy();
241 Ports::iterator x = p->find (old_relative_name);
244 boost::shared_ptr<Port> port = x->second;
246 p->insert (make_pair (new_relative_name, port));
251 PortManager::get_ports (DataType type, PortList& pl)
253 boost::shared_ptr<Ports> plist = ports.reader();
254 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
255 if (p->second->type() == type) {
256 pl.push_back (p->second);
263 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
271 return _backend->get_ports (port_name_pattern, type, flags, s);
275 PortManager::port_registration_failure (const std::string& portname)
281 string full_portname = _backend->my_name();
282 full_portname += ':';
283 full_portname += portname;
286 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
290 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
292 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);
295 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
298 boost::shared_ptr<Port>
299 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
301 boost::shared_ptr<Port> newport;
304 if (dtype == DataType::AUDIO) {
305 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
307 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
308 } else if (dtype == DataType::MIDI) {
310 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
312 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
314 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
316 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
319 throw PortRegistrationFailure("unable to create port (unknown type)");
322 RCUWriter<Ports> writer (ports);
323 boost::shared_ptr<Ports> ps = writer.get_copy ();
324 ps->insert (make_pair (make_port_name_relative (portname), newport));
326 /* writer goes out of scope, forces update */
330 catch (PortRegistrationFailure& err) {
332 } catch (std::exception& e) {
333 throw PortRegistrationFailure(string_compose(
334 _("unable to create port: %1"), e.what()).c_str());
336 throw PortRegistrationFailure("unable to create port (unknown error)");
339 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
343 boost::shared_ptr<Port>
344 PortManager::register_input_port (DataType type, const string& portname, bool async)
346 return register_port (type, portname, true, async);
349 boost::shared_ptr<Port>
350 PortManager::register_output_port (DataType type, const string& portname, bool async)
352 return register_port (type, portname, false, async);
356 PortManager::unregister_port (boost::shared_ptr<Port> port)
358 /* caller must hold process lock */
361 RCUWriter<Ports> writer (ports);
362 boost::shared_ptr<Ports> ps = writer.get_copy ();
363 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
365 if (x != ps->end()) {
369 /* writer goes out of scope, forces update */
378 PortManager::connected (const string& port_name)
384 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
390 return _backend->connected (handle);
394 PortManager::connect (const string& source, const string& destination)
398 string s = make_port_name_non_relative (source);
399 string d = make_port_name_non_relative (destination);
401 boost::shared_ptr<Port> src = get_port_by_name (s);
402 boost::shared_ptr<Port> dst = get_port_by_name (d);
405 ret = src->connect (d);
407 ret = dst->connect (s);
409 /* neither port is known to us ...hand-off to the PortEngine
412 ret = _backend->connect (s, d);
419 /* already exists - no error, no warning */
420 } else if (ret < 0) {
421 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
422 source, s, destination, d)
430 PortManager::disconnect (const string& source, const string& destination)
434 string s = make_port_name_non_relative (source);
435 string d = make_port_name_non_relative (destination);
437 boost::shared_ptr<Port> src = get_port_by_name (s);
438 boost::shared_ptr<Port> dst = get_port_by_name (d);
441 ret = src->disconnect (d);
443 ret = dst->disconnect (s);
445 /* neither port is known to us ...hand-off to the PortEngine
448 ret = _backend->disconnect (s, d);
457 PortManager::disconnect (boost::shared_ptr<Port> port)
459 return port->disconnect_all ();
463 PortManager::reestablish_ports ()
467 boost::shared_ptr<Ports> p = ports.reader ();
469 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
471 for (i = p->begin(); i != p->end(); ++i) {
472 if (i->second->reestablish ()) {
473 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
474 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
489 PortManager::reconnect_ports ()
491 boost::shared_ptr<Ports> p = ports.reader ();
493 if (!Profile->get_trx()) {
494 /* re-establish connections */
496 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
498 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
499 i->second->reconnect ();
507 PortManager::connect_callback (const string& a, const string& b, bool conn)
509 boost::shared_ptr<Port> port_a;
510 boost::shared_ptr<Port> port_b;
512 boost::shared_ptr<Ports> pr = ports.reader ();
514 x = pr->find (make_port_name_relative (a));
515 if (x != pr->end()) {
519 x = pr->find (make_port_name_relative (b));
520 if (x != pr->end()) {
524 PortConnectedOrDisconnected (
532 PortManager::registration_callback ()
534 if (!_port_remove_in_progress) {
535 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
540 PortManager::can_request_input_monitoring () const
546 return _backend->can_monitor_input ();
550 PortManager::request_input_monitoring (const string& name, bool yn) const
556 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
559 _backend->request_input_monitoring (ph, yn);
564 PortManager::ensure_input_monitoring (const string& name, bool yn) const
570 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
573 _backend->ensure_input_monitoring (ph, yn);
578 PortManager::port_name_size() const
584 return _backend->port_name_size ();
588 PortManager::my_name() const
594 return _backend->my_name();
598 PortManager::graph_order_callback ()
600 if (!_port_remove_in_progress) {
601 GraphReordered(); /* EMIT SIGNAL */
608 PortManager::cycle_start (pframes_t nframes)
610 Port::set_global_port_buffer_offset (0);
611 Port::set_cycle_framecnt (nframes);
613 _cycle_ports = ports.reader ();
615 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
616 p->second->cycle_start (nframes);
621 PortManager::cycle_end (pframes_t nframes)
623 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
624 p->second->cycle_end (nframes);
627 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
628 p->second->flush_buffers (nframes);
631 _cycle_ports.reset ();
637 PortManager::silence (pframes_t nframes)
639 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
640 if (i->second->sends_output()) {
641 i->second->get_buffer(nframes).silence(nframes);
647 PortManager::silence_outputs (pframes_t nframes)
649 std::vector<std::string> port_names;
650 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
651 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
652 if (!port_is_mine(*p)) {
655 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
659 void *buf = _backend->get_buffer(ph, nframes);
663 memset (buf, 0, sizeof(float) * nframes);
667 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
668 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
669 if (!port_is_mine(*p)) {
672 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
676 void *buf = _backend->get_buffer(ph, nframes);
680 _backend->midi_clear (buf);
686 PortManager::check_monitoring ()
688 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
692 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
693 i->second->set_last_monitor (x);
694 /* XXX I think this is dangerous, due to
695 a likely mutex in the signal handlers ...
697 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
703 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
705 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
707 if (i->second->sends_output()) {
709 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
711 Sample* s = ap->engine_get_whole_audio_buffer ();
712 gain_t g = base_gain;
714 for (pframes_t n = 0; n < nframes; ++n) {
724 PortManager::port_engine()