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()
167 _meter = new PeakMeter (_session);
171 no_panner_reset = false;
177 apply_gain_automation = false;
182 // IO::Meter is emitted from another thread so the
183 // Meter signal must be protected.
184 Glib::Mutex::Lock guard (m_meter_signal_lock);
185 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
188 // Connect to our own MoreChannels signal to connect output buffers
189 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
191 _session.add_controllable (&_gain_control);
196 Glib::Mutex::Lock guard (m_meter_signal_lock);
198 Glib::Mutex::Lock lm (io_lock);
200 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
201 _session.engine().unregister_port (*i);
204 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
205 _session.engine().unregister_port (*i);
208 m_meter_connection.disconnect();
212 delete _output_buffers;
216 IO::silence (nframes_t nframes, nframes_t offset)
218 /* io_lock, not taken: function must be called from Session::process() calltree */
220 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
221 i->get_buffer().silence (nframes, offset);
225 /** Deliver bufs to the IO's Jack outputs.
227 * This function should automatically do whatever it necessary to correctly deliver bufs
228 * to the outputs, eg applying gain or pan or whatever else needs to be done.
231 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
233 // FIXME: type specific code doesn't actually need to be here, it will go away in time
235 /* ********** AUDIO ********** */
237 // Apply gain if gain automation isn't playing
238 if ( ! apply_gain_automation) {
240 gain_t dg = _gain; // desired gain
243 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
251 if (dg != _gain || dg != 1.0)
252 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
255 // Use the panner to distribute audio to output port buffers
256 if (_panner && !_panner->empty() && !_panner->bypassed()) {
257 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
259 const DataType type = DataType::AUDIO;
261 // Copy any audio 1:1 to outputs
263 BufferSet::iterator o = output_buffers().begin(type);
264 BufferSet::iterator i = bufs.begin(type);
265 BufferSet::iterator prev = i;
267 while (i != bufs.end(type) && o != output_buffers().end (type)) {
268 o->read_from(*i, nframes, offset);
274 /* extra outputs get a copy of the last buffer */
276 while (o != output_buffers().end(type)) {
277 o->read_from(*prev, nframes, offset);
282 /* ********** MIDI ********** */
284 // No MIDI, we're done here
285 if (bufs.count().n_midi() == 0) {
289 const DataType type = DataType::MIDI;
291 // Copy any MIDI 1:1 to outputs
292 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
293 BufferSet::iterator o = output_buffers().begin(type);
294 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
295 o->read_from(*i, nframes, offset);
300 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
302 assert(outs.available() >= n_inputs());
304 outs.set_count(n_inputs());
306 if (outs.count() == ChanCount::ZERO)
309 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
311 BufferSet::iterator o = outs.begin(*t);
312 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
313 o->read_from(i->get_buffer(), nframes, offset);
320 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
321 nframes_t nframes, nframes_t offset)
323 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
325 collect_input (bufs, nframes, offset);
327 _meter->run(bufs, nframes);
331 IO::drop_input_bundle ()
334 input_bundle_configuration_connection.disconnect();
335 input_bundle_connection_connection.disconnect();
336 _session.set_dirty ();
340 IO::drop_output_bundle ()
343 output_bundle_configuration_connection.disconnect();
344 output_bundle_connection_connection.disconnect();
345 _session.set_dirty ();
349 IO::disconnect_input (Port* our_port, string other_port, void* src)
351 if (other_port.length() == 0 || our_port == 0) {
356 BLOCK_PROCESS_CALLBACK ();
359 Glib::Mutex::Lock lm (io_lock);
361 /* check that our_port is really one of ours */
363 if ( ! _inputs.contains(our_port)) {
367 /* disconnect it from the source */
369 if (_session.engine().disconnect (other_port, our_port->name())) {
370 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
374 drop_input_bundle ();
378 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
379 _session.set_dirty ();
385 IO::connect_input (Port* our_port, string other_port, void* src)
387 if (other_port.length() == 0 || our_port == 0) {
392 BLOCK_PROCESS_CALLBACK ();
395 Glib::Mutex::Lock lm (io_lock);
397 /* check that our_port is really one of ours */
399 if ( ! _inputs.contains(our_port) ) {
403 /* connect it to the source */
405 if (_session.engine().connect (other_port, our_port->name())) {
409 drop_input_bundle ();
413 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
414 _session.set_dirty ();
419 IO::disconnect_output (Port* our_port, string other_port, void* src)
421 if (other_port.length() == 0 || our_port == 0) {
426 BLOCK_PROCESS_CALLBACK ();
429 Glib::Mutex::Lock lm (io_lock);
431 /* check that our_port is really one of ours */
433 if ( ! _outputs.contains(our_port) ) {
437 /* disconnect it from the destination */
439 if (_session.engine().disconnect (our_port->name(), other_port)) {
440 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
444 drop_output_bundle ();
448 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
449 _session.set_dirty ();
454 IO::connect_output (Port* our_port, string other_port, void* src)
456 if (other_port.length() == 0 || our_port == 0) {
461 BLOCK_PROCESS_CALLBACK ();
465 Glib::Mutex::Lock lm (io_lock);
467 /* check that our_port is really one of ours */
469 if ( ! _outputs.contains(our_port) ) {
473 /* connect it to the destination */
475 if (_session.engine().connect (our_port->name(), other_port)) {
479 drop_output_bundle ();
483 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
484 _session.set_dirty ();
489 IO::set_input (Port* other_port, void* src)
491 /* this removes all but one ports, and connects that one port
492 to the specified source.
495 if (_input_minimum.n_total() > 1) {
496 /* sorry, you can't do this */
500 if (other_port == 0) {
501 if (_input_minimum == ChanCount::ZERO) {
502 return ensure_inputs (ChanCount::ZERO, false, true, src);
508 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
512 return connect_input (_inputs.port(0), other_port->name(), src);
516 IO::remove_output_port (Port* port, void* src)
518 IOChange change (NoChange);
521 BLOCK_PROCESS_CALLBACK ();
525 Glib::Mutex::Lock lm (io_lock);
527 if (n_outputs() <= _output_minimum) {
528 /* sorry, you can't do this */
532 if (_outputs.remove(port)) {
533 change = IOChange (change|ConfigurationChanged);
535 if (port->connected()) {
536 change = IOChange (change|ConnectionsChanged);
539 _session.engine().unregister_port (*port);
540 drop_output_bundle ();
542 setup_peak_meters ();
548 if (change != NoChange) {
549 output_changed (change, src);
550 _session.set_dirty ();
557 /** Add an output port.
559 * @param destination Name of input port to connect new port to.
560 * @param src Source for emitted ConfigurationChanged signal.
561 * @param type Data type of port. Default value (NIL) will use this IO's default type.
564 IO::add_output_port (string destination, void* src, DataType type)
569 if (type == DataType::NIL)
570 type = _default_type;
573 BLOCK_PROCESS_CALLBACK ();
577 Glib::Mutex::Lock lm (io_lock);
579 if (n_outputs() >= _output_maximum) {
583 /* Create a new output port */
585 // FIXME: naming scheme for differently typed ports?
586 if (_output_maximum.get(type) == 1) {
587 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
589 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
592 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
593 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
597 _outputs.add (our_port);
598 drop_output_bundle ();
599 setup_peak_meters ();
603 MoreChannels (n_outputs()); /* EMIT SIGNAL */
606 if (destination.length()) {
607 if (_session.engine().connect (our_port->name(), destination)) {
612 // pan_changed (src); /* EMIT SIGNAL */
613 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
614 _session.set_dirty ();
620 IO::remove_input_port (Port* port, void* src)
622 IOChange change (NoChange);
625 BLOCK_PROCESS_CALLBACK ();
629 Glib::Mutex::Lock lm (io_lock);
631 if (n_inputs() <= _input_minimum) {
632 /* sorry, you can't do this */
636 if (_inputs.remove(port)) {
637 change = IOChange (change|ConfigurationChanged);
639 if (port->connected()) {
640 change = IOChange (change|ConnectionsChanged);
643 _session.engine().unregister_port (*port);
644 drop_input_bundle ();
646 setup_peak_meters ();
652 if (change != NoChange) {
653 input_changed (change, src);
654 _session.set_dirty ();
662 /** Add an input port.
664 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
665 * @param destination Name of input port to connect new port to.
666 * @param src Source for emitted ConfigurationChanged signal.
669 IO::add_input_port (string source, void* src, DataType type)
674 if (type == DataType::NIL)
675 type = _default_type;
678 BLOCK_PROCESS_CALLBACK ();
681 Glib::Mutex::Lock lm (io_lock);
683 if (n_inputs() >= _input_maximum) {
687 /* Create a new input port */
689 // FIXME: naming scheme for differently typed ports?
690 if (_input_maximum.get(type) == 1) {
691 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
693 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
696 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
697 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
701 _inputs.add (our_port);
702 drop_input_bundle ();
703 setup_peak_meters ();
707 MoreChannels (n_inputs()); /* EMIT SIGNAL */
710 if (source.length()) {
712 if (_session.engine().connect (source, our_port->name())) {
717 // pan_changed (src); /* EMIT SIGNAL */
718 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
719 _session.set_dirty ();
725 IO::disconnect_inputs (void* src)
728 BLOCK_PROCESS_CALLBACK ();
731 Glib::Mutex::Lock lm (io_lock);
733 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
734 _session.engine().disconnect (*i);
737 drop_input_bundle ();
741 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
747 IO::disconnect_outputs (void* src)
750 BLOCK_PROCESS_CALLBACK ();
753 Glib::Mutex::Lock lm (io_lock);
755 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
756 _session.engine().disconnect (*i);
759 drop_output_bundle ();
763 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
764 _session.set_dirty ();
770 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
772 Port* input_port = 0;
773 bool changed = false;
776 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
778 const size_t n = count.get(*t);
780 /* remove unused ports */
781 for (size_t i = n_inputs().get(*t); i > n; --i) {
782 input_port = _inputs.port(*t, i-1);
785 _inputs.remove(input_port);
786 _session.engine().unregister_port (*input_port);
791 /* create any necessary new ports */
792 while (n_inputs().get(*t) < n) {
796 if (_input_maximum.get(*t) == 1) {
797 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
799 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
804 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
805 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
810 catch (AudioEngine::PortRegistrationFailure& err) {
811 setup_peak_meters ();
814 throw AudioEngine::PortRegistrationFailure();
817 _inputs.add (input_port);
823 drop_input_bundle ();
824 setup_peak_meters ();
826 MoreChannels (n_inputs()); /* EMIT SIGNAL */
827 _session.set_dirty ();
831 /* disconnect all existing ports so that we get a fresh start */
832 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
833 _session.engine().disconnect (*i);
840 /** Attach output_buffers to port buffers.
842 * Connected to IO's own MoreChannels signal.
845 IO::attach_buffers(ChanCount ignored)
847 _output_buffers->attach_buffers(_outputs);
851 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
853 bool in_changed = false;
854 bool out_changed = false;
855 bool need_pan_reset = false;
857 in = min (_input_maximum, in);
859 out = min (_output_maximum, out);
861 if (in == n_inputs() && out == n_outputs() && !clear) {
866 BLOCK_PROCESS_CALLBACK ();
867 Glib::Mutex::Lock lm (io_lock);
871 if (n_outputs() != out) {
872 need_pan_reset = true;
875 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
877 const size_t nin = in.get(*t);
878 const size_t nout = out.get(*t);
880 Port* output_port = 0;
881 Port* input_port = 0;
883 /* remove unused output ports */
884 for (size_t i = n_outputs().get(*t); i > nout; --i) {
885 output_port = _outputs.port(*t, i-1);
888 _outputs.remove(output_port);
889 _session.engine().unregister_port (*output_port);
894 /* remove unused input ports */
895 for (size_t i = n_inputs().get(*t); i > nin; --i) {
896 input_port = _inputs.port(*t, i-1);
899 _inputs.remove(input_port);
900 _session.engine().unregister_port (*input_port);
905 /* create any necessary new input ports */
907 while (n_inputs().get(*t) < nin) {
911 /* Create a new input port */
913 if (_input_maximum.get(*t) == 1) {
914 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
916 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
920 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
921 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
926 catch (AudioEngine::PortRegistrationFailure& err) {
927 setup_peak_meters ();
930 throw AudioEngine::PortRegistrationFailure();
937 /* create any necessary new output ports */
939 while (n_outputs().get(*t) < nout) {
943 /* Create a new output port */
945 if (_output_maximum.get(*t) == 1) {
946 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
948 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
952 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
953 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
958 catch (AudioEngine::PortRegistrationFailure& err) {
959 setup_peak_meters ();
962 throw AudioEngine::PortRegistrationFailure ();
972 /* disconnect all existing ports so that we get a fresh start */
974 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
975 _session.engine().disconnect (*i);
978 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
979 _session.engine().disconnect (*i);
983 if (in_changed || out_changed) {
984 setup_peak_meters ();
990 drop_output_bundle ();
991 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
995 drop_input_bundle ();
996 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
999 if (in_changed || out_changed) {
1000 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1001 _session.set_dirty ();
1008 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1010 bool changed = false;
1012 count = min (_input_maximum, count);
1014 if (count == n_inputs() && !clear) {
1019 BLOCK_PROCESS_CALLBACK ();
1020 Glib::Mutex::Lock im (io_lock);
1021 changed = ensure_inputs_locked (count, clear, src);
1023 changed = ensure_inputs_locked (count, clear, src);
1027 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1028 _session.set_dirty ();
1034 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1036 Port* output_port = 0;
1037 bool changed = false;
1038 bool need_pan_reset = false;
1040 if (n_outputs() != count) {
1041 need_pan_reset = true;
1044 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1046 const size_t n = count.get(*t);
1048 /* remove unused ports */
1049 for (size_t i = n_outputs().get(*t); i > n; --i) {
1050 output_port = _outputs.port(*t, i-1);
1052 assert(output_port);
1053 _outputs.remove(output_port);
1054 _session.engine().unregister_port (*output_port);
1059 /* create any necessary new ports */
1060 while (n_outputs().get(*t) < n) {
1064 if (_output_maximum.get(*t) == 1) {
1065 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1067 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1070 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1071 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1075 _outputs.add (output_port);
1077 setup_peak_meters ();
1079 if (need_pan_reset) {
1086 drop_output_bundle ();
1087 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1088 _session.set_dirty ();
1092 /* disconnect all existing ports so that we get a fresh start */
1093 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1094 _session.engine().disconnect (*i);
1102 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1104 bool changed = false;
1106 if (_output_maximum < ChanCount::INFINITE) {
1107 count = min (_output_maximum, count);
1108 if (count == n_outputs() && !clear) {
1113 /* XXX caller should hold io_lock, but generally doesn't */
1116 BLOCK_PROCESS_CALLBACK ();
1117 Glib::Mutex::Lock im (io_lock);
1118 changed = ensure_outputs_locked (count, clear, src);
1120 changed = ensure_outputs_locked (count, clear, src);
1124 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1131 IO::effective_gain () const
1133 if (gain_automation_playback()) {
1134 return _effective_gain;
1136 return _desired_gain;
1143 if (panners_legal) {
1144 if (!no_panner_reset) {
1145 _panner->reset (n_outputs().n_audio(), pans_required());
1148 panner_legal_c.disconnect ();
1149 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1154 IO::panners_became_legal ()
1156 _panner->reset (n_outputs().n_audio(), pans_required());
1157 _panner->load (); // automation
1158 panner_legal_c.disconnect ();
1163 IO::defer_pan_reset ()
1165 no_panner_reset = true;
1169 IO::allow_pan_reset ()
1171 no_panner_reset = false;
1177 IO::get_state (void)
1179 return state (true);
1183 IO::state (bool full_state)
1185 XMLNode* node = new XMLNode (state_node_name);
1188 bool need_ins = true;
1189 bool need_outs = true;
1190 LocaleGuard lg (X_("POSIX"));
1191 Glib::Mutex::Lock lm (io_lock);
1193 node->add_property("name", _name);
1194 id().print (buf, sizeof (buf));
1195 node->add_property("id", buf);
1199 if (_input_bundle) {
1200 node->add_property ("input-connection", _input_bundle->name());
1204 if (_output_bundle) {
1205 node->add_property ("output-connection", _output_bundle->name());
1210 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1212 const char **connections = i->get_connections();
1214 if (connections && connections[0]) {
1217 for (int n = 0; connections && connections[n]; ++n) {
1222 /* if its a connection to our own port,
1223 return only the port name, not the
1224 whole thing. this allows connections
1225 to be re-established even when our
1226 client name is different.
1229 str += _session.engine().make_port_name_relative (connections[n]);
1241 node->add_property ("inputs", str);
1247 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1249 const char **connections = i->get_connections();
1251 if (connections && connections[0]) {
1255 for (int n = 0; connections[n]; ++n) {
1260 str += _session.engine().make_port_name_relative (connections[n]);
1272 node->add_property ("outputs", str);
1275 node->add_child_nocopy (_panner->state (full_state));
1276 node->add_child_nocopy (_gain_control.get_state ());
1278 snprintf (buf, sizeof(buf), "%2.12f", gain());
1279 node->add_property ("gain", buf);
1281 // FIXME: this is NOT sufficient!
1282 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1283 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1284 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1285 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1287 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1289 node->add_property ("iolimits", buf);
1295 XMLNode* autonode = new XMLNode (X_("Automation"));
1296 autonode->add_child_nocopy (get_automation_state());
1297 node->add_child_nocopy (*autonode);
1299 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1301 /* never store anything except Off for automation state in a template */
1302 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1309 IO::set_state (const XMLNode& node)
1311 const XMLProperty* prop;
1312 XMLNodeConstIterator iter;
1313 LocaleGuard lg (X_("POSIX"));
1315 /* force use of non-localized representation of decimal point,
1316 since we use it a lot in XML files and so forth.
1319 if (node.name() != state_node_name) {
1320 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1324 if ((prop = node.property ("name")) != 0) {
1325 _name = prop->value();
1326 /* used to set panner name with this, but no more */
1329 if ((prop = node.property ("id")) != 0) {
1330 _id = prop->value ();
1335 size_t out_min = -1;
1336 size_t out_max = -1;
1338 if ((prop = node.property ("iolimits")) != 0) {
1339 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1340 &in_min, &in_max, &out_min, &out_max);
1341 _input_minimum = ChanCount(_default_type, in_min);
1342 _input_maximum = ChanCount(_default_type, in_max);
1343 _output_minimum = ChanCount(_default_type, out_min);
1344 _output_maximum = ChanCount(_default_type, out_max);
1347 if ((prop = node.property ("gain")) != 0) {
1348 set_gain (atof (prop->value().c_str()), this);
1349 _gain = _desired_gain;
1352 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1353 /* old school automation handling */
1356 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1358 if ((*iter)->name() == "Panner") {
1360 _panner = new Panner (_name, _session);
1362 _panner->set_state (**iter);
1365 if ((*iter)->name() == X_("Automation")) {
1367 set_automation_state (*(*iter)->children().front());
1370 if ((*iter)->name() == X_("controllable")) {
1371 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1372 _gain_control.set_state (**iter);
1379 if (create_ports (node)) {
1385 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1388 if (panners_legal) {
1391 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1394 if (connecting_legal) {
1396 if (make_connections (node)) {
1402 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1405 if (!ports_legal || !connecting_legal) {
1406 pending_state_node = new XMLNode (node);
1409 last_automation_snapshot = 0;
1415 IO::set_automation_state (const XMLNode& node)
1417 return _gain_automation_curve.set_state (node);
1421 IO::get_automation_state ()
1423 return (_gain_automation_curve.get_state ());
1427 IO::load_automation (string path)
1432 uint32_t linecnt = 0;
1434 LocaleGuard lg (X_("POSIX"));
1436 fullpath = _session.automation_dir();
1439 in.open (fullpath.c_str());
1442 fullpath = _session.automation_dir();
1443 fullpath += _session.snap_name();
1447 in.open (fullpath.c_str());
1450 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1455 clear_automation ();
1457 while (in.getline (line, sizeof(line), '\n')) {
1462 if (++linecnt == 1) {
1463 if (memcmp (line, "version", 7) == 0) {
1464 if (sscanf (line, "version %f", &version) != 1) {
1465 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1469 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1476 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1477 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1483 _gain_automation_curve.fast_simple_add (when, value);
1493 /* older (pre-1.0) versions of ardour used this */
1497 warning << _("dubious automation event found (and ignored)") << endmsg;
1505 IO::connecting_became_legal ()
1509 if (pending_state_node == 0) {
1510 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1515 connection_legal_c.disconnect ();
1517 ret = make_connections (*pending_state_node);
1520 delete pending_state_node;
1521 pending_state_node = 0;
1527 IO::ports_became_legal ()
1531 if (pending_state_node == 0) {
1532 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1537 port_legal_c.disconnect ();
1539 ret = create_ports (*pending_state_node);
1541 if (connecting_legal) {
1542 delete pending_state_node;
1543 pending_state_node = 0;
1550 IO::create_ports (const XMLNode& node)
1552 const XMLProperty* prop;
1554 int num_outputs = 0;
1556 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1557 * break the session file format.
1559 if ((prop = node.property ("input-connection")) != 0) {
1561 Bundle* c = _session.bundle_by_name (prop->value());
1564 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1566 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1567 error << _("No input bundles available as a replacement")
1571 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1576 num_inputs = c->nchannels();
1578 } else if ((prop = node.property ("inputs")) != 0) {
1580 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1583 if ((prop = node.property ("output-connection")) != 0) {
1584 Bundle* c = _session.bundle_by_name (prop->value());
1587 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1589 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1590 error << _("No output bundles available as a replacement")
1594 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1599 num_outputs = c->nchannels ();
1601 } else if ((prop = node.property ("outputs")) != 0) {
1602 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1605 no_panner_reset = true;
1607 // FIXME: audio-only
1608 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1609 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1613 no_panner_reset = false;
1615 set_deferred_state ();
1623 IO::make_connections (const XMLNode& node)
1625 const XMLProperty* prop;
1627 if ((prop = node.property ("input-connection")) != 0) {
1628 Bundle* c = _session.bundle_by_name (prop->value());
1631 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1633 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1634 error << _("No input connections available as a replacement")
1638 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1643 use_input_bundle (*c, this);
1645 } else if ((prop = node.property ("inputs")) != 0) {
1646 if (set_inputs (prop->value())) {
1647 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1652 if ((prop = node.property ("output-bundle")) != 0) {
1653 Bundle* c = _session.bundle_by_name (prop->value());
1656 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1658 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1659 error << _("No output bundles available as a replacement")
1663 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1668 use_output_bundle (*c, this);
1670 } else if ((prop = node.property ("outputs")) != 0) {
1671 if (set_outputs (prop->value())) {
1672 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1681 IO::set_inputs (const string& str)
1683 vector<string> ports;
1688 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1692 // FIXME: audio-only
1693 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1697 string::size_type start, end, ostart;
1704 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1707 if ((end = str.find_first_of ('}', start)) == string::npos) {
1708 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1712 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1713 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1719 for (int x = 0; x < n; ++x) {
1720 connect_input (input (i), ports[x], this);
1732 IO::set_outputs (const string& str)
1734 vector<string> ports;
1739 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1743 // FIXME: audio-only
1744 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1748 string::size_type start, end, ostart;
1755 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1758 if ((end = str.find_first_of ('}', start)) == string::npos) {
1759 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1763 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1764 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1770 for (int x = 0; x < n; ++x) {
1771 connect_output (output (i), ports[x], this);
1783 IO::parse_io_string (const string& str, vector<string>& ports)
1785 string::size_type pos, opos;
1787 if (str.length() == 0) {
1796 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1797 ports.push_back (str.substr (opos, pos - opos));
1801 if (opos < str.length()) {
1802 ports.push_back (str.substr(opos));
1805 return ports.size();
1809 IO::parse_gain_string (const string& str, vector<string>& ports)
1811 string::size_type pos, opos;
1817 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1818 ports.push_back (str.substr (opos, pos - opos));
1822 if (opos < str.length()) {
1823 ports.push_back (str.substr(opos));
1826 return ports.size();
1830 IO::set_name (string name, void* src)
1832 if (name == _name) {
1836 /* 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);
1855 name_changed (src); /* EMIT SIGNAL */
1861 IO::set_input_minimum (ChanCount n)
1867 IO::set_input_maximum (ChanCount n)
1873 IO::set_output_minimum (ChanCount n)
1875 _output_minimum = n;
1879 IO::set_output_maximum (ChanCount n)
1881 _output_maximum = n;
1885 IO::set_port_latency (nframes_t nframes)
1887 Glib::Mutex::Lock lm (io_lock);
1889 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1890 i->set_latency (nframes);
1895 IO::output_latency () const
1897 nframes_t max_latency;
1902 /* io lock not taken - must be protected by other means */
1904 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1905 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1906 max_latency = latency;
1914 IO::input_latency () const
1916 nframes_t max_latency;
1921 /* io lock not taken - must be protected by other means */
1923 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1924 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1925 max_latency = latency;
1933 IO::use_input_bundle (Bundle& c, void* src)
1938 BLOCK_PROCESS_CALLBACK ();
1939 Glib::Mutex::Lock lm2 (io_lock);
1941 limit = c.nchannels();
1943 drop_input_bundle ();
1945 // FIXME bundles only work for audio-only
1946 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1950 /* first pass: check the current state to see what's correctly
1951 connected, and drop anything that we don't want.
1954 for (uint32_t n = 0; n < limit; ++n) {
1955 const Bundle::PortList& pl = c.channel_ports (n);
1957 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1959 if (!_inputs.port(n)->connected_to ((*i))) {
1961 /* clear any existing connections */
1963 _session.engine().disconnect (*_inputs.port(n));
1965 } else if (_inputs.port(n)->connected() > 1) {
1967 /* OK, it is connected to the port we want,
1968 but its also connected to other ports.
1969 Change that situation.
1972 /* XXX could be optimized to not drop
1976 _session.engine().disconnect (*_inputs.port(n));
1982 /* second pass: connect all requested ports where necessary */
1984 for (uint32_t n = 0; n < limit; ++n) {
1985 const Bundle::PortList& pl = c.channel_ports (n);
1987 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1989 if (!_inputs.port(n)->connected_to ((*i))) {
1991 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2001 input_bundle_configuration_connection = c.ConfigurationChanged.connect
2002 (mem_fun (*this, &IO::input_bundle_configuration_changed));
2003 input_bundle_connection_connection = c.PortsChanged.connect
2004 (mem_fun (*this, &IO::input_bundle_connection_changed));
2007 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2012 IO::use_output_bundle (Bundle& c, void* src)
2017 BLOCK_PROCESS_CALLBACK ();
2018 Glib::Mutex::Lock lm2 (io_lock);
2020 limit = c.nchannels();
2022 drop_output_bundle ();
2024 // FIXME: audio-only
2025 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2029 /* first pass: check the current state to see what's correctly
2030 connected, and drop anything that we don't want.
2033 for (uint32_t n = 0; n < limit; ++n) {
2035 const Bundle::PortList& pl = c.channel_ports (n);
2037 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2039 if (!_outputs.port(n)->connected_to ((*i))) {
2041 /* clear any existing connections */
2043 _session.engine().disconnect (*_outputs.port(n));
2045 } else if (_outputs.port(n)->connected() > 1) {
2047 /* OK, it is connected to the port we want,
2048 but its also connected to other ports.
2049 Change that situation.
2052 /* XXX could be optimized to not drop
2056 _session.engine().disconnect (*_outputs.port(n));
2061 /* second pass: connect all requested ports where necessary */
2063 for (uint32_t n = 0; n < limit; ++n) {
2065 const Bundle::PortList& pl = c.channel_ports (n);
2067 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2069 if (!_outputs.port(n)->connected_to ((*i))) {
2071 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2078 _output_bundle = &c;
2080 output_bundle_configuration_connection = c.ConfigurationChanged.connect
2081 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2082 output_bundle_connection_connection = c.PortsChanged.connect
2083 (mem_fun (*this, &IO::output_bundle_connection_changed));
2086 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2092 IO::disable_connecting ()
2094 connecting_legal = false;
2099 IO::enable_connecting ()
2101 connecting_legal = true;
2102 return ConnectingLegal ();
2106 IO::disable_ports ()
2108 ports_legal = false;
2116 return PortsLegal ();
2120 IO::disable_panners (void)
2122 panners_legal = false;
2127 IO::reset_panners ()
2129 panners_legal = true;
2130 return PannersLegal ();
2134 IO::input_bundle_connection_changed (int ignored)
2136 use_input_bundle (*_input_bundle, this);
2140 IO::input_bundle_configuration_changed ()
2142 use_input_bundle (*_input_bundle, this);
2146 IO::output_bundle_connection_changed (int ignored)
2148 use_output_bundle (*_output_bundle, this);
2152 IO::output_bundle_configuration_changed ()
2154 use_output_bundle (*_output_bundle, this);
2158 IO::GainControllable::set_value (float val)
2160 io.set_gain (direct_control_to_gain (val), this);
2164 IO::GainControllable::get_value (void) const
2166 return direct_gain_to_control (io.effective_gain());
2170 IO::setup_peak_meters()
2172 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2176 Update the peak meters.
2178 The meter signal lock is taken to prevent modification of the
2179 Meter signal while updating the meters, taking the meter signal
2180 lock prior to taking the io_lock ensures that all IO will remain
2181 valid while metering.
2186 Glib::Mutex::Lock guard (m_meter_signal_lock);
2188 Meter(); /* EMIT SIGNAL */
2194 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2196 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2201 IO::clear_automation ()
2203 Glib::Mutex::Lock lm (automation_lock);
2204 _gain_automation_curve.clear ();
2205 _panner->clear_automation ();
2209 IO::set_gain_automation_state (AutoState state)
2211 bool changed = false;
2214 Glib::Mutex::Lock lm (automation_lock);
2216 if (state != _gain_automation_curve.automation_state()) {
2218 last_automation_snapshot = 0;
2219 _gain_automation_curve.set_automation_state (state);
2222 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2228 _session.set_dirty ();
2229 gain_automation_state_changed (); /* EMIT SIGNAL */
2234 IO::set_gain_automation_style (AutoStyle style)
2236 bool changed = false;
2239 Glib::Mutex::Lock lm (automation_lock);
2241 if (style != _gain_automation_curve.automation_style()) {
2243 _gain_automation_curve.set_automation_style (style);
2248 gain_automation_style_changed (); /* EMIT SIGNAL */
2252 IO::inc_gain (gain_t factor, void *src)
2254 if (_desired_gain == 0.0f)
2255 set_gain (0.000001f + (0.000001f * factor), src);
2257 set_gain (_desired_gain + (_desired_gain * factor), src);
2261 IO::set_gain (gain_t val, void *src)
2263 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2264 if (val>1.99526231f) val=1.99526231f;
2267 Glib::Mutex::Lock dm (declick_lock);
2268 _desired_gain = val;
2271 if (_session.transport_stopped()) {
2272 _effective_gain = val;
2277 _gain_control.Changed (); /* EMIT SIGNAL */
2279 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2280 _gain_automation_curve.add (_session.transport_frame(), val);
2284 _session.set_dirty();
2288 IO::start_gain_touch ()
2290 _gain_automation_curve.start_touch ();
2294 IO::end_gain_touch ()
2296 _gain_automation_curve.stop_touch ();
2300 IO::start_pan_touch (uint32_t which)
2302 if (which < _panner->size()) {
2303 (*_panner)[which]->automation().start_touch();
2308 IO::end_pan_touch (uint32_t which)
2310 if (which < _panner->size()) {
2311 (*_panner)[which]->automation().stop_touch();
2317 IO::automation_snapshot (nframes_t now)
2319 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2321 if (gain_automation_recording()) {
2322 _gain_automation_curve.rt_add (now, gain());
2325 _panner->snapshot (now);
2327 last_automation_snapshot = now;
2332 IO::transport_stopped (nframes_t frame)
2334 _gain_automation_curve.reposition_for_rt_add (frame);
2336 if (_gain_automation_curve.automation_state() != Off) {
2338 /* the src=0 condition is a special signal to not propagate
2339 automation gain changes into the mix group when locating.
2342 set_gain (_gain_automation_curve.eval (frame), 0);
2345 _panner->transport_stopped (frame);
2349 IO::find_input_port_hole ()
2351 /* CALLER MUST HOLD IO LOCK */
2355 if (_inputs.empty()) {
2359 for (n = 1; n < UINT_MAX; ++n) {
2360 char buf[jack_port_name_size()];
2361 PortSet::iterator i = _inputs.begin();
2363 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2365 for ( ; i != _inputs.end(); ++i) {
2366 if (i->short_name() == buf) {
2371 if (i == _inputs.end()) {
2379 IO::find_output_port_hole ()
2381 /* CALLER MUST HOLD IO LOCK */
2385 if (_outputs.empty()) {
2389 for (n = 1; n < UINT_MAX; ++n) {
2390 char buf[jack_port_name_size()];
2391 PortSet::iterator i = _outputs.begin();
2393 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2395 for ( ; i != _outputs.end(); ++i) {
2396 if (i->short_name() == buf) {
2401 if (i == _outputs.end()) {
2410 IO::audio_input(uint32_t n) const
2412 return dynamic_cast<AudioPort*>(input(n));
2416 IO::audio_output(uint32_t n) const
2418 return dynamic_cast<AudioPort*>(output(n));
2422 IO::midi_input(uint32_t n) const
2424 return dynamic_cast<MidiPort*>(input(n));
2428 IO::midi_output(uint32_t n) const
2430 return dynamic_cast<MidiPort*>(output(n));
2434 IO::set_phase_invert (bool yn, void *src)
2436 if (_phase_invert != yn) {
2438 // phase_invert_changed (src); /* EMIT SIGNAL */
2443 IO::set_denormal_protection (bool yn, void *src)
2445 if (_denormal_protection != yn) {
2446 _denormal_protection = yn;
2447 // denormal_protection_changed (src); /* EMIT SIGNAL */