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/error.h"
22 #include "ardour/async_midi_port.h"
23 #include "ardour/audio_backend.h"
24 #include "ardour/audio_port.h"
25 #include "ardour/debug.h"
26 #include "ardour/midi_port.h"
27 #include "ardour/midiport_manager.h"
28 #include "ardour/port_manager.h"
32 using namespace ARDOUR;
37 PortManager::PortManager ()
39 , _port_remove_in_progress (false)
44 PortManager::remove_all_ports ()
46 /* make sure that JACK callbacks that will be invoked as we cleanup
47 * ports know that they have nothing to do.
50 _port_remove_in_progress = true;
52 /* process lock MUST be held by caller
56 RCUWriter<Ports> writer (ports);
57 boost::shared_ptr<Ports> ps = writer.get_copy ();
61 /* clear dead wood list in RCU */
65 _port_remove_in_progress = false;
70 PortManager::make_port_name_relative (const string& portname) const
76 string::size_type len;
78 string self = _backend->my_name();
80 len = portname.length();
82 for (n = 0; n < len; ++n) {
83 if (portname[n] == ':') {
88 if ((n != len) && (portname.substr (0, n) == self)) {
89 return portname.substr (n+1);
96 PortManager::make_port_name_non_relative (const string& portname) const
100 if (portname.find_first_of (':') != string::npos) {
104 str = _backend->my_name();
112 PortManager::get_pretty_name_by_name(const std::string& portname) const
114 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
118 if (0 == _backend->get_port_property (ph,
119 "http://jackaudio.org/metadata/pretty-name",
129 PortManager::port_is_mine (const string& portname) const
135 string self = _backend->my_name();
137 if (portname.find_first_of (':') != string::npos) {
138 if (portname.substr (0, self.length ()) != self) {
147 PortManager::port_is_physical (const std::string& portname) const
153 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
158 return _backend->port_is_physical (ph);
162 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
167 _backend->get_physical_outputs (type, s);
171 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
177 _backend->get_physical_inputs (type, s);
181 PortManager::n_physical_outputs () const
184 return ChanCount::ZERO;
187 return _backend->n_physical_outputs ();
191 PortManager::n_physical_inputs () const
194 return ChanCount::ZERO;
196 return _backend->n_physical_inputs ();
199 /** @param name Full or short name of port
200 * @return Corresponding Port or 0.
203 boost::shared_ptr<Port>
204 PortManager::get_port_by_name (const string& portname)
207 return boost::shared_ptr<Port>();
210 if (!port_is_mine (portname)) {
211 /* not an ardour port */
212 return boost::shared_ptr<Port> ();
215 boost::shared_ptr<Ports> pr = ports.reader();
216 std::string rel = make_port_name_relative (portname);
217 Ports::iterator x = pr->find (rel);
219 if (x != pr->end()) {
220 /* its possible that the port was renamed by some 3rd party and
221 we don't know about it. check for this (the check is quick
222 and cheap), and if so, rename the port (which will alter
223 the port map as a side effect).
225 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
227 x->second->set_name (check);
232 return boost::shared_ptr<Port> ();
236 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
238 RCUWriter<Ports> writer (ports);
239 boost::shared_ptr<Ports> p = writer.get_copy();
240 Ports::iterator x = p->find (old_relative_name);
243 boost::shared_ptr<Port> port = x->second;
245 p->insert (make_pair (new_relative_name, port));
250 PortManager::get_ports (DataType type, PortList& pl)
252 boost::shared_ptr<Ports> plist = ports.reader();
253 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
254 if (p->second->type() == type) {
255 pl.push_back (p->second);
262 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::connect (const string& source, const string& destination)
395 string s = make_port_name_non_relative (source);
396 string d = make_port_name_non_relative (destination);
398 boost::shared_ptr<Port> src = get_port_by_name (s);
399 boost::shared_ptr<Port> dst = get_port_by_name (d);
402 ret = src->connect (d);
404 ret = dst->connect (s);
406 /* neither port is known to us ...hand-off to the PortEngine
409 ret = _backend->connect (s, d);
416 /* already exists - no error, no warning */
417 } else if (ret < 0) {
418 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
419 source, s, destination, d)
427 PortManager::disconnect (const string& source, const string& destination)
431 string s = make_port_name_non_relative (source);
432 string d = make_port_name_non_relative (destination);
434 boost::shared_ptr<Port> src = get_port_by_name (s);
435 boost::shared_ptr<Port> dst = get_port_by_name (d);
438 ret = src->disconnect (d);
440 ret = dst->disconnect (s);
442 /* neither port is known to us ...hand-off to the PortEngine
445 ret = _backend->disconnect (s, d);
454 PortManager::disconnect (boost::shared_ptr<Port> port)
456 return port->disconnect_all ();
460 PortManager::reestablish_ports ()
464 boost::shared_ptr<Ports> p = ports.reader ();
466 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
468 for (i = p->begin(); i != p->end(); ++i) {
469 if (i->second->reestablish ()) {
470 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
471 std::cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << std::endl;
486 PortManager::reconnect_ports ()
488 boost::shared_ptr<Ports> p = ports.reader ();
490 /* re-establish connections */
492 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
494 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
495 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::check_monitoring ()
644 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
648 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
649 i->second->set_last_monitor (x);
650 /* XXX I think this is dangerous, due to
651 a likely mutex in the signal handlers ...
653 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
659 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
661 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
663 if (i->second->sends_output()) {
665 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
667 Sample* s = ap->engine_get_whole_audio_buffer ();
668 gain_t g = base_gain;
670 for (pframes_t n = 0; n < nframes; ++n) {
680 PortManager::port_engine()