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"
31 #include "ardour/session.h"
35 using namespace ARDOUR;
40 PortManager::PortManager ()
42 , _port_remove_in_progress (false)
47 PortManager::remove_all_ports ()
49 /* make sure that JACK callbacks that will be invoked as we cleanup
50 * ports know that they have nothing to do.
53 _port_remove_in_progress = true;
55 /* process lock MUST be held by caller
59 RCUWriter<Ports> writer (ports);
60 boost::shared_ptr<Ports> ps = writer.get_copy ();
64 /* clear dead wood list in RCU */
68 _port_remove_in_progress = false;
73 PortManager::make_port_name_relative (const string& portname) const
79 string::size_type colon = portname.find (':');
81 if (colon == string::npos) {
85 if (portname.substr (0, colon) == _backend->my_name()) {
86 return portname.substr (colon+1);
93 PortManager::make_port_name_non_relative (const string& portname) const
97 if (portname.find_first_of (':') != string::npos) {
101 str = _backend->my_name();
109 PortManager::get_pretty_name_by_name(const std::string& portname) const
111 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
115 if (0 == _backend->get_port_property (ph,
116 "http://jackaudio.org/metadata/pretty-name",
126 PortManager::port_is_mine (const string& portname) const
132 string self = _backend->my_name();
134 if (portname.find_first_of (':') != string::npos) {
135 if (portname.substr (0, self.length ()) != self) {
144 PortManager::port_is_physical (const std::string& portname) const
150 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
155 return _backend->port_is_physical (ph);
159 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
165 _backend->get_physical_outputs (type, s);
169 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
176 _backend->get_physical_inputs (type, s);
180 PortManager::n_physical_outputs () const
183 return ChanCount::ZERO;
186 return _backend->n_physical_outputs ();
190 PortManager::n_physical_inputs () const
193 return ChanCount::ZERO;
195 return _backend->n_physical_inputs ();
198 /** @param name Full or short name of port
199 * @return Corresponding Port or 0.
202 boost::shared_ptr<Port>
203 PortManager::get_port_by_name (const string& portname)
206 return boost::shared_ptr<Port>();
209 if (!port_is_mine (portname)) {
210 /* not an ardour port */
211 return boost::shared_ptr<Port> ();
214 boost::shared_ptr<Ports> pr = ports.reader();
215 std::string rel = make_port_name_relative (portname);
216 Ports::iterator x = pr->find (rel);
218 if (x != pr->end()) {
219 /* its possible that the port was renamed by some 3rd party and
220 we don't know about it. check for this (the check is quick
221 and cheap), and if so, rename the port (which will alter
222 the port map as a side effect).
224 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
226 x->second->set_name (check);
231 return boost::shared_ptr<Port> ();
235 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
237 RCUWriter<Ports> writer (ports);
238 boost::shared_ptr<Ports> p = writer.get_copy();
239 Ports::iterator x = p->find (old_relative_name);
242 boost::shared_ptr<Port> port = x->second;
244 p->insert (make_pair (new_relative_name, port));
249 PortManager::get_ports (DataType type, PortList& pl)
251 boost::shared_ptr<Ports> plist = ports.reader();
252 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
253 if (p->second->type() == type) {
254 pl.push_back (p->second);
261 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
269 return _backend->get_ports (port_name_pattern, type, flags, s);
273 PortManager::port_registration_failure (const std::string& portname)
279 string full_portname = _backend->my_name();
280 full_portname += ':';
281 full_portname += portname;
284 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
288 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
290 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);
293 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
296 boost::shared_ptr<Port>
297 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
299 boost::shared_ptr<Port> newport;
302 if (dtype == DataType::AUDIO) {
303 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
305 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
306 } else if (dtype == DataType::MIDI) {
308 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
310 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
312 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
314 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
317 throw PortRegistrationFailure("unable to create port (unknown type)");
320 RCUWriter<Ports> writer (ports);
321 boost::shared_ptr<Ports> ps = writer.get_copy ();
322 ps->insert (make_pair (make_port_name_relative (portname), newport));
324 /* writer goes out of scope, forces update */
328 catch (PortRegistrationFailure& err) {
330 } catch (std::exception& e) {
331 throw PortRegistrationFailure(string_compose(
332 _("unable to create port: %1"), e.what()).c_str());
334 throw PortRegistrationFailure("unable to create port (unknown error)");
337 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
341 boost::shared_ptr<Port>
342 PortManager::register_input_port (DataType type, const string& portname, bool async)
344 return register_port (type, portname, true, async);
347 boost::shared_ptr<Port>
348 PortManager::register_output_port (DataType type, const string& portname, bool async)
350 return register_port (type, portname, false, async);
354 PortManager::unregister_port (boost::shared_ptr<Port> port)
356 /* This is a little subtle. We do not call the backend's port
357 * unregistration code from here. That is left for the Port
358 * destructor. We are trying to drop references to the Port object
359 * here, so that its destructor will run and it will unregister itself.
362 /* caller must hold process lock */
365 RCUWriter<Ports> writer (ports);
366 boost::shared_ptr<Ports> ps = writer.get_copy ();
367 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
369 if (x != ps->end()) {
373 /* writer goes out of scope, forces update */
382 PortManager::connected (const string& port_name)
388 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
394 return _backend->connected (handle);
398 PortManager::physically_connected (const string& port_name)
404 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
410 return _backend->physically_connected (handle);
414 PortManager::get_connections (const string& port_name, std::vector<std::string>& s)
421 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
428 return _backend->get_connections (handle, s);
432 PortManager::connect (const string& source, const string& destination)
436 string s = make_port_name_non_relative (source);
437 string d = make_port_name_non_relative (destination);
439 boost::shared_ptr<Port> src = get_port_by_name (s);
440 boost::shared_ptr<Port> dst = get_port_by_name (d);
443 ret = src->connect (d);
445 ret = dst->connect (s);
447 /* neither port is known to us ...hand-off to the PortEngine
450 ret = _backend->connect (s, d);
457 /* already exists - no error, no warning */
458 } else if (ret < 0) {
459 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
460 source, s, destination, d)
468 PortManager::disconnect (const string& source, const string& destination)
472 string s = make_port_name_non_relative (source);
473 string d = make_port_name_non_relative (destination);
475 boost::shared_ptr<Port> src = get_port_by_name (s);
476 boost::shared_ptr<Port> dst = get_port_by_name (d);
479 ret = src->disconnect (d);
481 ret = dst->disconnect (s);
483 /* neither port is known to us ...hand-off to the PortEngine
486 ret = _backend->disconnect (s, d);
495 PortManager::disconnect (boost::shared_ptr<Port> port)
497 return port->disconnect_all ();
501 PortManager::reestablish_ports ()
505 boost::shared_ptr<Ports> p = ports.reader ();
507 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
509 for (i = p->begin(); i != p->end(); ++i) {
510 if (i->second->reestablish ()) {
511 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
512 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
527 PortManager::reconnect_ports ()
529 boost::shared_ptr<Ports> p = ports.reader ();
531 if (!Profile->get_trx()) {
532 /* re-establish connections */
534 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
536 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
537 i->second->reconnect ();
545 PortManager::connect_callback (const string& a, const string& b, bool conn)
547 boost::shared_ptr<Port> port_a;
548 boost::shared_ptr<Port> port_b;
550 boost::shared_ptr<Ports> pr = ports.reader ();
552 x = pr->find (make_port_name_relative (a));
553 if (x != pr->end()) {
557 x = pr->find (make_port_name_relative (b));
558 if (x != pr->end()) {
562 PortConnectedOrDisconnected (
570 PortManager::registration_callback ()
572 if (!_port_remove_in_progress) {
573 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
578 PortManager::can_request_input_monitoring () const
584 return _backend->can_monitor_input ();
588 PortManager::request_input_monitoring (const string& name, bool yn) const
594 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
597 _backend->request_input_monitoring (ph, yn);
602 PortManager::ensure_input_monitoring (const string& name, bool yn) const
608 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
611 _backend->ensure_input_monitoring (ph, yn);
616 PortManager::port_name_size() const
622 return _backend->port_name_size ();
626 PortManager::my_name() const
632 return _backend->my_name();
636 PortManager::graph_order_callback ()
638 if (!_port_remove_in_progress) {
639 GraphReordered(); /* EMIT SIGNAL */
646 PortManager::cycle_start (pframes_t nframes)
648 Port::set_global_port_buffer_offset (0);
649 Port::set_cycle_framecnt (nframes);
651 _cycle_ports = ports.reader ();
653 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
654 p->second->cycle_start (nframes);
659 PortManager::cycle_end (pframes_t nframes)
661 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
662 p->second->cycle_end (nframes);
665 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
666 p->second->flush_buffers (nframes);
669 _cycle_ports.reset ();
675 PortManager::silence (pframes_t nframes, Session *s)
677 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
678 if (s && i->second == s->mtc_output_port ()) {
681 if (s && i->second == s->midi_clock_output_port ()) {
684 if (s && i->second == s->ltc_output_port ()) {
687 if (i->second->sends_output()) {
688 i->second->get_buffer(nframes).silence(nframes);
694 PortManager::silence_outputs (pframes_t nframes)
696 std::vector<std::string> port_names;
697 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
698 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
699 if (!port_is_mine(*p)) {
702 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
706 void *buf = _backend->get_buffer(ph, nframes);
710 memset (buf, 0, sizeof(float) * nframes);
714 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
715 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
716 if (!port_is_mine(*p)) {
719 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
723 void *buf = _backend->get_buffer(ph, nframes);
727 _backend->midi_clear (buf);
733 PortManager::check_monitoring ()
735 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
739 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
740 i->second->set_last_monitor (x);
741 /* XXX I think this is dangerous, due to
742 a likely mutex in the signal handlers ...
744 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
750 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
752 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
754 if (i->second->sends_output()) {
756 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
758 Sample* s = ap->engine_get_whole_audio_buffer ();
759 gain_t g = base_gain;
761 for (pframes_t n = 0; n < nframes; ++n) {
771 PortManager::port_engine()