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/debug.h"
24 #include "ardour/port_manager.h"
25 #include "ardour/audio_port.h"
26 #include "ardour/midi_port.h"
27 #include "ardour/midiport_manager.h"
31 using namespace ARDOUR;
36 PortManager::PortManager ()
38 , _port_remove_in_progress (false)
43 PortManager::remove_all_ports ()
45 /* make sure that JACK callbacks that will be invoked as we cleanup
46 * ports know that they have nothing to do.
49 _port_remove_in_progress = true;
51 /* process lock MUST be held by caller
55 RCUWriter<Ports> writer (ports);
56 boost::shared_ptr<Ports> ps = writer.get_copy ();
60 /* clear dead wood list in RCU */
64 _port_remove_in_progress = false;
69 PortManager::make_port_name_relative (const string& portname) const
75 string::size_type len;
77 string self = _impl->my_name();
79 len = portname.length();
81 for (n = 0; n < len; ++n) {
82 if (portname[n] == ':') {
87 if ((n != len) && (portname.substr (0, n) == self)) {
88 return portname.substr (n+1);
95 PortManager::make_port_name_non_relative (const string& portname) const
99 if (portname.find_first_of (':') != string::npos) {
103 str = _impl->my_name();
111 PortManager::port_is_mine (const string& portname) const
117 string self = _impl->my_name();
119 if (portname.find_first_of (':') != string::npos) {
120 if (portname.substr (0, self.length ()) != self) {
129 PortManager::port_is_physical (const std::string& portname) const
135 PortEngine::PortHandle ph = _impl->get_port_by_name (portname);
140 return _impl->port_is_physical (ph);
144 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
149 _impl->get_physical_outputs (type, s);
153 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
159 _impl->get_physical_inputs (type, s);
163 PortManager::n_physical_outputs () const
166 return ChanCount::ZERO;
169 return _impl->n_physical_outputs ();
173 PortManager::n_physical_inputs () const
176 return ChanCount::ZERO;
178 return _impl->n_physical_inputs ();
181 /** @param name Full or short name of port
182 * @return Corresponding Port or 0.
185 boost::shared_ptr<Port>
186 PortManager::get_port_by_name (const string& portname)
189 return boost::shared_ptr<Port>();
192 if (!port_is_mine (portname)) {
193 /* not an ardour port */
194 return boost::shared_ptr<Port> ();
197 boost::shared_ptr<Ports> pr = ports.reader();
198 std::string rel = make_port_name_relative (portname);
199 Ports::iterator x = pr->find (rel);
201 if (x != pr->end()) {
202 /* its possible that the port was renamed by some 3rd party and
203 we don't know about it. check for this (the check is quick
204 and cheap), and if so, rename the port (which will alter
205 the port map as a side effect).
207 const std::string check = make_port_name_relative (_impl->get_port_name (x->second->port_handle()));
209 x->second->set_name (check);
214 return boost::shared_ptr<Port> ();
218 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
220 RCUWriter<Ports> writer (ports);
221 boost::shared_ptr<Ports> p = writer.get_copy();
222 Ports::iterator x = p->find (old_relative_name);
225 boost::shared_ptr<Port> port = x->second;
227 p->insert (make_pair (new_relative_name, port));
232 PortManager::get_ports (DataType type, PortList& pl)
234 boost::shared_ptr<Ports> plist = ports.reader();
235 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
236 if (p->second->type() == type) {
237 pl.push_back (p->second);
244 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
250 return _impl->get_ports (port_name_pattern, type, flags, s);
254 PortManager::port_registration_failure (const std::string& portname)
260 string full_portname = _impl->my_name();
261 full_portname += ':';
262 full_portname += portname;
265 PortEngine::PortHandle p = _impl->get_port_by_name (full_portname);
269 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
271 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);
274 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
277 boost::shared_ptr<Port>
278 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
280 boost::shared_ptr<Port> newport;
283 if (dtype == DataType::AUDIO) {
284 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
286 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
287 } else if (dtype == DataType::MIDI) {
289 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
291 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
293 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
295 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
298 throw PortRegistrationFailure("unable to create port (unknown type)");
301 RCUWriter<Ports> writer (ports);
302 boost::shared_ptr<Ports> ps = writer.get_copy ();
303 ps->insert (make_pair (make_port_name_relative (portname), newport));
305 /* writer goes out of scope, forces update */
309 catch (PortRegistrationFailure& err) {
311 } catch (std::exception& e) {
312 throw PortRegistrationFailure(string_compose(
313 _("unable to create port: %1"), e.what()).c_str());
315 throw PortRegistrationFailure("unable to create port (unknown error)");
318 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
322 boost::shared_ptr<Port>
323 PortManager::register_input_port (DataType type, const string& portname, bool async)
325 return register_port (type, portname, true, async);
328 boost::shared_ptr<Port>
329 PortManager::register_output_port (DataType type, const string& portname, bool async)
331 return register_port (type, portname, false, async);
335 PortManager::unregister_port (boost::shared_ptr<Port> port)
337 /* caller must hold process lock */
340 RCUWriter<Ports> writer (ports);
341 boost::shared_ptr<Ports> ps = writer.get_copy ();
342 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
344 if (x != ps->end()) {
348 /* writer goes out of scope, forces update */
357 PortManager::connected (const string& port_name)
363 PortEngine::PortHandle handle = _impl->get_port_by_name (port_name);
369 return _impl->connected (handle);
373 PortManager::connect (const string& source, const string& destination)
377 string s = make_port_name_non_relative (source);
378 string d = make_port_name_non_relative (destination);
380 boost::shared_ptr<Port> src = get_port_by_name (s);
381 boost::shared_ptr<Port> dst = get_port_by_name (d);
384 ret = src->connect (d);
386 ret = dst->connect (s);
388 /* neither port is known to us ...hand-off to the PortEngine
391 ret = _impl->connect (s, d);
398 /* already exists - no error, no warning */
399 } else if (ret < 0) {
400 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
401 source, s, destination, d)
409 PortManager::disconnect (const string& source, const string& destination)
413 string s = make_port_name_non_relative (source);
414 string d = make_port_name_non_relative (destination);
416 boost::shared_ptr<Port> src = get_port_by_name (s);
417 boost::shared_ptr<Port> dst = get_port_by_name (d);
420 ret = src->disconnect (d);
422 ret = dst->disconnect (s);
424 /* neither port is known to us ...hand-off to the PortEngine
427 ret = _impl->disconnect (s, d);
436 PortManager::disconnect (boost::shared_ptr<Port> port)
438 return port->disconnect_all ();
442 PortManager::reestablish_ports ()
446 boost::shared_ptr<Ports> p = ports.reader ();
448 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
450 for (i = p->begin(); i != p->end(); ++i) {
451 if (i->second->reestablish ()) {
452 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
453 cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endl;
468 PortManager::reconnect_ports ()
470 boost::shared_ptr<Ports> p = ports.reader ();
472 /* re-establish connections */
474 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
476 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
477 i->second->reconnect ();
484 PortManager::connect_callback (const string& a, const string& b, bool conn)
486 boost::shared_ptr<Port> port_a;
487 boost::shared_ptr<Port> port_b;
489 boost::shared_ptr<Ports> pr = ports.reader ();
491 x = pr->find (make_port_name_relative (a));
492 if (x != pr->end()) {
496 x = pr->find (make_port_name_relative (b));
497 if (x != pr->end()) {
501 PortConnectedOrDisconnected (
509 PortManager::registration_callback ()
511 if (!_port_remove_in_progress) {
512 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
517 PortManager::can_request_input_monitoring () const
523 return _impl->can_monitor_input ();
527 PortManager::request_input_monitoring (const string& name, bool yn) const
533 PortEngine::PortHandle ph = _impl->get_port_by_name (name);
536 _impl->request_input_monitoring (ph, yn);
541 PortManager::ensure_input_monitoring (const string& name, bool yn) const
547 PortEngine::PortHandle ph = _impl->get_port_by_name (name);
550 _impl->ensure_input_monitoring (ph, yn);
555 PortManager::port_name_size() const
561 return _impl->port_name_size ();
565 PortManager::my_name() const
571 return _impl->my_name();
575 PortManager::graph_order_callback ()
577 if (!_port_remove_in_progress) {
578 GraphReordered(); /* EMIT SIGNAL */
585 PortManager::cycle_start (pframes_t nframes)
587 Port::set_global_port_buffer_offset (0);
588 Port::set_cycle_framecnt (nframes);
590 _cycle_ports = ports.reader ();
592 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
593 p->second->cycle_start (nframes);
598 PortManager::cycle_end (pframes_t nframes)
600 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
601 p->second->cycle_end (nframes);
604 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
605 p->second->flush_buffers (nframes);
608 _cycle_ports.reset ();
614 PortManager::silence (pframes_t nframes)
616 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
617 if (i->second->sends_output()) {
618 i->second->get_buffer(nframes).silence(nframes);
624 PortManager::check_monitoring ()
626 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
630 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
631 i->second->set_last_monitor (x);
632 /* XXX I think this is dangerous, due to
633 a likely mutex in the signal handlers ...
635 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
641 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
643 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
645 if (i->second->sends_output()) {
647 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
649 Sample* s = ap->engine_get_whole_audio_buffer ();
650 gain_t g = base_gain;
652 for (pframes_t n = 0; n < nframes; ++n) {