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 /* caller must hold process lock */
359 RCUWriter<Ports> writer (ports);
360 boost::shared_ptr<Ports> ps = writer.get_copy ();
361 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
363 if (x != ps->end()) {
367 /* writer goes out of scope, forces update */
376 PortManager::connected (const string& port_name)
382 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
388 return _backend->connected (handle);
392 PortManager::physically_connected (const string& port_name)
398 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
404 return _backend->physically_connected (handle);
408 PortManager::get_connections (const string& port_name, std::vector<std::string>& s)
415 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
422 return _backend->get_connections (handle, s);
426 PortManager::connect (const string& source, const string& destination)
430 string s = make_port_name_non_relative (source);
431 string d = make_port_name_non_relative (destination);
433 boost::shared_ptr<Port> src = get_port_by_name (s);
434 boost::shared_ptr<Port> dst = get_port_by_name (d);
437 ret = src->connect (d);
439 ret = dst->connect (s);
441 /* neither port is known to us ...hand-off to the PortEngine
444 ret = _backend->connect (s, d);
451 /* already exists - no error, no warning */
452 } else if (ret < 0) {
453 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
454 source, s, destination, d)
462 PortManager::disconnect (const string& source, const string& destination)
466 string s = make_port_name_non_relative (source);
467 string d = make_port_name_non_relative (destination);
469 boost::shared_ptr<Port> src = get_port_by_name (s);
470 boost::shared_ptr<Port> dst = get_port_by_name (d);
473 ret = src->disconnect (d);
475 ret = dst->disconnect (s);
477 /* neither port is known to us ...hand-off to the PortEngine
480 ret = _backend->disconnect (s, d);
489 PortManager::disconnect (boost::shared_ptr<Port> port)
491 return port->disconnect_all ();
495 PortManager::reestablish_ports ()
499 boost::shared_ptr<Ports> p = ports.reader ();
501 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
503 for (i = p->begin(); i != p->end(); ++i) {
504 if (i->second->reestablish ()) {
505 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
506 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
521 PortManager::reconnect_ports ()
523 boost::shared_ptr<Ports> p = ports.reader ();
525 if (!Profile->get_trx()) {
526 /* re-establish connections */
528 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
530 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
531 i->second->reconnect ();
539 PortManager::connect_callback (const string& a, const string& b, bool conn)
541 boost::shared_ptr<Port> port_a;
542 boost::shared_ptr<Port> port_b;
544 boost::shared_ptr<Ports> pr = ports.reader ();
546 x = pr->find (make_port_name_relative (a));
547 if (x != pr->end()) {
551 x = pr->find (make_port_name_relative (b));
552 if (x != pr->end()) {
556 PortConnectedOrDisconnected (
564 PortManager::registration_callback ()
566 if (!_port_remove_in_progress) {
567 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
572 PortManager::can_request_input_monitoring () const
578 return _backend->can_monitor_input ();
582 PortManager::request_input_monitoring (const string& name, bool yn) const
588 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
591 _backend->request_input_monitoring (ph, yn);
596 PortManager::ensure_input_monitoring (const string& name, bool yn) const
602 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
605 _backend->ensure_input_monitoring (ph, yn);
610 PortManager::port_name_size() const
616 return _backend->port_name_size ();
620 PortManager::my_name() const
626 return _backend->my_name();
630 PortManager::graph_order_callback ()
632 if (!_port_remove_in_progress) {
633 GraphReordered(); /* EMIT SIGNAL */
640 PortManager::cycle_start (pframes_t nframes)
642 Port::set_global_port_buffer_offset (0);
643 Port::set_cycle_framecnt (nframes);
645 _cycle_ports = ports.reader ();
647 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
648 p->second->cycle_start (nframes);
653 PortManager::cycle_end (pframes_t nframes)
655 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
656 p->second->cycle_end (nframes);
659 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
660 p->second->flush_buffers (nframes);
663 _cycle_ports.reset ();
669 PortManager::silence (pframes_t nframes, Session *s)
671 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
672 if (s && i->second == s->mtc_output_port ()) {
675 if (s && i->second == s->midi_clock_output_port ()) {
678 if (s && i->second == s->ltc_output_port ()) {
681 if (i->second->sends_output()) {
682 i->second->get_buffer(nframes).silence(nframes);
688 PortManager::silence_outputs (pframes_t nframes)
690 std::vector<std::string> port_names;
691 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
692 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
693 if (!port_is_mine(*p)) {
696 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
700 void *buf = _backend->get_buffer(ph, nframes);
704 memset (buf, 0, sizeof(float) * nframes);
708 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
709 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
710 if (!port_is_mine(*p)) {
713 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
717 void *buf = _backend->get_buffer(ph, nframes);
721 _backend->midi_clear (buf);
727 PortManager::check_monitoring ()
729 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
733 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
734 i->second->set_last_monitor (x);
735 /* XXX I think this is dangerous, due to
736 a likely mutex in the signal handlers ...
738 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
744 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
746 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
748 if (i->second->sends_output()) {
750 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
752 Sample* s = ap->engine_get_whole_audio_buffer ();
753 gain_t g = base_gain;
755 for (pframes_t n = 0; n < nframes; ++n) {
765 PortManager::port_engine()