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>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/audio_port.h>
36 #include <ardour/midi_port.h>
37 #include <ardour/bundle.h>
38 #include <ardour/session.h>
39 #include <ardour/cycle_timer.h>
40 #include <ardour/panner.h>
41 #include <ardour/buffer_set.h>
42 #include <ardour/meter.h>
43 #include <ardour/amp.h>
50 A bug in OS X's cmath that causes isnan() and isinf() to be
51 "undeclared". the following works around that
54 #if defined(__APPLE__) && defined(__MACH__)
55 extern "C" int isnan (double);
56 extern "C" int isinf (double);
59 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
62 using namespace ARDOUR;
65 nframes_t IO::_automation_interval = 0;
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::MoreChannels;
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.
84 static gain_t direct_control_to_gain (double fract) {
85 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
86 /* this maxes at +6dB */
87 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
90 static double direct_gain_to_control (gain_t gain) {
91 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
92 if (gain == 0) return 0.0;
94 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
98 /** @param default_type The type of port that will be created by ensure_io
99 * and friends if no type is explicitly requested (to avoid breakage).
101 IO::IO (Session& s, const string& name,
102 int input_min, int input_max, int output_min, int output_max,
103 DataType default_type)
104 : Automatable (s, name),
105 _output_buffers (new BufferSet()),
106 _default_type (default_type),
107 _gain_control (X_("gaincontrol"), *this),
108 _input_minimum (ChanCount::ZERO),
109 _input_maximum (ChanCount::INFINITE),
110 _output_minimum (ChanCount::ZERO),
111 _output_maximum (ChanCount::INFINITE)
113 _panner = new Panner (name, _session);
114 _meter = new PeakMeter (_session);
117 _input_minimum = ChanCount(_default_type, input_min);
119 if (input_max >= 0) {
120 _input_maximum = ChanCount(_default_type, input_max);
122 if (output_min > 0) {
123 _output_minimum = ChanCount(_default_type, output_min);
125 if (output_max >= 0) {
126 _output_maximum = ChanCount(_default_type, output_max);
133 pending_state_node = 0;
134 no_panner_reset = false;
135 _phase_invert = false;
138 add_automation_parameter(new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
140 apply_gain_automation = false;
142 last_automation_snapshot = 0;
144 /*_gain_automation_state = Off;
145 _gain_automation_style = Absolute;*/
148 // IO::Meter is emitted from another thread so the
149 // Meter signal must be protected.
150 Glib::Mutex::Lock guard (m_meter_signal_lock);
151 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
154 // Connect to our own MoreChannels signal to connect output buffers
155 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
157 _session.add_controllable (&_gain_control);
160 IO::IO (Session& s, const XMLNode& node, DataType dt)
161 : Automatable (s, "unnamed io"),
162 _output_buffers (new BufferSet()),
164 _gain_control (X_("gaincontrol"), *this)
166 _meter = new PeakMeter (_session);
170 no_panner_reset = false;
176 apply_gain_automation = false;
181 // IO::Meter is emitted from another thread so the
182 // Meter signal must be protected.
183 Glib::Mutex::Lock guard (m_meter_signal_lock);
184 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
187 // Connect to our own MoreChannels signal to connect output buffers
188 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
190 _session.add_controllable (&_gain_control);
195 Glib::Mutex::Lock guard (m_meter_signal_lock);
197 Glib::Mutex::Lock lm (io_lock);
199 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
200 _session.engine().unregister_port (*i);
203 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
204 _session.engine().unregister_port (*i);
207 m_meter_connection.disconnect();
211 delete _output_buffers;
215 IO::silence (nframes_t nframes, nframes_t offset)
217 /* io_lock, not taken: function must be called from Session::process() calltree */
219 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
220 i->get_buffer().silence (nframes, offset);
224 /** Deliver bufs to the IO's Jack outputs.
226 * This function should automatically do whatever it necessary to correctly deliver bufs
227 * to the outputs, eg applying gain or pan or whatever else needs to be done.
230 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
232 // FIXME: type specific code doesn't actually need to be here, it will go away in time
234 /* ********** AUDIO ********** */
236 // Apply gain if gain automation isn't playing
237 if ( ! apply_gain_automation) {
239 gain_t dg = _gain; // desired gain
242 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
250 if (dg != _gain || dg != 1.0)
251 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
254 // Use the panner to distribute audio to output port buffers
255 if (_panner && !_panner->empty() && !_panner->bypassed()) {
256 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
258 const DataType type = DataType::AUDIO;
260 // Copy any audio 1:1 to outputs
262 BufferSet::iterator o = output_buffers().begin(type);
263 BufferSet::iterator i = bufs.begin(type);
264 BufferSet::iterator prev = i;
266 while (i != bufs.end(type) && o != output_buffers().end (type)) {
267 o->read_from(*i, nframes, offset);
273 /* extra outputs get a copy of the last buffer */
275 while (o != output_buffers().end(type)) {
276 o->read_from(*prev, nframes, offset);
281 /* ********** MIDI ********** */
283 // No MIDI, we're done here
284 if (bufs.count().n_midi() == 0) {
288 const DataType type = DataType::MIDI;
290 // Copy any MIDI 1:1 to outputs
291 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
292 BufferSet::iterator o = output_buffers().begin(type);
293 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
294 o->read_from(*i, nframes, offset);
299 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
301 assert(outs.available() >= n_inputs());
303 outs.set_count(n_inputs());
305 if (outs.count() == ChanCount::ZERO)
308 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
310 BufferSet::iterator o = outs.begin(*t);
311 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
312 o->read_from(i->get_buffer(), nframes, offset);
319 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
320 nframes_t nframes, nframes_t offset)
322 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
324 collect_input (bufs, nframes, offset);
326 _meter->run(bufs, start_frame, end_frame, nframes, offset);
330 IO::drop_input_bundle ()
333 input_bundle_configuration_connection.disconnect();
334 input_bundle_connection_connection.disconnect();
335 _session.set_dirty ();
339 IO::drop_output_bundle ()
342 output_bundle_configuration_connection.disconnect();
343 output_bundle_connection_connection.disconnect();
344 _session.set_dirty ();
348 IO::disconnect_input (Port* our_port, string other_port, void* src)
350 if (other_port.length() == 0 || our_port == 0) {
355 BLOCK_PROCESS_CALLBACK ();
358 Glib::Mutex::Lock lm (io_lock);
360 /* check that our_port is really one of ours */
362 if ( ! _inputs.contains(our_port)) {
366 /* disconnect it from the source */
368 if (_session.engine().disconnect (other_port, our_port->name())) {
369 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
373 drop_input_bundle ();
377 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
378 _session.set_dirty ();
384 IO::connect_input (Port* our_port, string other_port, void* src)
386 if (other_port.length() == 0 || our_port == 0) {
391 BLOCK_PROCESS_CALLBACK ();
394 Glib::Mutex::Lock lm (io_lock);
396 /* check that our_port is really one of ours */
398 if ( ! _inputs.contains(our_port) ) {
402 /* connect it to the source */
404 if (_session.engine().connect (other_port, our_port->name())) {
408 drop_input_bundle ();
412 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
413 _session.set_dirty ();
418 IO::disconnect_output (Port* our_port, string other_port, void* src)
420 if (other_port.length() == 0 || our_port == 0) {
425 BLOCK_PROCESS_CALLBACK ();
428 Glib::Mutex::Lock lm (io_lock);
430 /* check that our_port is really one of ours */
432 if ( ! _outputs.contains(our_port) ) {
436 /* disconnect it from the destination */
438 if (_session.engine().disconnect (our_port->name(), other_port)) {
439 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
443 drop_output_bundle ();
447 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
448 _session.set_dirty ();
453 IO::connect_output (Port* our_port, string other_port, void* src)
455 if (other_port.length() == 0 || our_port == 0) {
460 BLOCK_PROCESS_CALLBACK ();
464 Glib::Mutex::Lock lm (io_lock);
466 /* check that our_port is really one of ours */
468 if ( ! _outputs.contains(our_port) ) {
472 /* connect it to the destination */
474 if (_session.engine().connect (our_port->name(), other_port)) {
478 drop_output_bundle ();
482 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
483 _session.set_dirty ();
488 IO::set_input (Port* other_port, void* src)
490 /* this removes all but one ports, and connects that one port
491 to the specified source.
494 if (_input_minimum.n_total() > 1) {
495 /* sorry, you can't do this */
499 if (other_port == 0) {
500 if (_input_minimum == ChanCount::ZERO) {
501 return ensure_inputs (ChanCount::ZERO, false, true, src);
507 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
511 return connect_input (_inputs.port(0), other_port->name(), src);
515 IO::remove_output_port (Port* port, void* src)
517 IOChange change (NoChange);
520 BLOCK_PROCESS_CALLBACK ();
524 Glib::Mutex::Lock lm (io_lock);
526 if (n_outputs() <= _output_minimum) {
527 /* sorry, you can't do this */
531 if (_outputs.remove(port)) {
532 change = IOChange (change|ConfigurationChanged);
534 if (port->connected()) {
535 change = IOChange (change|ConnectionsChanged);
538 _session.engine().unregister_port (*port);
539 drop_output_bundle ();
541 setup_peak_meters ();
547 if (change != NoChange) {
548 output_changed (change, src);
549 _session.set_dirty ();
556 /** Add an output port.
558 * @param destination Name of input port to connect new port to.
559 * @param src Source for emitted ConfigurationChanged signal.
560 * @param type Data type of port. Default value (NIL) will use this IO's default type.
563 IO::add_output_port (string destination, void* src, DataType type)
568 if (type == DataType::NIL)
569 type = _default_type;
572 BLOCK_PROCESS_CALLBACK ();
576 Glib::Mutex::Lock lm (io_lock);
578 if (n_outputs() >= _output_maximum) {
582 /* Create a new output port */
584 // FIXME: naming scheme for differently typed ports?
585 if (_output_maximum.get(type) == 1) {
586 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
588 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
591 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
592 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
596 _outputs.add (our_port);
597 drop_output_bundle ();
598 setup_peak_meters ();
602 MoreChannels (n_outputs()); /* EMIT SIGNAL */
605 if (destination.length()) {
606 if (_session.engine().connect (our_port->name(), destination)) {
611 // pan_changed (src); /* EMIT SIGNAL */
612 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
613 _session.set_dirty ();
619 IO::remove_input_port (Port* port, void* src)
621 IOChange change (NoChange);
624 BLOCK_PROCESS_CALLBACK ();
628 Glib::Mutex::Lock lm (io_lock);
630 if (n_inputs() <= _input_minimum) {
631 /* sorry, you can't do this */
635 if (_inputs.remove(port)) {
636 change = IOChange (change|ConfigurationChanged);
638 if (port->connected()) {
639 change = IOChange (change|ConnectionsChanged);
642 _session.engine().unregister_port (*port);
643 drop_input_bundle ();
645 setup_peak_meters ();
651 if (change != NoChange) {
652 input_changed (change, src);
653 _session.set_dirty ();
661 /** Add an input port.
663 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
664 * @param destination Name of input port to connect new port to.
665 * @param src Source for emitted ConfigurationChanged signal.
668 IO::add_input_port (string source, void* src, DataType type)
673 if (type == DataType::NIL)
674 type = _default_type;
677 BLOCK_PROCESS_CALLBACK ();
680 Glib::Mutex::Lock lm (io_lock);
682 if (n_inputs() >= _input_maximum) {
686 /* Create a new input port */
688 // FIXME: naming scheme for differently typed ports?
689 if (_input_maximum.get(type) == 1) {
690 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
692 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
695 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
696 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
700 _inputs.add (our_port);
701 drop_input_bundle ();
702 setup_peak_meters ();
706 MoreChannels (n_inputs()); /* EMIT SIGNAL */
709 if (source.length()) {
711 if (_session.engine().connect (source, our_port->name())) {
716 // pan_changed (src); /* EMIT SIGNAL */
717 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
718 _session.set_dirty ();
724 IO::disconnect_inputs (void* src)
727 BLOCK_PROCESS_CALLBACK ();
730 Glib::Mutex::Lock lm (io_lock);
732 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
733 _session.engine().disconnect (*i);
736 drop_input_bundle ();
740 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
746 IO::disconnect_outputs (void* src)
749 BLOCK_PROCESS_CALLBACK ();
752 Glib::Mutex::Lock lm (io_lock);
754 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
755 _session.engine().disconnect (*i);
758 drop_output_bundle ();
762 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
763 _session.set_dirty ();
769 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
771 Port* input_port = 0;
772 bool changed = false;
775 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
777 const size_t n = count.get(*t);
779 /* remove unused ports */
780 for (size_t i = n_inputs().get(*t); i > n; --i) {
781 input_port = _inputs.port(*t, i-1);
784 _inputs.remove(input_port);
785 _session.engine().unregister_port (*input_port);
790 /* create any necessary new ports */
791 while (n_inputs().get(*t) < n) {
795 if (_input_maximum.get(*t) == 1) {
796 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
798 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
803 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
804 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
809 catch (AudioEngine::PortRegistrationFailure& err) {
810 setup_peak_meters ();
813 throw AudioEngine::PortRegistrationFailure();
816 _inputs.add (input_port);
822 drop_input_bundle ();
823 setup_peak_meters ();
825 MoreChannels (n_inputs()); /* EMIT SIGNAL */
826 _session.set_dirty ();
830 /* disconnect all existing ports so that we get a fresh start */
831 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
832 _session.engine().disconnect (*i);
839 /** Attach output_buffers to port buffers.
841 * Connected to IO's own MoreChannels signal.
844 IO::attach_buffers(ChanCount ignored)
846 _output_buffers->attach_buffers(_outputs);
850 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
852 bool in_changed = false;
853 bool out_changed = false;
854 bool need_pan_reset = false;
856 in = min (_input_maximum, in);
858 out = min (_output_maximum, out);
860 if (in == n_inputs() && out == n_outputs() && !clear) {
865 BLOCK_PROCESS_CALLBACK ();
866 Glib::Mutex::Lock lm (io_lock);
870 if (n_outputs() != out) {
871 need_pan_reset = true;
874 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
876 const size_t nin = in.get(*t);
877 const size_t nout = out.get(*t);
879 Port* output_port = 0;
880 Port* input_port = 0;
882 /* remove unused output ports */
883 for (size_t i = n_outputs().get(*t); i > nout; --i) {
884 output_port = _outputs.port(*t, i-1);
887 _outputs.remove(output_port);
888 _session.engine().unregister_port (*output_port);
893 /* remove unused input ports */
894 for (size_t i = n_inputs().get(*t); i > nin; --i) {
895 input_port = _inputs.port(*t, i-1);
898 _inputs.remove(input_port);
899 _session.engine().unregister_port (*input_port);
904 /* create any necessary new input ports */
906 while (n_inputs().get(*t) < nin) {
910 /* Create a new input port */
912 if (_input_maximum.get(*t) == 1) {
913 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
915 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
919 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
920 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
925 catch (AudioEngine::PortRegistrationFailure& err) {
926 setup_peak_meters ();
929 throw AudioEngine::PortRegistrationFailure();
936 /* create any necessary new output ports */
938 while (n_outputs().get(*t) < nout) {
942 /* Create a new output port */
944 if (_output_maximum.get(*t) == 1) {
945 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
947 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
951 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
952 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
957 catch (AudioEngine::PortRegistrationFailure& err) {
958 setup_peak_meters ();
961 throw AudioEngine::PortRegistrationFailure ();
971 /* disconnect all existing ports so that we get a fresh start */
973 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
974 _session.engine().disconnect (*i);
977 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
978 _session.engine().disconnect (*i);
982 if (in_changed || out_changed) {
983 setup_peak_meters ();
989 drop_output_bundle ();
990 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
994 drop_input_bundle ();
995 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
998 if (in_changed || out_changed) {
999 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1000 _session.set_dirty ();
1007 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1009 bool changed = false;
1011 count = min (_input_maximum, count);
1013 if (count == n_inputs() && !clear) {
1018 BLOCK_PROCESS_CALLBACK ();
1019 Glib::Mutex::Lock im (io_lock);
1020 changed = ensure_inputs_locked (count, clear, src);
1022 changed = ensure_inputs_locked (count, clear, src);
1026 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1027 _session.set_dirty ();
1033 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1035 Port* output_port = 0;
1036 bool changed = false;
1037 bool need_pan_reset = false;
1039 if (n_outputs() != count) {
1040 need_pan_reset = true;
1043 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1045 const size_t n = count.get(*t);
1047 /* remove unused ports */
1048 for (size_t i = n_outputs().get(*t); i > n; --i) {
1049 output_port = _outputs.port(*t, i-1);
1051 assert(output_port);
1052 _outputs.remove(output_port);
1053 _session.engine().unregister_port (*output_port);
1058 /* create any necessary new ports */
1059 while (n_outputs().get(*t) < n) {
1063 if (_output_maximum.get(*t) == 1) {
1064 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1066 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1069 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1070 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1074 _outputs.add (output_port);
1076 setup_peak_meters ();
1078 if (need_pan_reset) {
1085 drop_output_bundle ();
1086 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1087 _session.set_dirty ();
1091 /* disconnect all existing ports so that we get a fresh start */
1092 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1093 _session.engine().disconnect (*i);
1101 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1103 bool changed = false;
1105 if (_output_maximum < ChanCount::INFINITE) {
1106 count = min (_output_maximum, count);
1107 if (count == n_outputs() && !clear) {
1112 /* XXX caller should hold io_lock, but generally doesn't */
1115 BLOCK_PROCESS_CALLBACK ();
1116 Glib::Mutex::Lock im (io_lock);
1117 changed = ensure_outputs_locked (count, clear, src);
1119 changed = ensure_outputs_locked (count, clear, src);
1123 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1130 IO::effective_gain () const
1132 if (gain_automation().automation_playback()) {
1133 return _effective_gain;
1135 return _desired_gain;
1142 if (panners_legal) {
1143 if (!no_panner_reset) {
1144 _panner->reset (n_outputs().n_audio(), pans_required());
1147 panner_legal_c.disconnect ();
1148 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1153 IO::panners_became_legal ()
1155 _panner->reset (n_outputs().n_audio(), pans_required());
1156 _panner->load (); // automation
1157 panner_legal_c.disconnect ();
1162 IO::defer_pan_reset ()
1164 no_panner_reset = true;
1168 IO::allow_pan_reset ()
1170 no_panner_reset = false;
1176 IO::get_state (void)
1178 return state (true);
1182 IO::state (bool full_state)
1184 XMLNode* node = new XMLNode (state_node_name);
1187 bool need_ins = true;
1188 bool need_outs = true;
1189 LocaleGuard lg (X_("POSIX"));
1190 Glib::Mutex::Lock lm (io_lock);
1192 node->add_property("name", _name);
1193 id().print (buf, sizeof (buf));
1194 node->add_property("id", buf);
1198 if (_input_bundle) {
1199 node->add_property ("input-connection", _input_bundle->name());
1203 if (_output_bundle) {
1204 node->add_property ("output-connection", _output_bundle->name());
1209 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1211 const char **connections = i->get_connections();
1213 if (connections && connections[0]) {
1216 for (int n = 0; connections && connections[n]; ++n) {
1221 /* if its a connection to our own port,
1222 return only the port name, not the
1223 whole thing. this allows connections
1224 to be re-established even when our
1225 client name is different.
1228 str += _session.engine().make_port_name_relative (connections[n]);
1240 node->add_property ("inputs", str);
1246 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1248 const char **connections = i->get_connections();
1250 if (connections && connections[0]) {
1254 for (int n = 0; connections[n]; ++n) {
1259 str += _session.engine().make_port_name_relative (connections[n]);
1271 node->add_property ("outputs", str);
1274 node->add_child_nocopy (_panner->state (full_state));
1275 node->add_child_nocopy (_gain_control.get_state ());
1277 snprintf (buf, sizeof(buf), "%2.12f", gain());
1278 node->add_property ("gain", buf);
1280 // FIXME: this is NOT sufficient!
1281 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1282 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1283 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1284 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1286 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1288 node->add_property ("iolimits", buf);
1293 node->add_child_nocopy (get_automation_state());
1299 IO::set_state (const XMLNode& node)
1301 const XMLProperty* prop;
1302 XMLNodeConstIterator iter;
1303 LocaleGuard lg (X_("POSIX"));
1305 /* force use of non-localized representation of decimal point,
1306 since we use it a lot in XML files and so forth.
1309 if (node.name() != state_node_name) {
1310 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1314 if ((prop = node.property ("name")) != 0) {
1315 _name = prop->value();
1316 /* used to set panner name with this, but no more */
1319 if ((prop = node.property ("id")) != 0) {
1320 _id = prop->value ();
1325 size_t out_min = -1;
1326 size_t out_max = -1;
1328 if ((prop = node.property ("iolimits")) != 0) {
1329 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1330 &in_min, &in_max, &out_min, &out_max);
1331 _input_minimum = ChanCount(_default_type, in_min);
1332 _input_maximum = ChanCount(_default_type, in_max);
1333 _output_minimum = ChanCount(_default_type, out_min);
1334 _output_maximum = ChanCount(_default_type, out_max);
1337 if ((prop = node.property ("gain")) != 0) {
1338 set_gain (atof (prop->value().c_str()), this);
1339 _gain = _desired_gain;
1342 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1343 /* old school automation handling */
1346 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1348 if ((*iter)->name() == "Panner") {
1350 _panner = new Panner (_name, _session);
1352 _panner->set_state (**iter);
1355 if ((*iter)->name() == X_("Automation")) {
1357 set_automation_state (*(*iter), ParamID(GainAutomation));
1360 if ((*iter)->name() == X_("controllable")) {
1361 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1362 _gain_control.set_state (**iter);
1369 if (create_ports (node)) {
1375 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1378 if (panners_legal) {
1381 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1384 if (connecting_legal) {
1386 if (make_connections (node)) {
1392 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1395 if (!ports_legal || !connecting_legal) {
1396 pending_state_node = new XMLNode (node);
1399 last_automation_snapshot = 0;
1405 IO::load_automation (string path)
1410 uint32_t linecnt = 0;
1412 LocaleGuard lg (X_("POSIX"));
1414 fullpath = _session.automation_dir();
1417 in.open (fullpath.c_str());
1420 fullpath = _session.automation_dir();
1421 fullpath += _session.snap_name();
1425 in.open (fullpath.c_str());
1428 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1433 clear_automation ();
1435 while (in.getline (line, sizeof(line), '\n')) {
1440 if (++linecnt == 1) {
1441 if (memcmp (line, "version", 7) == 0) {
1442 if (sscanf (line, "version %f", &version) != 1) {
1443 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1447 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1454 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1455 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1461 gain_automation().fast_simple_add (when, value);
1471 /* older (pre-1.0) versions of ardour used this */
1475 warning << _("dubious automation event found (and ignored)") << endmsg;
1483 IO::connecting_became_legal ()
1487 if (pending_state_node == 0) {
1488 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1493 connection_legal_c.disconnect ();
1495 ret = make_connections (*pending_state_node);
1498 delete pending_state_node;
1499 pending_state_node = 0;
1505 IO::ports_became_legal ()
1509 if (pending_state_node == 0) {
1510 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1515 port_legal_c.disconnect ();
1517 ret = create_ports (*pending_state_node);
1519 if (connecting_legal) {
1520 delete pending_state_node;
1521 pending_state_node = 0;
1528 IO::create_ports (const XMLNode& node)
1530 const XMLProperty* prop;
1532 int num_outputs = 0;
1534 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1535 * break the session file format.
1537 if ((prop = node.property ("input-connection")) != 0) {
1539 Bundle* c = _session.bundle_by_name (prop->value());
1542 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1544 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1545 error << _("No input bundles available as a replacement")
1549 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1554 num_inputs = c->nchannels();
1556 } else if ((prop = node.property ("inputs")) != 0) {
1558 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1561 if ((prop = node.property ("output-connection")) != 0) {
1562 Bundle* c = _session.bundle_by_name (prop->value());
1565 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1567 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1568 error << _("No output bundles available as a replacement")
1572 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1577 num_outputs = c->nchannels ();
1579 } else if ((prop = node.property ("outputs")) != 0) {
1580 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1583 no_panner_reset = true;
1585 // FIXME: audio-only
1586 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1587 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1591 no_panner_reset = false;
1593 set_deferred_state ();
1601 IO::make_connections (const XMLNode& node)
1603 const XMLProperty* prop;
1605 if ((prop = node.property ("input-connection")) != 0) {
1606 Bundle* c = _session.bundle_by_name (prop->value());
1609 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1611 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1612 error << _("No input connections available as a replacement")
1616 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1621 use_input_bundle (*c, this);
1623 } else if ((prop = node.property ("inputs")) != 0) {
1624 if (set_inputs (prop->value())) {
1625 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1630 if ((prop = node.property ("output-bundle")) != 0) {
1631 Bundle* c = _session.bundle_by_name (prop->value());
1634 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1636 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1637 error << _("No output bundles available as a replacement")
1641 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1646 use_output_bundle (*c, this);
1648 } else if ((prop = node.property ("outputs")) != 0) {
1649 if (set_outputs (prop->value())) {
1650 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1659 IO::set_inputs (const string& str)
1661 vector<string> ports;
1666 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1670 // FIXME: audio-only
1671 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1675 string::size_type start, end, ostart;
1682 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1685 if ((end = str.find_first_of ('}', start)) == string::npos) {
1686 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1690 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1691 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1697 for (int x = 0; x < n; ++x) {
1698 connect_input (input (i), ports[x], this);
1710 IO::set_outputs (const string& str)
1712 vector<string> ports;
1717 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1721 // FIXME: audio-only
1722 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1726 string::size_type start, end, ostart;
1733 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1736 if ((end = str.find_first_of ('}', start)) == string::npos) {
1737 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1741 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1742 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1748 for (int x = 0; x < n; ++x) {
1749 connect_output (output (i), ports[x], this);
1761 IO::parse_io_string (const string& str, vector<string>& ports)
1763 string::size_type pos, opos;
1765 if (str.length() == 0) {
1774 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1775 ports.push_back (str.substr (opos, pos - opos));
1779 if (opos < str.length()) {
1780 ports.push_back (str.substr(opos));
1783 return ports.size();
1787 IO::parse_gain_string (const string& str, vector<string>& ports)
1789 string::size_type pos, opos;
1795 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1796 ports.push_back (str.substr (opos, pos - opos));
1800 if (opos < str.length()) {
1801 ports.push_back (str.substr(opos));
1804 return ports.size();
1808 IO::set_name (const string& str)
1814 /* replace all colons in the name. i wish we didn't have to do this */
1817 if (replace_all (name, ":", "-")) {
1818 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1821 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1822 string current_name = i->short_name();
1823 current_name.replace (current_name.find (_name), _name.length(), name);
1824 i->set_name (current_name);
1827 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1828 string current_name = i->short_name();
1829 current_name.replace (current_name.find (_name), _name.length(), name);
1830 i->set_name (current_name);
1833 return SessionObject::set_name(name);
1837 IO::set_input_minimum (ChanCount n)
1843 IO::set_input_maximum (ChanCount n)
1849 IO::set_output_minimum (ChanCount n)
1851 _output_minimum = n;
1855 IO::set_output_maximum (ChanCount n)
1857 _output_maximum = n;
1861 IO::set_port_latency (nframes_t nframes)
1863 Glib::Mutex::Lock lm (io_lock);
1865 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1866 i->set_latency (nframes);
1871 IO::output_latency () const
1873 nframes_t max_latency;
1878 /* io lock not taken - must be protected by other means */
1880 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1881 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1882 max_latency = latency;
1890 IO::input_latency () const
1892 nframes_t max_latency;
1897 /* io lock not taken - must be protected by other means */
1899 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1900 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1901 max_latency = latency;
1909 IO::use_input_bundle (Bundle& c, void* src)
1914 BLOCK_PROCESS_CALLBACK ();
1915 Glib::Mutex::Lock lm2 (io_lock);
1917 limit = c.nchannels();
1919 drop_input_bundle ();
1921 // FIXME bundles only work for audio-only
1922 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1926 /* first pass: check the current state to see what's correctly
1927 connected, and drop anything that we don't want.
1930 for (uint32_t n = 0; n < limit; ++n) {
1931 const Bundle::PortList& pl = c.channel_ports (n);
1933 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1935 if (!_inputs.port(n)->connected_to ((*i))) {
1937 /* clear any existing connections */
1939 _session.engine().disconnect (*_inputs.port(n));
1941 } else if (_inputs.port(n)->connected() > 1) {
1943 /* OK, it is connected to the port we want,
1944 but its also connected to other ports.
1945 Change that situation.
1948 /* XXX could be optimized to not drop
1952 _session.engine().disconnect (*_inputs.port(n));
1958 /* second pass: connect all requested ports where necessary */
1960 for (uint32_t n = 0; n < limit; ++n) {
1961 const Bundle::PortList& pl = c.channel_ports (n);
1963 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1965 if (!_inputs.port(n)->connected_to ((*i))) {
1967 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1977 input_bundle_configuration_connection = c.ConfigurationChanged.connect
1978 (mem_fun (*this, &IO::input_bundle_configuration_changed));
1979 input_bundle_connection_connection = c.PortsChanged.connect
1980 (mem_fun (*this, &IO::input_bundle_connection_changed));
1983 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1988 IO::use_output_bundle (Bundle& c, void* src)
1993 BLOCK_PROCESS_CALLBACK ();
1994 Glib::Mutex::Lock lm2 (io_lock);
1996 limit = c.nchannels();
1998 drop_output_bundle ();
2000 // FIXME: audio-only
2001 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2005 /* first pass: check the current state to see what's correctly
2006 connected, and drop anything that we don't want.
2009 for (uint32_t n = 0; n < limit; ++n) {
2011 const Bundle::PortList& pl = c.channel_ports (n);
2013 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2015 if (!_outputs.port(n)->connected_to ((*i))) {
2017 /* clear any existing connections */
2019 _session.engine().disconnect (*_outputs.port(n));
2021 } else if (_outputs.port(n)->connected() > 1) {
2023 /* OK, it is connected to the port we want,
2024 but its also connected to other ports.
2025 Change that situation.
2028 /* XXX could be optimized to not drop
2032 _session.engine().disconnect (*_outputs.port(n));
2037 /* second pass: connect all requested ports where necessary */
2039 for (uint32_t n = 0; n < limit; ++n) {
2041 const Bundle::PortList& pl = c.channel_ports (n);
2043 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2045 if (!_outputs.port(n)->connected_to ((*i))) {
2047 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2054 _output_bundle = &c;
2056 output_bundle_configuration_connection = c.ConfigurationChanged.connect
2057 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2058 output_bundle_connection_connection = c.PortsChanged.connect
2059 (mem_fun (*this, &IO::output_bundle_connection_changed));
2062 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2068 IO::disable_connecting ()
2070 connecting_legal = false;
2075 IO::enable_connecting ()
2077 connecting_legal = true;
2078 return ConnectingLegal ();
2082 IO::disable_ports ()
2084 ports_legal = false;
2092 return PortsLegal ();
2096 IO::disable_panners (void)
2098 panners_legal = false;
2103 IO::reset_panners ()
2105 panners_legal = true;
2106 return PannersLegal ();
2110 IO::input_bundle_connection_changed (int ignored)
2112 use_input_bundle (*_input_bundle, this);
2116 IO::input_bundle_configuration_changed ()
2118 use_input_bundle (*_input_bundle, this);
2122 IO::output_bundle_connection_changed (int ignored)
2124 use_output_bundle (*_output_bundle, this);
2128 IO::output_bundle_configuration_changed ()
2130 use_output_bundle (*_output_bundle, this);
2134 IO::GainControllable::set_value (float val)
2136 io.set_gain (direct_control_to_gain (val), this);
2140 IO::GainControllable::get_value (void) const
2142 return direct_gain_to_control (io.effective_gain());
2146 IO::setup_peak_meters()
2148 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2149 _meter->configure_io(max_streams, max_streams);
2153 Update the peak meters.
2155 The meter signal lock is taken to prevent modification of the
2156 Meter signal while updating the meters, taking the meter signal
2157 lock prior to taking the io_lock ensures that all IO will remain
2158 valid while metering.
2163 Glib::Mutex::Lock guard (m_meter_signal_lock);
2165 Meter(); /* EMIT SIGNAL */
2171 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2173 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2178 IO::clear_automation ()
2180 Automatable::clear_automation (); // clears gain automation
2181 _panner->clear_automation ();
2185 IO::set_parameter_automation_state (ParamID param, AutoState state)
2187 // XXX: would be nice to get rid of this special hack
2189 if (param.type() == GainAutomation) {
2191 bool changed = false;
2194 Glib::Mutex::Lock lm (_automation_lock);
2196 ARDOUR::AutomationList& gain_auto = gain_automation();
2198 if (state != gain_auto.automation_state()) {
2200 last_automation_snapshot = 0;
2201 gain_auto.set_automation_state (state);
2204 // FIXME: shouldn't this use Curve?
2205 set_gain (gain_auto.eval (_session.transport_frame()), this);
2211 _session.set_dirty ();
2215 Automatable::set_parameter_automation_state(param, state);
2220 IO::inc_gain (gain_t factor, void *src)
2222 if (_desired_gain == 0.0f)
2223 set_gain (0.000001f + (0.000001f * factor), src);
2225 set_gain (_desired_gain + (_desired_gain * factor), src);
2229 IO::set_gain (gain_t val, void *src)
2231 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2232 if (val>1.99526231f) val=1.99526231f;
2235 Glib::Mutex::Lock dm (declick_lock);
2236 _desired_gain = val;
2239 if (_session.transport_stopped()) {
2240 _effective_gain = val;
2245 _gain_control.Changed (); /* EMIT SIGNAL */
2247 ARDOUR::AutomationList& gain_auto = gain_automation();
2249 if (_session.transport_stopped() && src != 0 && src != this && gain_auto.automation_write()) {
2250 gain_auto.add (_session.transport_frame(), val);
2254 _session.set_dirty();
2258 IO::start_pan_touch (uint32_t which)
2260 if (which < _panner->size()) {
2261 (*_panner)[which]->automation().start_touch();
2266 IO::end_pan_touch (uint32_t which)
2268 if (which < _panner->size()) {
2269 (*_panner)[which]->automation().stop_touch();
2275 IO::automation_snapshot (nframes_t now)
2277 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2279 ARDOUR::AutomationList& gain_auto = gain_automation();
2281 if (gain_auto.automation_write()) {
2282 gain_auto.rt_add (now, gain());
2285 _panner->snapshot (now);
2287 last_automation_snapshot = now;
2292 IO::transport_stopped (nframes_t frame)
2294 ARDOUR::AutomationList& gain_auto = gain_automation();
2296 gain_auto.reposition_for_rt_add (frame);
2298 if (gain_auto.automation_state() != Off) {
2300 /* the src=0 condition is a special signal to not propagate
2301 automation gain changes into the mix group when locating.
2304 // FIXME: shouldn't this use Curve?
2305 set_gain (gain_auto.eval (frame), 0);
2308 _panner->transport_stopped (frame);
2312 IO::find_input_port_hole ()
2314 /* CALLER MUST HOLD IO LOCK */
2318 if (_inputs.empty()) {
2322 for (n = 1; n < UINT_MAX; ++n) {
2323 char buf[jack_port_name_size()];
2324 PortSet::iterator i = _inputs.begin();
2326 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2328 for ( ; i != _inputs.end(); ++i) {
2329 if (i->short_name() == buf) {
2334 if (i == _inputs.end()) {
2342 IO::find_output_port_hole ()
2344 /* CALLER MUST HOLD IO LOCK */
2348 if (_outputs.empty()) {
2352 for (n = 1; n < UINT_MAX; ++n) {
2353 char buf[jack_port_name_size()];
2354 PortSet::iterator i = _outputs.begin();
2356 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2358 for ( ; i != _outputs.end(); ++i) {
2359 if (i->short_name() == buf) {
2364 if (i == _outputs.end()) {
2373 IO::audio_input(uint32_t n) const
2375 return dynamic_cast<AudioPort*>(input(n));
2379 IO::audio_output(uint32_t n) const
2381 return dynamic_cast<AudioPort*>(output(n));
2385 IO::midi_input(uint32_t n) const
2387 return dynamic_cast<MidiPort*>(input(n));
2391 IO::midi_output(uint32_t n) const
2393 return dynamic_cast<MidiPort*>(output(n));
2397 IO::set_phase_invert (bool yn, void *src)
2399 if (_phase_invert != yn) {
2401 // phase_invert_changed (src); /* EMIT SIGNAL */
2406 IO::set_denormal_protection (bool yn, void *src)
2408 if (_denormal_protection != yn) {
2409 _denormal_protection = yn;
2410 // denormal_protection_changed (src); /* EMIT SIGNAL */