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 (ChanCount::ZERO),
110 _input_maximum (ChanCount::INFINITE),
111 _output_minimum (ChanCount::ZERO),
112 _output_maximum (ChanCount::INFINITE)
114 _panner = new Panner (name, _session);
115 _meter = new PeakMeter (_session);
118 _input_minimum = ChanCount(_default_type, input_min);
120 if (input_max >= 0) {
121 _input_maximum = ChanCount(_default_type, input_max);
123 if (output_min > 0) {
124 _output_minimum = ChanCount(_default_type, output_min);
126 if (output_max >= 0) {
127 _output_maximum = ChanCount(_default_type, output_max);
132 _input_connection = 0;
133 _output_connection = 0;
134 pending_state_node = 0;
135 no_panner_reset = false;
136 _phase_invert = false;
139 apply_gain_automation = false;
141 last_automation_snapshot = 0;
143 _gain_automation_state = Off;
144 _gain_automation_style = Absolute;
147 // IO::Meter is emitted from another thread so the
148 // Meter signal must be protected.
149 Glib::Mutex::Lock guard (m_meter_signal_lock);
150 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
153 // Connect to our own MoreChannels signal to connect output buffers
154 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
159 Glib::Mutex::Lock guard (m_meter_signal_lock);
161 Glib::Mutex::Lock lm (io_lock);
163 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
164 _session.engine().unregister_port (*i);
167 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
168 _session.engine().unregister_port (*i);
171 m_meter_connection.disconnect();
175 delete _output_buffers;
179 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
181 /* io_lock, not taken: function must be called from Session::process() calltree */
183 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
184 i->silence (nframes, offset);
188 /** Deliver bufs to the IO's Jack outputs.
190 * This function should automatically do whatever it necessary to correctly deliver bufs
191 * to the outputs, eg applying gain or pan or whatever else needs to be done.
194 IO::deliver_output (BufferSet& bufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset)
196 // FIXME: type specific code doesn't actually need to be here, it will go away in time
199 /* ********** AUDIO ********** */
201 // Apply gain if gain automation isn't playing
202 if ( ! apply_gain_automation) {
204 gain_t dg = _gain; // desired gain
207 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
214 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
217 // Use the panner to distribute audio to output port buffers
218 if (_panner && !_panner->empty() && !_panner->bypassed()) {
219 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
223 /* ********** MIDI ********** */
225 // No MIDI, we're done here
226 if (bufs.count().get(DataType::MIDI) == 0) {
230 const DataType type = DataType::MIDI;
232 // Just dump any MIDI 1-to-1, we're not at all clever with MIDI routing yet
233 BufferSet::iterator o = output_buffers().begin(type);
234 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
235 o->read_from(*i, nframes, offset);
240 IO::collect_input (BufferSet& outs, jack_nframes_t nframes, jack_nframes_t offset)
242 assert(outs.available() >= n_inputs());
244 outs.set_count(n_inputs());
246 if (outs.count() == ChanCount::ZERO)
249 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
251 BufferSet::iterator o = outs.begin(*t);
252 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
253 o->read_from(i->get_buffer(), nframes, offset);
260 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
261 jack_nframes_t nframes, jack_nframes_t offset)
263 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
265 collect_input (bufs, nframes, offset);
267 _meter->run(bufs, nframes);
271 IO::drop_input_connection ()
273 _input_connection = 0;
274 input_connection_configuration_connection.disconnect();
275 input_connection_connection_connection.disconnect();
276 _session.set_dirty ();
280 IO::drop_output_connection ()
282 _output_connection = 0;
283 output_connection_configuration_connection.disconnect();
284 output_connection_connection_connection.disconnect();
285 _session.set_dirty ();
289 IO::disconnect_input (Port* our_port, string other_port, void* src)
291 if (other_port.length() == 0 || our_port == 0) {
296 Glib::Mutex::Lock em (_session.engine().process_lock());
299 Glib::Mutex::Lock lm (io_lock);
301 /* check that our_port is really one of ours */
303 if ( ! _inputs.contains(our_port)) {
307 /* disconnect it from the source */
309 if (_session.engine().disconnect (other_port, our_port->name())) {
310 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
314 drop_input_connection();
318 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
319 _session.set_dirty ();
325 IO::connect_input (Port* our_port, string other_port, void* src)
327 if (other_port.length() == 0 || our_port == 0) {
332 Glib::Mutex::Lock em(_session.engine().process_lock());
335 Glib::Mutex::Lock lm (io_lock);
337 /* check that our_port is really one of ours */
339 if ( ! _inputs.contains(our_port) ) {
343 /* connect it to the source */
345 if (_session.engine().connect (other_port, our_port->name())) {
349 drop_input_connection ();
353 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
354 _session.set_dirty ();
359 IO::disconnect_output (Port* our_port, string other_port, void* src)
361 if (other_port.length() == 0 || our_port == 0) {
366 Glib::Mutex::Lock em(_session.engine().process_lock());
369 Glib::Mutex::Lock lm (io_lock);
371 /* check that our_port is really one of ours */
373 if ( ! _outputs.contains(our_port) ) {
377 /* disconnect it from the destination */
379 if (_session.engine().disconnect (our_port->name(), other_port)) {
380 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
384 drop_output_connection ();
388 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
389 _session.set_dirty ();
394 IO::connect_output (Port* our_port, string other_port, void* src)
396 if (other_port.length() == 0 || our_port == 0) {
401 Glib::Mutex::Lock em(_session.engine().process_lock());
404 Glib::Mutex::Lock lm (io_lock);
406 /* check that our_port is really one of ours */
408 if ( ! _outputs.contains(our_port) ) {
412 /* connect it to the destination */
414 if (_session.engine().connect (our_port->name(), other_port)) {
418 drop_output_connection ();
422 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
423 _session.set_dirty ();
428 IO::set_input (Port* other_port, void* src)
430 /* this removes all but one ports, and connects that one port
431 to the specified source.
434 if (_input_minimum.get_total() > 1) {
435 /* sorry, you can't do this */
439 if (other_port == 0) {
440 if (_input_minimum == ChanCount::ZERO) {
441 return ensure_inputs (ChanCount::ZERO, false, true, src);
447 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
451 return connect_input (_inputs.port(0), other_port->name(), src);
455 IO::remove_output_port (Port* port, void* src)
457 IOChange change (NoChange);
460 Glib::Mutex::Lock em(_session.engine().process_lock());
463 Glib::Mutex::Lock lm (io_lock);
465 if (n_outputs() <= _output_minimum) {
466 /* sorry, you can't do this */
470 if (_outputs.remove(port)) {
471 change = IOChange (change|ConfigurationChanged);
473 if (port->connected()) {
474 change = IOChange (change|ConnectionsChanged);
477 _session.engine().unregister_port (*port);
478 drop_output_connection ();
480 setup_peak_meters ();
486 if (change != NoChange) {
487 output_changed (change, src);
488 _session.set_dirty ();
495 /** Add an output port.
497 * @param destination Name of input port to connect new port to.
498 * @param src Source for emitted ConfigurationChanged signal.
499 * @param type Data type of port. Default value (NIL) will use this IO's default type.
502 IO::add_output_port (string destination, void* src, DataType type)
507 if (type == DataType::NIL)
508 type = _default_type;
511 Glib::Mutex::Lock em(_session.engine().process_lock());
514 Glib::Mutex::Lock lm (io_lock);
516 if (n_outputs() >= _output_maximum) {
520 /* Create a new output port */
522 // FIXME: naming scheme for differently typed ports?
523 if (_output_maximum.get(type) == 1) {
524 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
526 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
529 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
530 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
534 _outputs.add (our_port);
535 drop_output_connection ();
536 setup_peak_meters ();
540 MoreChannels (n_outputs()); /* EMIT SIGNAL */
543 if (destination.length()) {
544 if (_session.engine().connect (our_port->name(), destination)) {
549 // pan_changed (src); /* EMIT SIGNAL */
550 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
551 _session.set_dirty ();
557 IO::remove_input_port (Port* port, void* src)
559 IOChange change (NoChange);
562 Glib::Mutex::Lock em(_session.engine().process_lock());
565 Glib::Mutex::Lock lm (io_lock);
567 if (n_inputs() <= _input_minimum) {
568 /* sorry, you can't do this */
572 if (_inputs.remove(port)) {
573 change = IOChange (change|ConfigurationChanged);
575 if (port->connected()) {
576 change = IOChange (change|ConnectionsChanged);
579 _session.engine().unregister_port (*port);
580 drop_input_connection ();
582 setup_peak_meters ();
588 if (change != NoChange) {
589 input_changed (change, src);
590 _session.set_dirty ();
598 /** Add an input port.
600 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
601 * @param destination Name of input port to connect new port to.
602 * @param src Source for emitted ConfigurationChanged signal.
605 IO::add_input_port (string source, void* src, DataType type)
610 if (type == DataType::NIL)
611 type = _default_type;
614 Glib::Mutex::Lock em (_session.engine().process_lock());
617 Glib::Mutex::Lock lm (io_lock);
619 if (n_inputs() >= _input_maximum) {
623 /* Create a new input port */
625 // FIXME: naming scheme for differently typed ports?
626 if (_input_maximum.get(type) == 1) {
627 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
629 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
632 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
633 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
637 _inputs.add (our_port);
638 drop_input_connection ();
639 setup_peak_meters ();
643 MoreChannels (n_inputs()); /* EMIT SIGNAL */
646 if (source.length()) {
648 if (_session.engine().connect (source, our_port->name())) {
653 // pan_changed (src); /* EMIT SIGNAL */
654 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
655 _session.set_dirty ();
661 IO::disconnect_inputs (void* src)
664 Glib::Mutex::Lock em (_session.engine().process_lock());
667 Glib::Mutex::Lock lm (io_lock);
669 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
670 _session.engine().disconnect (*i);
673 drop_input_connection ();
677 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
683 IO::disconnect_outputs (void* src)
686 Glib::Mutex::Lock em (_session.engine().process_lock());
689 Glib::Mutex::Lock lm (io_lock);
691 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
692 _session.engine().disconnect (*i);
695 drop_output_connection ();
699 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
700 _session.set_dirty ();
706 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
708 Port* input_port = 0;
709 bool changed = false;
712 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
714 const size_t n = count.get(*t);
716 /* remove unused ports */
717 for (size_t i = n_inputs().get(*t); i > n; --i) {
718 input_port = _inputs.port(*t, i-1);
721 _inputs.remove(input_port);
722 _session.engine().unregister_port (*input_port);
727 /* create any necessary new ports */
728 while (n_inputs().get(*t) < n) {
732 if (_input_maximum.get(*t) == 1) {
733 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
735 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
740 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
741 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
746 catch (AudioEngine::PortRegistrationFailure& err) {
747 setup_peak_meters ();
753 _inputs.add (input_port);
759 drop_input_connection ();
760 setup_peak_meters ();
762 MoreChannels (n_inputs()); /* EMIT SIGNAL */
763 _session.set_dirty ();
767 /* disconnect all existing ports so that we get a fresh start */
768 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
769 _session.engine().disconnect (*i);
776 /** Attach output_buffers to port buffers.
778 * Connected to IO's own MoreChannels signal.
781 IO::attach_buffers(ChanCount ignored)
783 _output_buffers->attach_buffers(_outputs);
787 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
789 bool in_changed = false;
790 bool out_changed = false;
791 bool need_pan_reset = false;
793 in = min (_input_maximum, in);
795 out = min (_output_maximum, out);
797 if (in == n_inputs() && out == n_outputs() && !clear) {
802 Glib::Mutex::Lock em (_session.engine().process_lock());
803 Glib::Mutex::Lock lm (io_lock);
807 if (n_outputs() != out) {
808 need_pan_reset = true;
811 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
813 const size_t nin = in.get(*t);
814 const size_t nout = out.get(*t);
816 Port* output_port = 0;
817 Port* input_port = 0;
819 /* remove unused output ports */
820 for (size_t i = n_outputs().get(*t); i > nout; --i) {
821 output_port = _outputs.port(*t, i-1);
824 _outputs.remove(output_port);
825 _session.engine().unregister_port (*output_port);
830 /* remove unused input ports */
831 for (size_t i = n_inputs().get(*t); i > nin; --i) {
832 input_port = _inputs.port(*t, i-1);
835 _inputs.remove(input_port);
836 _session.engine().unregister_port (*input_port);
841 /* create any necessary new input ports */
843 while (n_inputs().get(*t) < nin) {
847 /* Create a new input port */
849 if (_input_maximum.get(*t) == 1) {
850 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
852 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
856 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
857 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
862 catch (AudioEngine::PortRegistrationFailure& err) {
863 setup_peak_meters ();
873 /* create any necessary new output ports */
875 while (n_outputs().get(*t) < nout) {
879 /* Create a new output port */
881 if (_output_maximum.get(*t) == 1) {
882 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
884 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
888 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
889 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
894 catch (AudioEngine::PortRegistrationFailure& err) {
895 setup_peak_meters ();
908 /* disconnect all existing ports so that we get a fresh start */
910 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
911 _session.engine().disconnect (*i);
914 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
915 _session.engine().disconnect (*i);
919 if (in_changed || out_changed) {
920 setup_peak_meters ();
926 drop_output_connection ();
927 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
931 drop_input_connection ();
932 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
935 if (in_changed || out_changed) {
936 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
937 _session.set_dirty ();
944 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
946 bool changed = false;
948 count = min (_input_maximum, count);
950 if (count == n_inputs() && !clear) {
955 Glib::Mutex::Lock em (_session.engine().process_lock());
956 Glib::Mutex::Lock im (io_lock);
957 changed = ensure_inputs_locked (count, clear, src);
959 changed = ensure_inputs_locked (count, clear, src);
963 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
964 _session.set_dirty ();
970 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
972 Port* output_port = 0;
973 bool changed = false;
974 bool need_pan_reset = false;
976 if (n_outputs() != count) {
977 need_pan_reset = true;
980 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
982 const size_t n = count.get(*t);
984 /* remove unused ports */
985 for (size_t i = n_outputs().get(*t); i > n; --i) {
986 output_port = _outputs.port(*t, i-1);
989 _outputs.remove(output_port);
990 _session.engine().unregister_port (*output_port);
995 /* create any necessary new ports */
996 while (n_outputs().get(*t) < n) {
1000 if (_output_maximum.get(*t) == 1) {
1001 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1003 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1006 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1007 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1011 _outputs.add (output_port);
1013 setup_peak_meters ();
1015 if (need_pan_reset) {
1022 drop_output_connection ();
1023 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1024 _session.set_dirty ();
1028 /* disconnect all existing ports so that we get a fresh start */
1029 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1030 _session.engine().disconnect (*i);
1038 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1040 bool changed = false;
1042 if (_output_maximum < ChanCount::INFINITE) {
1043 count = min (_output_maximum, count);
1044 if (count == n_outputs() && !clear) {
1049 /* XXX caller should hold io_lock, but generally doesn't */
1052 Glib::Mutex::Lock em (_session.engine().process_lock());
1053 Glib::Mutex::Lock im (io_lock);
1054 changed = ensure_outputs_locked (count, clear, src);
1056 changed = ensure_outputs_locked (count, clear, src);
1060 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1067 IO::effective_gain () const
1069 if (gain_automation_playback()) {
1070 return _effective_gain;
1072 return _desired_gain;
1079 if (panners_legal) {
1080 if (!no_panner_reset) {
1081 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1084 panner_legal_c.disconnect ();
1085 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1090 IO::panners_became_legal ()
1092 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1093 _panner->load (); // automation
1094 panner_legal_c.disconnect ();
1099 IO::defer_pan_reset ()
1101 no_panner_reset = true;
1105 IO::allow_pan_reset ()
1107 no_panner_reset = false;
1113 IO::get_state (void)
1115 return state (true);
1119 IO::state (bool full_state)
1121 XMLNode* node = new XMLNode (state_node_name);
1124 bool need_ins = true;
1125 bool need_outs = true;
1126 LocaleGuard lg (X_("POSIX"));
1127 Glib::Mutex::Lock lm (io_lock);
1129 node->add_property("name", _name);
1131 node->add_property("id", buf);
1135 if (_input_connection) {
1136 node->add_property ("input-connection", _input_connection->name());
1140 if (_output_connection) {
1141 node->add_property ("output-connection", _output_connection->name());
1146 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1148 const char **connections = i->get_connections();
1150 if (connections && connections[0]) {
1153 for (int n = 0; connections && connections[n]; ++n) {
1158 /* if its a connection to our own port,
1159 return only the port name, not the
1160 whole thing. this allows connections
1161 to be re-established even when our
1162 client name is different.
1165 str += _session.engine().make_port_name_relative (connections[n]);
1177 node->add_property ("inputs", str);
1183 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1185 const char **connections = i->get_connections();
1187 if (connections && connections[0]) {
1191 for (int n = 0; connections[n]; ++n) {
1196 str += _session.engine().make_port_name_relative (connections[n]);
1208 node->add_property ("outputs", str);
1211 node->add_child_nocopy (_panner->state (full_state));
1213 snprintf (buf, sizeof(buf), "%2.12f", gain());
1214 node->add_property ("gain", buf);
1216 // FIXME: this is NOT sufficient!
1217 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1218 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1219 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1220 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1222 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1224 node->add_property ("iolimits", buf);
1229 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1231 /* never store anything except Off for automation state in a template */
1232 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1234 node->add_property ("automation-state", buf);
1235 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1236 node->add_property ("automation-style", buf);
1238 /* XXX same for pan etc. */
1244 IO::connecting_became_legal ()
1248 if (pending_state_node == 0) {
1249 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1254 connection_legal_c.disconnect ();
1256 ret = make_connections (*pending_state_node);
1259 delete pending_state_node;
1260 pending_state_node = 0;
1267 IO::ports_became_legal ()
1271 if (pending_state_node == 0) {
1272 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1277 port_legal_c.disconnect ();
1279 ret = create_ports (*pending_state_node);
1281 if (connecting_legal) {
1282 delete pending_state_node;
1283 pending_state_node = 0;
1290 IO::set_state (const XMLNode& node)
1292 const XMLProperty* prop;
1293 XMLNodeConstIterator iter;
1294 LocaleGuard lg (X_("POSIX"));
1296 /* force use of non-localized representation of decimal point,
1297 since we use it a lot in XML files and so forth.
1300 if (node.name() != state_node_name) {
1301 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1305 if ((prop = node.property ("name")) != 0) {
1306 _name = prop->value();
1307 _panner->set_name (_name);
1310 if ((prop = node.property ("id")) != 0) {
1311 _id = prop->value ();
1316 size_t out_min = -1;
1317 size_t out_max = -1;
1319 if ((prop = node.property ("iolimits")) != 0) {
1320 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1321 &in_min, &in_max, &out_min, &out_max);
1322 _input_minimum = ChanCount(_default_type, in_min);
1323 _input_maximum = ChanCount(_default_type, in_max);
1324 _output_minimum = ChanCount(_default_type, out_min);
1325 _output_maximum = ChanCount(_default_type, out_max);
1328 if ((prop = node.property ("gain")) != 0) {
1329 set_gain (atof (prop->value().c_str()), this);
1330 _gain = _desired_gain;
1333 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1334 if ((*iter)->name() == "Panner") {
1335 _panner->set_state (**iter);
1339 if ((prop = node.property ("automation-state")) != 0) {
1342 x = strtol (prop->value().c_str(), 0, 16);
1343 set_gain_automation_state (AutoState (x));
1346 if ((prop = node.property ("automation-style")) != 0) {
1349 x = strtol (prop->value().c_str(), 0, 16);
1350 set_gain_automation_style (AutoStyle (x));
1355 if (create_ports (node)) {
1361 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1364 if (panners_legal) {
1367 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1370 if (connecting_legal) {
1372 if (make_connections (node)) {
1378 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1381 if (!ports_legal || !connecting_legal) {
1382 pending_state_node = new XMLNode (node);
1389 IO::create_ports (const XMLNode& node)
1391 const XMLProperty* prop;
1393 int num_outputs = 0;
1395 if ((prop = node.property ("input-connection")) != 0) {
1397 Connection* c = _session.connection_by_name (prop->value());
1400 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1402 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1403 error << _("No input connections available as a replacement")
1407 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1412 num_inputs = c->nports();
1414 } else if ((prop = node.property ("inputs")) != 0) {
1416 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1419 if ((prop = node.property ("output-connection")) != 0) {
1420 Connection* c = _session.connection_by_name (prop->value());
1423 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1425 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1426 error << _("No output connections available as a replacement")
1430 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1435 num_outputs = c->nports ();
1437 } else if ((prop = node.property ("outputs")) != 0) {
1438 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1441 no_panner_reset = true;
1443 // FIXME: audio-only
1444 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1445 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1449 no_panner_reset = false;
1451 set_deferred_state ();
1459 IO::make_connections (const XMLNode& node)
1461 const XMLProperty* prop;
1463 if ((prop = node.property ("input-connection")) != 0) {
1464 Connection* c = _session.connection_by_name (prop->value());
1467 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1469 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1470 error << _("No input connections available as a replacement")
1474 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1479 use_input_connection (*c, this);
1481 } else if ((prop = node.property ("inputs")) != 0) {
1482 if (set_inputs (prop->value())) {
1483 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1488 if ((prop = node.property ("output-connection")) != 0) {
1489 Connection* c = _session.connection_by_name (prop->value());
1492 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1494 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1495 error << _("No output connections available as a replacement")
1499 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1504 use_output_connection (*c, this);
1506 } else if ((prop = node.property ("outputs")) != 0) {
1507 if (set_outputs (prop->value())) {
1508 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1517 IO::set_inputs (const string& str)
1519 vector<string> ports;
1524 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1528 // FIXME: audio-only
1529 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1533 string::size_type start, end, ostart;
1540 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1543 if ((end = str.find_first_of ('}', start)) == string::npos) {
1544 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1548 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1549 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1555 for (int x = 0; x < n; ++x) {
1556 connect_input (input (i), ports[x], this);
1568 IO::set_outputs (const string& str)
1570 vector<string> ports;
1575 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1579 // FIXME: audio-only
1580 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1584 string::size_type start, end, ostart;
1591 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1594 if ((end = str.find_first_of ('}', start)) == string::npos) {
1595 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1599 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1600 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1606 for (int x = 0; x < n; ++x) {
1607 connect_output (output (i), ports[x], this);
1619 IO::parse_io_string (const string& str, vector<string>& ports)
1621 string::size_type pos, opos;
1623 if (str.length() == 0) {
1632 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1633 ports.push_back (str.substr (opos, pos - opos));
1637 if (opos < str.length()) {
1638 ports.push_back (str.substr(opos));
1641 return ports.size();
1645 IO::parse_gain_string (const string& str, vector<string>& ports)
1647 string::size_type pos, opos;
1653 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1654 ports.push_back (str.substr (opos, pos - opos));
1658 if (opos < str.length()) {
1659 ports.push_back (str.substr(opos));
1662 return ports.size();
1666 IO::set_name (string name, void* src)
1668 if (name == _name) {
1672 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1673 string current_name = i->short_name();
1674 current_name.replace (current_name.find (_name), _name.length(), name);
1675 i->set_name (current_name);
1678 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1679 string current_name = i->short_name();
1680 current_name.replace (current_name.find (_name), _name.length(), name);
1681 i->set_name (current_name);
1685 name_changed (src); /* EMIT SIGNAL */
1691 IO::set_input_minimum (int n)
1694 _input_minimum = ChanCount::ZERO;
1696 _input_minimum = ChanCount(_default_type, n);
1700 IO::set_input_maximum (int n)
1703 _input_maximum = ChanCount::INFINITE;
1705 _input_maximum = ChanCount(_default_type, n);
1709 IO::set_output_minimum (int n)
1712 _output_minimum = ChanCount::ZERO;
1714 _output_minimum = ChanCount(_default_type, n);
1718 IO::set_output_maximum (int n)
1721 _output_maximum = ChanCount::INFINITE;
1723 _output_maximum = ChanCount(_default_type, n);
1727 IO::set_input_minimum (ChanCount n)
1733 IO::set_input_maximum (ChanCount n)
1739 IO::set_output_minimum (ChanCount n)
1741 _output_minimum = n;
1745 IO::set_output_maximum (ChanCount n)
1747 _output_maximum = n;
1751 IO::set_port_latency (jack_nframes_t nframes)
1753 Glib::Mutex::Lock lm (io_lock);
1755 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1756 i->set_latency (nframes);
1761 IO::output_latency () const
1763 jack_nframes_t max_latency;
1764 jack_nframes_t latency;
1768 /* io lock not taken - must be protected by other means */
1770 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1771 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1772 max_latency = latency;
1780 IO::input_latency () const
1782 jack_nframes_t max_latency;
1783 jack_nframes_t latency;
1787 /* io lock not taken - must be protected by other means */
1789 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1790 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1791 max_latency = latency;
1799 IO::use_input_connection (Connection& c, void* src)
1804 Glib::Mutex::Lock lm (_session.engine().process_lock());
1805 Glib::Mutex::Lock lm2 (io_lock);
1809 drop_input_connection ();
1811 // FIXME connections only work for audio-only
1812 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1816 /* first pass: check the current state to see what's correctly
1817 connected, and drop anything that we don't want.
1820 for (uint32_t n = 0; n < limit; ++n) {
1821 const Connection::PortList& pl = c.port_connections (n);
1823 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1825 if (!_inputs.port(n)->connected_to ((*i))) {
1827 /* clear any existing connections */
1829 _session.engine().disconnect (*_inputs.port(n));
1831 } else if (_inputs.port(n)->connected() > 1) {
1833 /* OK, it is connected to the port we want,
1834 but its also connected to other ports.
1835 Change that situation.
1838 /* XXX could be optimized to not drop
1842 _session.engine().disconnect (*_inputs.port(n));
1848 /* second pass: connect all requested ports where necessary */
1850 for (uint32_t n = 0; n < limit; ++n) {
1851 const Connection::PortList& pl = c.port_connections (n);
1853 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1855 if (!_inputs.port(n)->connected_to ((*i))) {
1857 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1865 _input_connection = &c;
1867 input_connection_configuration_connection = c.ConfigurationChanged.connect
1868 (mem_fun (*this, &IO::input_connection_configuration_changed));
1869 input_connection_connection_connection = c.ConnectionsChanged.connect
1870 (mem_fun (*this, &IO::input_connection_connection_changed));
1873 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1878 IO::use_output_connection (Connection& c, void* src)
1883 Glib::Mutex::Lock lm (_session.engine().process_lock());
1884 Glib::Mutex::Lock lm2 (io_lock);
1888 drop_output_connection ();
1890 // FIXME: audio-only
1891 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1895 /* first pass: check the current state to see what's correctly
1896 connected, and drop anything that we don't want.
1899 for (uint32_t n = 0; n < limit; ++n) {
1901 const Connection::PortList& pl = c.port_connections (n);
1903 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1905 if (!_outputs.port(n)->connected_to ((*i))) {
1907 /* clear any existing connections */
1909 _session.engine().disconnect (*_outputs.port(n));
1911 } else if (_outputs.port(n)->connected() > 1) {
1913 /* OK, it is connected to the port we want,
1914 but its also connected to other ports.
1915 Change that situation.
1918 /* XXX could be optimized to not drop
1922 _session.engine().disconnect (*_outputs.port(n));
1927 /* second pass: connect all requested ports where necessary */
1929 for (uint32_t n = 0; n < limit; ++n) {
1931 const Connection::PortList& pl = c.port_connections (n);
1933 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1935 if (!_outputs.port(n)->connected_to ((*i))) {
1937 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
1944 _output_connection = &c;
1946 output_connection_configuration_connection = c.ConfigurationChanged.connect
1947 (mem_fun (*this, &IO::output_connection_configuration_changed));
1948 output_connection_connection_connection = c.ConnectionsChanged.connect
1949 (mem_fun (*this, &IO::output_connection_connection_changed));
1952 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
1958 IO::disable_connecting ()
1960 connecting_legal = false;
1965 IO::enable_connecting ()
1967 connecting_legal = true;
1968 return ConnectingLegal ();
1972 IO::disable_ports ()
1974 ports_legal = false;
1982 return PortsLegal ();
1986 IO::disable_panners (void)
1988 panners_legal = false;
1993 IO::reset_panners ()
1995 panners_legal = true;
1996 return PannersLegal ();
2000 IO::input_connection_connection_changed (int ignored)
2002 use_input_connection (*_input_connection, this);
2006 IO::input_connection_configuration_changed ()
2008 use_input_connection (*_input_connection, this);
2012 IO::output_connection_connection_changed (int ignored)
2014 use_output_connection (*_output_connection, this);
2018 IO::output_connection_configuration_changed ()
2020 use_output_connection (*_output_connection, this);
2024 IO::GainControllable::set_value (float val)
2026 io.set_gain (direct_control_to_gain (val), this);
2030 IO::GainControllable::get_value (void) const
2032 return direct_gain_to_control (io.effective_gain());
2036 IO::get_memento() const
2038 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2042 IO::restore_state (StateManager::State& state)
2047 StateManager::State*
2048 IO::state_factory (std::string why) const
2050 StateManager::State* state = new StateManager::State (why);
2055 IO::setup_peak_meters()
2057 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2061 Update the peak meters.
2063 The meter signal lock is taken to prevent modification of the
2064 Meter signal while updating the meters, taking the meter signal
2065 lock prior to taking the io_lock ensures that all IO will remain
2066 valid while metering.
2071 Glib::Mutex::Lock guard (m_meter_signal_lock);
2073 Meter(); /* EMIT SIGNAL */
2079 // FIXME: Remove this function and just connect signal directly to PeakMeter::meter
2081 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2086 IO::save_automation (const string& path)
2091 fullpath = _session.automation_dir();
2094 out.open (fullpath.c_str());
2097 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2101 out << X_("version ") << current_automation_version_number << endl;
2103 /* XXX use apply_to_points to get thread safety */
2105 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2106 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2115 IO::load_automation (const string& path)
2120 uint32_t linecnt = 0;
2122 LocaleGuard lg (X_("POSIX"));
2124 fullpath = _session.automation_dir();
2127 in.open (fullpath.c_str());
2130 fullpath = _session.automation_dir();
2131 fullpath += _session.snap_name();
2134 in.open (fullpath.c_str());
2136 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2141 clear_automation ();
2143 while (in.getline (line, sizeof(line), '\n')) {
2145 jack_nframes_t when;
2148 if (++linecnt == 1) {
2149 if (memcmp (line, "version", 7) == 0) {
2150 if (sscanf (line, "version %f", &version) != 1) {
2151 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2155 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2159 if (version != current_automation_version_number) {
2160 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2167 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2168 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2174 _gain_automation_curve.add (when, value, true);
2184 /* older (pre-1.0) versions of ardour used this */
2188 warning << _("dubious automation event found (and ignored)") << endmsg;
2192 _gain_automation_curve.save_state (_("loaded from disk"));
2198 IO::clear_automation ()
2200 Glib::Mutex::Lock lm (automation_lock);
2201 _gain_automation_curve.clear ();
2202 _panner->clear_automation ();
2206 IO::set_gain_automation_state (AutoState state)
2208 bool changed = false;
2211 Glib::Mutex::Lock lm (automation_lock);
2213 if (state != _gain_automation_curve.automation_state()) {
2215 last_automation_snapshot = 0;
2216 _gain_automation_curve.set_automation_state (state);
2219 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2225 _session.set_dirty ();
2226 gain_automation_state_changed (); /* EMIT SIGNAL */
2231 IO::set_gain_automation_style (AutoStyle style)
2233 bool changed = false;
2236 Glib::Mutex::Lock lm (automation_lock);
2238 if (style != _gain_automation_curve.automation_style()) {
2240 _gain_automation_curve.set_automation_style (style);
2245 gain_automation_style_changed (); /* EMIT SIGNAL */
2249 IO::inc_gain (gain_t factor, void *src)
2251 if (_desired_gain == 0.0f)
2252 set_gain (0.000001f + (0.000001f * factor), src);
2254 set_gain (_desired_gain + (_desired_gain * factor), src);
2258 IO::set_gain (gain_t val, void *src)
2260 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2261 if (val>1.99526231f) val=1.99526231f;
2264 Glib::Mutex::Lock dm (declick_lock);
2265 _desired_gain = val;
2268 if (_session.transport_stopped()) {
2269 _effective_gain = val;
2274 _gain_control.Changed (); /* EMIT SIGNAL */
2276 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2277 _gain_automation_curve.add (_session.transport_frame(), val);
2281 _session.set_dirty();
2285 IO::start_gain_touch ()
2287 _gain_automation_curve.start_touch ();
2291 IO::end_gain_touch ()
2293 _gain_automation_curve.stop_touch ();
2297 IO::start_pan_touch (uint32_t which)
2299 if (which < _panner->size()) {
2300 (*_panner)[which]->automation().start_touch();
2305 IO::end_pan_touch (uint32_t which)
2307 if (which < _panner->size()) {
2308 (*_panner)[which]->automation().stop_touch();
2314 IO::automation_snapshot (jack_nframes_t now)
2316 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2318 if (gain_automation_recording()) {
2319 _gain_automation_curve.rt_add (now, gain());
2322 _panner->snapshot (now);
2324 last_automation_snapshot = now;
2329 IO::transport_stopped (jack_nframes_t frame)
2331 _gain_automation_curve.reposition_for_rt_add (frame);
2333 if (_gain_automation_curve.automation_state() != Off) {
2335 if (gain_automation_recording()) {
2336 _gain_automation_curve.save_state (_("automation write/touch"));
2339 /* the src=0 condition is a special signal to not propagate
2340 automation gain changes into the mix group when locating.
2343 set_gain (_gain_automation_curve.eval (frame), 0);
2346 _panner->transport_stopped (frame);
2350 IO::find_input_port_hole ()
2352 /* CALLER MUST HOLD IO LOCK */
2356 if (_inputs.empty()) {
2360 for (n = 1; n < UINT_MAX; ++n) {
2361 char buf[jack_port_name_size()];
2362 PortSet::iterator i = _inputs.begin();
2364 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2366 for ( ; i != _inputs.end(); ++i) {
2367 if (i->short_name() == buf) {
2372 if (i == _inputs.end()) {
2380 IO::find_output_port_hole ()
2382 /* CALLER MUST HOLD IO LOCK */
2386 if (_outputs.empty()) {
2390 for (n = 1; n < UINT_MAX; ++n) {
2391 char buf[jack_port_name_size()];
2392 PortSet::iterator i = _outputs.begin();
2394 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2396 for ( ; i != _outputs.end(); ++i) {
2397 if (i->short_name() == buf) {
2402 if (i == _outputs.end()) {
2411 IO::audio_input(uint32_t n) const
2413 return dynamic_cast<AudioPort*>(input(n));
2417 IO::audio_output(uint32_t n) const
2419 return dynamic_cast<AudioPort*>(output(n));
2423 IO::midi_input(uint32_t n) const
2425 return dynamic_cast<MidiPort*>(input(n));
2429 IO::midi_output(uint32_t n) const
2431 return dynamic_cast<MidiPort*>(output(n));
2435 IO::set_phase_invert (bool yn, void *src)
2437 if (_phase_invert != yn) {
2440 // phase_invert_changed (src); /* EMIT SIGNAL */