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)
164 _backend->get_physical_outputs (type, s);
168 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
175 _backend->get_physical_inputs (type, s);
179 PortManager::n_physical_outputs () const
182 return ChanCount::ZERO;
185 return _backend->n_physical_outputs ();
189 PortManager::n_physical_inputs () const
192 return ChanCount::ZERO;
194 return _backend->n_physical_inputs ();
197 /** @param name Full or short name of port
198 * @return Corresponding Port or 0.
201 boost::shared_ptr<Port>
202 PortManager::get_port_by_name (const string& portname)
205 return boost::shared_ptr<Port>();
208 if (!port_is_mine (portname)) {
209 /* not an ardour port */
210 return boost::shared_ptr<Port> ();
213 boost::shared_ptr<Ports> pr = ports.reader();
214 std::string rel = make_port_name_relative (portname);
215 Ports::iterator x = pr->find (rel);
217 if (x != pr->end()) {
218 /* its possible that the port was renamed by some 3rd party and
219 we don't know about it. check for this (the check is quick
220 and cheap), and if so, rename the port (which will alter
221 the port map as a side effect).
223 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
225 x->second->set_name (check);
230 return boost::shared_ptr<Port> ();
234 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
236 RCUWriter<Ports> writer (ports);
237 boost::shared_ptr<Ports> p = writer.get_copy();
238 Ports::iterator x = p->find (old_relative_name);
241 boost::shared_ptr<Port> port = x->second;
243 p->insert (make_pair (new_relative_name, port));
248 PortManager::get_ports (DataType type, PortList& pl)
250 boost::shared_ptr<Ports> plist = ports.reader();
251 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
252 if (p->second->type() == type) {
253 pl.push_back (p->second);
260 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
268 return _backend->get_ports (port_name_pattern, type, flags, s);
272 PortManager::port_registration_failure (const std::string& portname)
278 string full_portname = _backend->my_name();
279 full_portname += ':';
280 full_portname += portname;
283 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
287 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
289 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);
292 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
295 boost::shared_ptr<Port>
296 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
298 boost::shared_ptr<Port> newport;
301 if (dtype == DataType::AUDIO) {
302 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
304 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
305 } else if (dtype == DataType::MIDI) {
307 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
309 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
311 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
313 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
316 throw PortRegistrationFailure("unable to create port (unknown type)");
319 RCUWriter<Ports> writer (ports);
320 boost::shared_ptr<Ports> ps = writer.get_copy ();
321 ps->insert (make_pair (make_port_name_relative (portname), newport));
323 /* writer goes out of scope, forces update */
327 catch (PortRegistrationFailure& err) {
329 } catch (std::exception& e) {
330 throw PortRegistrationFailure(string_compose(
331 _("unable to create port: %1"), e.what()).c_str());
333 throw PortRegistrationFailure("unable to create port (unknown error)");
336 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
340 boost::shared_ptr<Port>
341 PortManager::register_input_port (DataType type, const string& portname, bool async)
343 return register_port (type, portname, true, async);
346 boost::shared_ptr<Port>
347 PortManager::register_output_port (DataType type, const string& portname, bool async)
349 return register_port (type, portname, false, async);
353 PortManager::unregister_port (boost::shared_ptr<Port> port)
355 /* caller must hold process lock */
358 RCUWriter<Ports> writer (ports);
359 boost::shared_ptr<Ports> ps = writer.get_copy ();
360 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
362 if (x != ps->end()) {
366 /* writer goes out of scope, forces update */
375 PortManager::connected (const string& port_name)
381 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
387 return _backend->connected (handle);
391 PortManager::physically_connected (const string& port_name)
397 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
403 return _backend->physically_connected (handle);
407 PortManager::get_connections (const string& port_name, std::vector<std::string>& s)
414 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
421 return _backend->get_connections (handle, s);
425 PortManager::connect (const string& source, const string& destination)
429 string s = make_port_name_non_relative (source);
430 string d = make_port_name_non_relative (destination);
432 boost::shared_ptr<Port> src = get_port_by_name (s);
433 boost::shared_ptr<Port> dst = get_port_by_name (d);
436 ret = src->connect (d);
438 ret = dst->connect (s);
440 /* neither port is known to us ...hand-off to the PortEngine
443 ret = _backend->connect (s, d);
450 /* already exists - no error, no warning */
451 } else if (ret < 0) {
452 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
453 source, s, destination, d)
461 PortManager::disconnect (const string& source, const string& destination)
465 string s = make_port_name_non_relative (source);
466 string d = make_port_name_non_relative (destination);
468 boost::shared_ptr<Port> src = get_port_by_name (s);
469 boost::shared_ptr<Port> dst = get_port_by_name (d);
472 ret = src->disconnect (d);
474 ret = dst->disconnect (s);
476 /* neither port is known to us ...hand-off to the PortEngine
479 ret = _backend->disconnect (s, d);
488 PortManager::disconnect (boost::shared_ptr<Port> port)
490 return port->disconnect_all ();
494 PortManager::reestablish_ports ()
498 boost::shared_ptr<Ports> p = ports.reader ();
500 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
502 for (i = p->begin(); i != p->end(); ++i) {
503 if (i->second->reestablish ()) {
504 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
505 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
520 PortManager::reconnect_ports ()
522 boost::shared_ptr<Ports> p = ports.reader ();
524 if (!Profile->get_trx()) {
525 /* re-establish connections */
527 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
529 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
530 i->second->reconnect ();
538 PortManager::connect_callback (const string& a, const string& b, bool conn)
540 boost::shared_ptr<Port> port_a;
541 boost::shared_ptr<Port> port_b;
543 boost::shared_ptr<Ports> pr = ports.reader ();
545 x = pr->find (make_port_name_relative (a));
546 if (x != pr->end()) {
550 x = pr->find (make_port_name_relative (b));
551 if (x != pr->end()) {
555 PortConnectedOrDisconnected (
563 PortManager::registration_callback ()
565 if (!_port_remove_in_progress) {
566 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
571 PortManager::can_request_input_monitoring () const
577 return _backend->can_monitor_input ();
581 PortManager::request_input_monitoring (const string& name, bool yn) const
587 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
590 _backend->request_input_monitoring (ph, yn);
595 PortManager::ensure_input_monitoring (const string& name, bool yn) const
601 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
604 _backend->ensure_input_monitoring (ph, yn);
609 PortManager::port_name_size() const
615 return _backend->port_name_size ();
619 PortManager::my_name() const
625 return _backend->my_name();
629 PortManager::graph_order_callback ()
631 if (!_port_remove_in_progress) {
632 GraphReordered(); /* EMIT SIGNAL */
639 PortManager::cycle_start (pframes_t nframes)
641 Port::set_global_port_buffer_offset (0);
642 Port::set_cycle_framecnt (nframes);
644 _cycle_ports = ports.reader ();
646 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
647 p->second->cycle_start (nframes);
652 PortManager::cycle_end (pframes_t nframes)
654 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
655 p->second->cycle_end (nframes);
658 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
659 p->second->flush_buffers (nframes);
662 _cycle_ports.reset ();
668 PortManager::silence (pframes_t nframes)
670 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
671 if (i->second->sends_output()) {
672 i->second->get_buffer(nframes).silence(nframes);
678 PortManager::silence_outputs (pframes_t nframes)
680 std::vector<std::string> port_names;
681 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
682 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
683 if (!port_is_mine(*p)) {
686 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
690 void *buf = _backend->get_buffer(ph, nframes);
694 memset (buf, 0, sizeof(float) * nframes);
698 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
699 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
700 if (!port_is_mine(*p)) {
703 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
707 void *buf = _backend->get_buffer(ph, nframes);
711 _backend->midi_clear (buf);
717 PortManager::check_monitoring ()
719 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
723 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
724 i->second->set_last_monitor (x);
725 /* XXX I think this is dangerous, due to
726 a likely mutex in the signal handlers ...
728 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
734 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
736 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
738 if (i->second->sends_output()) {
740 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
742 Sample* s = ap->engine_get_whole_audio_buffer ();
743 gain_t g = base_gain;
745 for (pframes_t n = 0; n < nframes; ++n) {
755 PortManager::port_engine()