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 : SessionObject(s, name),
105 _output_buffers(new BufferSet()),
106 _default_type(default_type),
107 _gain_control (X_("gaincontrol"), *this),
108 _gain_automation_curve (0.0, 2.0, 1.0),
109 _input_minimum (ChanCount::ZERO),
110 _input_maximum (ChanCount::INFINITE),
111 _output_minimum (ChanCount::ZERO),
112 _output_maximum (ChanCount::INFINITE)
114 _panner = new Panner (name, _session);
115 _meter = new PeakMeter (_session);
118 _input_minimum = ChanCount(_default_type, input_min);
120 if (input_max >= 0) {
121 _input_maximum = ChanCount(_default_type, input_max);
123 if (output_min > 0) {
124 _output_minimum = ChanCount(_default_type, output_min);
126 if (output_max >= 0) {
127 _output_maximum = ChanCount(_default_type, output_max);
134 pending_state_node = 0;
135 no_panner_reset = false;
136 _phase_invert = false;
139 apply_gain_automation = false;
141 last_automation_snapshot = 0;
143 _gain_automation_state = Off;
144 _gain_automation_style = Absolute;
147 // IO::Meter is emitted from another thread so the
148 // Meter signal must be protected.
149 Glib::Mutex::Lock guard (m_meter_signal_lock);
150 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
153 // Connect to our own MoreChannels signal to connect output buffers
154 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
156 _session.add_controllable (&_gain_control);
159 IO::IO (Session& s, const XMLNode& node, DataType dt)
160 : SessionObject(s, "unnamed io"),
161 _output_buffers(new BufferSet()),
163 _gain_control (X_("gaincontrol"), *this),
164 _gain_automation_curve (0, 0, 0) // all reset in set_state()
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_curve.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);
1294 XMLNode* autonode = new XMLNode (X_("Automation"));
1295 autonode->add_child_nocopy (get_automation_state());
1296 node->add_child_nocopy (*autonode);
1298 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1300 /* never store anything except Off for automation state in a template */
1301 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1308 IO::set_state (const XMLNode& node)
1310 const XMLProperty* prop;
1311 XMLNodeConstIterator iter;
1312 LocaleGuard lg (X_("POSIX"));
1314 /* force use of non-localized representation of decimal point,
1315 since we use it a lot in XML files and so forth.
1318 if (node.name() != state_node_name) {
1319 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1323 if ((prop = node.property ("name")) != 0) {
1324 _name = prop->value();
1325 /* used to set panner name with this, but no more */
1328 if ((prop = node.property ("id")) != 0) {
1329 _id = prop->value ();
1334 size_t out_min = -1;
1335 size_t out_max = -1;
1337 if ((prop = node.property ("iolimits")) != 0) {
1338 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1339 &in_min, &in_max, &out_min, &out_max);
1340 _input_minimum = ChanCount(_default_type, in_min);
1341 _input_maximum = ChanCount(_default_type, in_max);
1342 _output_minimum = ChanCount(_default_type, out_min);
1343 _output_maximum = ChanCount(_default_type, out_max);
1346 if ((prop = node.property ("gain")) != 0) {
1347 set_gain (atof (prop->value().c_str()), this);
1348 _gain = _desired_gain;
1351 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1352 /* old school automation handling */
1355 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1357 if ((*iter)->name() == "Panner") {
1359 _panner = new Panner (_name, _session);
1361 _panner->set_state (**iter);
1364 if ((*iter)->name() == X_("Automation")) {
1366 set_automation_state (*(*iter)->children().front());
1369 if ((*iter)->name() == X_("controllable")) {
1370 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1371 _gain_control.set_state (**iter);
1378 if (create_ports (node)) {
1384 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1387 if (panners_legal) {
1390 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1393 if (connecting_legal) {
1395 if (make_connections (node)) {
1401 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1404 if (!ports_legal || !connecting_legal) {
1405 pending_state_node = new XMLNode (node);
1408 last_automation_snapshot = 0;
1414 IO::set_automation_state (const XMLNode& node)
1416 return _gain_automation_curve.set_state (node);
1420 IO::get_automation_state ()
1422 return (_gain_automation_curve.get_state ());
1426 IO::load_automation (string path)
1431 uint32_t linecnt = 0;
1433 LocaleGuard lg (X_("POSIX"));
1435 fullpath = _session.automation_dir();
1438 in.open (fullpath.c_str());
1441 fullpath = _session.automation_dir();
1442 fullpath += _session.snap_name();
1446 in.open (fullpath.c_str());
1449 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1454 clear_automation ();
1456 while (in.getline (line, sizeof(line), '\n')) {
1461 if (++linecnt == 1) {
1462 if (memcmp (line, "version", 7) == 0) {
1463 if (sscanf (line, "version %f", &version) != 1) {
1464 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1468 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1475 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1476 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1482 _gain_automation_curve.fast_simple_add (when, value);
1492 /* older (pre-1.0) versions of ardour used this */
1496 warning << _("dubious automation event found (and ignored)") << endmsg;
1504 IO::connecting_became_legal ()
1508 if (pending_state_node == 0) {
1509 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1514 connection_legal_c.disconnect ();
1516 ret = make_connections (*pending_state_node);
1519 delete pending_state_node;
1520 pending_state_node = 0;
1526 IO::ports_became_legal ()
1530 if (pending_state_node == 0) {
1531 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1536 port_legal_c.disconnect ();
1538 ret = create_ports (*pending_state_node);
1540 if (connecting_legal) {
1541 delete pending_state_node;
1542 pending_state_node = 0;
1549 IO::create_ports (const XMLNode& node)
1551 const XMLProperty* prop;
1553 int num_outputs = 0;
1555 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1556 * break the session file format.
1558 if ((prop = node.property ("input-connection")) != 0) {
1560 Bundle* c = _session.bundle_by_name (prop->value());
1563 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1565 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1566 error << _("No input bundles available as a replacement")
1570 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1575 num_inputs = c->nchannels();
1577 } else if ((prop = node.property ("inputs")) != 0) {
1579 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1582 if ((prop = node.property ("output-connection")) != 0) {
1583 Bundle* c = _session.bundle_by_name (prop->value());
1586 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1588 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1589 error << _("No output bundles available as a replacement")
1593 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1598 num_outputs = c->nchannels ();
1600 } else if ((prop = node.property ("outputs")) != 0) {
1601 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1604 no_panner_reset = true;
1606 // FIXME: audio-only
1607 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1608 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1612 no_panner_reset = false;
1614 set_deferred_state ();
1622 IO::make_connections (const XMLNode& node)
1624 const XMLProperty* prop;
1626 if ((prop = node.property ("input-connection")) != 0) {
1627 Bundle* c = _session.bundle_by_name (prop->value());
1630 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1632 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1633 error << _("No input connections available as a replacement")
1637 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1642 use_input_bundle (*c, this);
1644 } else if ((prop = node.property ("inputs")) != 0) {
1645 if (set_inputs (prop->value())) {
1646 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1651 if ((prop = node.property ("output-bundle")) != 0) {
1652 Bundle* c = _session.bundle_by_name (prop->value());
1655 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1657 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1658 error << _("No output bundles available as a replacement")
1662 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1667 use_output_bundle (*c, this);
1669 } else if ((prop = node.property ("outputs")) != 0) {
1670 if (set_outputs (prop->value())) {
1671 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1680 IO::set_inputs (const string& str)
1682 vector<string> ports;
1687 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1691 // FIXME: audio-only
1692 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1696 string::size_type start, end, ostart;
1703 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1706 if ((end = str.find_first_of ('}', start)) == string::npos) {
1707 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1711 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1712 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1718 for (int x = 0; x < n; ++x) {
1719 connect_input (input (i), ports[x], this);
1731 IO::set_outputs (const string& str)
1733 vector<string> ports;
1738 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1742 // FIXME: audio-only
1743 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1747 string::size_type start, end, ostart;
1754 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1757 if ((end = str.find_first_of ('}', start)) == string::npos) {
1758 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1762 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1763 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1769 for (int x = 0; x < n; ++x) {
1770 connect_output (output (i), ports[x], this);
1782 IO::parse_io_string (const string& str, vector<string>& ports)
1784 string::size_type pos, opos;
1786 if (str.length() == 0) {
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::parse_gain_string (const string& str, vector<string>& ports)
1810 string::size_type pos, opos;
1816 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1817 ports.push_back (str.substr (opos, pos - opos));
1821 if (opos < str.length()) {
1822 ports.push_back (str.substr(opos));
1825 return ports.size();
1829 IO::set_name (const string& str)
1835 /* replace all colons in the name. i wish we didn't have to do this */
1838 if (replace_all (name, ":", "-")) {
1839 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1842 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1843 string current_name = i->short_name();
1844 current_name.replace (current_name.find (_name), _name.length(), name);
1845 i->set_name (current_name);
1848 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1849 string current_name = i->short_name();
1850 current_name.replace (current_name.find (_name), _name.length(), name);
1851 i->set_name (current_name);
1854 return SessionObject::set_name(name);
1858 IO::set_input_minimum (ChanCount n)
1864 IO::set_input_maximum (ChanCount n)
1870 IO::set_output_minimum (ChanCount n)
1872 _output_minimum = n;
1876 IO::set_output_maximum (ChanCount n)
1878 _output_maximum = n;
1882 IO::set_port_latency (nframes_t nframes)
1884 Glib::Mutex::Lock lm (io_lock);
1886 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1887 i->set_latency (nframes);
1892 IO::output_latency () const
1894 nframes_t max_latency;
1899 /* io lock not taken - must be protected by other means */
1901 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1902 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1903 max_latency = latency;
1911 IO::input_latency () const
1913 nframes_t max_latency;
1918 /* io lock not taken - must be protected by other means */
1920 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1921 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1922 max_latency = latency;
1930 IO::use_input_bundle (Bundle& c, void* src)
1935 BLOCK_PROCESS_CALLBACK ();
1936 Glib::Mutex::Lock lm2 (io_lock);
1938 limit = c.nchannels();
1940 drop_input_bundle ();
1942 // FIXME bundles only work for audio-only
1943 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1947 /* first pass: check the current state to see what's correctly
1948 connected, and drop anything that we don't want.
1951 for (uint32_t n = 0; n < limit; ++n) {
1952 const Bundle::PortList& pl = c.channel_ports (n);
1954 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1956 if (!_inputs.port(n)->connected_to ((*i))) {
1958 /* clear any existing connections */
1960 _session.engine().disconnect (*_inputs.port(n));
1962 } else if (_inputs.port(n)->connected() > 1) {
1964 /* OK, it is connected to the port we want,
1965 but its also connected to other ports.
1966 Change that situation.
1969 /* XXX could be optimized to not drop
1973 _session.engine().disconnect (*_inputs.port(n));
1979 /* second pass: connect all requested ports where necessary */
1981 for (uint32_t n = 0; n < limit; ++n) {
1982 const Bundle::PortList& pl = c.channel_ports (n);
1984 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1986 if (!_inputs.port(n)->connected_to ((*i))) {
1988 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1998 input_bundle_configuration_connection = c.ConfigurationChanged.connect
1999 (mem_fun (*this, &IO::input_bundle_configuration_changed));
2000 input_bundle_connection_connection = c.PortsChanged.connect
2001 (mem_fun (*this, &IO::input_bundle_connection_changed));
2004 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2009 IO::use_output_bundle (Bundle& c, void* src)
2014 BLOCK_PROCESS_CALLBACK ();
2015 Glib::Mutex::Lock lm2 (io_lock);
2017 limit = c.nchannels();
2019 drop_output_bundle ();
2021 // FIXME: audio-only
2022 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2026 /* first pass: check the current state to see what's correctly
2027 connected, and drop anything that we don't want.
2030 for (uint32_t n = 0; n < limit; ++n) {
2032 const Bundle::PortList& pl = c.channel_ports (n);
2034 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2036 if (!_outputs.port(n)->connected_to ((*i))) {
2038 /* clear any existing connections */
2040 _session.engine().disconnect (*_outputs.port(n));
2042 } else if (_outputs.port(n)->connected() > 1) {
2044 /* OK, it is connected to the port we want,
2045 but its also connected to other ports.
2046 Change that situation.
2049 /* XXX could be optimized to not drop
2053 _session.engine().disconnect (*_outputs.port(n));
2058 /* second pass: connect all requested ports where necessary */
2060 for (uint32_t n = 0; n < limit; ++n) {
2062 const Bundle::PortList& pl = c.channel_ports (n);
2064 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2066 if (!_outputs.port(n)->connected_to ((*i))) {
2068 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2075 _output_bundle = &c;
2077 output_bundle_configuration_connection = c.ConfigurationChanged.connect
2078 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2079 output_bundle_connection_connection = c.PortsChanged.connect
2080 (mem_fun (*this, &IO::output_bundle_connection_changed));
2083 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2089 IO::disable_connecting ()
2091 connecting_legal = false;
2096 IO::enable_connecting ()
2098 connecting_legal = true;
2099 return ConnectingLegal ();
2103 IO::disable_ports ()
2105 ports_legal = false;
2113 return PortsLegal ();
2117 IO::disable_panners (void)
2119 panners_legal = false;
2124 IO::reset_panners ()
2126 panners_legal = true;
2127 return PannersLegal ();
2131 IO::input_bundle_connection_changed (int ignored)
2133 use_input_bundle (*_input_bundle, this);
2137 IO::input_bundle_configuration_changed ()
2139 use_input_bundle (*_input_bundle, this);
2143 IO::output_bundle_connection_changed (int ignored)
2145 use_output_bundle (*_output_bundle, this);
2149 IO::output_bundle_configuration_changed ()
2151 use_output_bundle (*_output_bundle, this);
2155 IO::GainControllable::set_value (float val)
2157 io.set_gain (direct_control_to_gain (val), this);
2161 IO::GainControllable::get_value (void) const
2163 return direct_gain_to_control (io.effective_gain());
2167 IO::setup_peak_meters()
2169 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2170 _meter->configure_io(max_streams, max_streams);
2174 Update the peak meters.
2176 The meter signal lock is taken to prevent modification of the
2177 Meter signal while updating the meters, taking the meter signal
2178 lock prior to taking the io_lock ensures that all IO will remain
2179 valid while metering.
2184 Glib::Mutex::Lock guard (m_meter_signal_lock);
2186 Meter(); /* EMIT SIGNAL */
2192 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2194 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2199 IO::clear_automation ()
2201 Glib::Mutex::Lock lm (automation_lock);
2202 _gain_automation_curve.clear ();
2203 _panner->clear_automation ();
2207 IO::set_gain_automation_state (AutoState state)
2209 bool changed = false;
2212 Glib::Mutex::Lock lm (automation_lock);
2214 if (state != _gain_automation_curve.automation_state()) {
2216 last_automation_snapshot = 0;
2217 _gain_automation_curve.set_automation_state (state);
2220 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2226 _session.set_dirty ();
2227 //gain_automation_state_changed (); /* EMIT SIGNAL */
2232 IO::set_gain_automation_style (AutoStyle style)
2234 Glib::Mutex::Lock lm (automation_lock);
2235 _gain_automation_curve.set_automation_style (style);
2239 IO::inc_gain (gain_t factor, void *src)
2241 if (_desired_gain == 0.0f)
2242 set_gain (0.000001f + (0.000001f * factor), src);
2244 set_gain (_desired_gain + (_desired_gain * factor), src);
2248 IO::set_gain (gain_t val, void *src)
2250 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2251 if (val>1.99526231f) val=1.99526231f;
2254 Glib::Mutex::Lock dm (declick_lock);
2255 _desired_gain = val;
2258 if (_session.transport_stopped()) {
2259 _effective_gain = val;
2264 _gain_control.Changed (); /* EMIT SIGNAL */
2266 if (_session.transport_stopped() && src != 0 && src != this && _gain_automation_curve.automation_write()) {
2267 _gain_automation_curve.add (_session.transport_frame(), val);
2271 _session.set_dirty();
2275 IO::start_gain_touch ()
2277 _gain_automation_curve.start_touch ();
2281 IO::end_gain_touch ()
2283 _gain_automation_curve.stop_touch ();
2287 IO::start_pan_touch (uint32_t which)
2289 if (which < _panner->size()) {
2290 (*_panner)[which]->automation().start_touch();
2295 IO::end_pan_touch (uint32_t which)
2297 if (which < _panner->size()) {
2298 (*_panner)[which]->automation().stop_touch();
2304 IO::automation_snapshot (nframes_t now)
2306 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2308 if (_gain_automation_curve.automation_write()) {
2309 _gain_automation_curve.rt_add (now, gain());
2312 _panner->snapshot (now);
2314 last_automation_snapshot = now;
2319 IO::transport_stopped (nframes_t frame)
2321 _gain_automation_curve.reposition_for_rt_add (frame);
2323 if (_gain_automation_curve.automation_state() != Off) {
2325 /* the src=0 condition is a special signal to not propagate
2326 automation gain changes into the mix group when locating.
2329 set_gain (_gain_automation_curve.eval (frame), 0);
2332 _panner->transport_stopped (frame);
2336 IO::find_input_port_hole ()
2338 /* CALLER MUST HOLD IO LOCK */
2342 if (_inputs.empty()) {
2346 for (n = 1; n < UINT_MAX; ++n) {
2347 char buf[jack_port_name_size()];
2348 PortSet::iterator i = _inputs.begin();
2350 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2352 for ( ; i != _inputs.end(); ++i) {
2353 if (i->short_name() == buf) {
2358 if (i == _inputs.end()) {
2366 IO::find_output_port_hole ()
2368 /* CALLER MUST HOLD IO LOCK */
2372 if (_outputs.empty()) {
2376 for (n = 1; n < UINT_MAX; ++n) {
2377 char buf[jack_port_name_size()];
2378 PortSet::iterator i = _outputs.begin();
2380 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2382 for ( ; i != _outputs.end(); ++i) {
2383 if (i->short_name() == buf) {
2388 if (i == _outputs.end()) {
2397 IO::audio_input(uint32_t n) const
2399 return dynamic_cast<AudioPort*>(input(n));
2403 IO::audio_output(uint32_t n) const
2405 return dynamic_cast<AudioPort*>(output(n));
2409 IO::midi_input(uint32_t n) const
2411 return dynamic_cast<MidiPort*>(input(n));
2415 IO::midi_output(uint32_t n) const
2417 return dynamic_cast<MidiPort*>(output(n));
2421 IO::set_phase_invert (bool yn, void *src)
2423 if (_phase_invert != yn) {
2425 // phase_invert_changed (src); /* EMIT SIGNAL */
2430 IO::set_denormal_protection (bool yn, void *src)
2432 if (_denormal_protection != yn) {
2433 _denormal_protection = yn;
2434 // denormal_protection_changed (src); /* EMIT SIGNAL */