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, string name,
102 int input_min, int input_max, int output_min, int output_max,
103 DataType default_type)
105 _output_buffers(new BufferSet()),
107 _default_type(default_type),
108 _gain_control (X_("gaincontrol"), *this),
109 _gain_automation_curve (0.0, 2.0, 1.0),
110 _input_minimum (ChanCount::ZERO),
111 _input_maximum (ChanCount::INFINITE),
112 _output_minimum (ChanCount::ZERO),
113 _output_maximum (ChanCount::INFINITE)
115 _panner = new Panner (name, _session);
116 _meter = new PeakMeter (_session);
119 _input_minimum = ChanCount(_default_type, input_min);
121 if (input_max >= 0) {
122 _input_maximum = ChanCount(_default_type, input_max);
124 if (output_min > 0) {
125 _output_minimum = ChanCount(_default_type, output_min);
127 if (output_max >= 0) {
128 _output_maximum = ChanCount(_default_type, output_max);
135 pending_state_node = 0;
136 no_panner_reset = false;
137 _phase_invert = false;
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)
162 _output_buffers(new BufferSet()),
164 _gain_control (X_("gaincontrol"), *this),
165 _gain_automation_curve (0, 0, 0) // all reset in set_state()
168 _meter = new PeakMeter (_session);
172 no_panner_reset = false;
178 apply_gain_automation = false;
183 // IO::Meter is emitted from another thread so the
184 // Meter signal must be protected.
185 Glib::Mutex::Lock guard (m_meter_signal_lock);
186 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
189 // Connect to our own MoreChannels signal to connect output buffers
190 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
192 _session.add_controllable (&_gain_control);
197 Glib::Mutex::Lock guard (m_meter_signal_lock);
199 Glib::Mutex::Lock lm (io_lock);
201 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
202 _session.engine().unregister_port (*i);
205 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
206 _session.engine().unregister_port (*i);
209 m_meter_connection.disconnect();
213 delete _output_buffers;
217 IO::silence (nframes_t nframes, nframes_t offset)
219 /* io_lock, not taken: function must be called from Session::process() calltree */
221 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
222 i->get_buffer().silence (nframes, offset);
226 /** Deliver bufs to the IO's Jack outputs.
228 * This function should automatically do whatever it necessary to correctly deliver bufs
229 * to the outputs, eg applying gain or pan or whatever else needs to be done.
232 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
234 // FIXME: type specific code doesn't actually need to be here, it will go away in time
236 /* ********** AUDIO ********** */
238 // Apply gain if gain automation isn't playing
239 if ( ! apply_gain_automation) {
241 gain_t dg = _gain; // desired gain
244 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
252 if (dg != _gain || dg != 1.0)
253 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
256 // Use the panner to distribute audio to output port buffers
257 if (_panner && !_panner->empty() && !_panner->bypassed()) {
258 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
260 const DataType type = DataType::AUDIO;
262 // Copy any audio 1:1 to outputs
264 BufferSet::iterator o = output_buffers().begin(type);
265 BufferSet::iterator i = bufs.begin(type);
266 BufferSet::iterator prev = i;
268 while (i != bufs.end(type) && o != output_buffers().end (type)) {
269 o->read_from(*i, nframes, offset);
275 /* extra outputs get a copy of the last buffer */
277 while (o != output_buffers().end(type)) {
278 o->read_from(*prev, nframes, offset);
283 /* ********** MIDI ********** */
285 // No MIDI, we're done here
286 if (bufs.count().n_midi() == 0) {
290 const DataType type = DataType::MIDI;
292 // Copy any MIDI 1:1 to outputs
293 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
294 BufferSet::iterator o = output_buffers().begin(type);
295 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
296 o->read_from(*i, nframes, offset);
301 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
303 assert(outs.available() >= n_inputs());
305 outs.set_count(n_inputs());
307 if (outs.count() == ChanCount::ZERO)
310 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
312 BufferSet::iterator o = outs.begin(*t);
313 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
314 o->read_from(i->get_buffer(), nframes, offset);
321 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
322 nframes_t nframes, nframes_t offset)
324 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
326 collect_input (bufs, nframes, offset);
328 _meter->run(bufs, nframes);
332 IO::drop_input_bundle ()
335 input_bundle_configuration_connection.disconnect();
336 input_bundle_connection_connection.disconnect();
337 _session.set_dirty ();
341 IO::drop_output_bundle ()
344 output_bundle_configuration_connection.disconnect();
345 output_bundle_connection_connection.disconnect();
346 _session.set_dirty ();
350 IO::disconnect_input (Port* our_port, string other_port, void* src)
352 if (other_port.length() == 0 || our_port == 0) {
357 BLOCK_PROCESS_CALLBACK ();
360 Glib::Mutex::Lock lm (io_lock);
362 /* check that our_port is really one of ours */
364 if ( ! _inputs.contains(our_port)) {
368 /* disconnect it from the source */
370 if (_session.engine().disconnect (other_port, our_port->name())) {
371 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
375 drop_input_bundle ();
379 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
380 _session.set_dirty ();
386 IO::connect_input (Port* our_port, string other_port, void* src)
388 if (other_port.length() == 0 || our_port == 0) {
393 BLOCK_PROCESS_CALLBACK ();
396 Glib::Mutex::Lock lm (io_lock);
398 /* check that our_port is really one of ours */
400 if ( ! _inputs.contains(our_port) ) {
404 /* connect it to the source */
406 if (_session.engine().connect (other_port, our_port->name())) {
410 drop_input_bundle ();
414 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
415 _session.set_dirty ();
420 IO::disconnect_output (Port* our_port, string other_port, void* src)
422 if (other_port.length() == 0 || our_port == 0) {
427 BLOCK_PROCESS_CALLBACK ();
430 Glib::Mutex::Lock lm (io_lock);
432 /* check that our_port is really one of ours */
434 if ( ! _outputs.contains(our_port) ) {
438 /* disconnect it from the destination */
440 if (_session.engine().disconnect (our_port->name(), other_port)) {
441 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
445 drop_output_bundle ();
449 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
450 _session.set_dirty ();
455 IO::connect_output (Port* our_port, string other_port, void* src)
457 if (other_port.length() == 0 || our_port == 0) {
462 BLOCK_PROCESS_CALLBACK ();
466 Glib::Mutex::Lock lm (io_lock);
468 /* check that our_port is really one of ours */
470 if ( ! _outputs.contains(our_port) ) {
474 /* connect it to the destination */
476 if (_session.engine().connect (our_port->name(), other_port)) {
480 drop_output_bundle ();
484 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
485 _session.set_dirty ();
490 IO::set_input (Port* other_port, void* src)
492 /* this removes all but one ports, and connects that one port
493 to the specified source.
496 if (_input_minimum.n_total() > 1) {
497 /* sorry, you can't do this */
501 if (other_port == 0) {
502 if (_input_minimum == ChanCount::ZERO) {
503 return ensure_inputs (ChanCount::ZERO, false, true, src);
509 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
513 return connect_input (_inputs.port(0), other_port->name(), src);
517 IO::remove_output_port (Port* port, void* src)
519 IOChange change (NoChange);
522 BLOCK_PROCESS_CALLBACK ();
526 Glib::Mutex::Lock lm (io_lock);
528 if (n_outputs() <= _output_minimum) {
529 /* sorry, you can't do this */
533 if (_outputs.remove(port)) {
534 change = IOChange (change|ConfigurationChanged);
536 if (port->connected()) {
537 change = IOChange (change|ConnectionsChanged);
540 _session.engine().unregister_port (*port);
541 drop_output_bundle ();
543 setup_peak_meters ();
549 if (change != NoChange) {
550 output_changed (change, src);
551 _session.set_dirty ();
558 /** Add an output port.
560 * @param destination Name of input port to connect new port to.
561 * @param src Source for emitted ConfigurationChanged signal.
562 * @param type Data type of port. Default value (NIL) will use this IO's default type.
565 IO::add_output_port (string destination, void* src, DataType type)
570 if (type == DataType::NIL)
571 type = _default_type;
574 BLOCK_PROCESS_CALLBACK ();
578 Glib::Mutex::Lock lm (io_lock);
580 if (n_outputs() >= _output_maximum) {
584 /* Create a new output port */
586 // FIXME: naming scheme for differently typed ports?
587 if (_output_maximum.get(type) == 1) {
588 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
590 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
593 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
594 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
598 _outputs.add (our_port);
599 drop_output_bundle ();
600 setup_peak_meters ();
604 MoreChannels (n_outputs()); /* EMIT SIGNAL */
607 if (destination.length()) {
608 if (_session.engine().connect (our_port->name(), destination)) {
613 // pan_changed (src); /* EMIT SIGNAL */
614 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
615 _session.set_dirty ();
621 IO::remove_input_port (Port* port, void* src)
623 IOChange change (NoChange);
626 BLOCK_PROCESS_CALLBACK ();
630 Glib::Mutex::Lock lm (io_lock);
632 if (n_inputs() <= _input_minimum) {
633 /* sorry, you can't do this */
637 if (_inputs.remove(port)) {
638 change = IOChange (change|ConfigurationChanged);
640 if (port->connected()) {
641 change = IOChange (change|ConnectionsChanged);
644 _session.engine().unregister_port (*port);
645 drop_input_bundle ();
647 setup_peak_meters ();
653 if (change != NoChange) {
654 input_changed (change, src);
655 _session.set_dirty ();
663 /** Add an input port.
665 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
666 * @param destination Name of input port to connect new port to.
667 * @param src Source for emitted ConfigurationChanged signal.
670 IO::add_input_port (string source, void* src, DataType type)
675 if (type == DataType::NIL)
676 type = _default_type;
679 BLOCK_PROCESS_CALLBACK ();
682 Glib::Mutex::Lock lm (io_lock);
684 if (n_inputs() >= _input_maximum) {
688 /* Create a new input port */
690 // FIXME: naming scheme for differently typed ports?
691 if (_input_maximum.get(type) == 1) {
692 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
694 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
697 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
698 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
702 _inputs.add (our_port);
703 drop_input_bundle ();
704 setup_peak_meters ();
708 MoreChannels (n_inputs()); /* EMIT SIGNAL */
711 if (source.length()) {
713 if (_session.engine().connect (source, our_port->name())) {
718 // pan_changed (src); /* EMIT SIGNAL */
719 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
720 _session.set_dirty ();
726 IO::disconnect_inputs (void* src)
729 BLOCK_PROCESS_CALLBACK ();
732 Glib::Mutex::Lock lm (io_lock);
734 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
735 _session.engine().disconnect (*i);
738 drop_input_bundle ();
742 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
748 IO::disconnect_outputs (void* src)
751 BLOCK_PROCESS_CALLBACK ();
754 Glib::Mutex::Lock lm (io_lock);
756 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
757 _session.engine().disconnect (*i);
760 drop_output_bundle ();
764 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
765 _session.set_dirty ();
771 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
773 Port* input_port = 0;
774 bool changed = false;
777 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
779 const size_t n = count.get(*t);
781 /* remove unused ports */
782 for (size_t i = n_inputs().get(*t); i > n; --i) {
783 input_port = _inputs.port(*t, i-1);
786 _inputs.remove(input_port);
787 _session.engine().unregister_port (*input_port);
792 /* create any necessary new ports */
793 while (n_inputs().get(*t) < n) {
797 if (_input_maximum.get(*t) == 1) {
798 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
800 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
805 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
806 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
811 catch (AudioEngine::PortRegistrationFailure& err) {
812 setup_peak_meters ();
815 throw AudioEngine::PortRegistrationFailure();
818 _inputs.add (input_port);
824 drop_input_bundle ();
825 setup_peak_meters ();
827 MoreChannels (n_inputs()); /* EMIT SIGNAL */
828 _session.set_dirty ();
832 /* disconnect all existing ports so that we get a fresh start */
833 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
834 _session.engine().disconnect (*i);
841 /** Attach output_buffers to port buffers.
843 * Connected to IO's own MoreChannels signal.
846 IO::attach_buffers(ChanCount ignored)
848 _output_buffers->attach_buffers(_outputs);
852 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
854 bool in_changed = false;
855 bool out_changed = false;
856 bool need_pan_reset = false;
858 in = min (_input_maximum, in);
860 out = min (_output_maximum, out);
862 if (in == n_inputs() && out == n_outputs() && !clear) {
867 BLOCK_PROCESS_CALLBACK ();
868 Glib::Mutex::Lock lm (io_lock);
872 if (n_outputs() != out) {
873 need_pan_reset = true;
876 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
878 const size_t nin = in.get(*t);
879 const size_t nout = out.get(*t);
881 Port* output_port = 0;
882 Port* input_port = 0;
884 /* remove unused output ports */
885 for (size_t i = n_outputs().get(*t); i > nout; --i) {
886 output_port = _outputs.port(*t, i-1);
889 _outputs.remove(output_port);
890 _session.engine().unregister_port (*output_port);
895 /* remove unused input ports */
896 for (size_t i = n_inputs().get(*t); i > nin; --i) {
897 input_port = _inputs.port(*t, i-1);
900 _inputs.remove(input_port);
901 _session.engine().unregister_port (*input_port);
906 /* create any necessary new input ports */
908 while (n_inputs().get(*t) < nin) {
912 /* Create a new input port */
914 if (_input_maximum.get(*t) == 1) {
915 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
917 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
921 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
922 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
927 catch (AudioEngine::PortRegistrationFailure& err) {
928 setup_peak_meters ();
931 throw AudioEngine::PortRegistrationFailure();
938 /* create any necessary new output ports */
940 while (n_outputs().get(*t) < nout) {
944 /* Create a new output port */
946 if (_output_maximum.get(*t) == 1) {
947 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
949 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
953 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
954 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
959 catch (AudioEngine::PortRegistrationFailure& err) {
960 setup_peak_meters ();
963 throw AudioEngine::PortRegistrationFailure ();
973 /* disconnect all existing ports so that we get a fresh start */
975 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
976 _session.engine().disconnect (*i);
979 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
980 _session.engine().disconnect (*i);
984 if (in_changed || out_changed) {
985 setup_peak_meters ();
991 drop_output_bundle ();
992 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
996 drop_input_bundle ();
997 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1000 if (in_changed || out_changed) {
1001 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1002 _session.set_dirty ();
1009 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1011 bool changed = false;
1013 count = min (_input_maximum, count);
1015 if (count == n_inputs() && !clear) {
1020 BLOCK_PROCESS_CALLBACK ();
1021 Glib::Mutex::Lock im (io_lock);
1022 changed = ensure_inputs_locked (count, clear, src);
1024 changed = ensure_inputs_locked (count, clear, src);
1028 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1029 _session.set_dirty ();
1035 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1037 Port* output_port = 0;
1038 bool changed = false;
1039 bool need_pan_reset = false;
1041 if (n_outputs() != count) {
1042 need_pan_reset = true;
1045 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1047 const size_t n = count.get(*t);
1049 /* remove unused ports */
1050 for (size_t i = n_outputs().get(*t); i > n; --i) {
1051 output_port = _outputs.port(*t, i-1);
1053 assert(output_port);
1054 _outputs.remove(output_port);
1055 _session.engine().unregister_port (*output_port);
1060 /* create any necessary new ports */
1061 while (n_outputs().get(*t) < n) {
1065 if (_output_maximum.get(*t) == 1) {
1066 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1068 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1071 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1072 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1076 _outputs.add (output_port);
1078 setup_peak_meters ();
1080 if (need_pan_reset) {
1087 drop_output_bundle ();
1088 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1089 _session.set_dirty ();
1093 /* disconnect all existing ports so that we get a fresh start */
1094 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1095 _session.engine().disconnect (*i);
1103 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1105 bool changed = false;
1107 if (_output_maximum < ChanCount::INFINITE) {
1108 count = min (_output_maximum, count);
1109 if (count == n_outputs() && !clear) {
1114 /* XXX caller should hold io_lock, but generally doesn't */
1117 BLOCK_PROCESS_CALLBACK ();
1118 Glib::Mutex::Lock im (io_lock);
1119 changed = ensure_outputs_locked (count, clear, src);
1121 changed = ensure_outputs_locked (count, clear, src);
1125 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1132 IO::effective_gain () const
1134 if (gain_automation_playback()) {
1135 return _effective_gain;
1137 return _desired_gain;
1144 if (panners_legal) {
1145 if (!no_panner_reset) {
1146 _panner->reset (n_outputs().n_audio(), pans_required());
1149 panner_legal_c.disconnect ();
1150 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1155 IO::panners_became_legal ()
1157 _panner->reset (n_outputs().n_audio(), pans_required());
1158 _panner->load (); // automation
1159 panner_legal_c.disconnect ();
1164 IO::defer_pan_reset ()
1166 no_panner_reset = true;
1170 IO::allow_pan_reset ()
1172 no_panner_reset = false;
1178 IO::get_state (void)
1180 return state (true);
1184 IO::state (bool full_state)
1186 XMLNode* node = new XMLNode (state_node_name);
1189 bool need_ins = true;
1190 bool need_outs = true;
1191 LocaleGuard lg (X_("POSIX"));
1192 Glib::Mutex::Lock lm (io_lock);
1194 node->add_property("name", _name);
1195 id().print (buf, sizeof (buf));
1196 node->add_property("id", buf);
1200 if (_input_bundle) {
1201 node->add_property ("input-connection", _input_bundle->name());
1205 if (_output_bundle) {
1206 node->add_property ("output-connection", _output_bundle->name());
1211 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1213 const char **connections = i->get_connections();
1215 if (connections && connections[0]) {
1218 for (int n = 0; connections && connections[n]; ++n) {
1223 /* if its a connection to our own port,
1224 return only the port name, not the
1225 whole thing. this allows connections
1226 to be re-established even when our
1227 client name is different.
1230 str += _session.engine().make_port_name_relative (connections[n]);
1242 node->add_property ("inputs", str);
1248 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1250 const char **connections = i->get_connections();
1252 if (connections && connections[0]) {
1256 for (int n = 0; connections[n]; ++n) {
1261 str += _session.engine().make_port_name_relative (connections[n]);
1273 node->add_property ("outputs", str);
1276 node->add_child_nocopy (_panner->state (full_state));
1277 node->add_child_nocopy (_gain_control.get_state ());
1279 snprintf (buf, sizeof(buf), "%2.12f", gain());
1280 node->add_property ("gain", buf);
1282 // FIXME: this is NOT sufficient!
1283 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1284 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1285 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1286 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1288 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1290 node->add_property ("iolimits", buf);
1296 XMLNode* autonode = new XMLNode (X_("Automation"));
1297 autonode->add_child_nocopy (get_automation_state());
1298 node->add_child_nocopy (*autonode);
1300 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1302 /* never store anything except Off for automation state in a template */
1303 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1310 IO::set_state (const XMLNode& node)
1312 const XMLProperty* prop;
1313 XMLNodeConstIterator iter;
1314 LocaleGuard lg (X_("POSIX"));
1316 /* force use of non-localized representation of decimal point,
1317 since we use it a lot in XML files and so forth.
1320 if (node.name() != state_node_name) {
1321 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1325 if ((prop = node.property ("name")) != 0) {
1326 _name = prop->value();
1327 /* used to set panner name with this, but no more */
1330 if ((prop = node.property ("id")) != 0) {
1331 _id = prop->value ();
1336 size_t out_min = -1;
1337 size_t out_max = -1;
1339 if ((prop = node.property ("iolimits")) != 0) {
1340 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1341 &in_min, &in_max, &out_min, &out_max);
1342 _input_minimum = ChanCount(_default_type, in_min);
1343 _input_maximum = ChanCount(_default_type, in_max);
1344 _output_minimum = ChanCount(_default_type, out_min);
1345 _output_maximum = ChanCount(_default_type, out_max);
1348 if ((prop = node.property ("gain")) != 0) {
1349 set_gain (atof (prop->value().c_str()), this);
1350 _gain = _desired_gain;
1353 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1354 /* old school automation handling */
1357 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1359 if ((*iter)->name() == "Panner") {
1361 _panner = new Panner (_name, _session);
1363 _panner->set_state (**iter);
1366 if ((*iter)->name() == X_("Automation")) {
1368 set_automation_state (*(*iter)->children().front());
1371 if ((*iter)->name() == X_("controllable")) {
1372 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1373 _gain_control.set_state (**iter);
1380 if (create_ports (node)) {
1386 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1389 if (panners_legal) {
1392 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1395 if (connecting_legal) {
1397 if (make_connections (node)) {
1403 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1406 if (!ports_legal || !connecting_legal) {
1407 pending_state_node = new XMLNode (node);
1410 last_automation_snapshot = 0;
1416 IO::set_automation_state (const XMLNode& node)
1418 return _gain_automation_curve.set_state (node);
1422 IO::get_automation_state ()
1424 return (_gain_automation_curve.get_state ());
1428 IO::load_automation (string path)
1433 uint32_t linecnt = 0;
1435 LocaleGuard lg (X_("POSIX"));
1437 fullpath = _session.automation_dir();
1440 in.open (fullpath.c_str());
1443 fullpath = _session.automation_dir();
1444 fullpath += _session.snap_name();
1448 in.open (fullpath.c_str());
1451 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1456 clear_automation ();
1458 while (in.getline (line, sizeof(line), '\n')) {
1463 if (++linecnt == 1) {
1464 if (memcmp (line, "version", 7) == 0) {
1465 if (sscanf (line, "version %f", &version) != 1) {
1466 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1470 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1477 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1478 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1484 _gain_automation_curve.fast_simple_add (when, value);
1494 /* older (pre-1.0) versions of ardour used this */
1498 warning << _("dubious automation event found (and ignored)") << endmsg;
1506 IO::connecting_became_legal ()
1510 if (pending_state_node == 0) {
1511 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1516 connection_legal_c.disconnect ();
1518 ret = make_connections (*pending_state_node);
1521 delete pending_state_node;
1522 pending_state_node = 0;
1528 IO::ports_became_legal ()
1532 if (pending_state_node == 0) {
1533 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1538 port_legal_c.disconnect ();
1540 ret = create_ports (*pending_state_node);
1542 if (connecting_legal) {
1543 delete pending_state_node;
1544 pending_state_node = 0;
1551 IO::create_ports (const XMLNode& node)
1553 const XMLProperty* prop;
1555 int num_outputs = 0;
1557 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1558 * break the session file format.
1560 if ((prop = node.property ("input-connection")) != 0) {
1562 Bundle* c = _session.bundle_by_name (prop->value());
1565 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1567 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1568 error << _("No input bundles available as a replacement")
1572 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1577 num_inputs = c->nchannels();
1579 } else if ((prop = node.property ("inputs")) != 0) {
1581 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1584 if ((prop = node.property ("output-connection")) != 0) {
1585 Bundle* c = _session.bundle_by_name (prop->value());
1588 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1590 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1591 error << _("No output bundles available as a replacement")
1595 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1600 num_outputs = c->nchannels ();
1602 } else if ((prop = node.property ("outputs")) != 0) {
1603 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1606 no_panner_reset = true;
1608 // FIXME: audio-only
1609 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1610 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1614 no_panner_reset = false;
1616 set_deferred_state ();
1624 IO::make_connections (const XMLNode& node)
1626 const XMLProperty* prop;
1628 if ((prop = node.property ("input-connection")) != 0) {
1629 Bundle* c = _session.bundle_by_name (prop->value());
1632 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1634 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1635 error << _("No input connections available as a replacement")
1639 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1644 use_input_bundle (*c, this);
1646 } else if ((prop = node.property ("inputs")) != 0) {
1647 if (set_inputs (prop->value())) {
1648 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1653 if ((prop = node.property ("output-bundle")) != 0) {
1654 Bundle* c = _session.bundle_by_name (prop->value());
1657 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1659 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1660 error << _("No output bundles available as a replacement")
1664 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1669 use_output_bundle (*c, this);
1671 } else if ((prop = node.property ("outputs")) != 0) {
1672 if (set_outputs (prop->value())) {
1673 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1682 IO::set_inputs (const string& str)
1684 vector<string> ports;
1689 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1693 // FIXME: audio-only
1694 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1698 string::size_type start, end, ostart;
1705 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1708 if ((end = str.find_first_of ('}', start)) == string::npos) {
1709 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1713 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1714 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1720 for (int x = 0; x < n; ++x) {
1721 connect_input (input (i), ports[x], this);
1733 IO::set_outputs (const string& str)
1735 vector<string> ports;
1740 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1744 // FIXME: audio-only
1745 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1749 string::size_type start, end, ostart;
1756 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1759 if ((end = str.find_first_of ('}', start)) == string::npos) {
1760 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1764 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1765 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1771 for (int x = 0; x < n; ++x) {
1772 connect_output (output (i), ports[x], this);
1784 IO::parse_io_string (const string& str, vector<string>& ports)
1786 string::size_type pos, opos;
1788 if (str.length() == 0) {
1797 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1798 ports.push_back (str.substr (opos, pos - opos));
1802 if (opos < str.length()) {
1803 ports.push_back (str.substr(opos));
1806 return ports.size();
1810 IO::parse_gain_string (const string& str, vector<string>& ports)
1812 string::size_type pos, opos;
1818 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1819 ports.push_back (str.substr (opos, pos - opos));
1823 if (opos < str.length()) {
1824 ports.push_back (str.substr(opos));
1827 return ports.size();
1831 IO::set_name (string name, void* src)
1833 if (name == _name) {
1837 /* replace all colons in the name. i wish we didn't have to do this */
1839 if (replace_all (name, ":", "-")) {
1840 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1843 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1844 string current_name = i->short_name();
1845 current_name.replace (current_name.find (_name), _name.length(), name);
1846 i->set_name (current_name);
1849 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1850 string current_name = i->short_name();
1851 current_name.replace (current_name.find (_name), _name.length(), name);
1852 i->set_name (current_name);
1856 name_changed (src); /* EMIT SIGNAL */
1862 IO::set_input_minimum (ChanCount n)
1868 IO::set_input_maximum (ChanCount n)
1874 IO::set_output_minimum (ChanCount n)
1876 _output_minimum = n;
1880 IO::set_output_maximum (ChanCount n)
1882 _output_maximum = n;
1886 IO::set_port_latency (nframes_t nframes)
1888 Glib::Mutex::Lock lm (io_lock);
1890 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1891 i->set_latency (nframes);
1896 IO::output_latency () const
1898 nframes_t max_latency;
1903 /* io lock not taken - must be protected by other means */
1905 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1906 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1907 max_latency = latency;
1915 IO::input_latency () const
1917 nframes_t max_latency;
1922 /* io lock not taken - must be protected by other means */
1924 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1925 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1926 max_latency = latency;
1934 IO::use_input_bundle (Bundle& c, void* src)
1939 BLOCK_PROCESS_CALLBACK ();
1940 Glib::Mutex::Lock lm2 (io_lock);
1942 limit = c.nchannels();
1944 drop_input_bundle ();
1946 // FIXME bundles only work for audio-only
1947 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1951 /* first pass: check the current state to see what's correctly
1952 connected, and drop anything that we don't want.
1955 for (uint32_t n = 0; n < limit; ++n) {
1956 const Bundle::PortList& pl = c.channel_ports (n);
1958 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1960 if (!_inputs.port(n)->connected_to ((*i))) {
1962 /* clear any existing connections */
1964 _session.engine().disconnect (*_inputs.port(n));
1966 } else if (_inputs.port(n)->connected() > 1) {
1968 /* OK, it is connected to the port we want,
1969 but its also connected to other ports.
1970 Change that situation.
1973 /* XXX could be optimized to not drop
1977 _session.engine().disconnect (*_inputs.port(n));
1983 /* second pass: connect all requested ports where necessary */
1985 for (uint32_t n = 0; n < limit; ++n) {
1986 const Bundle::PortList& pl = c.channel_ports (n);
1988 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1990 if (!_inputs.port(n)->connected_to ((*i))) {
1992 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2002 input_bundle_configuration_connection = c.ConfigurationChanged.connect
2003 (mem_fun (*this, &IO::input_bundle_configuration_changed));
2004 input_bundle_connection_connection = c.PortsChanged.connect
2005 (mem_fun (*this, &IO::input_bundle_connection_changed));
2008 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2013 IO::use_output_bundle (Bundle& c, void* src)
2018 BLOCK_PROCESS_CALLBACK ();
2019 Glib::Mutex::Lock lm2 (io_lock);
2021 limit = c.nchannels();
2023 drop_output_bundle ();
2025 // FIXME: audio-only
2026 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2030 /* first pass: check the current state to see what's correctly
2031 connected, and drop anything that we don't want.
2034 for (uint32_t n = 0; n < limit; ++n) {
2036 const Bundle::PortList& pl = c.channel_ports (n);
2038 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2040 if (!_outputs.port(n)->connected_to ((*i))) {
2042 /* clear any existing connections */
2044 _session.engine().disconnect (*_outputs.port(n));
2046 } else if (_outputs.port(n)->connected() > 1) {
2048 /* OK, it is connected to the port we want,
2049 but its also connected to other ports.
2050 Change that situation.
2053 /* XXX could be optimized to not drop
2057 _session.engine().disconnect (*_outputs.port(n));
2062 /* second pass: connect all requested ports where necessary */
2064 for (uint32_t n = 0; n < limit; ++n) {
2066 const Bundle::PortList& pl = c.channel_ports (n);
2068 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2070 if (!_outputs.port(n)->connected_to ((*i))) {
2072 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2079 _output_bundle = &c;
2081 output_bundle_configuration_connection = c.ConfigurationChanged.connect
2082 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2083 output_bundle_connection_connection = c.PortsChanged.connect
2084 (mem_fun (*this, &IO::output_bundle_connection_changed));
2087 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2093 IO::disable_connecting ()
2095 connecting_legal = false;
2100 IO::enable_connecting ()
2102 connecting_legal = true;
2103 return ConnectingLegal ();
2107 IO::disable_ports ()
2109 ports_legal = false;
2117 return PortsLegal ();
2121 IO::disable_panners (void)
2123 panners_legal = false;
2128 IO::reset_panners ()
2130 panners_legal = true;
2131 return PannersLegal ();
2135 IO::input_bundle_connection_changed (int ignored)
2137 use_input_bundle (*_input_bundle, this);
2141 IO::input_bundle_configuration_changed ()
2143 use_input_bundle (*_input_bundle, this);
2147 IO::output_bundle_connection_changed (int ignored)
2149 use_output_bundle (*_output_bundle, this);
2153 IO::output_bundle_configuration_changed ()
2155 use_output_bundle (*_output_bundle, this);
2159 IO::GainControllable::set_value (float val)
2161 io.set_gain (direct_control_to_gain (val), this);
2165 IO::GainControllable::get_value (void) const
2167 return direct_gain_to_control (io.effective_gain());
2171 IO::setup_peak_meters()
2173 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2177 Update the peak meters.
2179 The meter signal lock is taken to prevent modification of the
2180 Meter signal while updating the meters, taking the meter signal
2181 lock prior to taking the io_lock ensures that all IO will remain
2182 valid while metering.
2187 Glib::Mutex::Lock guard (m_meter_signal_lock);
2189 Meter(); /* EMIT SIGNAL */
2195 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2197 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2202 IO::clear_automation ()
2204 Glib::Mutex::Lock lm (automation_lock);
2205 _gain_automation_curve.clear ();
2206 _panner->clear_automation ();
2210 IO::set_gain_automation_state (AutoState state)
2212 bool changed = false;
2215 Glib::Mutex::Lock lm (automation_lock);
2217 if (state != _gain_automation_curve.automation_state()) {
2219 last_automation_snapshot = 0;
2220 _gain_automation_curve.set_automation_state (state);
2223 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2229 _session.set_dirty ();
2230 gain_automation_state_changed (); /* EMIT SIGNAL */
2235 IO::set_gain_automation_style (AutoStyle style)
2237 bool changed = false;
2240 Glib::Mutex::Lock lm (automation_lock);
2242 if (style != _gain_automation_curve.automation_style()) {
2244 _gain_automation_curve.set_automation_style (style);
2249 gain_automation_style_changed (); /* EMIT SIGNAL */
2253 IO::inc_gain (gain_t factor, void *src)
2255 if (_desired_gain == 0.0f)
2256 set_gain (0.000001f + (0.000001f * factor), src);
2258 set_gain (_desired_gain + (_desired_gain * factor), src);
2262 IO::set_gain (gain_t val, void *src)
2264 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2265 if (val>1.99526231f) val=1.99526231f;
2268 Glib::Mutex::Lock dm (declick_lock);
2269 _desired_gain = val;
2272 if (_session.transport_stopped()) {
2273 _effective_gain = val;
2278 _gain_control.Changed (); /* EMIT SIGNAL */
2280 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2281 _gain_automation_curve.add (_session.transport_frame(), val);
2285 _session.set_dirty();
2289 IO::start_gain_touch ()
2291 _gain_automation_curve.start_touch ();
2295 IO::end_gain_touch ()
2297 _gain_automation_curve.stop_touch ();
2301 IO::start_pan_touch (uint32_t which)
2303 if (which < _panner->size()) {
2304 (*_panner)[which]->automation().start_touch();
2309 IO::end_pan_touch (uint32_t which)
2311 if (which < _panner->size()) {
2312 (*_panner)[which]->automation().stop_touch();
2318 IO::automation_snapshot (nframes_t now)
2320 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2322 if (gain_automation_recording()) {
2323 _gain_automation_curve.rt_add (now, gain());
2326 _panner->snapshot (now);
2328 last_automation_snapshot = now;
2333 IO::transport_stopped (nframes_t frame)
2335 _gain_automation_curve.reposition_for_rt_add (frame);
2337 if (_gain_automation_curve.automation_state() != Off) {
2339 /* the src=0 condition is a special signal to not propagate
2340 automation gain changes into the mix group when locating.
2343 set_gain (_gain_automation_curve.eval (frame), 0);
2346 _panner->transport_stopped (frame);
2350 IO::find_input_port_hole ()
2352 /* CALLER MUST HOLD IO LOCK */
2356 if (_inputs.empty()) {
2360 for (n = 1; n < UINT_MAX; ++n) {
2361 char buf[jack_port_name_size()];
2362 PortSet::iterator i = _inputs.begin();
2364 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2366 for ( ; i != _inputs.end(); ++i) {
2367 if (i->short_name() == buf) {
2372 if (i == _inputs.end()) {
2380 IO::find_output_port_hole ()
2382 /* CALLER MUST HOLD IO LOCK */
2386 if (_outputs.empty()) {
2390 for (n = 1; n < UINT_MAX; ++n) {
2391 char buf[jack_port_name_size()];
2392 PortSet::iterator i = _outputs.begin();
2394 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2396 for ( ; i != _outputs.end(); ++i) {
2397 if (i->short_name() == buf) {
2402 if (i == _outputs.end()) {
2411 IO::audio_input(uint32_t n) const
2413 return dynamic_cast<AudioPort*>(input(n));
2417 IO::audio_output(uint32_t n) const
2419 return dynamic_cast<AudioPort*>(output(n));
2423 IO::midi_input(uint32_t n) const
2425 return dynamic_cast<MidiPort*>(input(n));
2429 IO::midi_output(uint32_t n) const
2431 return dynamic_cast<MidiPort*>(output(n));
2435 IO::set_phase_invert (bool yn, void *src)
2437 if (_phase_invert != yn) {
2439 // phase_invert_changed (src); /* EMIT SIGNAL */
2444 IO::set_denormal_protection (bool yn, void *src)
2446 if (_denormal_protection != yn) {
2447 _denormal_protection = yn;
2448 // denormal_protection_changed (src); /* EMIT SIGNAL */