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)
163 _backend->get_physical_outputs (type, s);
167 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
173 _backend->get_physical_inputs (type, s);
177 PortManager::n_physical_outputs () const
180 return ChanCount::ZERO;
183 return _backend->n_physical_outputs ();
187 PortManager::n_physical_inputs () const
190 return ChanCount::ZERO;
192 return _backend->n_physical_inputs ();
195 /** @param name Full or short name of port
196 * @return Corresponding Port or 0.
199 boost::shared_ptr<Port>
200 PortManager::get_port_by_name (const string& portname)
203 return boost::shared_ptr<Port>();
206 if (!port_is_mine (portname)) {
207 /* not an ardour port */
208 return boost::shared_ptr<Port> ();
211 boost::shared_ptr<Ports> pr = ports.reader();
212 std::string rel = make_port_name_relative (portname);
213 Ports::iterator x = pr->find (rel);
215 if (x != pr->end()) {
216 /* its possible that the port was renamed by some 3rd party and
217 we don't know about it. check for this (the check is quick
218 and cheap), and if so, rename the port (which will alter
219 the port map as a side effect).
221 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
223 x->second->set_name (check);
228 return boost::shared_ptr<Port> ();
232 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
234 RCUWriter<Ports> writer (ports);
235 boost::shared_ptr<Ports> p = writer.get_copy();
236 Ports::iterator x = p->find (old_relative_name);
239 boost::shared_ptr<Port> port = x->second;
241 p->insert (make_pair (new_relative_name, port));
246 PortManager::get_ports (DataType type, PortList& pl)
248 boost::shared_ptr<Ports> plist = ports.reader();
249 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
250 if (p->second->type() == type) {
251 pl.push_back (p->second);
258 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
266 return _backend->get_ports (port_name_pattern, type, flags, s);
270 PortManager::port_registration_failure (const std::string& portname)
276 string full_portname = _backend->my_name();
277 full_portname += ':';
278 full_portname += portname;
281 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
285 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
287 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);
290 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
293 boost::shared_ptr<Port>
294 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
296 boost::shared_ptr<Port> newport;
299 if (dtype == DataType::AUDIO) {
300 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
302 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
303 } else if (dtype == DataType::MIDI) {
305 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
307 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
309 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
311 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
314 throw PortRegistrationFailure("unable to create port (unknown type)");
317 RCUWriter<Ports> writer (ports);
318 boost::shared_ptr<Ports> ps = writer.get_copy ();
319 ps->insert (make_pair (make_port_name_relative (portname), newport));
321 /* writer goes out of scope, forces update */
325 catch (PortRegistrationFailure& err) {
327 } catch (std::exception& e) {
328 throw PortRegistrationFailure(string_compose(
329 _("unable to create port: %1"), e.what()).c_str());
331 throw PortRegistrationFailure("unable to create port (unknown error)");
334 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
338 boost::shared_ptr<Port>
339 PortManager::register_input_port (DataType type, const string& portname, bool async)
341 return register_port (type, portname, true, async);
344 boost::shared_ptr<Port>
345 PortManager::register_output_port (DataType type, const string& portname, bool async)
347 return register_port (type, portname, false, async);
351 PortManager::unregister_port (boost::shared_ptr<Port> port)
353 /* caller must hold process lock */
356 RCUWriter<Ports> writer (ports);
357 boost::shared_ptr<Ports> ps = writer.get_copy ();
358 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
360 if (x != ps->end()) {
364 /* writer goes out of scope, forces update */
373 PortManager::connected (const string& port_name)
379 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
385 return _backend->connected (handle);
389 PortManager::connect (const string& source, const string& destination)
393 string s = make_port_name_non_relative (source);
394 string d = make_port_name_non_relative (destination);
396 boost::shared_ptr<Port> src = get_port_by_name (s);
397 boost::shared_ptr<Port> dst = get_port_by_name (d);
400 ret = src->connect (d);
402 ret = dst->connect (s);
404 /* neither port is known to us ...hand-off to the PortEngine
407 ret = _backend->connect (s, d);
414 /* already exists - no error, no warning */
415 } else if (ret < 0) {
416 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
417 source, s, destination, d)
425 PortManager::disconnect (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->disconnect (d);
438 ret = dst->disconnect (s);
440 /* neither port is known to us ...hand-off to the PortEngine
443 ret = _backend->disconnect (s, d);
452 PortManager::disconnect (boost::shared_ptr<Port> port)
454 return port->disconnect_all ();
458 PortManager::reestablish_ports ()
462 boost::shared_ptr<Ports> p = ports.reader ();
464 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
466 for (i = p->begin(); i != p->end(); ++i) {
467 if (i->second->reestablish ()) {
468 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
469 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
484 PortManager::reconnect_ports ()
486 boost::shared_ptr<Ports> p = ports.reader ();
488 if (!Profile->get_trx()) {
489 /* re-establish connections */
491 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
493 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
494 i->second->reconnect ();
502 PortManager::connect_callback (const string& a, const string& b, bool conn)
504 boost::shared_ptr<Port> port_a;
505 boost::shared_ptr<Port> port_b;
507 boost::shared_ptr<Ports> pr = ports.reader ();
509 x = pr->find (make_port_name_relative (a));
510 if (x != pr->end()) {
514 x = pr->find (make_port_name_relative (b));
515 if (x != pr->end()) {
519 PortConnectedOrDisconnected (
527 PortManager::registration_callback ()
529 if (!_port_remove_in_progress) {
530 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
535 PortManager::can_request_input_monitoring () const
541 return _backend->can_monitor_input ();
545 PortManager::request_input_monitoring (const string& name, bool yn) const
551 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
554 _backend->request_input_monitoring (ph, yn);
559 PortManager::ensure_input_monitoring (const string& name, bool yn) const
565 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
568 _backend->ensure_input_monitoring (ph, yn);
573 PortManager::port_name_size() const
579 return _backend->port_name_size ();
583 PortManager::my_name() const
589 return _backend->my_name();
593 PortManager::graph_order_callback ()
595 if (!_port_remove_in_progress) {
596 GraphReordered(); /* EMIT SIGNAL */
603 PortManager::cycle_start (pframes_t nframes)
605 Port::set_global_port_buffer_offset (0);
606 Port::set_cycle_framecnt (nframes);
608 _cycle_ports = ports.reader ();
610 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
611 p->second->cycle_start (nframes);
616 PortManager::cycle_end (pframes_t nframes)
618 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
619 p->second->cycle_end (nframes);
622 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
623 p->second->flush_buffers (nframes);
626 _cycle_ports.reset ();
632 PortManager::silence (pframes_t nframes)
634 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
635 if (i->second->sends_output()) {
636 i->second->get_buffer(nframes).silence(nframes);
642 PortManager::silence_outputs (pframes_t nframes)
644 std::vector<std::string> port_names;
645 if (get_ports("", DataType::AUDIO, IsOutput, port_names)) {
646 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
647 if (!port_is_mine(*p)) {
650 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
654 void *buf = _backend->get_buffer(ph, nframes);
658 memset (buf, 0, sizeof(float) * nframes);
662 if (get_ports("", DataType::MIDI, IsOutput, port_names)) {
663 for (std::vector<std::string>::iterator p = port_names.begin(); p != port_names.end(); ++p) {
664 if (!port_is_mine(*p)) {
667 PortEngine::PortHandle ph = _backend->get_port_by_name (*p);
671 void *buf = _backend->get_buffer(ph, nframes);
675 _backend->midi_clear (buf);
681 PortManager::check_monitoring ()
683 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
687 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
688 i->second->set_last_monitor (x);
689 /* XXX I think this is dangerous, due to
690 a likely mutex in the signal handlers ...
692 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
698 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
700 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
702 if (i->second->sends_output()) {
704 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
706 Sample* s = ap->engine_get_whole_audio_buffer ();
707 gain_t g = base_gain;
709 for (pframes_t n = 0; n < nframes; ++n) {
719 PortManager::port_engine()