2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <sigc++/bind.h>
27 #include <glibmm/thread.h>
29 #include <pbd/xml++.h>
31 #include <ardour/audioengine.h>
32 #include <ardour/io.h>
33 #include <ardour/port.h>
34 #include <ardour/audio_port.h>
35 #include <ardour/midi_port.h>
36 #include <ardour/connection.h>
37 #include <ardour/session.h>
38 #include <ardour/cycle_timer.h>
39 #include <ardour/panner.h>
40 #include <ardour/buffer_set.h>
41 #include <ardour/meter.h>
42 #include <ardour/amp.h>
49 A bug in OS X's cmath that causes isnan() and isinf() to be
50 "undeclared". the following works around that
53 #if defined(__APPLE__) && defined(__MACH__)
54 extern "C" int isnan (double);
55 extern "C" int isinf (double);
58 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
61 using namespace ARDOUR;
64 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 (X_("gaincontrol"), *this),
108 _gain_automation_curve (0.0, 2.0, 1.0),
109 _input_minimum (ChanCount::ZERO),
110 _input_maximum (ChanCount::INFINITE),
111 _output_minimum (ChanCount::ZERO),
112 _output_maximum (ChanCount::INFINITE)
114 _panner = new Panner (name, _session);
115 _meter = new PeakMeter (_session);
118 _input_minimum = ChanCount(_default_type, input_min);
120 if (input_max >= 0) {
121 _input_maximum = ChanCount(_default_type, input_max);
123 if (output_min > 0) {
124 _output_minimum = ChanCount(_default_type, output_min);
126 if (output_max >= 0) {
127 _output_maximum = ChanCount(_default_type, output_max);
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));
156 _session.add_controllable (&_gain_control);
159 IO::IO (Session& s, const XMLNode& node, DataType dt)
161 _output_buffers(new BufferSet()),
163 _gain_control (X_("gaincontrol"), *this),
164 _gain_automation_curve (0, 0, 0) // all reset in set_state()
167 _meter = new PeakMeter (_session);
171 no_panner_reset = false;
174 _input_connection = 0;
175 _output_connection = 0;
177 apply_gain_automation = false;
182 // IO::Meter is emitted from another thread so the
183 // Meter signal must be protected.
184 Glib::Mutex::Lock guard (m_meter_signal_lock);
185 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
188 // Connect to our own MoreChannels signal to connect output buffers
189 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
191 _session.add_controllable (&_gain_control);
196 Glib::Mutex::Lock guard (m_meter_signal_lock);
198 Glib::Mutex::Lock lm (io_lock);
200 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
201 _session.engine().unregister_port (*i);
204 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
205 _session.engine().unregister_port (*i);
208 m_meter_connection.disconnect();
212 delete _output_buffers;
216 IO::silence (nframes_t nframes, nframes_t offset)
218 /* io_lock, not taken: function must be called from Session::process() calltree */
220 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
221 i->get_buffer().silence (nframes, offset);
225 /** Deliver bufs to the IO's Jack outputs.
227 * This function should automatically do whatever it necessary to correctly deliver bufs
228 * to the outputs, eg applying gain or pan or whatever else needs to be done.
231 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
233 // FIXME: type specific code doesn't actually need to be here, it will go away in time
235 /* ********** AUDIO ********** */
237 // Apply gain if gain automation isn't playing
238 if ( ! apply_gain_automation) {
240 gain_t dg = _gain; // desired gain
243 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
251 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
254 // Use the panner to distribute audio to output port buffers
255 if (_panner && !_panner->empty() && !_panner->bypassed()) {
256 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
258 const DataType type = DataType::AUDIO;
260 // Copy any audio 1:1 to outputs
261 assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
262 BufferSet::iterator o = output_buffers().begin(type);
263 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
264 o->read_from(*i, nframes, offset);
269 /* ********** MIDI ********** */
271 // No MIDI, we're done here
272 if (bufs.count().get(DataType::MIDI) == 0) {
276 const DataType type = DataType::MIDI;
278 // Copy any MIDI 1:1 to outputs
279 assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
280 BufferSet::iterator o = output_buffers().begin(type);
281 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
282 o->read_from(*i, nframes, offset);
287 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
289 assert(outs.available() >= n_inputs());
291 outs.set_count(n_inputs());
293 if (outs.count() == ChanCount::ZERO)
296 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
298 BufferSet::iterator o = outs.begin(*t);
299 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
300 o->read_from(i->get_buffer(), nframes, offset);
307 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
308 nframes_t nframes, nframes_t offset)
310 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
312 collect_input (bufs, nframes, offset);
314 _meter->run(bufs, nframes);
318 IO::drop_input_connection ()
320 _input_connection = 0;
321 input_connection_configuration_connection.disconnect();
322 input_connection_connection_connection.disconnect();
323 _session.set_dirty ();
327 IO::drop_output_connection ()
329 _output_connection = 0;
330 output_connection_configuration_connection.disconnect();
331 output_connection_connection_connection.disconnect();
332 _session.set_dirty ();
336 IO::disconnect_input (Port* our_port, string other_port, void* src)
338 if (other_port.length() == 0 || our_port == 0) {
343 BLOCK_PROCESS_CALLBACK ();
346 Glib::Mutex::Lock lm (io_lock);
348 /* check that our_port is really one of ours */
350 if ( ! _inputs.contains(our_port)) {
354 /* disconnect it from the source */
356 if (_session.engine().disconnect (other_port, our_port->name())) {
357 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
361 drop_input_connection();
365 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
366 _session.set_dirty ();
372 IO::connect_input (Port* our_port, string other_port, void* src)
374 if (other_port.length() == 0 || our_port == 0) {
379 BLOCK_PROCESS_CALLBACK ();
382 Glib::Mutex::Lock lm (io_lock);
384 /* check that our_port is really one of ours */
386 if ( ! _inputs.contains(our_port) ) {
390 /* connect it to the source */
392 if (_session.engine().connect (other_port, our_port->name())) {
396 drop_input_connection ();
400 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
401 _session.set_dirty ();
406 IO::disconnect_output (Port* our_port, string other_port, void* src)
408 if (other_port.length() == 0 || our_port == 0) {
413 BLOCK_PROCESS_CALLBACK ();
416 Glib::Mutex::Lock lm (io_lock);
418 /* check that our_port is really one of ours */
420 if ( ! _outputs.contains(our_port) ) {
424 /* disconnect it from the destination */
426 if (_session.engine().disconnect (our_port->name(), other_port)) {
427 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
431 drop_output_connection ();
435 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
436 _session.set_dirty ();
441 IO::connect_output (Port* our_port, string other_port, void* src)
443 if (other_port.length() == 0 || our_port == 0) {
448 BLOCK_PROCESS_CALLBACK ();
452 Glib::Mutex::Lock lm (io_lock);
454 /* check that our_port is really one of ours */
456 if ( ! _outputs.contains(our_port) ) {
460 /* connect it to the destination */
462 if (_session.engine().connect (our_port->name(), other_port)) {
466 drop_output_connection ();
470 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
471 _session.set_dirty ();
476 IO::set_input (Port* other_port, void* src)
478 /* this removes all but one ports, and connects that one port
479 to the specified source.
482 if (_input_minimum.get_total() > 1) {
483 /* sorry, you can't do this */
487 if (other_port == 0) {
488 if (_input_minimum == ChanCount::ZERO) {
489 return ensure_inputs (ChanCount::ZERO, false, true, src);
495 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
499 return connect_input (_inputs.port(0), other_port->name(), src);
503 IO::remove_output_port (Port* port, void* src)
505 IOChange change (NoChange);
508 BLOCK_PROCESS_CALLBACK ();
512 Glib::Mutex::Lock lm (io_lock);
514 if (n_outputs() <= _output_minimum) {
515 /* sorry, you can't do this */
519 if (_outputs.remove(port)) {
520 change = IOChange (change|ConfigurationChanged);
522 if (port->connected()) {
523 change = IOChange (change|ConnectionsChanged);
526 _session.engine().unregister_port (*port);
527 drop_output_connection ();
529 setup_peak_meters ();
535 if (change != NoChange) {
536 output_changed (change, src);
537 _session.set_dirty ();
544 /** Add an output port.
546 * @param destination Name of input port to connect new port to.
547 * @param src Source for emitted ConfigurationChanged signal.
548 * @param type Data type of port. Default value (NIL) will use this IO's default type.
551 IO::add_output_port (string destination, void* src, DataType type)
556 if (type == DataType::NIL)
557 type = _default_type;
560 BLOCK_PROCESS_CALLBACK ();
564 Glib::Mutex::Lock lm (io_lock);
566 if (n_outputs() >= _output_maximum) {
570 /* Create a new output port */
572 // FIXME: naming scheme for differently typed ports?
573 if (_output_maximum.get(type) == 1) {
574 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
576 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
579 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
580 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
584 _outputs.add (our_port);
585 drop_output_connection ();
586 setup_peak_meters ();
590 MoreChannels (n_outputs()); /* EMIT SIGNAL */
593 if (destination.length()) {
594 if (_session.engine().connect (our_port->name(), destination)) {
599 // pan_changed (src); /* EMIT SIGNAL */
600 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
601 _session.set_dirty ();
607 IO::remove_input_port (Port* port, void* src)
609 IOChange change (NoChange);
612 BLOCK_PROCESS_CALLBACK ();
616 Glib::Mutex::Lock lm (io_lock);
618 if (n_inputs() <= _input_minimum) {
619 /* sorry, you can't do this */
623 if (_inputs.remove(port)) {
624 change = IOChange (change|ConfigurationChanged);
626 if (port->connected()) {
627 change = IOChange (change|ConnectionsChanged);
630 _session.engine().unregister_port (*port);
631 drop_input_connection ();
633 setup_peak_meters ();
639 if (change != NoChange) {
640 input_changed (change, src);
641 _session.set_dirty ();
649 /** Add an input port.
651 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
652 * @param destination Name of input port to connect new port to.
653 * @param src Source for emitted ConfigurationChanged signal.
656 IO::add_input_port (string source, void* src, DataType type)
661 if (type == DataType::NIL)
662 type = _default_type;
665 BLOCK_PROCESS_CALLBACK ();
668 Glib::Mutex::Lock lm (io_lock);
670 if (n_inputs() >= _input_maximum) {
674 /* Create a new input port */
676 // FIXME: naming scheme for differently typed ports?
677 if (_input_maximum.get(type) == 1) {
678 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
680 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
683 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
684 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
688 _inputs.add (our_port);
689 drop_input_connection ();
690 setup_peak_meters ();
694 MoreChannels (n_inputs()); /* EMIT SIGNAL */
697 if (source.length()) {
699 if (_session.engine().connect (source, our_port->name())) {
704 // pan_changed (src); /* EMIT SIGNAL */
705 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
706 _session.set_dirty ();
712 IO::disconnect_inputs (void* src)
715 BLOCK_PROCESS_CALLBACK ();
718 Glib::Mutex::Lock lm (io_lock);
720 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
721 _session.engine().disconnect (*i);
724 drop_input_connection ();
728 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
734 IO::disconnect_outputs (void* src)
737 BLOCK_PROCESS_CALLBACK ();
740 Glib::Mutex::Lock lm (io_lock);
742 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
743 _session.engine().disconnect (*i);
746 drop_output_connection ();
750 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
751 _session.set_dirty ();
757 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
759 Port* input_port = 0;
760 bool changed = false;
763 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
765 const size_t n = count.get(*t);
767 /* remove unused ports */
768 for (size_t i = n_inputs().get(*t); i > n; --i) {
769 input_port = _inputs.port(*t, i-1);
772 _inputs.remove(input_port);
773 _session.engine().unregister_port (*input_port);
778 /* create any necessary new ports */
779 while (n_inputs().get(*t) < n) {
783 if (_input_maximum.get(*t) == 1) {
784 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
786 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
791 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
792 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
797 catch (AudioEngine::PortRegistrationFailure& err) {
798 setup_peak_meters ();
801 throw AudioEngine::PortRegistrationFailure();
804 _inputs.add (input_port);
810 drop_input_connection ();
811 setup_peak_meters ();
813 MoreChannels (n_inputs()); /* EMIT SIGNAL */
814 _session.set_dirty ();
818 /* disconnect all existing ports so that we get a fresh start */
819 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
820 _session.engine().disconnect (*i);
827 /** Attach output_buffers to port buffers.
829 * Connected to IO's own MoreChannels signal.
832 IO::attach_buffers(ChanCount ignored)
834 _output_buffers->attach_buffers(_outputs);
838 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
840 bool in_changed = false;
841 bool out_changed = false;
842 bool need_pan_reset = false;
844 in = min (_input_maximum, in);
846 out = min (_output_maximum, out);
848 if (in == n_inputs() && out == n_outputs() && !clear) {
853 BLOCK_PROCESS_CALLBACK ();
854 Glib::Mutex::Lock lm (io_lock);
858 if (n_outputs() != out) {
859 need_pan_reset = true;
862 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
864 const size_t nin = in.get(*t);
865 const size_t nout = out.get(*t);
867 Port* output_port = 0;
868 Port* input_port = 0;
870 /* remove unused output ports */
871 for (size_t i = n_outputs().get(*t); i > nout; --i) {
872 output_port = _outputs.port(*t, i-1);
875 _outputs.remove(output_port);
876 _session.engine().unregister_port (*output_port);
881 /* remove unused input ports */
882 for (size_t i = n_inputs().get(*t); i > nin; --i) {
883 input_port = _inputs.port(*t, i-1);
886 _inputs.remove(input_port);
887 _session.engine().unregister_port (*input_port);
892 /* create any necessary new input ports */
894 while (n_inputs().get(*t) < nin) {
898 /* Create a new input port */
900 if (_input_maximum.get(*t) == 1) {
901 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
903 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
907 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
908 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
913 catch (AudioEngine::PortRegistrationFailure& err) {
914 setup_peak_meters ();
917 throw AudioEngine::PortRegistrationFailure();
924 /* create any necessary new output ports */
926 while (n_outputs().get(*t) < nout) {
930 /* Create a new output port */
932 if (_output_maximum.get(*t) == 1) {
933 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
935 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
939 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
940 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
945 catch (AudioEngine::PortRegistrationFailure& err) {
946 setup_peak_meters ();
949 throw AudioEngine::PortRegistrationFailure ();
959 /* disconnect all existing ports so that we get a fresh start */
961 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
962 _session.engine().disconnect (*i);
965 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
966 _session.engine().disconnect (*i);
970 if (in_changed || out_changed) {
971 setup_peak_meters ();
977 drop_output_connection ();
978 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
982 drop_input_connection ();
983 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
986 if (in_changed || out_changed) {
987 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
988 _session.set_dirty ();
995 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
997 bool changed = false;
999 count = min (_input_maximum, count);
1001 if (count == n_inputs() && !clear) {
1006 BLOCK_PROCESS_CALLBACK ();
1007 Glib::Mutex::Lock im (io_lock);
1008 changed = ensure_inputs_locked (count, clear, src);
1010 changed = ensure_inputs_locked (count, clear, src);
1014 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1015 _session.set_dirty ();
1021 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1023 Port* output_port = 0;
1024 bool changed = false;
1025 bool need_pan_reset = false;
1027 if (n_outputs() != count) {
1028 need_pan_reset = true;
1031 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1033 const size_t n = count.get(*t);
1035 /* remove unused ports */
1036 for (size_t i = n_outputs().get(*t); i > n; --i) {
1037 output_port = _outputs.port(*t, i-1);
1039 assert(output_port);
1040 _outputs.remove(output_port);
1041 _session.engine().unregister_port (*output_port);
1046 /* create any necessary new ports */
1047 while (n_outputs().get(*t) < n) {
1051 if (_output_maximum.get(*t) == 1) {
1052 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1054 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1057 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1058 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1062 _outputs.add (output_port);
1064 setup_peak_meters ();
1066 if (need_pan_reset) {
1073 drop_output_connection ();
1074 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1075 _session.set_dirty ();
1079 /* disconnect all existing ports so that we get a fresh start */
1080 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1081 _session.engine().disconnect (*i);
1089 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1091 bool changed = false;
1093 if (_output_maximum < ChanCount::INFINITE) {
1094 count = min (_output_maximum, count);
1095 if (count == n_outputs() && !clear) {
1100 /* XXX caller should hold io_lock, but generally doesn't */
1103 BLOCK_PROCESS_CALLBACK ();
1104 Glib::Mutex::Lock im (io_lock);
1105 changed = ensure_outputs_locked (count, clear, src);
1107 changed = ensure_outputs_locked (count, clear, src);
1111 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1118 IO::effective_gain () const
1120 if (gain_automation_playback()) {
1121 return _effective_gain;
1123 return _desired_gain;
1130 if (panners_legal) {
1131 if (!no_panner_reset) {
1132 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1135 panner_legal_c.disconnect ();
1136 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1141 IO::panners_became_legal ()
1143 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1144 _panner->load (); // automation
1145 panner_legal_c.disconnect ();
1150 IO::defer_pan_reset ()
1152 no_panner_reset = true;
1156 IO::allow_pan_reset ()
1158 no_panner_reset = false;
1164 IO::get_state (void)
1166 return state (true);
1170 IO::state (bool full_state)
1172 XMLNode* node = new XMLNode (state_node_name);
1175 bool need_ins = true;
1176 bool need_outs = true;
1177 LocaleGuard lg (X_("POSIX"));
1178 Glib::Mutex::Lock lm (io_lock);
1180 node->add_property("name", _name);
1181 id().print (buf, sizeof (buf));
1182 node->add_property("id", buf);
1186 if (_input_connection) {
1187 node->add_property ("input-connection", _input_connection->name());
1191 if (_output_connection) {
1192 node->add_property ("output-connection", _output_connection->name());
1197 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1199 const char **connections = i->get_connections();
1201 if (connections && connections[0]) {
1204 for (int n = 0; connections && connections[n]; ++n) {
1209 /* if its a connection to our own port,
1210 return only the port name, not the
1211 whole thing. this allows connections
1212 to be re-established even when our
1213 client name is different.
1216 str += _session.engine().make_port_name_relative (connections[n]);
1228 node->add_property ("inputs", str);
1234 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1236 const char **connections = i->get_connections();
1238 if (connections && connections[0]) {
1242 for (int n = 0; connections[n]; ++n) {
1247 str += _session.engine().make_port_name_relative (connections[n]);
1259 node->add_property ("outputs", str);
1262 node->add_child_nocopy (_panner->state (full_state));
1263 node->add_child_nocopy (_gain_control.get_state ());
1265 snprintf (buf, sizeof(buf), "%2.12f", gain());
1266 node->add_property ("gain", buf);
1268 // FIXME: this is NOT sufficient!
1269 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1270 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1271 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1272 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1274 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1276 node->add_property ("iolimits", buf);
1282 XMLNode* autonode = new XMLNode (X_("Automation"));
1283 autonode->add_child_nocopy (get_automation_state());
1284 node->add_child_nocopy (*autonode);
1286 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1288 /* never store anything except Off for automation state in a template */
1289 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1296 IO::set_state (const XMLNode& node)
1298 const XMLProperty* prop;
1299 XMLNodeConstIterator iter;
1300 LocaleGuard lg (X_("POSIX"));
1302 /* force use of non-localized representation of decimal point,
1303 since we use it a lot in XML files and so forth.
1306 if (node.name() != state_node_name) {
1307 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1311 if ((prop = node.property ("name")) != 0) {
1312 _name = prop->value();
1313 /* used to set panner name with this, but no more */
1316 if ((prop = node.property ("id")) != 0) {
1317 _id = prop->value ();
1322 size_t out_min = -1;
1323 size_t out_max = -1;
1325 if ((prop = node.property ("iolimits")) != 0) {
1326 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1327 &in_min, &in_max, &out_min, &out_max);
1328 _input_minimum = ChanCount(_default_type, in_min);
1329 _input_maximum = ChanCount(_default_type, in_max);
1330 _output_minimum = ChanCount(_default_type, out_min);
1331 _output_maximum = ChanCount(_default_type, out_max);
1334 if ((prop = node.property ("gain")) != 0) {
1335 set_gain (atof (prop->value().c_str()), this);
1336 _gain = _desired_gain;
1339 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1340 /* old school automation handling */
1343 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1345 if ((*iter)->name() == "Panner") {
1347 _panner = new Panner (_name, _session);
1349 _panner->set_state (**iter);
1352 if ((*iter)->name() == X_("Automation")) {
1354 set_automation_state (*(*iter)->children().front());
1357 if ((*iter)->name() == X_("gaincontrol")) {
1358 _gain_control.set_state (**iter);
1364 if (create_ports (node)) {
1370 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1373 if (panners_legal) {
1376 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1379 if (connecting_legal) {
1381 if (make_connections (node)) {
1387 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1390 if (!ports_legal || !connecting_legal) {
1391 pending_state_node = new XMLNode (node);
1394 last_automation_snapshot = 0;
1400 IO::set_automation_state (const XMLNode& node)
1402 return _gain_automation_curve.set_state (node);
1406 IO::get_automation_state ()
1408 return (_gain_automation_curve.get_state ());
1412 IO::load_automation (string path)
1417 uint32_t linecnt = 0;
1419 LocaleGuard lg (X_("POSIX"));
1421 fullpath = _session.automation_dir();
1424 in.open (fullpath.c_str());
1427 fullpath = _session.automation_dir();
1428 fullpath += _session.snap_name();
1432 in.open (fullpath.c_str());
1435 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1440 clear_automation ();
1442 while (in.getline (line, sizeof(line), '\n')) {
1444 jack_nframes_t when;
1447 if (++linecnt == 1) {
1448 if (memcmp (line, "version", 7) == 0) {
1449 if (sscanf (line, "version %f", &version) != 1) {
1450 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1454 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1461 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1462 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1468 _gain_automation_curve.fast_simple_add (when, value);
1478 /* older (pre-1.0) versions of ardour used this */
1482 warning << _("dubious automation event found (and ignored)") << endmsg;
1490 IO::connecting_became_legal ()
1494 if (pending_state_node == 0) {
1495 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1500 connection_legal_c.disconnect ();
1502 ret = make_connections (*pending_state_node);
1505 delete pending_state_node;
1506 pending_state_node = 0;
1512 IO::ports_became_legal ()
1516 if (pending_state_node == 0) {
1517 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1522 port_legal_c.disconnect ();
1524 ret = create_ports (*pending_state_node);
1526 if (connecting_legal) {
1527 delete pending_state_node;
1528 pending_state_node = 0;
1535 IO::create_ports (const XMLNode& node)
1537 const XMLProperty* prop;
1539 int num_outputs = 0;
1541 if ((prop = node.property ("input-connection")) != 0) {
1543 Connection* c = _session.connection_by_name (prop->value());
1546 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1548 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1549 error << _("No input connections available as a replacement")
1553 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1558 num_inputs = c->nports();
1560 } else if ((prop = node.property ("inputs")) != 0) {
1562 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1565 if ((prop = node.property ("output-connection")) != 0) {
1566 Connection* c = _session.connection_by_name (prop->value());
1569 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1571 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1572 error << _("No output connections available as a replacement")
1576 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1581 num_outputs = c->nports ();
1583 } else if ((prop = node.property ("outputs")) != 0) {
1584 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1587 no_panner_reset = true;
1589 // FIXME: audio-only
1590 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1591 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1595 no_panner_reset = false;
1597 set_deferred_state ();
1605 IO::make_connections (const XMLNode& node)
1607 const XMLProperty* prop;
1609 if ((prop = node.property ("input-connection")) != 0) {
1610 Connection* c = _session.connection_by_name (prop->value());
1613 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1615 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1616 error << _("No input connections available as a replacement")
1620 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1625 use_input_connection (*c, this);
1627 } else if ((prop = node.property ("inputs")) != 0) {
1628 if (set_inputs (prop->value())) {
1629 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1634 if ((prop = node.property ("output-connection")) != 0) {
1635 Connection* c = _session.connection_by_name (prop->value());
1638 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1640 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1641 error << _("No output connections available as a replacement")
1645 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1650 use_output_connection (*c, this);
1652 } else if ((prop = node.property ("outputs")) != 0) {
1653 if (set_outputs (prop->value())) {
1654 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1663 IO::set_inputs (const string& str)
1665 vector<string> ports;
1670 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1674 // FIXME: audio-only
1675 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1679 string::size_type start, end, ostart;
1686 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1689 if ((end = str.find_first_of ('}', start)) == string::npos) {
1690 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1694 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1695 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1701 for (int x = 0; x < n; ++x) {
1702 connect_input (input (i), ports[x], this);
1714 IO::set_outputs (const string& str)
1716 vector<string> ports;
1721 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1725 // FIXME: audio-only
1726 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1730 string::size_type start, end, ostart;
1737 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1740 if ((end = str.find_first_of ('}', start)) == string::npos) {
1741 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1745 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1746 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1752 for (int x = 0; x < n; ++x) {
1753 connect_output (output (i), ports[x], this);
1765 IO::parse_io_string (const string& str, vector<string>& ports)
1767 string::size_type pos, opos;
1769 if (str.length() == 0) {
1778 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1779 ports.push_back (str.substr (opos, pos - opos));
1783 if (opos < str.length()) {
1784 ports.push_back (str.substr(opos));
1787 return ports.size();
1791 IO::parse_gain_string (const string& str, vector<string>& ports)
1793 string::size_type pos, opos;
1799 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1800 ports.push_back (str.substr (opos, pos - opos));
1804 if (opos < str.length()) {
1805 ports.push_back (str.substr(opos));
1808 return ports.size();
1812 IO::set_name (string name, void* src)
1814 if (name == _name) {
1818 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1819 string current_name = i->short_name();
1820 current_name.replace (current_name.find (_name), _name.length(), name);
1821 i->set_name (current_name);
1824 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1825 string current_name = i->short_name();
1826 current_name.replace (current_name.find (_name), _name.length(), name);
1827 i->set_name (current_name);
1831 name_changed (src); /* EMIT SIGNAL */
1837 IO::set_input_minimum (ChanCount n)
1843 IO::set_input_maximum (ChanCount n)
1849 IO::set_output_minimum (ChanCount n)
1851 _output_minimum = n;
1855 IO::set_output_maximum (ChanCount n)
1857 _output_maximum = n;
1861 IO::set_port_latency (nframes_t nframes)
1863 Glib::Mutex::Lock lm (io_lock);
1865 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1866 i->set_latency (nframes);
1871 IO::output_latency () const
1873 nframes_t max_latency;
1878 /* io lock not taken - must be protected by other means */
1880 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1881 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1882 max_latency = latency;
1890 IO::input_latency () const
1892 nframes_t max_latency;
1897 /* io lock not taken - must be protected by other means */
1899 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1900 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1901 max_latency = latency;
1909 IO::use_input_connection (Connection& c, void* src)
1914 BLOCK_PROCESS_CALLBACK ();
1915 Glib::Mutex::Lock lm2 (io_lock);
1919 drop_input_connection ();
1921 // FIXME connections only work for audio-only
1922 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1926 /* first pass: check the current state to see what's correctly
1927 connected, and drop anything that we don't want.
1930 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 (!_inputs.port(n)->connected_to ((*i))) {
1937 /* clear any existing connections */
1939 _session.engine().disconnect (*_inputs.port(n));
1941 } else if (_inputs.port(n)->connected() > 1) {
1943 /* OK, it is connected to the port we want,
1944 but its also connected to other ports.
1945 Change that situation.
1948 /* XXX could be optimized to not drop
1952 _session.engine().disconnect (*_inputs.port(n));
1958 /* second pass: connect all requested ports where necessary */
1960 for (uint32_t n = 0; n < limit; ++n) {
1961 const Connection::PortList& pl = c.port_connections (n);
1963 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1965 if (!_inputs.port(n)->connected_to ((*i))) {
1967 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1975 _input_connection = &c;
1977 input_connection_configuration_connection = c.ConfigurationChanged.connect
1978 (mem_fun (*this, &IO::input_connection_configuration_changed));
1979 input_connection_connection_connection = c.ConnectionsChanged.connect
1980 (mem_fun (*this, &IO::input_connection_connection_changed));
1983 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1988 IO::use_output_connection (Connection& c, void* src)
1993 BLOCK_PROCESS_CALLBACK ();
1994 Glib::Mutex::Lock lm2 (io_lock);
1998 drop_output_connection ();
2000 // FIXME: audio-only
2001 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2005 /* first pass: check the current state to see what's correctly
2006 connected, and drop anything that we don't want.
2009 for (uint32_t n = 0; n < limit; ++n) {
2011 const Connection::PortList& pl = c.port_connections (n);
2013 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2015 if (!_outputs.port(n)->connected_to ((*i))) {
2017 /* clear any existing connections */
2019 _session.engine().disconnect (*_outputs.port(n));
2021 } else if (_outputs.port(n)->connected() > 1) {
2023 /* OK, it is connected to the port we want,
2024 but its also connected to other ports.
2025 Change that situation.
2028 /* XXX could be optimized to not drop
2032 _session.engine().disconnect (*_outputs.port(n));
2037 /* second pass: connect all requested ports where necessary */
2039 for (uint32_t n = 0; n < limit; ++n) {
2041 const Connection::PortList& pl = c.port_connections (n);
2043 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2045 if (!_outputs.port(n)->connected_to ((*i))) {
2047 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2054 _output_connection = &c;
2056 output_connection_configuration_connection = c.ConfigurationChanged.connect
2057 (mem_fun (*this, &IO::output_connection_configuration_changed));
2058 output_connection_connection_connection = c.ConnectionsChanged.connect
2059 (mem_fun (*this, &IO::output_connection_connection_changed));
2062 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2068 IO::disable_connecting ()
2070 connecting_legal = false;
2075 IO::enable_connecting ()
2077 connecting_legal = true;
2078 return ConnectingLegal ();
2082 IO::disable_ports ()
2084 ports_legal = false;
2092 return PortsLegal ();
2096 IO::disable_panners (void)
2098 panners_legal = false;
2103 IO::reset_panners ()
2105 panners_legal = true;
2106 return PannersLegal ();
2110 IO::input_connection_connection_changed (int ignored)
2112 use_input_connection (*_input_connection, this);
2116 IO::input_connection_configuration_changed ()
2118 use_input_connection (*_input_connection, this);
2122 IO::output_connection_connection_changed (int ignored)
2124 use_output_connection (*_output_connection, this);
2128 IO::output_connection_configuration_changed ()
2130 use_output_connection (*_output_connection, this);
2134 IO::GainControllable::set_value (float val)
2136 io.set_gain (direct_control_to_gain (val), this);
2140 IO::GainControllable::get_value (void) const
2142 return direct_gain_to_control (io.effective_gain());
2146 IO::setup_peak_meters()
2148 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2152 Update the peak meters.
2154 The meter signal lock is taken to prevent modification of the
2155 Meter signal while updating the meters, taking the meter signal
2156 lock prior to taking the io_lock ensures that all IO will remain
2157 valid while metering.
2162 Glib::Mutex::Lock guard (m_meter_signal_lock);
2164 Meter(); /* EMIT SIGNAL */
2170 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2172 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2177 IO::clear_automation ()
2179 Glib::Mutex::Lock lm (automation_lock);
2180 _gain_automation_curve.clear ();
2181 _panner->clear_automation ();
2185 IO::set_gain_automation_state (AutoState state)
2187 bool changed = false;
2190 Glib::Mutex::Lock lm (automation_lock);
2192 if (state != _gain_automation_curve.automation_state()) {
2194 last_automation_snapshot = 0;
2195 _gain_automation_curve.set_automation_state (state);
2198 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2204 _session.set_dirty ();
2205 gain_automation_state_changed (); /* EMIT SIGNAL */
2210 IO::set_gain_automation_style (AutoStyle style)
2212 bool changed = false;
2215 Glib::Mutex::Lock lm (automation_lock);
2217 if (style != _gain_automation_curve.automation_style()) {
2219 _gain_automation_curve.set_automation_style (style);
2224 gain_automation_style_changed (); /* EMIT SIGNAL */
2228 IO::inc_gain (gain_t factor, void *src)
2230 if (_desired_gain == 0.0f)
2231 set_gain (0.000001f + (0.000001f * factor), src);
2233 set_gain (_desired_gain + (_desired_gain * factor), src);
2237 IO::set_gain (gain_t val, void *src)
2239 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2240 if (val>1.99526231f) val=1.99526231f;
2243 Glib::Mutex::Lock dm (declick_lock);
2244 _desired_gain = val;
2247 if (_session.transport_stopped()) {
2248 _effective_gain = val;
2253 _gain_control.Changed (); /* EMIT SIGNAL */
2255 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2256 _gain_automation_curve.add (_session.transport_frame(), val);
2260 _session.set_dirty();
2264 IO::start_gain_touch ()
2266 _gain_automation_curve.start_touch ();
2270 IO::end_gain_touch ()
2272 _gain_automation_curve.stop_touch ();
2276 IO::start_pan_touch (uint32_t which)
2278 if (which < _panner->size()) {
2279 (*_panner)[which]->automation().start_touch();
2284 IO::end_pan_touch (uint32_t which)
2286 if (which < _panner->size()) {
2287 (*_panner)[which]->automation().stop_touch();
2293 IO::automation_snapshot (nframes_t now)
2295 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2297 if (gain_automation_recording()) {
2298 _gain_automation_curve.rt_add (now, gain());
2301 _panner->snapshot (now);
2303 last_automation_snapshot = now;
2308 IO::transport_stopped (nframes_t frame)
2310 _gain_automation_curve.reposition_for_rt_add (frame);
2312 if (_gain_automation_curve.automation_state() != Off) {
2314 /* the src=0 condition is a special signal to not propagate
2315 automation gain changes into the mix group when locating.
2318 set_gain (_gain_automation_curve.eval (frame), 0);
2321 _panner->transport_stopped (frame);
2325 IO::find_input_port_hole ()
2327 /* CALLER MUST HOLD IO LOCK */
2331 if (_inputs.empty()) {
2335 for (n = 1; n < UINT_MAX; ++n) {
2336 char buf[jack_port_name_size()];
2337 PortSet::iterator i = _inputs.begin();
2339 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2341 for ( ; i != _inputs.end(); ++i) {
2342 if (i->short_name() == buf) {
2347 if (i == _inputs.end()) {
2355 IO::find_output_port_hole ()
2357 /* CALLER MUST HOLD IO LOCK */
2361 if (_outputs.empty()) {
2365 for (n = 1; n < UINT_MAX; ++n) {
2366 char buf[jack_port_name_size()];
2367 PortSet::iterator i = _outputs.begin();
2369 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2371 for ( ; i != _outputs.end(); ++i) {
2372 if (i->short_name() == buf) {
2377 if (i == _outputs.end()) {
2386 IO::audio_input(uint32_t n) const
2388 return dynamic_cast<AudioPort*>(input(n));
2392 IO::audio_output(uint32_t n) const
2394 return dynamic_cast<AudioPort*>(output(n));
2398 IO::midi_input(uint32_t n) const
2400 return dynamic_cast<MidiPort*>(input(n));
2404 IO::midi_output(uint32_t n) const
2406 return dynamic_cast<MidiPort*>(output(n));
2410 IO::set_phase_invert (bool yn, void *src)
2412 if (_phase_invert != yn) {
2415 // phase_invert_changed (src); /* EMIT SIGNAL */