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/convert.h"
21 #include "pbd/error.h"
23 #include "ardour/async_midi_port.h"
24 #include "ardour/audio_backend.h"
25 #include "ardour/audio_port.h"
26 #include "ardour/debug.h"
27 #include "ardour/midi_port.h"
28 #include "ardour/midiport_manager.h"
29 #include "ardour/port_manager.h"
30 #include "ardour/profile.h"
34 using namespace ARDOUR;
39 PortManager::PortManager ()
41 , _port_remove_in_progress (false)
46 PortManager::remove_all_ports ()
48 /* make sure that JACK callbacks that will be invoked as we cleanup
49 * ports know that they have nothing to do.
52 _port_remove_in_progress = true;
54 /* process lock MUST be held by caller
58 RCUWriter<Ports> writer (ports);
59 boost::shared_ptr<Ports> ps = writer.get_copy ();
63 /* clear dead wood list in RCU */
67 _port_remove_in_progress = false;
72 PortManager::make_port_name_relative (const string& portname) const
78 string::size_type colon = portname.find (':');
80 if (colon == string::npos) {
84 if (portname.substr (0, colon) == _backend->my_name()) {
85 return portname.substr (colon+1);
92 PortManager::make_port_name_non_relative (const string& portname) const
96 if (portname.find_first_of (':') != string::npos) {
100 str = _backend->my_name();
108 PortManager::get_pretty_name_by_name(const std::string& portname) const
110 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
114 if (0 == _backend->get_port_property (ph,
115 "http://jackaudio.org/metadata/pretty-name",
125 PortManager::port_is_mine (const string& portname) const
131 string self = _backend->my_name();
133 if (portname.find_first_of (':') != string::npos) {
134 if (portname.substr (0, self.length ()) != self) {
143 PortManager::port_is_physical (const std::string& portname) const
149 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
154 return _backend->port_is_physical (ph);
158 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
163 _backend->get_physical_outputs (type, s);
167 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
173 _backend->get_physical_inputs (type, s);
177 PortManager::n_physical_outputs () const
180 return ChanCount::ZERO;
183 return _backend->n_physical_outputs ();
187 PortManager::n_physical_inputs () const
190 return ChanCount::ZERO;
192 return _backend->n_physical_inputs ();
196 PortManager::port_name_prefix_is_unique (const string& first_part_of_port_name) const
199 return boost::shared_ptr<Port>();
202 boost::shared_ptr<const Ports> pr = ports.reader();
203 const string::size_type len = first_part_of_port_name.length();
205 for (Ports::const_iterator x = pr->begin(); x != pr->end(); ++x) {
207 string prefix = x->first.substr (0, len);
209 if (strings_equal_ignore_case (prefix, first_part_of_port_name)) {
217 /** @param name Full or short name of port
218 * @return Corresponding Port or 0.
221 boost::shared_ptr<Port>
222 PortManager::get_port_by_name (const string& portname)
225 return boost::shared_ptr<Port>();
228 if (!port_is_mine (portname)) {
229 /* not an ardour port */
230 return boost::shared_ptr<Port> ();
233 boost::shared_ptr<Ports> pr = ports.reader();
234 std::string rel = make_port_name_relative (portname);
235 Ports::iterator x = pr->find (rel);
237 if (x != pr->end()) {
238 /* its possible that the port was renamed by some 3rd party and
239 we don't know about it. check for this (the check is quick
240 and cheap), and if so, rename the port (which will alter
241 the port map as a side effect).
243 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
245 x->second->set_name (check);
250 return boost::shared_ptr<Port> ();
254 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
256 RCUWriter<Ports> writer (ports);
257 boost::shared_ptr<Ports> p = writer.get_copy();
258 Ports::iterator x = p->find (old_relative_name);
261 boost::shared_ptr<Port> port = x->second;
263 p->insert (make_pair (new_relative_name, port));
268 PortManager::get_ports (DataType type, PortList& pl)
270 boost::shared_ptr<Ports> plist = ports.reader();
271 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
272 if (p->second->type() == type) {
273 pl.push_back (p->second);
280 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
288 return _backend->get_ports (port_name_pattern, type, flags, s);
292 PortManager::port_registration_failure (const std::string& portname)
298 string full_portname = _backend->my_name();
299 full_portname += ':';
300 full_portname += portname;
303 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
307 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
309 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);
312 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
315 boost::shared_ptr<Port>
316 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
318 boost::shared_ptr<Port> newport;
321 if (dtype == DataType::AUDIO) {
322 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
324 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
325 } else if (dtype == DataType::MIDI) {
327 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
329 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
331 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
333 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
336 throw PortRegistrationFailure("unable to create port (unknown type)");
339 RCUWriter<Ports> writer (ports);
340 boost::shared_ptr<Ports> ps = writer.get_copy ();
341 ps->insert (make_pair (make_port_name_relative (portname), newport));
343 /* writer goes out of scope, forces update */
347 catch (PortRegistrationFailure& err) {
349 } catch (std::exception& e) {
350 throw PortRegistrationFailure(string_compose(
351 _("unable to create port: %1"), e.what()).c_str());
353 throw PortRegistrationFailure("unable to create port (unknown error)");
356 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
360 boost::shared_ptr<Port>
361 PortManager::register_input_port (DataType type, const string& portname, bool async)
363 return register_port (type, portname, true, async);
366 boost::shared_ptr<Port>
367 PortManager::register_output_port (DataType type, const string& portname, bool async)
369 return register_port (type, portname, false, async);
373 PortManager::unregister_port (boost::shared_ptr<Port> port)
375 /* caller must hold process lock */
378 RCUWriter<Ports> writer (ports);
379 boost::shared_ptr<Ports> ps = writer.get_copy ();
380 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
382 if (x != ps->end()) {
386 /* writer goes out of scope, forces update */
395 PortManager::connected (const string& port_name)
401 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
407 return _backend->connected (handle);
411 PortManager::connect (const string& source, const string& destination)
415 string s = make_port_name_non_relative (source);
416 string d = make_port_name_non_relative (destination);
418 boost::shared_ptr<Port> src = get_port_by_name (s);
419 boost::shared_ptr<Port> dst = get_port_by_name (d);
422 ret = src->connect (d);
424 ret = dst->connect (s);
426 /* neither port is known to us ...hand-off to the PortEngine
429 ret = _backend->connect (s, d);
436 /* already exists - no error, no warning */
437 } else if (ret < 0) {
438 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
439 source, s, destination, d)
447 PortManager::disconnect (const string& source, const string& destination)
451 string s = make_port_name_non_relative (source);
452 string d = make_port_name_non_relative (destination);
454 boost::shared_ptr<Port> src = get_port_by_name (s);
455 boost::shared_ptr<Port> dst = get_port_by_name (d);
458 ret = src->disconnect (d);
460 ret = dst->disconnect (s);
462 /* neither port is known to us ...hand-off to the PortEngine
465 ret = _backend->disconnect (s, d);
474 PortManager::disconnect (boost::shared_ptr<Port> port)
476 return port->disconnect_all ();
480 PortManager::reestablish_ports ()
484 boost::shared_ptr<Ports> p = ports.reader ();
486 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
488 for (i = p->begin(); i != p->end(); ++i) {
489 if (i->second->reestablish ()) {
490 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
491 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
506 PortManager::reconnect_ports ()
508 boost::shared_ptr<Ports> p = ports.reader ();
510 if (!Profile->get_trx()) {
511 /* re-establish connections */
513 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
515 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
516 i->second->reconnect ();
524 PortManager::connect_callback (const string& a, const string& b, bool conn)
526 boost::shared_ptr<Port> port_a;
527 boost::shared_ptr<Port> port_b;
529 boost::shared_ptr<Ports> pr = ports.reader ();
531 x = pr->find (make_port_name_relative (a));
532 if (x != pr->end()) {
536 x = pr->find (make_port_name_relative (b));
537 if (x != pr->end()) {
541 PortConnectedOrDisconnected (
549 PortManager::registration_callback ()
551 if (!_port_remove_in_progress) {
552 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
557 PortManager::can_request_input_monitoring () const
563 return _backend->can_monitor_input ();
567 PortManager::request_input_monitoring (const string& name, bool yn) const
573 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
576 _backend->request_input_monitoring (ph, yn);
581 PortManager::ensure_input_monitoring (const string& name, bool yn) const
587 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
590 _backend->ensure_input_monitoring (ph, yn);
595 PortManager::port_name_size() const
601 return _backend->port_name_size ();
605 PortManager::my_name() const
611 return _backend->my_name();
615 PortManager::graph_order_callback ()
617 if (!_port_remove_in_progress) {
618 GraphReordered(); /* EMIT SIGNAL */
625 PortManager::cycle_start (pframes_t nframes)
627 Port::set_global_port_buffer_offset (0);
628 Port::set_cycle_framecnt (nframes);
630 _cycle_ports = ports.reader ();
632 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
633 p->second->cycle_start (nframes);
638 PortManager::cycle_end (pframes_t nframes)
640 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
641 p->second->cycle_end (nframes);
644 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
645 p->second->flush_buffers (nframes);
648 _cycle_ports.reset ();
654 PortManager::silence (pframes_t nframes)
656 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
657 if (i->second->sends_output()) {
658 i->second->get_buffer(nframes).silence(nframes);
664 PortManager::silence_outputs (pframes_t nframes)
666 std::vector<std::string> port_names;
667 if (get_ports("", DataType::AUDIO, 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 memset (buf, 0, sizeof(float) * nframes);
684 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
685 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
686 if (!port_is_mine(*p)) {
689 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
693 void *buf = _backend->get_buffer(ph, nframes);
697 _backend->midi_clear (buf);
703 PortManager::check_monitoring ()
705 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
709 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
710 i->second->set_last_monitor (x);
711 /* XXX I think this is dangerous, due to
712 a likely mutex in the signal handlers ...
714 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
720 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
722 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
724 if (i->second->sends_output()) {
726 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
728 Sample* s = ap->engine_get_whole_audio_buffer ();
729 gain_t g = base_gain;
731 for (pframes_t n = 0; n < nframes; ++n) {
741 PortManager::port_engine()