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 len;
80 string self = _backend->my_name();
82 len = portname.length();
84 for (n = 0; n < len; ++n) {
85 if (portname[n] == ':') {
90 if ((n != len) && (portname.substr (0, n) == self)) {
91 return portname.substr (n+1);
98 PortManager::make_port_name_non_relative (const string& portname) const
102 if (portname.find_first_of (':') != string::npos) {
106 str = _backend->my_name();
114 PortManager::get_pretty_name_by_name(const std::string& portname) const
116 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
120 if (0 == _backend->get_port_property (ph,
121 "http://jackaudio.org/metadata/pretty-name",
131 PortManager::port_is_mine (const string& portname) const
137 string self = _backend->my_name();
139 if (portname.find_first_of (':') != string::npos) {
140 if (portname.substr (0, self.length ()) != self) {
149 PortManager::port_is_physical (const std::string& portname) const
155 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
160 return _backend->port_is_physical (ph);
164 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
169 _backend->get_physical_outputs (type, s);
173 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
179 _backend->get_physical_inputs (type, s);
183 PortManager::n_physical_outputs () const
186 return ChanCount::ZERO;
189 return _backend->n_physical_outputs ();
193 PortManager::n_physical_inputs () const
196 return ChanCount::ZERO;
198 return _backend->n_physical_inputs ();
202 PortManager::port_name_prefix_is_unique (const string& first_part_of_port_name) const
205 return boost::shared_ptr<Port>();
208 boost::shared_ptr<const Ports> pr = ports.reader();
209 const string::size_type len = first_part_of_port_name.length();
211 for (Ports::const_iterator x = pr->begin(); x != pr->end(); ++x) {
213 string prefix = x->first.substr (0, len);
215 if (strings_equal_ignore_case (prefix, first_part_of_port_name)) {
223 /** @param name Full or short name of port
224 * @return Corresponding Port or 0.
227 boost::shared_ptr<Port>
228 PortManager::get_port_by_name (const string& portname)
231 return boost::shared_ptr<Port>();
234 if (!port_is_mine (portname)) {
235 /* not an ardour port */
236 return boost::shared_ptr<Port> ();
239 boost::shared_ptr<Ports> pr = ports.reader();
240 std::string rel = make_port_name_relative (portname);
241 Ports::iterator x = pr->find (rel);
243 if (x != pr->end()) {
244 /* its possible that the port was renamed by some 3rd party and
245 we don't know about it. check for this (the check is quick
246 and cheap), and if so, rename the port (which will alter
247 the port map as a side effect).
249 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
251 x->second->set_name (check);
256 return boost::shared_ptr<Port> ();
260 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
262 RCUWriter<Ports> writer (ports);
263 boost::shared_ptr<Ports> p = writer.get_copy();
264 Ports::iterator x = p->find (old_relative_name);
267 boost::shared_ptr<Port> port = x->second;
269 p->insert (make_pair (new_relative_name, port));
274 PortManager::get_ports (DataType type, PortList& pl)
276 boost::shared_ptr<Ports> plist = ports.reader();
277 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
278 if (p->second->type() == type) {
279 pl.push_back (p->second);
286 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
294 return _backend->get_ports (port_name_pattern, type, flags, s);
298 PortManager::port_registration_failure (const std::string& portname)
304 string full_portname = _backend->my_name();
305 full_portname += ':';
306 full_portname += portname;
309 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
313 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
315 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);
318 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
321 boost::shared_ptr<Port>
322 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
324 boost::shared_ptr<Port> newport;
327 if (dtype == DataType::AUDIO) {
328 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
330 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
331 } else if (dtype == DataType::MIDI) {
333 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
335 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
337 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
339 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
342 throw PortRegistrationFailure("unable to create port (unknown type)");
345 RCUWriter<Ports> writer (ports);
346 boost::shared_ptr<Ports> ps = writer.get_copy ();
347 ps->insert (make_pair (make_port_name_relative (portname), newport));
349 /* writer goes out of scope, forces update */
353 catch (PortRegistrationFailure& err) {
355 } catch (std::exception& e) {
356 throw PortRegistrationFailure(string_compose(
357 _("unable to create port: %1"), e.what()).c_str());
359 throw PortRegistrationFailure("unable to create port (unknown error)");
362 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
366 boost::shared_ptr<Port>
367 PortManager::register_input_port (DataType type, const string& portname, bool async)
369 return register_port (type, portname, true, async);
372 boost::shared_ptr<Port>
373 PortManager::register_output_port (DataType type, const string& portname, bool async)
375 return register_port (type, portname, false, async);
379 PortManager::unregister_port (boost::shared_ptr<Port> port)
381 /* caller must hold process lock */
384 RCUWriter<Ports> writer (ports);
385 boost::shared_ptr<Ports> ps = writer.get_copy ();
386 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
388 if (x != ps->end()) {
392 /* writer goes out of scope, forces update */
401 PortManager::connected (const string& port_name)
407 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
413 return _backend->connected (handle);
417 PortManager::connect (const string& source, const string& destination)
421 string s = make_port_name_non_relative (source);
422 string d = make_port_name_non_relative (destination);
424 boost::shared_ptr<Port> src = get_port_by_name (s);
425 boost::shared_ptr<Port> dst = get_port_by_name (d);
428 ret = src->connect (d);
430 ret = dst->connect (s);
432 /* neither port is known to us ...hand-off to the PortEngine
435 ret = _backend->connect (s, d);
442 /* already exists - no error, no warning */
443 } else if (ret < 0) {
444 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
445 source, s, destination, d)
453 PortManager::disconnect (const string& source, const string& destination)
457 string s = make_port_name_non_relative (source);
458 string d = make_port_name_non_relative (destination);
460 boost::shared_ptr<Port> src = get_port_by_name (s);
461 boost::shared_ptr<Port> dst = get_port_by_name (d);
464 ret = src->disconnect (d);
466 ret = dst->disconnect (s);
468 /* neither port is known to us ...hand-off to the PortEngine
471 ret = _backend->disconnect (s, d);
480 PortManager::disconnect (boost::shared_ptr<Port> port)
482 return port->disconnect_all ();
486 PortManager::reestablish_ports ()
490 boost::shared_ptr<Ports> p = ports.reader ();
492 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
494 for (i = p->begin(); i != p->end(); ++i) {
495 if (i->second->reestablish ()) {
496 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
497 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
512 PortManager::reconnect_ports ()
514 boost::shared_ptr<Ports> p = ports.reader ();
516 if (!Profile->get_trx()) {
517 /* re-establish connections */
519 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
521 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
522 i->second->reconnect ();
530 PortManager::connect_callback (const string& a, const string& b, bool conn)
532 boost::shared_ptr<Port> port_a;
533 boost::shared_ptr<Port> port_b;
535 boost::shared_ptr<Ports> pr = ports.reader ();
537 x = pr->find (make_port_name_relative (a));
538 if (x != pr->end()) {
542 x = pr->find (make_port_name_relative (b));
543 if (x != pr->end()) {
547 PortConnectedOrDisconnected (
555 PortManager::registration_callback ()
557 if (!_port_remove_in_progress) {
558 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
563 PortManager::can_request_input_monitoring () const
569 return _backend->can_monitor_input ();
573 PortManager::request_input_monitoring (const string& name, bool yn) const
579 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
582 _backend->request_input_monitoring (ph, yn);
587 PortManager::ensure_input_monitoring (const string& name, bool yn) const
593 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
596 _backend->ensure_input_monitoring (ph, yn);
601 PortManager::port_name_size() const
607 return _backend->port_name_size ();
611 PortManager::my_name() const
617 return _backend->my_name();
621 PortManager::graph_order_callback ()
623 if (!_port_remove_in_progress) {
624 GraphReordered(); /* EMIT SIGNAL */
631 PortManager::cycle_start (pframes_t nframes)
633 Port::set_global_port_buffer_offset (0);
634 Port::set_cycle_framecnt (nframes);
636 _cycle_ports = ports.reader ();
638 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
639 p->second->cycle_start (nframes);
644 PortManager::cycle_end (pframes_t nframes)
646 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
647 p->second->cycle_end (nframes);
650 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
651 p->second->flush_buffers (nframes);
654 _cycle_ports.reset ();
660 PortManager::silence (pframes_t nframes)
662 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
663 if (i->second->sends_output()) {
664 i->second->get_buffer(nframes).silence(nframes);
670 PortManager::silence_outputs (pframes_t nframes)
672 std::vector<std::string> port_names;
673 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
674 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
675 if (!port_is_mine(*p)) {
678 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
682 void *buf = _backend->get_buffer(ph, nframes);
686 memset (buf, 0, sizeof(float) * nframes);
690 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
691 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
692 if (!port_is_mine(*p)) {
695 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
699 void *buf = _backend->get_buffer(ph, nframes);
703 _backend->midi_clear (buf);
709 PortManager::check_monitoring ()
711 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
715 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
716 i->second->set_last_monitor (x);
717 /* XXX I think this is dangerous, due to
718 a likely mutex in the signal handlers ...
720 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
726 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
728 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
730 if (i->second->sends_output()) {
732 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
734 Sample* s = ap->engine_get_whole_audio_buffer ();
735 gain_t g = base_gain;
737 for (pframes_t n = 0; n < nframes; ++n) {
747 PortManager::port_engine()