2 Copyright (C) 2000-2006 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.
25 #include <sigc++/bind.h>
27 #include <glibmm/thread.h>
29 #include <pbd/xml++.h>
30 #include <pbd/replace_all.h>
31 #include <pbd/unknown_type.h>
33 #include <ardour/audioengine.h>
34 #include <ardour/io.h>
35 #include <ardour/route.h>
36 #include <ardour/port.h>
37 #include <ardour/audio_port.h>
38 #include <ardour/midi_port.h>
39 #include <ardour/auto_bundle.h>
40 #include <ardour/session.h>
41 #include <ardour/cycle_timer.h>
42 #include <ardour/panner.h>
43 #include <ardour/buffer_set.h>
44 #include <ardour/meter.h>
45 #include <ardour/amp.h>
52 A bug in OS X's cmath that causes isnan() and isinf() to be
53 "undeclared". the following works around that
56 #if defined(__APPLE__) && defined(__MACH__)
57 extern "C" int isnan (double);
58 extern "C" int isinf (double);
61 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
64 using namespace ARDOUR;
67 const string IO::state_node_name = "IO";
68 bool IO::connecting_legal = false;
69 bool IO::ports_legal = false;
70 bool IO::panners_legal = false;
71 sigc::signal<void> IO::Meter;
72 sigc::signal<int> IO::ConnectingLegal;
73 sigc::signal<int> IO::PortsLegal;
74 sigc::signal<int> IO::PannersLegal;
75 sigc::signal<void,ChanCount> IO::PortCountChanged;
76 sigc::signal<int> IO::PortsCreated;
78 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
80 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
81 others can be imagined.
85 static gain_t direct_control_to_gain (double fract) {
86 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
87 /* this maxes at +6dB */
88 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
91 static double direct_gain_to_control (gain_t gain) {
92 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
93 if (gain == 0) return 0.0;
95 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
99 /** @param default_type The type of port that will be created by ensure_io
100 * and friends if no type is explicitly requested (to avoid breakage).
102 IO::IO (Session& s, const string& name,
103 int input_min, int input_max, int output_min, int output_max,
104 DataType default_type, bool public_ports)
105 : Automatable (s, name),
106 _output_buffers (new BufferSet()),
108 _default_type (default_type),
109 _public_ports (public_ports),
110 _input_minimum (ChanCount::ZERO),
111 _input_maximum (ChanCount::INFINITE),
112 _output_minimum (ChanCount::ZERO),
113 _output_maximum (ChanCount::INFINITE)
115 _panner = new Panner (name, _session);
116 _meter = new PeakMeter (_session);
119 _input_minimum = ChanCount(_default_type, input_min);
121 if (input_max >= 0) {
122 _input_maximum = ChanCount(_default_type, input_max);
124 if (output_min > 0) {
125 _output_minimum = ChanCount(_default_type, output_min);
127 if (output_max >= 0) {
128 _output_maximum = ChanCount(_default_type, output_max);
133 pending_state_node = 0;
134 no_panner_reset = false;
135 _phase_invert = false;
138 boost::shared_ptr<AutomationList> gl(
139 new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
141 _gain_control = boost::shared_ptr<GainControl>(
142 new GainControl(X_("gaincontrol"), *this, gl));
144 add_control(_gain_control);
146 apply_gain_automation = false;
149 // IO::Meter is emitted from another thread so the
150 // Meter signal must be protected.
151 Glib::Mutex::Lock guard (m_meter_signal_lock);
152 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
155 // Connect to our own PortCountChanged signal to connect output buffers
156 IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
158 _session.add_controllable (_gain_control);
160 create_bundles_for_inputs_and_outputs ();
163 IO::IO (Session& s, const XMLNode& node, DataType dt)
164 : Automatable (s, "unnamed io"),
165 _output_buffers (new BufferSet()),
168 _meter = new PeakMeter (_session);
169 _public_ports = true; // XXX get this from node
172 no_panner_reset = false;
176 apply_gain_automation = false;
178 boost::shared_ptr<AutomationList> gl(
179 new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
181 _gain_control = boost::shared_ptr<GainControl>(
182 new GainControl(X_("gaincontrol"), *this, gl));
184 add_control(_gain_control);
189 // IO::Meter is emitted from another thread so the
190 // Meter signal must be protected.
191 Glib::Mutex::Lock guard (m_meter_signal_lock);
192 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
195 // Connect to our own PortCountChanged signal to connect output buffers
196 IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
198 _session.add_controllable (_gain_control);
200 create_bundles_for_inputs_and_outputs ();
205 Glib::Mutex::Lock guard (m_meter_signal_lock);
206 Glib::Mutex::Lock lm (io_lock);
208 BLOCK_PROCESS_CALLBACK ();
210 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
211 _session.engine().unregister_port (*i);
214 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
215 _session.engine().unregister_port (*i);
218 m_meter_connection.disconnect();
222 delete _output_buffers;
226 IO::silence (nframes_t nframes, nframes_t offset)
228 /* io_lock, not taken: function must be called from Session::process() calltree */
230 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
231 i->get_buffer().silence (nframes, offset);
235 /** Deliver bufs to the IO's output ports
237 * This function should automatically do whatever it necessary to correctly deliver bufs
238 * to the outputs, eg applying gain or pan or whatever else needs to be done.
241 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
243 // FIXME: type specific code doesn't actually need to be here, it will go away in time
245 /* ********** AUDIO ********** */
247 // Apply gain if gain automation isn't playing
248 if ( ! apply_gain_automation) {
250 gain_t dg = _gain; // desired gain
253 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
261 if (dg != _gain || dg != 1.0)
262 Amp::run_in_place(bufs, nframes, _gain, dg, _phase_invert);
265 // Use the panner to distribute audio to output port buffers
266 if (_panner && !_panner->empty() && !_panner->bypassed()) {
267 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
269 const DataType type = DataType::AUDIO;
271 // Copy any audio 1:1 to outputs
273 BufferSet::iterator o = output_buffers().begin(type);
274 BufferSet::iterator i = bufs.begin(type);
275 BufferSet::iterator prev = i;
277 while (i != bufs.end(type) && o != output_buffers().end (type)) {
278 o->read_from(*i, nframes, offset);
284 /* extra outputs get a copy of the last buffer */
286 while (o != output_buffers().end(type)) {
287 o->read_from(*prev, nframes, offset);
292 /* ********** MIDI ********** */
294 // No MIDI, we're done here
295 if (bufs.count().n_midi() == 0) {
299 const DataType type = DataType::MIDI;
301 // Copy any MIDI 1:1 to outputs
302 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
303 BufferSet::iterator o = output_buffers().begin(type);
304 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
305 o->read_from(*i, nframes, offset);
310 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
312 assert(outs.available() >= n_inputs());
314 if (n_inputs() == ChanCount::ZERO)
317 outs.set_count(n_inputs());
319 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
321 BufferSet::iterator o = outs.begin(*t);
322 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
323 o->read_from(i->get_buffer(), nframes, offset);
330 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
331 nframes_t nframes, nframes_t offset)
333 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
335 collect_input (bufs, nframes, offset);
337 _meter->run_in_place(bufs, start_frame, end_frame, nframes, offset);
342 IO::check_bundles_connected_to_inputs ()
344 check_bundles (_bundles_connected_to_inputs, inputs());
348 IO::check_bundles_connected_to_outputs ()
350 check_bundles (_bundles_connected_to_outputs, outputs());
354 IO::check_bundles (std::vector<UserBundleInfo>& list, const PortSet& ports)
356 std::vector<UserBundleInfo> new_list;
358 for (std::vector<UserBundleInfo>::iterator i = list.begin(); i != list.end(); ++i) {
360 uint32_t const N = i->bundle->nchannels ();
362 if (ports.num_ports() < N) {
367 for (uint32_t j = 0; j < N; ++j) {
368 /* Every port on bundle channel j must be connected to our input j */
369 PortList const pl = i->bundle->channel_ports (j);
370 for (uint32_t k = 0; k < pl.size(); ++k) {
371 if (ports.port(j)->connected_to (pl[k]) == false) {
383 new_list.push_back (*i);
385 i->configuration_will_change.disconnect ();
386 i->configuration_has_changed.disconnect ();
387 i->ports_will_change.disconnect ();
388 i->ports_have_changed.disconnect ();
397 IO::disconnect_input (Port* our_port, string other_port, void* src)
399 if (other_port.length() == 0 || our_port == 0) {
404 BLOCK_PROCESS_CALLBACK ();
407 Glib::Mutex::Lock lm (io_lock);
409 /* check that our_port is really one of ours */
411 if ( ! _inputs.contains(our_port)) {
415 /* disconnect it from the source */
417 if (_session.engine().disconnect (other_port, our_port->name())) {
418 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
422 check_bundles_connected_to_inputs ();
426 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
427 _session.set_dirty ();
433 IO::connect_input (Port* our_port, string other_port, void* src)
435 if (other_port.length() == 0 || our_port == 0) {
440 BLOCK_PROCESS_CALLBACK ();
443 Glib::Mutex::Lock lm (io_lock);
445 /* check that our_port is really one of ours */
447 if ( ! _inputs.contains(our_port) ) {
451 /* connect it to the source */
453 if (_session.engine().connect (other_port, our_port->name())) {
459 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
460 _session.set_dirty ();
465 IO::disconnect_output (Port* our_port, string other_port, void* src)
467 if (other_port.length() == 0 || our_port == 0) {
472 BLOCK_PROCESS_CALLBACK ();
475 Glib::Mutex::Lock lm (io_lock);
477 /* check that our_port is really one of ours */
479 if ( ! _outputs.contains(our_port) ) {
483 /* disconnect it from the destination */
485 if (_session.engine().disconnect (our_port->name(), other_port)) {
486 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
490 check_bundles_connected_to_outputs ();
494 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
495 _session.set_dirty ();
500 IO::connect_output (Port* our_port, string other_port, void* src)
502 if (other_port.length() == 0 || our_port == 0) {
507 BLOCK_PROCESS_CALLBACK ();
511 Glib::Mutex::Lock lm (io_lock);
513 /* check that our_port is really one of ours */
515 if ( ! _outputs.contains(our_port) ) {
519 /* connect it to the destination */
521 if (_session.engine().connect (our_port->name(), other_port)) {
527 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
528 _session.set_dirty ();
533 IO::set_input (Port* other_port, void* src)
535 /* this removes all but one ports, and connects that one port
536 to the specified source.
539 if (_input_minimum.n_total() > 1) {
540 /* sorry, you can't do this */
544 if (other_port == 0) {
545 if (_input_minimum == ChanCount::ZERO) {
546 return ensure_inputs (ChanCount::ZERO, false, true, src);
552 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
556 return connect_input (_inputs.port(0), other_port->name(), src);
560 IO::remove_output_port (Port* port, void* src)
562 IOChange change (NoChange);
565 BLOCK_PROCESS_CALLBACK ();
569 Glib::Mutex::Lock lm (io_lock);
571 if (n_outputs() <= _output_minimum) {
572 /* sorry, you can't do this */
576 if (_outputs.remove(port)) {
577 change = IOChange (change|ConfigurationChanged);
579 if (port->connected()) {
580 change = IOChange (change|ConnectionsChanged);
583 _session.engine().unregister_port (*port);
584 check_bundles_connected_to_outputs ();
586 setup_peak_meters ();
591 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
594 if (change == ConnectionsChanged) {
595 setup_bundles_for_inputs_and_outputs ();
598 if (change != NoChange) {
599 output_changed (change, src);
600 _session.set_dirty ();
607 /** Add an output port.
609 * @param destination Name of input port to connect new port to.
610 * @param src Source for emitted ConfigurationChanged signal.
611 * @param type Data type of port. Default value (NIL) will use this IO's default type.
614 IO::add_output_port (string destination, void* src, DataType type)
618 if (type == DataType::NIL)
619 type = _default_type;
622 BLOCK_PROCESS_CALLBACK ();
626 Glib::Mutex::Lock lm (io_lock);
628 if (n_outputs() >= _output_maximum) {
632 /* Create a new output port */
634 string portname = build_legal_port_name (type, false);
636 if ((our_port = _session.engine().register_output_port (type, portname, _public_ports)) == 0) {
637 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
641 _outputs.add (our_port);
642 setup_peak_meters ();
646 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
649 if (destination.length()) {
650 if (_session.engine().connect (our_port->name(), destination)) {
655 // pan_changed (src); /* EMIT SIGNAL */
656 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
657 setup_bundles_for_inputs_and_outputs ();
658 _session.set_dirty ();
664 IO::remove_input_port (Port* port, void* src)
666 IOChange change (NoChange);
669 BLOCK_PROCESS_CALLBACK ();
673 Glib::Mutex::Lock lm (io_lock);
675 if (n_inputs() <= _input_minimum) {
676 /* sorry, you can't do this */
680 if (_inputs.remove(port)) {
681 change = IOChange (change|ConfigurationChanged);
683 if (port->connected()) {
684 change = IOChange (change|ConnectionsChanged);
687 _session.engine().unregister_port (*port);
688 check_bundles_connected_to_inputs ();
690 setup_peak_meters ();
695 PortCountChanged (n_inputs ()); /* EMIT SIGNAL */
698 if (change == ConfigurationChanged) {
699 setup_bundles_for_inputs_and_outputs ();
702 if (change != NoChange) {
703 input_changed (change, src);
704 _session.set_dirty ();
712 /** Add an input port.
714 * @param type Data type of port. The appropriate port type, and @ref Port will be created.
715 * @param destination Name of input port to connect new port to.
716 * @param src Source for emitted ConfigurationChanged signal.
719 IO::add_input_port (string source, void* src, DataType type)
723 if (type == DataType::NIL)
724 type = _default_type;
727 BLOCK_PROCESS_CALLBACK ();
730 Glib::Mutex::Lock lm (io_lock);
732 if (n_inputs() >= _input_maximum) {
736 /* Create a new input port */
738 string portname = build_legal_port_name (type, true);
740 if ((our_port = _session.engine().register_input_port (type, portname, _public_ports)) == 0) {
741 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
745 _inputs.add (our_port);
746 setup_peak_meters ();
750 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
753 if (source.length()) {
755 if (_session.engine().connect (source, our_port->name())) {
760 // pan_changed (src); /* EMIT SIGNAL */
761 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
762 setup_bundles_for_inputs_and_outputs ();
763 _session.set_dirty ();
769 IO::disconnect_inputs (void* src)
772 BLOCK_PROCESS_CALLBACK ();
775 Glib::Mutex::Lock lm (io_lock);
777 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
778 _session.engine().disconnect (*i);
781 check_bundles_connected_to_inputs ();
785 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
791 IO::disconnect_outputs (void* src)
794 BLOCK_PROCESS_CALLBACK ();
797 Glib::Mutex::Lock lm (io_lock);
799 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
800 _session.engine().disconnect (*i);
803 check_bundles_connected_to_outputs ();
807 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
808 _session.set_dirty ();
814 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
816 Port* input_port = 0;
817 bool changed = false;
820 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
822 const size_t n = count.get(*t);
824 /* remove unused ports */
825 for (size_t i = n_inputs().get(*t); i > n; --i) {
826 input_port = _inputs.port(*t, i-1);
829 _inputs.remove(input_port);
830 _session.engine().unregister_port (*input_port);
835 /* create any necessary new ports */
836 while (n_inputs().get(*t) < n) {
838 string portname = build_legal_port_name (*t, true);
842 if ((input_port = _session.engine().register_input_port (*t, portname, _public_ports)) == 0) {
843 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
848 catch (AudioEngine::PortRegistrationFailure& err) {
849 setup_peak_meters ();
852 throw AudioEngine::PortRegistrationFailure();
855 _inputs.add (input_port);
861 check_bundles_connected_to_inputs ();
862 setup_peak_meters ();
864 PortCountChanged (n_inputs()); /* EMIT SIGNAL */
865 _session.set_dirty ();
869 /* disconnect all existing ports so that we get a fresh start */
870 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
871 _session.engine().disconnect (*i);
878 /** Attach output_buffers to port buffers.
880 * Connected to IO's own PortCountChanged signal.
883 IO::attach_buffers(ChanCount ignored)
885 _output_buffers->attach_buffers(_outputs);
889 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
891 bool in_changed = false;
892 bool out_changed = false;
893 bool need_pan_reset = false;
895 in = min (_input_maximum, in);
897 out = min (_output_maximum, out);
899 if (in == n_inputs() && out == n_outputs() && !clear) {
904 BLOCK_PROCESS_CALLBACK ();
905 Glib::Mutex::Lock lm (io_lock);
909 if (n_outputs() != out) {
910 need_pan_reset = true;
913 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
915 const size_t nin = in.get(*t);
916 const size_t nout = out.get(*t);
918 Port* output_port = 0;
919 Port* input_port = 0;
921 /* remove unused output ports */
922 for (size_t i = n_outputs().get(*t); i > nout; --i) {
923 output_port = _outputs.port(*t, i-1);
926 _outputs.remove(output_port);
927 _session.engine().unregister_port (*output_port);
932 /* remove unused input ports */
933 for (size_t i = n_inputs().get(*t); i > nin; --i) {
934 input_port = _inputs.port(*t, i-1);
937 _inputs.remove(input_port);
938 _session.engine().unregister_port (*input_port);
943 /* create any necessary new input ports */
945 while (n_inputs().get(*t) < nin) {
947 string portname = build_legal_port_name (*t, true);
950 if ((port = _session.engine().register_input_port (*t, portname, _public_ports)) == 0) {
951 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
956 catch (AudioEngine::PortRegistrationFailure& err) {
957 setup_peak_meters ();
960 throw AudioEngine::PortRegistrationFailure();
967 /* create any necessary new output ports */
969 while (n_outputs().get(*t) < nout) {
971 string portname = build_legal_port_name (*t, false);
974 if ((port = _session.engine().register_output_port (*t, portname, _public_ports)) == 0) {
975 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
980 catch (AudioEngine::PortRegistrationFailure& err) {
981 setup_peak_meters ();
984 throw AudioEngine::PortRegistrationFailure ();
994 /* disconnect all existing ports so that we get a fresh start */
996 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
997 _session.engine().disconnect (*i);
1000 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1001 _session.engine().disconnect (*i);
1005 if (in_changed || out_changed) {
1006 setup_peak_meters ();
1012 check_bundles_connected_to_outputs ();
1013 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1017 check_bundles_connected_to_inputs ();
1018 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1021 if (in_changed || out_changed) {
1022 PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1023 setup_bundles_for_inputs_and_outputs ();
1024 _session.set_dirty ();
1031 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1033 bool changed = false;
1035 count = min (_input_maximum, count);
1037 if (count == n_inputs() && !clear) {
1042 BLOCK_PROCESS_CALLBACK ();
1043 Glib::Mutex::Lock im (io_lock);
1044 changed = ensure_inputs_locked (count, clear, src);
1046 changed = ensure_inputs_locked (count, clear, src);
1050 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1051 setup_bundles_for_inputs_and_outputs ();
1052 _session.set_dirty ();
1058 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1060 Port* output_port = 0;
1061 bool changed = false;
1062 bool need_pan_reset = false;
1064 if (n_outputs() != count) {
1065 need_pan_reset = true;
1068 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1070 const size_t n = count.get(*t);
1072 /* remove unused ports */
1073 for (size_t i = n_outputs().get(*t); i > n; --i) {
1074 output_port = _outputs.port(*t, i-1);
1076 assert(output_port);
1077 _outputs.remove(output_port);
1078 _session.engine().unregister_port (*output_port);
1083 /* create any necessary new ports */
1084 while (n_outputs().get(*t) < n) {
1086 string portname = build_legal_port_name (*t, false);
1088 if ((output_port = _session.engine().register_output_port (*t, portname, _public_ports)) == 0) {
1089 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
1093 _outputs.add (output_port);
1095 setup_peak_meters ();
1097 if (need_pan_reset) {
1104 check_bundles_connected_to_outputs ();
1105 PortCountChanged (n_outputs()); /* EMIT SIGNAL */
1106 _session.set_dirty ();
1110 /* disconnect all existing ports so that we get a fresh start */
1111 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1112 _session.engine().disconnect (*i);
1120 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1122 bool changed = false;
1124 if (_output_maximum < ChanCount::INFINITE) {
1125 count = min (_output_maximum, count);
1126 if (count == n_outputs() && !clear) {
1131 /* XXX caller should hold io_lock, but generally doesn't */
1134 BLOCK_PROCESS_CALLBACK ();
1135 Glib::Mutex::Lock im (io_lock);
1136 changed = ensure_outputs_locked (count, clear, src);
1138 changed = ensure_outputs_locked (count, clear, src);
1142 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1143 setup_bundles_for_inputs_and_outputs ();
1150 IO::effective_gain () const
1152 if (_gain_control->list()->automation_playback()) {
1153 return _gain_control->get_value();
1155 return _desired_gain;
1162 if (panners_legal) {
1163 if (!no_panner_reset) {
1164 _panner->reset (n_outputs().n_audio(), pans_required());
1167 panner_legal_c.disconnect ();
1168 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1173 IO::panners_became_legal ()
1175 _panner->reset (n_outputs().n_audio(), pans_required());
1176 _panner->load (); // automation
1177 panner_legal_c.disconnect ();
1182 IO::defer_pan_reset ()
1184 no_panner_reset = true;
1188 IO::allow_pan_reset ()
1190 no_panner_reset = false;
1196 IO::get_state (void)
1198 return state (true);
1202 IO::state (bool full_state)
1204 XMLNode* node = new XMLNode (state_node_name);
1207 vector<string>::iterator ci;
1209 LocaleGuard lg (X_("POSIX"));
1210 Glib::Mutex::Lock lm (io_lock);
1212 node->add_property("name", _name);
1213 id().print (buf, sizeof (buf));
1214 node->add_property("id", buf);
1217 std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin();
1218 i != _bundles_connected_to_inputs.end();
1222 XMLNode* n = new XMLNode ("InputBundle");
1223 n->add_property ("name", i->bundle->name ());
1224 node->add_child_nocopy (*n);
1228 std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin();
1229 i != _bundles_connected_to_outputs.end();
1233 XMLNode* n = new XMLNode ("OutputBundle");
1234 n->add_property ("name", i->bundle->name ());
1235 node->add_child_nocopy (*n);
1240 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1242 vector<string> connections;
1244 if (i->get_connections (connections)) {
1248 for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) {
1253 /* if its a connection to our own port,
1254 return only the port name, not the
1255 whole thing. this allows connections
1256 to be re-established even when our
1257 client name is different.
1260 str += _session.engine().make_port_name_relative (*ci);
1270 node->add_property ("inputs", str);
1274 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1276 vector<string> connections;
1278 if (i->get_connections (connections)) {
1282 for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) {
1287 str += _session.engine().make_port_name_relative (*ci);
1297 node->add_property ("outputs", str);
1299 node->add_child_nocopy (_panner->state (full_state));
1300 node->add_child_nocopy (_gain_control->get_state ());
1302 snprintf (buf, sizeof(buf), "%2.12f", gain());
1303 node->add_property ("gain", buf);
1305 /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
1309 int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
1310 int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
1312 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
1314 node->add_property ("iolimits", buf);
1319 node->add_child_nocopy (get_automation_state());
1325 IO::set_state (const XMLNode& node)
1327 const XMLProperty* prop;
1328 XMLNodeConstIterator iter;
1329 LocaleGuard lg (X_("POSIX"));
1331 /* force use of non-localized representation of decimal point,
1332 since we use it a lot in XML files and so forth.
1335 if (node.name() != state_node_name) {
1336 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1340 if ((prop = node.property ("name")) != 0) {
1341 _name = prop->value();
1342 /* used to set panner name with this, but no more */
1345 if ((prop = node.property ("id")) != 0) {
1346 _id = prop->value ();
1354 if ((prop = node.property ("iolimits")) != 0) {
1355 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1356 &in_min, &in_max, &out_min, &out_max);
1358 /* Correct for the difference between the way we write things to session files and the
1359 way things are described by ChanCount; see comments in io.h about what the different
1360 ChanCount values mean. */
1363 _input_minimum = ChanCount::ZERO;
1365 _input_minimum = ChanCount (_default_type, in_min);
1369 _input_maximum = ChanCount::INFINITE;
1371 _input_maximum = ChanCount (_default_type, in_max);
1375 _output_minimum = ChanCount::ZERO;
1377 _output_minimum = ChanCount (_default_type, out_min);
1381 _output_maximum = ChanCount::INFINITE;
1383 _output_maximum = ChanCount (_default_type, out_max);
1387 if ((prop = node.property ("gain")) != 0) {
1388 set_gain (atof (prop->value().c_str()), this);
1389 _gain = _desired_gain;
1392 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1393 /* old school automation handling */
1396 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1398 if ((*iter)->name() == "Panner") {
1400 _panner = new Panner (_name, _session);
1402 _panner->set_state (**iter);
1405 if ((*iter)->name() == X_("Automation")) {
1407 set_automation_state (*(*iter), Parameter(GainAutomation));
1410 if ((*iter)->name() == X_("controllable")) {
1411 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1412 _gain_control->set_state (**iter);
1419 if (create_ports (node)) {
1425 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1428 if (panners_legal) {
1431 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1434 if (connecting_legal) {
1436 if (make_connections (node)) {
1442 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1445 if (!ports_legal || !connecting_legal) {
1446 pending_state_node = new XMLNode (node);
1453 IO::load_automation (string path)
1458 uint32_t linecnt = 0;
1460 LocaleGuard lg (X_("POSIX"));
1462 fullpath = _session.automation_dir();
1465 in.open (fullpath.c_str());
1468 fullpath = _session.automation_dir();
1469 fullpath += _session.snap_name();
1473 in.open (fullpath.c_str());
1476 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1481 clear_automation ();
1483 while (in.getline (line, sizeof(line), '\n')) {
1488 if (++linecnt == 1) {
1489 if (memcmp (line, "version", 7) == 0) {
1490 if (sscanf (line, "version %f", &version) != 1) {
1491 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1495 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1502 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1503 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1509 _gain_control->list()->fast_simple_add (when, value);
1519 /* older (pre-1.0) versions of ardour used this */
1523 warning << _("dubious automation event found (and ignored)") << endmsg;
1531 IO::connecting_became_legal ()
1535 if (pending_state_node == 0) {
1536 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1541 connection_legal_c.disconnect ();
1543 ret = make_connections (*pending_state_node);
1546 delete pending_state_node;
1547 pending_state_node = 0;
1553 IO::ports_became_legal ()
1557 if (pending_state_node == 0) {
1558 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1563 port_legal_c.disconnect ();
1565 ret = create_ports (*pending_state_node);
1567 if (connecting_legal) {
1568 delete pending_state_node;
1569 pending_state_node = 0;
1576 IO::create_ports (const XMLNode& node)
1578 XMLProperty const * prop;
1580 int num_outputs = 0;
1582 if ((prop = node.property ("inputs")) != 0) {
1583 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1584 } else if ((prop = node.property ("outputs")) != 0) {
1585 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1588 no_panner_reset = true;
1590 // FIXME: audio-only
1591 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1592 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1596 no_panner_reset = false;
1598 set_deferred_state ();
1606 IO::make_connections (const XMLNode& node)
1608 XMLProperty const * prop;
1610 if ((prop = node.property ("inputs")) != 0) {
1611 if (set_inputs (prop->value())) {
1612 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1618 if ((prop = node.property ("outputs")) != 0) {
1619 if (set_outputs (prop->value())) {
1620 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1625 for (XMLNodeConstIterator i = node.children().begin(); i != node.children().end(); ++i) {
1627 if ((*i)->name() == "InputBundle") {
1628 XMLProperty const * prop = (*i)->property ("name");
1630 boost::shared_ptr<Bundle> b = _session.bundle_by_name (prop->value());
1632 connect_input_ports_to_bundle (b, this);
1634 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1638 } else if ((*i)->name() == "OutputBundle") {
1639 XMLProperty const * prop = (*i)->property ("name");
1641 boost::shared_ptr<Bundle> b = _session.bundle_by_name (prop->value());
1643 connect_output_ports_to_bundle (b, this);
1645 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1655 IO::set_inputs (const string& str)
1657 vector<string> ports;
1662 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1666 // FIXME: audio-only
1667 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1671 string::size_type start, end, ostart;
1678 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1681 if ((end = str.find_first_of ('}', start)) == string::npos) {
1682 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1686 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1687 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1693 for (int x = 0; x < n; ++x) {
1694 connect_input (input (i), ports[x], this);
1706 IO::set_outputs (const string& str)
1708 vector<string> ports;
1713 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1717 // FIXME: audio-only
1718 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1722 string::size_type start, end, ostart;
1729 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1732 if ((end = str.find_first_of ('}', start)) == string::npos) {
1733 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1737 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1738 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1744 for (int x = 0; x < n; ++x) {
1745 connect_output (output (i), ports[x], this);
1757 IO::parse_io_string (const string& str, vector<string>& ports)
1759 string::size_type pos, opos;
1761 if (str.length() == 0) {
1770 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1771 ports.push_back (str.substr (opos, pos - opos));
1775 if (opos < str.length()) {
1776 ports.push_back (str.substr(opos));
1779 return ports.size();
1783 IO::parse_gain_string (const string& str, vector<string>& ports)
1785 string::size_type pos, opos;
1791 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1792 ports.push_back (str.substr (opos, pos - opos));
1796 if (opos < str.length()) {
1797 ports.push_back (str.substr(opos));
1800 return ports.size();
1804 IO::set_name (const string& requested_name)
1806 if (requested_name == _name) {
1812 if ( (rt = dynamic_cast<Route *>(this))) {
1813 name = Route::ensure_track_or_route_name(requested_name, _session);
1815 name = requested_name;
1819 /* replace all colons in the name. i wish we didn't have to do this */
1821 if (replace_all (name, ":", "-")) {
1822 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1825 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1826 string current_name = i->short_name();
1827 current_name.replace (current_name.find (_name), _name.length(), name);
1828 i->set_name (current_name);
1831 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1832 string current_name = i->short_name();
1833 current_name.replace (current_name.find (_name), _name.length(), name);
1834 i->set_name (current_name);
1837 bool const r = SessionObject::set_name(name);
1839 setup_bundles_for_inputs_and_outputs ();
1845 IO::set_input_minimum (ChanCount n)
1851 IO::set_input_maximum (ChanCount n)
1857 IO::set_output_minimum (ChanCount n)
1859 _output_minimum = n;
1863 IO::set_output_maximum (ChanCount n)
1865 _output_maximum = n;
1869 IO::set_port_latency (nframes_t nframes)
1871 Glib::Mutex::Lock lm (io_lock);
1873 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1874 i->set_latency (nframes);
1879 IO::output_latency () const
1881 nframes_t max_latency;
1886 /* io lock not taken - must be protected by other means */
1888 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1889 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1890 max_latency = latency;
1898 IO::input_latency () const
1900 nframes_t max_latency;
1905 /* io lock not taken - must be protected by other means */
1907 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1908 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1909 max_latency = latency;
1917 IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1920 BLOCK_PROCESS_CALLBACK ();
1921 Glib::Mutex::Lock lm2 (io_lock);
1923 /* Connect to the bundle, not worrying about any connections
1924 that are already made. */
1926 uint32_t const channels = c->nchannels ();
1928 for (uint32_t n = 0; n < channels; ++n) {
1929 const PortList& pl = c->channel_ports (n);
1931 for (PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1933 if (!_inputs.port(n)->connected_to (*i)) {
1935 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1943 /* If this is a UserBundle, make a note of what we've done */
1945 boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
1948 /* See if we already know about this one */
1949 std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin();
1950 while (i != _bundles_connected_to_inputs.end() && i->bundle != ub) {
1954 if (i == _bundles_connected_to_inputs.end()) {
1955 /* We don't, so make a note */
1956 _bundles_connected_to_inputs.push_back (UserBundleInfo (this, ub));
1961 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1966 IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1969 BLOCK_PROCESS_CALLBACK ();
1970 Glib::Mutex::Lock lm2 (io_lock);
1972 /* Connect to the bundle, not worrying about any connections
1973 that are already made. */
1975 uint32_t const channels = c->nchannels ();
1977 for (uint32_t n = 0; n < channels; ++n) {
1979 const PortList& pl = c->channel_ports (n);
1981 for (PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1983 if (!_outputs.port(n)->connected_to (*i)) {
1985 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
1992 /* If this is a UserBundle, make a note of what we've done */
1994 boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
1997 /* See if we already know about this one */
1998 std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin();
1999 while (i != _bundles_connected_to_outputs.end() && i->bundle != ub) {
2003 if (i == _bundles_connected_to_outputs.end()) {
2004 /* We don't, so make a note */
2005 _bundles_connected_to_outputs.push_back (UserBundleInfo (this, ub));
2010 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2016 IO::disable_connecting ()
2018 connecting_legal = false;
2023 IO::enable_connecting ()
2025 connecting_legal = true;
2026 return ConnectingLegal ();
2030 IO::disable_ports ()
2032 ports_legal = false;
2040 return PortsLegal ();
2044 IO::disable_panners (void)
2046 panners_legal = false;
2051 IO::reset_panners ()
2053 panners_legal = true;
2054 return PannersLegal ();
2058 IO::bundle_configuration_will_change ()
2061 // connect_input_ports_to_bundle (_input_bundle, this);
2065 IO::bundle_configuration_has_changed ()
2068 // connect_input_ports_to_bundle (_input_bundle, this);
2072 IO::bundle_ports_will_change (int ignored)
2075 // connect_output_ports_to_bundle (_output_bundle, this);
2079 IO::bundle_ports_have_changed (int ignored)
2082 // connect_output_ports_to_bundle (_output_bundle, this);
2086 IO::GainControl::set_value (float val)
2088 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2089 if (val > 1.99526231f)
2093 _io.set_gain (val, this);
2095 Changed(); /* EMIT SIGNAL */
2099 IO::GainControl::get_value (void) const
2101 return AutomationControl::get_value();
2105 IO::setup_peak_meters()
2107 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2108 _meter->configure_io(max_streams, max_streams);
2112 Update the peak meters.
2114 The meter signal lock is taken to prevent modification of the
2115 Meter signal while updating the meters, taking the meter signal
2116 lock prior to taking the io_lock ensures that all IO will remain
2117 valid while metering.
2122 Glib::Mutex::Lock guard (m_meter_signal_lock);
2123 Meter(); /* EMIT SIGNAL */
2129 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2131 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2136 IO::clear_automation ()
2138 Automatable::clear_automation (); // clears gain automation
2139 _panner->clear_automation ();
2143 IO::set_parameter_automation_state (Parameter param, AutoState state)
2145 // XXX: would be nice to get rid of this special hack
2147 if (param.type() == GainAutomation) {
2149 bool changed = false;
2152 Glib::Mutex::Lock lm (_automation_lock);
2154 boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2156 if (state != gain_auto->automation_state()) {
2158 _last_automation_snapshot = 0;
2159 gain_auto->set_automation_state (state);
2162 // FIXME: shouldn't this use Curve?
2163 set_gain (gain_auto->eval (_session.transport_frame()), this);
2169 _session.set_dirty ();
2173 Automatable::set_parameter_automation_state(param, state);
2178 IO::inc_gain (gain_t factor, void *src)
2180 if (_desired_gain == 0.0f)
2181 set_gain (0.000001f + (0.000001f * factor), src);
2183 set_gain (_desired_gain + (_desired_gain * factor), src);
2187 IO::set_gain (gain_t val, void *src)
2189 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2190 if (val > 1.99526231f)
2193 if (src != _gain_control.get()) {
2194 _gain_control->set_value(val);
2195 // bit twisty, this will come back and call us again
2196 // (this keeps control in sync with reality)
2201 Glib::Mutex::Lock dm (declick_lock);
2202 _desired_gain = val;
2205 if (_session.transport_stopped()) {
2209 if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2210 _gain_control->list()->add (_session.transport_frame(), val);
2214 _session.set_dirty();
2218 IO::start_pan_touch (uint32_t which)
2220 if (which < _panner->size()) {
2221 (*_panner)[which]->pan_control()->list()->start_touch();
2226 IO::end_pan_touch (uint32_t which)
2228 if (which < _panner->size()) {
2229 (*_panner)[which]->pan_control()->list()->stop_touch();
2235 IO::automation_snapshot (nframes_t now, bool force)
2237 Automatable::automation_snapshot (now, force);
2239 if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
2240 _panner->snapshot (now);
2243 _panner->snapshot (now);
2244 _last_automation_snapshot = now;
2248 IO::transport_stopped (nframes_t frame)
2250 _gain_control->list()->reposition_for_rt_add (frame);
2252 if (_gain_control->list()->automation_state() != Off) {
2254 /* the src=0 condition is a special signal to not propagate
2255 automation gain changes into the mix group when locating.
2258 // FIXME: shouldn't this use Curve?
2259 set_gain (_gain_control->list()->eval (frame), 0);
2262 _panner->transport_stopped (frame);
2266 IO::build_legal_port_name (DataType type, bool in)
2268 const int name_size = jack_port_name_size();
2273 if (type == DataType::AUDIO) {
2274 suffix = _("audio");
2275 } else if (type == DataType::MIDI) {
2278 throw unknown_type();
2283 maxports = _input_maximum.get(type);
2285 suffix += _("_out");
2286 maxports = _output_maximum.get(type);
2289 if (maxports == 1) {
2290 // allow space for the slash + the suffix
2291 limit = name_size - _session.engine().client_name().length() - (suffix.length() + 1);
2292 char buf[name_size+1];
2293 snprintf (buf, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix.c_str());
2294 return string (buf);
2297 // allow up to 4 digits for the output port number, plus the slash, suffix and extra space
2299 limit = name_size - _session.engine().client_name().length() - (suffix.length() + 5);
2301 char buf1[name_size+1];
2302 char buf2[name_size+1];
2304 snprintf (buf1, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix.c_str());
2309 port_number = find_input_port_hole (buf1);
2311 port_number = find_output_port_hole (buf1);
2314 snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
2316 return string (buf2);
2320 IO::find_input_port_hole (const char* base)
2322 /* CALLER MUST HOLD IO LOCK */
2326 if (_inputs.empty()) {
2330 /* we only allow up to 4 characters for the port number
2333 for (n = 1; n < 9999; ++n) {
2334 char buf[jack_port_name_size()];
2335 PortSet::iterator i = _inputs.begin();
2337 snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
2339 for ( ; i != _inputs.end(); ++i) {
2340 if (i->short_name() == buf) {
2345 if (i == _inputs.end()) {
2353 IO::find_output_port_hole (const char* base)
2355 /* CALLER MUST HOLD IO LOCK */
2359 if (_outputs.empty()) {
2363 /* we only allow up to 4 characters for the port number
2366 for (n = 1; n < 9999; ++n) {
2367 char buf[jack_port_name_size()];
2368 PortSet::iterator i = _outputs.begin();
2370 snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
2372 for ( ; i != _outputs.end(); ++i) {
2373 if (i->short_name() == buf) {
2378 if (i == _outputs.end()) {
2387 IO::set_active (bool yn)
2390 active_changed(); /* EMIT SIGNAL */
2395 IO::audio_input(uint32_t n) const
2397 return dynamic_cast<AudioPort*>(input(n));
2401 IO::audio_output(uint32_t n) const
2403 return dynamic_cast<AudioPort*>(output(n));
2407 IO::midi_input(uint32_t n) const
2409 return dynamic_cast<MidiPort*>(input(n));
2413 IO::midi_output(uint32_t n) const
2415 return dynamic_cast<MidiPort*>(output(n));
2419 IO::set_phase_invert (bool yn, void *src)
2421 if (_phase_invert != yn) {
2423 // phase_invert_changed (src); /* EMIT SIGNAL */
2428 IO::set_denormal_protection (bool yn, void *src)
2430 if (_denormal_protection != yn) {
2431 _denormal_protection = yn;
2432 // denormal_protection_changed (src); /* EMIT SIGNAL */
2437 IO::update_port_total_latencies ()
2439 /* io_lock, not taken: function must be called from Session::process() calltree */
2441 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2442 _session.engine().update_total_latency (*i);
2445 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2446 _session.engine().update_total_latency (*i);
2452 * Setup bundles that describe our inputs and outputs.
2456 IO::setup_bundles_for_inputs_and_outputs ()
2460 snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
2461 _bundle_for_inputs->set_name (buf);
2462 uint32_t const ni = inputs().num_ports();
2463 _bundle_for_inputs->set_channels (ni);
2464 for (uint32_t i = 0; i < ni; ++i) {
2465 _bundle_for_inputs->set_port (i, inputs().port(i)->name());
2468 snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
2469 _bundle_for_outputs->set_name (buf);
2470 uint32_t const no = outputs().num_ports();
2471 _bundle_for_outputs->set_channels (no);
2472 for (uint32_t i = 0; i < no; ++i) {
2473 _bundle_for_outputs->set_port (i, outputs().port(i)->name());
2479 * Create and setup bundles that describe our inputs and outputs.
2483 IO::create_bundles_for_inputs_and_outputs ()
2485 _bundle_for_inputs = boost::shared_ptr<AutoBundle> (new AutoBundle (true));
2486 _bundle_for_outputs = boost::shared_ptr<AutoBundle> (new AutoBundle (false));
2487 setup_bundles_for_inputs_and_outputs ();
2490 /** Add a bundle to a list if is connected to our inputs.
2491 * @param b Bundle to check.
2492 * @param bundles List to add to.
2495 IO::maybe_add_input_bundle_to_list (boost::shared_ptr<Bundle> b, std::vector<boost::shared_ptr<Bundle> >* bundles)
2497 boost::shared_ptr<AutoBundle> ab = boost::dynamic_pointer_cast<AutoBundle, Bundle> (b);
2498 if (ab == 0 || ab->ports_are_outputs() == false) {
2502 if (ab->nchannels () != n_inputs().n_total ()) {
2506 for (uint32_t i = 0; i < n_inputs().n_total (); ++i) {
2508 PortList const & pl = b->channel_ports (i);
2514 if (!input(i)->connected_to (pl[0])) {
2519 bundles->push_back (b);
2522 /** @return Bundles connected to our inputs */
2523 std::vector<boost::shared_ptr<Bundle> >
2524 IO::bundles_connected_to_inputs ()
2526 std::vector<boost::shared_ptr<Bundle> > bundles;
2529 for (std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin(); i != _bundles_connected_to_inputs.end(); ++i) {
2530 bundles.push_back (i->bundle);
2534 _session.foreach_bundle (
2535 sigc::bind (sigc::mem_fun (*this, &IO::maybe_add_input_bundle_to_list), &bundles)
2542 /** Add a bundle to a list if is connected to our outputs.
2543 * @param b Bundle to check.
2544 * @param bundles List to add to.
2547 IO::maybe_add_output_bundle_to_list (boost::shared_ptr<Bundle> b, std::vector<boost::shared_ptr<Bundle> >* bundles)
2549 boost::shared_ptr<AutoBundle> ab = boost::dynamic_pointer_cast<AutoBundle, Bundle> (b);
2550 if (ab == 0 || ab->ports_are_inputs() == false) {
2554 if (ab->nchannels () != n_outputs().n_total ()) {
2558 for (uint32_t i = 0; i < n_outputs().n_total (); ++i) {
2560 PortList const & pl = b->channel_ports (i);
2566 if (!output(i)->connected_to (pl[0])) {
2571 bundles->push_back (b);
2575 /* @return Bundles connected to our outputs */
2576 std::vector<boost::shared_ptr<Bundle> >
2577 IO::bundles_connected_to_outputs ()
2579 std::vector<boost::shared_ptr<Bundle> > bundles;
2582 for (std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin(); i != _bundles_connected_to_outputs.end(); ++i) {
2583 bundles.push_back (i->bundle);
2587 _session.foreach_bundle (
2588 sigc::bind (sigc::mem_fun (*this, &IO::maybe_add_output_bundle_to_list), &bundles)
2595 IO::UserBundleInfo::UserBundleInfo (IO* io, boost::shared_ptr<UserBundle> b)
2598 configuration_will_change = b->ConfigurationWillChange.connect (
2599 sigc::mem_fun (*io, &IO::bundle_configuration_will_change)
2601 configuration_has_changed = b->ConfigurationHasChanged.connect (
2602 sigc::mem_fun (*io, &IO::bundle_configuration_has_changed)
2604 ports_will_change = b->PortsWillChange.connect (
2605 sigc::mem_fun (*io, &IO::bundle_ports_will_change)
2607 ports_have_changed = b->PortsHaveChanged.connect (
2608 sigc::mem_fun (*io, &IO::bundle_ports_have_changed)