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.
24 #include <sigc++/bind.h>
26 #include <glibmm/thread.h>
28 #include <pbd/xml++.h>
30 #include <ardour/audioengine.h>
31 #include <ardour/io.h>
32 #include <ardour/port.h>
33 #include <ardour/audio_port.h>
34 #include <ardour/midi_port.h>
35 #include <ardour/connection.h>
36 #include <ardour/session.h>
37 #include <ardour/cycle_timer.h>
38 #include <ardour/panner.h>
39 #include <ardour/buffer_set.h>
40 #include <ardour/meter.h>
41 #include <ardour/amp.h>
48 A bug in OS X's cmath that causes isnan() and isinf() to be
49 "undeclared". the following works around that
52 #if defined(__APPLE__) && defined(__MACH__)
53 extern "C" int isnan (double);
54 extern "C" int isinf (double);
59 using namespace ARDOUR;
63 static float current_automation_version_number = 1.0;
65 jack_nframes_t IO::_automation_interval = 0;
66 const string IO::state_node_name = "IO";
67 bool IO::connecting_legal = false;
68 bool IO::ports_legal = false;
69 bool IO::panners_legal = false;
70 sigc::signal<void> IO::Meter;
71 sigc::signal<int> IO::ConnectingLegal;
72 sigc::signal<int> IO::PortsLegal;
73 sigc::signal<int> IO::PannersLegal;
74 sigc::signal<void,ChanCount> IO::MoreChannels;
75 sigc::signal<int> IO::PortsCreated;
77 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
79 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
80 others can be imagined.
83 static gain_t direct_control_to_gain (double fract) {
84 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
85 /* this maxes at +6dB */
86 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
89 static double direct_gain_to_control (gain_t gain) {
90 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
91 if (gain == 0) return 0.0;
93 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
97 /** @param default_type The type of port that will be created by ensure_io
98 * and friends if no type is explicitly requested (to avoid breakage).
100 IO::IO (Session& s, string name,
101 int input_min, int input_max, int output_min, int output_max,
102 DataType default_type)
104 _output_buffers(new BufferSet()),
106 _default_type(default_type),
107 _gain_control (*this),
108 _gain_automation_curve (0.0, 2.0, 1.0),
109 _input_minimum (_default_type, input_min),
110 _input_maximum (_default_type, input_max),
111 _output_minimum (_default_type, output_min),
112 _output_maximum (_default_type, output_max)
114 _panner = new Panner (name, _session);
115 _meter = new PeakMeter (_session);
119 _input_connection = 0;
120 _output_connection = 0;
121 pending_state_node = 0;
122 no_panner_reset = false;
123 _phase_invert = false;
126 apply_gain_automation = false;
128 last_automation_snapshot = 0;
130 _gain_automation_state = Off;
131 _gain_automation_style = Absolute;
134 // IO::Meter is emitted from another thread so the
135 // Meter signal must be protected.
136 Glib::Mutex::Lock guard (m_meter_signal_lock);
137 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
140 // Connect to our own MoreChannels signal to connect output buffers
141 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
146 Glib::Mutex::Lock guard (m_meter_signal_lock);
148 Glib::Mutex::Lock lm (io_lock);
150 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
151 _session.engine().unregister_port (*i);
154 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
155 _session.engine().unregister_port (*i);
158 m_meter_connection.disconnect();
162 delete _output_buffers;
166 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
168 /* io_lock, not taken: function must be called from Session::process() calltree */
170 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
171 i->silence (nframes, offset);
175 /** Deliver bufs to the IO's Jack outputs.
177 * This function should automatically do whatever it necessary to correctly deliver bufs
178 * to the outputs, eg applying gain or pan or whatever else needs to be done.
181 IO::deliver_output (BufferSet& bufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset)
183 // FIXME: type specific code doesn't actually need to be here, it will go away in time
186 /* ********** AUDIO ********** */
188 // Apply gain if gain automation isn't playing
189 if ( ! apply_gain_automation) {
191 gain_t dg = _gain; // desired gain
194 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
201 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
204 // Use the panner to distribute audio to output port buffers
205 if (_panner && !_panner->empty() && !_panner->bypassed()) {
206 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
210 /* ********** MIDI ********** */
212 // No MIDI, we're done here
213 if (bufs.count().get(DataType::MIDI) == 0) {
217 const DataType type = DataType::MIDI;
219 // Just dump any MIDI 1-to-1, we're not at all clever with MIDI routing yet
220 BufferSet::iterator o = output_buffers().begin(type);
221 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
222 o->read_from(*i, nframes, offset);
227 IO::collect_input (BufferSet& outs, jack_nframes_t nframes, jack_nframes_t offset)
229 assert(outs.available() >= n_inputs());
231 outs.set_count(n_inputs());
233 if (outs.count() == ChanCount::ZERO)
236 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
238 BufferSet::iterator o = outs.begin(*t);
239 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
240 o->read_from(i->get_buffer(), nframes, offset);
247 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
248 jack_nframes_t nframes, jack_nframes_t offset)
250 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
252 collect_input (bufs, nframes, offset);
254 _meter->run(bufs, nframes);
258 IO::drop_input_connection ()
260 _input_connection = 0;
261 input_connection_configuration_connection.disconnect();
262 input_connection_connection_connection.disconnect();
263 _session.set_dirty ();
267 IO::drop_output_connection ()
269 _output_connection = 0;
270 output_connection_configuration_connection.disconnect();
271 output_connection_connection_connection.disconnect();
272 _session.set_dirty ();
276 IO::disconnect_input (Port* our_port, string other_port, void* src)
278 if (other_port.length() == 0 || our_port == 0) {
283 Glib::Mutex::Lock em (_session.engine().process_lock());
286 Glib::Mutex::Lock lm (io_lock);
288 /* check that our_port is really one of ours */
290 if ( ! _inputs.contains(our_port)) {
294 /* disconnect it from the source */
296 if (_session.engine().disconnect (other_port, our_port->name())) {
297 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
301 drop_input_connection();
305 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
306 _session.set_dirty ();
312 IO::connect_input (Port* our_port, string other_port, void* src)
314 if (other_port.length() == 0 || our_port == 0) {
319 Glib::Mutex::Lock em(_session.engine().process_lock());
322 Glib::Mutex::Lock lm (io_lock);
324 /* check that our_port is really one of ours */
326 if ( ! _inputs.contains(our_port) ) {
330 /* connect it to the source */
332 if (_session.engine().connect (other_port, our_port->name())) {
336 drop_input_connection ();
340 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
341 _session.set_dirty ();
346 IO::disconnect_output (Port* our_port, string other_port, void* src)
348 if (other_port.length() == 0 || our_port == 0) {
353 Glib::Mutex::Lock em(_session.engine().process_lock());
356 Glib::Mutex::Lock lm (io_lock);
358 /* check that our_port is really one of ours */
360 if ( ! _outputs.contains(our_port) ) {
364 /* disconnect it from the destination */
366 if (_session.engine().disconnect (our_port->name(), other_port)) {
367 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
371 drop_output_connection ();
375 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
376 _session.set_dirty ();
381 IO::connect_output (Port* our_port, string other_port, void* src)
383 if (other_port.length() == 0 || our_port == 0) {
388 Glib::Mutex::Lock em(_session.engine().process_lock());
391 Glib::Mutex::Lock lm (io_lock);
393 /* check that our_port is really one of ours */
395 if ( ! _outputs.contains(our_port) ) {
399 /* connect it to the destination */
401 if (_session.engine().connect (our_port->name(), other_port)) {
405 drop_output_connection ();
409 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
410 _session.set_dirty ();
415 IO::set_input (Port* other_port, void* src)
417 /* this removes all but one ports, and connects that one port
418 to the specified source.
421 if (_input_minimum.get_total() > 1) {
422 /* sorry, you can't do this */
426 if (other_port == 0) {
427 if (_input_minimum == ChanCount::ZERO) {
428 return ensure_inputs (ChanCount::ZERO, false, true, src);
434 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
438 return connect_input (_inputs.port(0), other_port->name(), src);
442 IO::remove_output_port (Port* port, void* src)
444 IOChange change (NoChange);
447 Glib::Mutex::Lock em(_session.engine().process_lock());
450 Glib::Mutex::Lock lm (io_lock);
452 if (n_outputs() <= _output_minimum) {
453 /* sorry, you can't do this */
457 if (_outputs.remove(port)) {
458 change = IOChange (change|ConfigurationChanged);
460 if (port->connected()) {
461 change = IOChange (change|ConnectionsChanged);
464 _session.engine().unregister_port (*port);
465 drop_output_connection ();
467 setup_peak_meters ();
473 if (change != NoChange) {
474 output_changed (change, src);
475 _session.set_dirty ();
482 /** Add an output port.
484 * @param destination Name of input port to connect new port to.
485 * @param src Source for emitted ConfigurationChanged signal.
486 * @param type Data type of port. Default value (NIL) will use this IO's default type.
489 IO::add_output_port (string destination, void* src, DataType type)
494 if (type == DataType::NIL)
495 type = _default_type;
498 Glib::Mutex::Lock em(_session.engine().process_lock());
501 Glib::Mutex::Lock lm (io_lock);
503 if (n_outputs() >= _output_maximum) {
507 /* Create a new output port */
509 // FIXME: naming scheme for differently typed ports?
510 if (_output_maximum.get(type) == 1) {
511 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
513 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
516 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
517 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
521 _outputs.add (our_port);
522 drop_output_connection ();
523 setup_peak_meters ();
527 MoreChannels (n_outputs()); /* EMIT SIGNAL */
530 if (destination.length()) {
531 if (_session.engine().connect (our_port->name(), destination)) {
536 // pan_changed (src); /* EMIT SIGNAL */
537 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
538 _session.set_dirty ();
544 IO::remove_input_port (Port* port, void* src)
546 IOChange change (NoChange);
549 Glib::Mutex::Lock em(_session.engine().process_lock());
552 Glib::Mutex::Lock lm (io_lock);
554 if (n_inputs() <= _input_minimum) {
555 /* sorry, you can't do this */
559 if (_inputs.remove(port)) {
560 change = IOChange (change|ConfigurationChanged);
562 if (port->connected()) {
563 change = IOChange (change|ConnectionsChanged);
566 _session.engine().unregister_port (*port);
567 drop_input_connection ();
569 setup_peak_meters ();
575 if (change != NoChange) {
576 input_changed (change, src);
577 _session.set_dirty ();
585 /** Add an input port.
587 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
588 * @param destination Name of input port to connect new port to.
589 * @param src Source for emitted ConfigurationChanged signal.
592 IO::add_input_port (string source, void* src, DataType type)
597 if (type == DataType::NIL)
598 type = _default_type;
601 Glib::Mutex::Lock em (_session.engine().process_lock());
604 Glib::Mutex::Lock lm (io_lock);
606 if (n_inputs() >= _input_maximum) {
610 /* Create a new input port */
612 // FIXME: naming scheme for differently typed ports?
613 if (_input_maximum.get(type) == 1) {
614 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
616 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
619 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
620 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
624 _inputs.add (our_port);
625 drop_input_connection ();
626 setup_peak_meters ();
630 MoreChannels (n_inputs()); /* EMIT SIGNAL */
633 if (source.length()) {
635 if (_session.engine().connect (source, our_port->name())) {
640 // pan_changed (src); /* EMIT SIGNAL */
641 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
642 _session.set_dirty ();
648 IO::disconnect_inputs (void* src)
651 Glib::Mutex::Lock em (_session.engine().process_lock());
654 Glib::Mutex::Lock lm (io_lock);
656 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
657 _session.engine().disconnect (*i);
660 drop_input_connection ();
664 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
670 IO::disconnect_outputs (void* src)
673 Glib::Mutex::Lock em (_session.engine().process_lock());
676 Glib::Mutex::Lock lm (io_lock);
678 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
679 _session.engine().disconnect (*i);
682 drop_output_connection ();
686 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
687 _session.set_dirty ();
693 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
695 Port* input_port = 0;
696 bool changed = false;
699 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
701 const size_t n = count.get(*t);
703 /* remove unused ports */
704 for (size_t i = n_inputs().get(*t); i > n; --i) {
705 input_port = _inputs.port(*t, i-1);
708 _inputs.remove(input_port);
709 _session.engine().unregister_port (*input_port);
714 /* create any necessary new ports */
715 while (n_inputs().get(*t) < n) {
719 if (_input_maximum.get(*t) == 1) {
720 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
722 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
727 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
728 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
733 catch (AudioEngine::PortRegistrationFailure& err) {
734 setup_peak_meters ();
740 _inputs.add (input_port);
746 drop_input_connection ();
747 setup_peak_meters ();
749 MoreChannels (n_inputs()); /* EMIT SIGNAL */
750 _session.set_dirty ();
754 /* disconnect all existing ports so that we get a fresh start */
755 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
756 _session.engine().disconnect (*i);
763 /** Attach output_buffers to port buffers.
765 * Connected to IO's own MoreChannels signal.
768 IO::attach_buffers(ChanCount ignored)
770 _output_buffers->attach_buffers(_outputs);
774 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
776 bool in_changed = false;
777 bool out_changed = false;
778 bool need_pan_reset = false;
780 in = min (_input_maximum, in);
782 out = min (_output_maximum, out);
784 if (in == n_inputs() && out == n_outputs() && !clear) {
789 Glib::Mutex::Lock em (_session.engine().process_lock());
790 Glib::Mutex::Lock lm (io_lock);
794 if (n_outputs() != out) {
795 need_pan_reset = true;
798 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
800 const size_t nin = in.get(*t);
801 const size_t nout = out.get(*t);
803 Port* output_port = 0;
804 Port* input_port = 0;
806 /* remove unused output ports */
807 for (size_t i = n_outputs().get(*t); i > nout; --i) {
808 output_port = _outputs.port(*t, i-1);
811 _outputs.remove(output_port);
812 _session.engine().unregister_port (*output_port);
817 /* remove unused input ports */
818 for (size_t i = n_inputs().get(*t); i > nin; --i) {
819 input_port = _inputs.port(*t, i-1);
822 _inputs.remove(input_port);
823 _session.engine().unregister_port (*input_port);
828 /* create any necessary new input ports */
830 while (n_inputs().get(*t) < nin) {
834 /* Create a new input port */
836 if (_input_maximum.get(*t) == 1) {
837 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
839 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
843 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
844 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
849 catch (AudioEngine::PortRegistrationFailure& err) {
850 setup_peak_meters ();
860 /* create any necessary new output ports */
862 while (n_outputs().get(*t) < nout) {
866 /* Create a new output port */
868 if (_output_maximum.get(*t) == 1) {
869 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
871 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
875 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
876 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
881 catch (AudioEngine::PortRegistrationFailure& err) {
882 setup_peak_meters ();
895 /* disconnect all existing ports so that we get a fresh start */
897 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
898 _session.engine().disconnect (*i);
901 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
902 _session.engine().disconnect (*i);
906 if (in_changed || out_changed) {
907 setup_peak_meters ();
913 drop_output_connection ();
914 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
918 drop_input_connection ();
919 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
922 if (in_changed || out_changed) {
923 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
924 _session.set_dirty ();
931 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
933 bool changed = false;
935 count = min (_input_maximum, count);
937 if (count == n_inputs() && !clear) {
942 Glib::Mutex::Lock em (_session.engine().process_lock());
943 Glib::Mutex::Lock im (io_lock);
944 changed = ensure_inputs_locked (count, clear, src);
946 changed = ensure_inputs_locked (count, clear, src);
950 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
951 _session.set_dirty ();
957 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
959 Port* output_port = 0;
960 bool changed = false;
961 bool need_pan_reset = false;
963 if (n_outputs() != count) {
964 need_pan_reset = true;
967 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
969 const size_t n = count.get(*t);
971 /* remove unused ports */
972 for (size_t i = n_outputs().get(*t); i > n; --i) {
973 output_port = _outputs.port(*t, i-1);
976 _outputs.remove(output_port);
977 _session.engine().unregister_port (*output_port);
982 /* create any necessary new ports */
983 while (n_outputs().get(*t) < n) {
987 if (_output_maximum.get(*t) == 1) {
988 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
990 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
993 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
994 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
998 _outputs.add (output_port);
1000 setup_peak_meters ();
1002 if (need_pan_reset) {
1009 drop_output_connection ();
1010 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1011 _session.set_dirty ();
1015 /* disconnect all existing ports so that we get a fresh start */
1016 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1017 _session.engine().disconnect (*i);
1025 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1027 bool changed = false;
1029 if (_output_maximum < ChanCount::INFINITE) {
1030 count = min (_output_maximum, count);
1031 if (count == n_outputs() && !clear) {
1036 /* XXX caller should hold io_lock, but generally doesn't */
1039 Glib::Mutex::Lock em (_session.engine().process_lock());
1040 Glib::Mutex::Lock im (io_lock);
1041 changed = ensure_outputs_locked (count, clear, src);
1043 changed = ensure_outputs_locked (count, clear, src);
1047 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1054 IO::effective_gain () const
1056 if (gain_automation_playback()) {
1057 return _effective_gain;
1059 return _desired_gain;
1066 if (panners_legal) {
1067 if (!no_panner_reset) {
1068 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1071 panner_legal_c.disconnect ();
1072 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1077 IO::panners_became_legal ()
1079 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1080 _panner->load (); // automation
1081 panner_legal_c.disconnect ();
1086 IO::defer_pan_reset ()
1088 no_panner_reset = true;
1092 IO::allow_pan_reset ()
1094 no_panner_reset = false;
1100 IO::get_state (void)
1102 return state (true);
1106 IO::state (bool full_state)
1108 XMLNode* node = new XMLNode (state_node_name);
1111 bool need_ins = true;
1112 bool need_outs = true;
1113 LocaleGuard lg (X_("POSIX"));
1114 Glib::Mutex::Lock lm (io_lock);
1116 node->add_property("name", _name);
1118 node->add_property("id", buf);
1122 if (_input_connection) {
1123 node->add_property ("input-connection", _input_connection->name());
1127 if (_output_connection) {
1128 node->add_property ("output-connection", _output_connection->name());
1133 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1135 const char **connections = i->get_connections();
1137 if (connections && connections[0]) {
1140 for (int n = 0; connections && connections[n]; ++n) {
1145 /* if its a connection to our own port,
1146 return only the port name, not the
1147 whole thing. this allows connections
1148 to be re-established even when our
1149 client name is different.
1152 str += _session.engine().make_port_name_relative (connections[n]);
1164 node->add_property ("inputs", str);
1170 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1172 const char **connections = i->get_connections();
1174 if (connections && connections[0]) {
1178 for (int n = 0; connections[n]; ++n) {
1183 str += _session.engine().make_port_name_relative (connections[n]);
1195 node->add_property ("outputs", str);
1198 node->add_child_nocopy (_panner->state (full_state));
1200 snprintf (buf, sizeof(buf), "%2.12f", gain());
1201 node->add_property ("gain", buf);
1203 // FIXME: this is NOT sufficient!
1204 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1205 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1206 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1207 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1209 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1211 node->add_property ("iolimits", buf);
1216 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1218 /* never store anything except Off for automation state in a template */
1219 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1221 node->add_property ("automation-state", buf);
1222 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1223 node->add_property ("automation-style", buf);
1225 /* XXX same for pan etc. */
1231 IO::connecting_became_legal ()
1235 if (pending_state_node == 0) {
1236 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1241 connection_legal_c.disconnect ();
1243 ret = make_connections (*pending_state_node);
1246 delete pending_state_node;
1247 pending_state_node = 0;
1254 IO::ports_became_legal ()
1258 if (pending_state_node == 0) {
1259 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1264 port_legal_c.disconnect ();
1266 ret = create_ports (*pending_state_node);
1268 if (connecting_legal) {
1269 delete pending_state_node;
1270 pending_state_node = 0;
1277 IO::set_state (const XMLNode& node)
1279 const XMLProperty* prop;
1280 XMLNodeConstIterator iter;
1281 LocaleGuard lg (X_("POSIX"));
1283 /* force use of non-localized representation of decimal point,
1284 since we use it a lot in XML files and so forth.
1287 if (node.name() != state_node_name) {
1288 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1292 if ((prop = node.property ("name")) != 0) {
1293 _name = prop->value();
1294 _panner->set_name (_name);
1297 if ((prop = node.property ("id")) != 0) {
1298 _id = prop->value ();
1303 size_t out_min = -1;
1304 size_t out_max = -1;
1306 if ((prop = node.property ("iolimits")) != 0) {
1307 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1308 &in_min, &in_max, &out_min, &out_max);
1309 _input_minimum = ChanCount(_default_type, in_min);
1310 _input_maximum = ChanCount(_default_type, in_max);
1311 _output_minimum = ChanCount(_default_type, out_min);
1312 _output_maximum = ChanCount(_default_type, out_max);
1315 if ((prop = node.property ("gain")) != 0) {
1316 set_gain (atof (prop->value().c_str()), this);
1317 _gain = _desired_gain;
1320 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1321 if ((*iter)->name() == "Panner") {
1322 _panner->set_state (**iter);
1326 if ((prop = node.property ("automation-state")) != 0) {
1329 x = strtol (prop->value().c_str(), 0, 16);
1330 set_gain_automation_state (AutoState (x));
1333 if ((prop = node.property ("automation-style")) != 0) {
1336 x = strtol (prop->value().c_str(), 0, 16);
1337 set_gain_automation_style (AutoStyle (x));
1342 if (create_ports (node)) {
1348 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1351 if (panners_legal) {
1354 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1357 if (connecting_legal) {
1359 if (make_connections (node)) {
1365 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1368 if (!ports_legal || !connecting_legal) {
1369 pending_state_node = new XMLNode (node);
1376 IO::create_ports (const XMLNode& node)
1378 const XMLProperty* prop;
1380 int num_outputs = 0;
1382 if ((prop = node.property ("input-connection")) != 0) {
1384 Connection* c = _session.connection_by_name (prop->value());
1387 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1389 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1390 error << _("No input connections available as a replacement")
1394 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1399 num_inputs = c->nports();
1401 } else if ((prop = node.property ("inputs")) != 0) {
1403 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1406 if ((prop = node.property ("output-connection")) != 0) {
1407 Connection* c = _session.connection_by_name (prop->value());
1410 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1412 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1413 error << _("No output connections available as a replacement")
1417 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1422 num_outputs = c->nports ();
1424 } else if ((prop = node.property ("outputs")) != 0) {
1425 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1428 no_panner_reset = true;
1430 // FIXME: audio-only
1431 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1432 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1436 no_panner_reset = false;
1438 set_deferred_state ();
1446 IO::make_connections (const XMLNode& node)
1448 const XMLProperty* prop;
1450 if ((prop = node.property ("input-connection")) != 0) {
1451 Connection* c = _session.connection_by_name (prop->value());
1454 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1456 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1457 error << _("No input connections available as a replacement")
1461 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1466 use_input_connection (*c, this);
1468 } else if ((prop = node.property ("inputs")) != 0) {
1469 if (set_inputs (prop->value())) {
1470 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1475 if ((prop = node.property ("output-connection")) != 0) {
1476 Connection* c = _session.connection_by_name (prop->value());
1479 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1481 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1482 error << _("No output connections available as a replacement")
1486 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1491 use_output_connection (*c, this);
1493 } else if ((prop = node.property ("outputs")) != 0) {
1494 if (set_outputs (prop->value())) {
1495 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1504 IO::set_inputs (const string& str)
1506 vector<string> ports;
1511 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1515 // FIXME: audio-only
1516 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1520 string::size_type start, end, ostart;
1527 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1530 if ((end = str.find_first_of ('}', start)) == string::npos) {
1531 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1535 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1536 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1542 for (int x = 0; x < n; ++x) {
1543 connect_input (input (i), ports[x], this);
1555 IO::set_outputs (const string& str)
1557 vector<string> ports;
1562 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1566 // FIXME: audio-only
1567 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1571 string::size_type start, end, ostart;
1578 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1581 if ((end = str.find_first_of ('}', start)) == string::npos) {
1582 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1586 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1587 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1593 for (int x = 0; x < n; ++x) {
1594 connect_output (output (i), ports[x], this);
1606 IO::parse_io_string (const string& str, vector<string>& ports)
1608 string::size_type pos, opos;
1610 if (str.length() == 0) {
1619 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1620 ports.push_back (str.substr (opos, pos - opos));
1624 if (opos < str.length()) {
1625 ports.push_back (str.substr(opos));
1628 return ports.size();
1632 IO::parse_gain_string (const string& str, vector<string>& ports)
1634 string::size_type pos, opos;
1640 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1641 ports.push_back (str.substr (opos, pos - opos));
1645 if (opos < str.length()) {
1646 ports.push_back (str.substr(opos));
1649 return ports.size();
1653 IO::set_name (string name, void* src)
1655 if (name == _name) {
1659 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1660 string current_name = i->short_name();
1661 current_name.replace (current_name.find (_name), _name.length(), name);
1662 i->set_name (current_name);
1665 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1666 string current_name = i->short_name();
1667 current_name.replace (current_name.find (_name), _name.length(), name);
1668 i->set_name (current_name);
1672 name_changed (src); /* EMIT SIGNAL */
1678 IO::set_input_minimum (int n)
1681 _input_minimum = ChanCount::ZERO;
1683 _input_minimum = ChanCount(_default_type, n);
1687 IO::set_input_maximum (int n)
1690 _input_maximum = ChanCount::INFINITE;
1692 _input_maximum = ChanCount(_default_type, n);
1696 IO::set_output_minimum (int n)
1699 _output_minimum = ChanCount::ZERO;
1701 _output_minimum = ChanCount(_default_type, n);
1705 IO::set_output_maximum (int n)
1708 _output_maximum = ChanCount::INFINITE;
1710 _output_maximum = ChanCount(_default_type, n);
1714 IO::set_input_minimum (ChanCount n)
1720 IO::set_input_maximum (ChanCount n)
1726 IO::set_output_minimum (ChanCount n)
1728 _output_minimum = n;
1732 IO::set_output_maximum (ChanCount n)
1734 _output_maximum = n;
1738 IO::set_port_latency (jack_nframes_t nframes)
1740 Glib::Mutex::Lock lm (io_lock);
1742 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1743 i->set_latency (nframes);
1748 IO::output_latency () const
1750 jack_nframes_t max_latency;
1751 jack_nframes_t latency;
1755 /* io lock not taken - must be protected by other means */
1757 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1758 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1759 max_latency = latency;
1767 IO::input_latency () const
1769 jack_nframes_t max_latency;
1770 jack_nframes_t latency;
1774 /* io lock not taken - must be protected by other means */
1776 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1777 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1778 max_latency = latency;
1786 IO::use_input_connection (Connection& c, void* src)
1791 Glib::Mutex::Lock lm (_session.engine().process_lock());
1792 Glib::Mutex::Lock lm2 (io_lock);
1796 drop_input_connection ();
1798 // FIXME connections only work for audio-only
1799 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1803 /* first pass: check the current state to see what's correctly
1804 connected, and drop anything that we don't want.
1807 for (uint32_t n = 0; n < limit; ++n) {
1808 const Connection::PortList& pl = c.port_connections (n);
1810 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1812 if (!_inputs.port(n)->connected_to ((*i))) {
1814 /* clear any existing connections */
1816 _session.engine().disconnect (*_inputs.port(n));
1818 } else if (_inputs.port(n)->connected() > 1) {
1820 /* OK, it is connected to the port we want,
1821 but its also connected to other ports.
1822 Change that situation.
1825 /* XXX could be optimized to not drop
1829 _session.engine().disconnect (*_inputs.port(n));
1835 /* second pass: connect all requested ports where necessary */
1837 for (uint32_t n = 0; n < limit; ++n) {
1838 const Connection::PortList& pl = c.port_connections (n);
1840 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1842 if (!_inputs.port(n)->connected_to ((*i))) {
1844 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1852 _input_connection = &c;
1854 input_connection_configuration_connection = c.ConfigurationChanged.connect
1855 (mem_fun (*this, &IO::input_connection_configuration_changed));
1856 input_connection_connection_connection = c.ConnectionsChanged.connect
1857 (mem_fun (*this, &IO::input_connection_connection_changed));
1860 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1865 IO::use_output_connection (Connection& c, void* src)
1870 Glib::Mutex::Lock lm (_session.engine().process_lock());
1871 Glib::Mutex::Lock lm2 (io_lock);
1875 drop_output_connection ();
1877 // FIXME: audio-only
1878 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1882 /* first pass: check the current state to see what's correctly
1883 connected, and drop anything that we don't want.
1886 for (uint32_t n = 0; n < limit; ++n) {
1888 const Connection::PortList& pl = c.port_connections (n);
1890 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1892 if (!_outputs.port(n)->connected_to ((*i))) {
1894 /* clear any existing connections */
1896 _session.engine().disconnect (*_outputs.port(n));
1898 } else if (_outputs.port(n)->connected() > 1) {
1900 /* OK, it is connected to the port we want,
1901 but its also connected to other ports.
1902 Change that situation.
1905 /* XXX could be optimized to not drop
1909 _session.engine().disconnect (*_outputs.port(n));
1914 /* second pass: connect all requested ports where necessary */
1916 for (uint32_t n = 0; n < limit; ++n) {
1918 const Connection::PortList& pl = c.port_connections (n);
1920 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1922 if (!_outputs.port(n)->connected_to ((*i))) {
1924 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
1931 _output_connection = &c;
1933 output_connection_configuration_connection = c.ConfigurationChanged.connect
1934 (mem_fun (*this, &IO::output_connection_configuration_changed));
1935 output_connection_connection_connection = c.ConnectionsChanged.connect
1936 (mem_fun (*this, &IO::output_connection_connection_changed));
1939 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
1945 IO::disable_connecting ()
1947 connecting_legal = false;
1952 IO::enable_connecting ()
1954 connecting_legal = true;
1955 return ConnectingLegal ();
1959 IO::disable_ports ()
1961 ports_legal = false;
1969 return PortsLegal ();
1973 IO::disable_panners (void)
1975 panners_legal = false;
1980 IO::reset_panners ()
1982 panners_legal = true;
1983 return PannersLegal ();
1987 IO::input_connection_connection_changed (int ignored)
1989 use_input_connection (*_input_connection, this);
1993 IO::input_connection_configuration_changed ()
1995 use_input_connection (*_input_connection, this);
1999 IO::output_connection_connection_changed (int ignored)
2001 use_output_connection (*_output_connection, this);
2005 IO::output_connection_configuration_changed ()
2007 use_output_connection (*_output_connection, this);
2011 IO::GainControllable::set_value (float val)
2013 io.set_gain (direct_control_to_gain (val), this);
2017 IO::GainControllable::get_value (void) const
2019 return direct_gain_to_control (io.effective_gain());
2023 IO::get_memento() const
2025 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2029 IO::restore_state (StateManager::State& state)
2034 StateManager::State*
2035 IO::state_factory (std::string why) const
2037 StateManager::State* state = new StateManager::State (why);
2042 IO::setup_peak_meters()
2044 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2048 Update the peak meters.
2050 The meter signal lock is taken to prevent modification of the
2051 Meter signal while updating the meters, taking the meter signal
2052 lock prior to taking the io_lock ensures that all IO will remain
2053 valid while metering.
2058 Glib::Mutex::Lock guard (m_meter_signal_lock);
2060 Meter(); /* EMIT SIGNAL */
2066 // FIXME: Remove this function and just connect signal directly to PeakMeter::meter
2068 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2073 IO::save_automation (const string& path)
2078 fullpath = _session.automation_dir();
2081 out.open (fullpath.c_str());
2084 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2088 out << X_("version ") << current_automation_version_number << endl;
2090 /* XXX use apply_to_points to get thread safety */
2092 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2093 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2102 IO::load_automation (const string& path)
2107 uint32_t linecnt = 0;
2109 LocaleGuard lg (X_("POSIX"));
2111 fullpath = _session.automation_dir();
2114 in.open (fullpath.c_str());
2117 fullpath = _session.automation_dir();
2118 fullpath += _session.snap_name();
2121 in.open (fullpath.c_str());
2123 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2128 clear_automation ();
2130 while (in.getline (line, sizeof(line), '\n')) {
2132 jack_nframes_t when;
2135 if (++linecnt == 1) {
2136 if (memcmp (line, "version", 7) == 0) {
2137 if (sscanf (line, "version %f", &version) != 1) {
2138 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2142 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2146 if (version != current_automation_version_number) {
2147 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2154 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2155 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2161 _gain_automation_curve.add (when, value, true);
2171 /* older (pre-1.0) versions of ardour used this */
2175 warning << _("dubious automation event found (and ignored)") << endmsg;
2179 _gain_automation_curve.save_state (_("loaded from disk"));
2185 IO::clear_automation ()
2187 Glib::Mutex::Lock lm (automation_lock);
2188 _gain_automation_curve.clear ();
2189 _panner->clear_automation ();
2193 IO::set_gain_automation_state (AutoState state)
2195 bool changed = false;
2198 Glib::Mutex::Lock lm (automation_lock);
2200 if (state != _gain_automation_curve.automation_state()) {
2202 last_automation_snapshot = 0;
2203 _gain_automation_curve.set_automation_state (state);
2206 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2212 _session.set_dirty ();
2213 gain_automation_state_changed (); /* EMIT SIGNAL */
2218 IO::set_gain_automation_style (AutoStyle style)
2220 bool changed = false;
2223 Glib::Mutex::Lock lm (automation_lock);
2225 if (style != _gain_automation_curve.automation_style()) {
2227 _gain_automation_curve.set_automation_style (style);
2232 gain_automation_style_changed (); /* EMIT SIGNAL */
2236 IO::inc_gain (gain_t factor, void *src)
2238 if (_desired_gain == 0.0f)
2239 set_gain (0.000001f + (0.000001f * factor), src);
2241 set_gain (_desired_gain + (_desired_gain * factor), src);
2245 IO::set_gain (gain_t val, void *src)
2247 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2248 if (val>1.99526231f) val=1.99526231f;
2251 Glib::Mutex::Lock dm (declick_lock);
2252 _desired_gain = val;
2255 if (_session.transport_stopped()) {
2256 _effective_gain = val;
2261 _gain_control.Changed (); /* EMIT SIGNAL */
2263 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2264 _gain_automation_curve.add (_session.transport_frame(), val);
2268 _session.set_dirty();
2272 IO::start_gain_touch ()
2274 _gain_automation_curve.start_touch ();
2278 IO::end_gain_touch ()
2280 _gain_automation_curve.stop_touch ();
2284 IO::start_pan_touch (uint32_t which)
2286 if (which < _panner->size()) {
2287 (*_panner)[which]->automation().start_touch();
2292 IO::end_pan_touch (uint32_t which)
2294 if (which < _panner->size()) {
2295 (*_panner)[which]->automation().stop_touch();
2301 IO::automation_snapshot (jack_nframes_t now)
2303 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2305 if (gain_automation_recording()) {
2306 _gain_automation_curve.rt_add (now, gain());
2309 _panner->snapshot (now);
2311 last_automation_snapshot = now;
2316 IO::transport_stopped (jack_nframes_t frame)
2318 _gain_automation_curve.reposition_for_rt_add (frame);
2320 if (_gain_automation_curve.automation_state() != Off) {
2322 if (gain_automation_recording()) {
2323 _gain_automation_curve.save_state (_("automation write/touch"));
2326 /* the src=0 condition is a special signal to not propagate
2327 automation gain changes into the mix group when locating.
2330 set_gain (_gain_automation_curve.eval (frame), 0);
2333 _panner->transport_stopped (frame);
2337 IO::find_input_port_hole ()
2339 /* CALLER MUST HOLD IO LOCK */
2343 if (_inputs.empty()) {
2347 for (n = 1; n < UINT_MAX; ++n) {
2348 char buf[jack_port_name_size()];
2349 PortSet::iterator i = _inputs.begin();
2351 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2353 for ( ; i != _inputs.end(); ++i) {
2354 if (i->short_name() == buf) {
2359 if (i == _inputs.end()) {
2367 IO::find_output_port_hole ()
2369 /* CALLER MUST HOLD IO LOCK */
2373 if (_outputs.empty()) {
2377 for (n = 1; n < UINT_MAX; ++n) {
2378 char buf[jack_port_name_size()];
2379 PortSet::iterator i = _outputs.begin();
2381 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2383 for ( ; i != _outputs.end(); ++i) {
2384 if (i->short_name() == buf) {
2389 if (i == _outputs.end()) {
2398 IO::audio_input(uint32_t n) const
2400 return dynamic_cast<AudioPort*>(input(n));
2404 IO::audio_output(uint32_t n) const
2406 return dynamic_cast<AudioPort*>(output(n));
2410 IO::midi_input(uint32_t n) const
2412 return dynamic_cast<MidiPort*>(input(n));
2416 IO::midi_output(uint32_t n) const
2418 return dynamic_cast<MidiPort*>(output(n));
2422 IO::set_phase_invert (bool yn, void *src)
2424 if (_phase_invert != yn) {
2427 // phase_invert_changed (src); /* EMIT SIGNAL */