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::port_is_mine (const string& portname) const
118 string self = _backend->my_name();
120 if (portname.find_first_of (':') != string::npos) {
121 if (portname.substr (0, self.length ()) != self) {
130 PortManager::port_is_physical (const std::string& portname) const
136 PortEngine::PortHandle ph = _backend->get_port_by_name (portname);
141 return _backend->port_is_physical (ph);
145 PortManager::get_physical_outputs (DataType type, std::vector<std::string>& s)
150 _backend->get_physical_outputs (type, s);
154 PortManager::get_physical_inputs (DataType type, std::vector<std::string>& s)
160 _backend->get_physical_inputs (type, s);
164 PortManager::n_physical_outputs () const
167 return ChanCount::ZERO;
170 return _backend->n_physical_outputs ();
174 PortManager::n_physical_inputs () const
177 return ChanCount::ZERO;
179 return _backend->n_physical_inputs ();
182 /** @param name Full or short name of port
183 * @return Corresponding Port or 0.
186 boost::shared_ptr<Port>
187 PortManager::get_port_by_name (const string& portname)
190 return boost::shared_ptr<Port>();
193 if (!port_is_mine (portname)) {
194 /* not an ardour port */
195 return boost::shared_ptr<Port> ();
198 boost::shared_ptr<Ports> pr = ports.reader();
199 std::string rel = make_port_name_relative (portname);
200 Ports::iterator x = pr->find (rel);
202 if (x != pr->end()) {
203 /* its possible that the port was renamed by some 3rd party and
204 we don't know about it. check for this (the check is quick
205 and cheap), and if so, rename the port (which will alter
206 the port map as a side effect).
208 const std::string check = make_port_name_relative (_backend->get_port_name (x->second->port_handle()));
210 x->second->set_name (check);
215 return boost::shared_ptr<Port> ();
219 PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
221 RCUWriter<Ports> writer (ports);
222 boost::shared_ptr<Ports> p = writer.get_copy();
223 Ports::iterator x = p->find (old_relative_name);
226 boost::shared_ptr<Port> port = x->second;
228 p->insert (make_pair (new_relative_name, port));
233 PortManager::get_ports (DataType type, PortList& pl)
235 boost::shared_ptr<Ports> plist = ports.reader();
236 for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) {
237 if (p->second->type() == type) {
238 pl.push_back (p->second);
245 PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s)
251 return _backend->get_ports (port_name_pattern, type, flags, s);
255 PortManager::port_registration_failure (const std::string& portname)
261 string full_portname = _backend->my_name();
262 full_portname += ':';
263 full_portname += portname;
266 PortEngine::PortHandle p = _backend->get_port_by_name (full_portname);
270 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
272 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);
275 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
278 boost::shared_ptr<Port>
279 PortManager::register_port (DataType dtype, const string& portname, bool input, bool async)
281 boost::shared_ptr<Port> newport;
284 if (dtype == DataType::AUDIO) {
285 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n",
287 newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput)));
288 } else if (dtype == DataType::MIDI) {
290 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n",
292 newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput)));
294 DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n",
296 newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput)));
299 throw PortRegistrationFailure("unable to create port (unknown type)");
302 RCUWriter<Ports> writer (ports);
303 boost::shared_ptr<Ports> ps = writer.get_copy ();
304 ps->insert (make_pair (make_port_name_relative (portname), newport));
306 /* writer goes out of scope, forces update */
310 catch (PortRegistrationFailure& err) {
312 } catch (std::exception& e) {
313 throw PortRegistrationFailure(string_compose(
314 _("unable to create port: %1"), e.what()).c_str());
316 throw PortRegistrationFailure("unable to create port (unknown error)");
319 DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this));
323 boost::shared_ptr<Port>
324 PortManager::register_input_port (DataType type, const string& portname, bool async)
326 return register_port (type, portname, true, async);
329 boost::shared_ptr<Port>
330 PortManager::register_output_port (DataType type, const string& portname, bool async)
332 return register_port (type, portname, false, async);
336 PortManager::unregister_port (boost::shared_ptr<Port> port)
338 /* caller must hold process lock */
341 RCUWriter<Ports> writer (ports);
342 boost::shared_ptr<Ports> ps = writer.get_copy ();
343 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
345 if (x != ps->end()) {
349 /* writer goes out of scope, forces update */
358 PortManager::connected (const string& port_name)
364 PortEngine::PortHandle handle = _backend->get_port_by_name (port_name);
370 return _backend->connected (handle);
374 PortManager::connect (const string& source, const string& destination)
378 string s = make_port_name_non_relative (source);
379 string d = make_port_name_non_relative (destination);
381 boost::shared_ptr<Port> src = get_port_by_name (s);
382 boost::shared_ptr<Port> dst = get_port_by_name (d);
385 ret = src->connect (d);
387 ret = dst->connect (s);
389 /* neither port is known to us ...hand-off to the PortEngine
392 ret = _backend->connect (s, d);
399 /* already exists - no error, no warning */
400 } else if (ret < 0) {
401 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
402 source, s, destination, d)
410 PortManager::disconnect (const string& source, const string& destination)
414 string s = make_port_name_non_relative (source);
415 string d = make_port_name_non_relative (destination);
417 boost::shared_ptr<Port> src = get_port_by_name (s);
418 boost::shared_ptr<Port> dst = get_port_by_name (d);
421 ret = src->disconnect (d);
423 ret = dst->disconnect (s);
425 /* neither port is known to us ...hand-off to the PortEngine
428 ret = _backend->disconnect (s, d);
437 PortManager::disconnect (boost::shared_ptr<Port> port)
439 return port->disconnect_all ();
443 PortManager::reestablish_ports ()
447 boost::shared_ptr<Ports> p = ports.reader ();
449 DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size()));
451 for (i = p->begin(); i != p->end(); ++i) {
452 if (i->second->reestablish ()) {
453 error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
454 cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endl;
469 PortManager::reconnect_ports ()
471 boost::shared_ptr<Ports> p = ports.reader ();
473 /* re-establish connections */
475 DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
477 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
478 i->second->reconnect ();
485 PortManager::connect_callback (const string& a, const string& b, bool conn)
487 boost::shared_ptr<Port> port_a;
488 boost::shared_ptr<Port> port_b;
490 boost::shared_ptr<Ports> pr = ports.reader ();
492 x = pr->find (make_port_name_relative (a));
493 if (x != pr->end()) {
497 x = pr->find (make_port_name_relative (b));
498 if (x != pr->end()) {
502 PortConnectedOrDisconnected (
510 PortManager::registration_callback ()
512 if (!_port_remove_in_progress) {
513 PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
518 PortManager::can_request_input_monitoring () const
524 return _backend->can_monitor_input ();
528 PortManager::request_input_monitoring (const string& name, bool yn) const
534 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
537 _backend->request_input_monitoring (ph, yn);
542 PortManager::ensure_input_monitoring (const string& name, bool yn) const
548 PortEngine::PortHandle ph = _backend->get_port_by_name (name);
551 _backend->ensure_input_monitoring (ph, yn);
556 PortManager::port_name_size() const
562 return _backend->port_name_size ();
566 PortManager::my_name() const
572 return _backend->my_name();
576 PortManager::graph_order_callback ()
578 if (!_port_remove_in_progress) {
579 GraphReordered(); /* EMIT SIGNAL */
586 PortManager::cycle_start (pframes_t nframes)
588 Port::set_global_port_buffer_offset (0);
589 Port::set_cycle_framecnt (nframes);
591 _cycle_ports = ports.reader ();
593 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
594 p->second->cycle_start (nframes);
599 PortManager::cycle_end (pframes_t nframes)
601 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
602 p->second->cycle_end (nframes);
605 for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
606 p->second->flush_buffers (nframes);
609 _cycle_ports.reset ();
615 PortManager::silence (pframes_t nframes)
617 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
618 if (i->second->sends_output()) {
619 i->second->get_buffer(nframes).silence(nframes);
625 PortManager::check_monitoring ()
627 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
631 if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
632 i->second->set_last_monitor (x);
633 /* XXX I think this is dangerous, due to
634 a likely mutex in the signal handlers ...
636 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
642 PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes)
644 for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) {
646 if (i->second->sends_output()) {
648 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
650 Sample* s = ap->engine_get_whole_audio_buffer ();
651 gain_t g = base_gain;
653 for (pframes_t n = 0; n < nframes; ++n) {
663 PortManager::port_engine()