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, PortFlags flags)
299 boost::shared_ptr<Port> newport;
301 /* limit the possible flags that can be set */
303 flags = PortFlags (flags & (Hidden|Shadow|IsTerminal));
306 if (dtype == DataType::AUDIO) {
307 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
309 newport.reset (new AudioPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)));
310 } else if (dtype == DataType::MIDI) {
312 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
314 newport.reset (new AsyncMIDIPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)));
316 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
318 newport.reset (new MidiPort (portname, PortFlags ((input ? IsInput : IsOutput) | flags)));
321 throw PortRegistrationFailure("unable to create port (unknown type)");
324 RCUWriter<Ports> writer (ports);
325 boost::shared_ptr<Ports> ps = writer.get_copy ();
326 ps->insert (make_pair (make_port_name_relative (portname), newport));
328 /* writer goes out of scope, forces update */
332 catch (PortRegistrationFailure& err) {
334 } catch (std::exception& e) {
335 throw PortRegistrationFailure(string_compose(
336 _("unable to create port: %1"), e.what()).c_str());
338 throw PortRegistrationFailure("unable to create port (unknown error)");
341 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
345 boost::shared_ptr<Port>
346 PortManager::register_input_port (DataType type, const string& portname, bool async, PortFlags extra_flags)
348 return register_port (type, portname, true, async, extra_flags);
351 boost::shared_ptr<Port>
352 PortManager::register_output_port (DataType type, const string& portname, bool async, PortFlags extra_flags)
354 return register_port (type, portname, false, async, extra_flags);
358 PortManager::unregister_port (boost::shared_ptr<Port> port)
360 /* This is a little subtle. We do not call the backend's port
361 * unregistration code from here. That is left for the Port
362 * destructor. We are trying to drop references to the Port object
363 * here, so that its destructor will run and it will unregister itself.
366 /* caller must hold process lock */
369 RCUWriter<Ports> writer (ports);
370 boost::shared_ptr<Ports> ps = writer.get_copy ();
371 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
373 if (x != ps->end()) {
377 /* writer goes out of scope, forces update */
386 PortManager::connected (const string& port_name)
392 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
398 return _backend->connected (handle);
402 PortManager::physically_connected (const string& port_name)
408 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
414 return _backend->physically_connected (handle);
418 PortManager::get_connections (const string& port_name, std::vector<std::string>& s)
425 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
432 return _backend->get_connections (handle, s);
436 PortManager::connect (const string& source, const string& destination)
440 string s = make_port_name_non_relative (source);
441 string d = make_port_name_non_relative (destination);
443 boost::shared_ptr<Port> src = get_port_by_name (s);
444 boost::shared_ptr<Port> dst = get_port_by_name (d);
447 ret = src->connect (d);
449 ret = dst->connect (s);
451 /* neither port is known to us ...hand-off to the PortEngine
454 ret = _backend->connect (s, d);
461 /* already exists - no error, no warning */
462 } else if (ret < 0) {
463 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
464 source, s, destination, d)
472 PortManager::disconnect (const string& source, const string& destination)
476 string s = make_port_name_non_relative (source);
477 string d = make_port_name_non_relative (destination);
479 boost::shared_ptr<Port> src = get_port_by_name (s);
480 boost::shared_ptr<Port> dst = get_port_by_name (d);
483 ret = src->disconnect (d);
485 ret = dst->disconnect (s);
487 /* neither port is known to us ...hand-off to the PortEngine
490 ret = _backend->disconnect (s, d);
499 PortManager::disconnect (boost::shared_ptr<Port> port)
501 return port->disconnect_all ();
505 PortManager::reestablish_ports ()
509 boost::shared_ptr<Ports> p = ports.reader ();
511 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
513 for (i = p->begin(); i != p->end(); ++i) {
514 if (i->second->reestablish ()) {
515 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
516 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
531 PortManager::reconnect_ports ()
533 boost::shared_ptr<Ports> p = ports.reader ();
535 if (!Profile->get_trx()) {
536 /* re-establish connections */
538 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
540 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
541 i->second->reconnect ();
549 PortManager::connect_callback (const string& a, const string& b, bool conn)
551 boost::shared_ptr<Port> port_a;
552 boost::shared_ptr<Port> port_b;
554 boost::shared_ptr<Ports> pr = ports.reader ();
556 x = pr->find (make_port_name_relative (a));
557 if (x != pr->end()) {
561 x = pr->find (make_port_name_relative (b));
562 if (x != pr->end()) {
566 PortConnectedOrDisconnected (
574 PortManager::registration_callback ()
576 if (!_port_remove_in_progress) {
577 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
582 PortManager::can_request_input_monitoring () const
588 return _backend->can_monitor_input ();
592 PortManager::request_input_monitoring (const string& name, bool yn) const
598 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
601 _backend->request_input_monitoring (ph, yn);
606 PortManager::ensure_input_monitoring (const string& name, bool yn) const
612 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
615 _backend->ensure_input_monitoring (ph, yn);
620 PortManager::port_name_size() const
626 return _backend->port_name_size ();
630 PortManager::my_name() const
636 return _backend->my_name();
640 PortManager::graph_order_callback ()
642 if (!_port_remove_in_progress) {
643 GraphReordered(); /* EMIT SIGNAL */
650 PortManager::cycle_start (pframes_t nframes)
652 Port::set_global_port_buffer_offset (0);
653 Port::set_cycle_framecnt (nframes);
655 _cycle_ports = ports.reader ();
657 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
658 p->second->cycle_start (nframes);
663 PortManager::cycle_end (pframes_t nframes)
665 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
666 p->second->cycle_end (nframes);
669 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
670 p->second->flush_buffers (nframes);
673 _cycle_ports.reset ();
679 PortManager::silence (pframes_t nframes, Session *s)
681 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
682 if (s && i->second == s->mtc_output_port ()) {
685 if (s && i->second == s->midi_clock_output_port ()) {
688 if (s && i->second == s->ltc_output_port ()) {
691 if (boost::dynamic_pointer_cast<AsyncMIDIPort>(i->second)) {
694 if (i->second->sends_output()) {
695 i->second->get_buffer(nframes).silence(nframes);
701 PortManager::silence_outputs (pframes_t nframes)
703 std::vector<std::string> port_names;
704 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
705 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
706 if (!port_is_mine(*p)) {
709 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
713 void *buf = _backend->get_buffer(ph, nframes);
717 memset (buf, 0, sizeof(float) * nframes);
721 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
722 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
723 if (!port_is_mine(*p)) {
726 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
730 void *buf = _backend->get_buffer(ph, nframes);
734 _backend->midi_clear (buf);
740 PortManager::check_monitoring ()
742 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
746 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
747 i->second->set_last_monitor (x);
748 /* XXX I think this is dangerous, due to
749 a likely mutex in the signal handlers ...
751 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
757 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
759 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
761 if (i->second->sends_output()) {
763 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
765 Sample* s = ap->engine_get_whole_audio_buffer ();
766 gain_t g = base_gain;
768 for (pframes_t n = 0; n < nframes; ++n) {
778 PortManager::port_engine()