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);
60 using namespace ARDOUR;
63 static float current_automation_version_number = 1.0;
65 const string IO::state_node_name = "IO";
66 bool IO::connecting_legal = false;
67 bool IO::ports_legal = false;
68 bool IO::panners_legal = false;
69 sigc::signal<void> IO::Meter;
70 sigc::signal<int> IO::ConnectingLegal;
71 sigc::signal<int> IO::PortsLegal;
72 sigc::signal<int> IO::PannersLegal;
73 sigc::signal<void,ChanCount> IO::MoreChannels;
74 sigc::signal<int> IO::PortsCreated;
76 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
78 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
79 others can be imagined.
82 static gain_t direct_control_to_gain (double fract) {
83 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
84 /* this maxes at +6dB */
85 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
88 static double direct_gain_to_control (gain_t gain) {
89 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
90 if (gain == 0) return 0.0;
92 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
96 /** @param default_type The type of port that will be created by ensure_io
97 * and friends if no type is explicitly requested (to avoid breakage).
99 IO::IO (Session& s, string name,
100 int input_min, int input_max, int output_min, int output_max,
101 DataType default_type)
103 _output_buffers(new BufferSet()),
105 _default_type(default_type),
106 _gain_control (X_("gaincontrol"), *this),
107 _gain_automation_curve (0.0, 2.0, 1.0),
108 _input_minimum (ChanCount::ZERO),
109 _input_maximum (ChanCount::INFINITE),
110 _output_minimum (ChanCount::ZERO),
111 _output_maximum (ChanCount::INFINITE)
113 _panner = new Panner (name, _session);
114 _meter = new PeakMeter (_session);
117 _input_minimum = ChanCount(_default_type, input_min);
119 if (input_max >= 0) {
120 _input_maximum = ChanCount(_default_type, input_max);
122 if (output_min > 0) {
123 _output_minimum = ChanCount(_default_type, output_min);
125 if (output_max >= 0) {
126 _output_maximum = ChanCount(_default_type, output_max);
131 _input_connection = 0;
132 _output_connection = 0;
133 pending_state_node = 0;
134 no_panner_reset = false;
135 _phase_invert = false;
138 apply_gain_automation = false;
140 _gain_automation_state = Off;
141 _gain_automation_style = Absolute;
144 // IO::Meter is emitted from another thread so the
145 // Meter signal must be protected.
146 Glib::Mutex::Lock guard (m_meter_signal_lock);
147 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
150 // Connect to our own MoreChannels signal to connect output buffers
151 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
156 Glib::Mutex::Lock guard (m_meter_signal_lock);
158 Glib::Mutex::Lock lm (io_lock);
160 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
161 _session.engine().unregister_port (*i);
164 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
165 _session.engine().unregister_port (*i);
168 m_meter_connection.disconnect();
172 delete _output_buffers;
176 IO::silence (nframes_t nframes, nframes_t offset)
178 /* io_lock, not taken: function must be called from Session::process() calltree */
180 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
181 i->get_buffer().silence (nframes, offset);
185 /** Deliver bufs to the IO's Jack outputs.
187 * This function should automatically do whatever it necessary to correctly deliver bufs
188 * to the outputs, eg applying gain or pan or whatever else needs to be done.
191 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
193 // FIXME: type specific code doesn't actually need to be here, it will go away in time
195 /* ********** AUDIO ********** */
197 // Apply gain if gain automation isn't playing
198 if ( ! apply_gain_automation) {
200 gain_t dg = _gain; // desired gain
203 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
211 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
214 // Use the panner to distribute audio to output port buffers
215 if (_panner && !_panner->empty() && !_panner->bypassed()) {
216 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
218 const DataType type = DataType::AUDIO;
220 // Copy any audio 1:1 to outputs
221 assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
222 BufferSet::iterator o = output_buffers().begin(type);
223 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
224 o->read_from(*i, nframes, offset);
229 /* ********** MIDI ********** */
231 // No MIDI, we're done here
232 if (bufs.count().get(DataType::MIDI) == 0) {
236 const DataType type = DataType::MIDI;
238 // Copy any MIDI 1:1 to outputs
239 assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
240 BufferSet::iterator o = output_buffers().begin(type);
241 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
242 o->read_from(*i, nframes, offset);
247 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
249 assert(outs.available() >= n_inputs());
251 outs.set_count(n_inputs());
253 if (outs.count() == ChanCount::ZERO)
256 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
258 BufferSet::iterator o = outs.begin(*t);
259 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
260 o->read_from(i->get_buffer(), nframes, offset);
267 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
268 nframes_t nframes, nframes_t offset)
270 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
272 collect_input (bufs, nframes, offset);
274 _meter->run(bufs, nframes);
278 IO::drop_input_connection ()
280 _input_connection = 0;
281 input_connection_configuration_connection.disconnect();
282 input_connection_connection_connection.disconnect();
283 _session.set_dirty ();
287 IO::drop_output_connection ()
289 _output_connection = 0;
290 output_connection_configuration_connection.disconnect();
291 output_connection_connection_connection.disconnect();
292 _session.set_dirty ();
296 IO::disconnect_input (Port* our_port, string other_port, void* src)
298 if (other_port.length() == 0 || our_port == 0) {
303 Glib::Mutex::Lock em (_session.engine().process_lock());
306 Glib::Mutex::Lock lm (io_lock);
308 /* check that our_port is really one of ours */
310 if ( ! _inputs.contains(our_port)) {
314 /* disconnect it from the source */
316 if (_session.engine().disconnect (other_port, our_port->name())) {
317 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
321 drop_input_connection();
325 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
326 _session.set_dirty ();
332 IO::connect_input (Port* our_port, string other_port, void* src)
334 if (other_port.length() == 0 || our_port == 0) {
339 Glib::Mutex::Lock em(_session.engine().process_lock());
342 Glib::Mutex::Lock lm (io_lock);
344 /* check that our_port is really one of ours */
346 if ( ! _inputs.contains(our_port) ) {
350 /* connect it to the source */
352 if (_session.engine().connect (other_port, our_port->name())) {
356 drop_input_connection ();
360 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
361 _session.set_dirty ();
366 IO::disconnect_output (Port* our_port, string other_port, void* src)
368 if (other_port.length() == 0 || our_port == 0) {
373 Glib::Mutex::Lock em(_session.engine().process_lock());
376 Glib::Mutex::Lock lm (io_lock);
378 /* check that our_port is really one of ours */
380 if ( ! _outputs.contains(our_port) ) {
384 /* disconnect it from the destination */
386 if (_session.engine().disconnect (our_port->name(), other_port)) {
387 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
391 drop_output_connection ();
395 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
396 _session.set_dirty ();
401 IO::connect_output (Port* our_port, string other_port, void* src)
403 if (other_port.length() == 0 || our_port == 0) {
408 Glib::Mutex::Lock em(_session.engine().process_lock());
411 Glib::Mutex::Lock lm (io_lock);
413 /* check that our_port is really one of ours */
415 if ( ! _outputs.contains(our_port) ) {
419 /* connect it to the destination */
421 if (_session.engine().connect (our_port->name(), other_port)) {
425 drop_output_connection ();
429 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
430 _session.set_dirty ();
435 IO::set_input (Port* other_port, void* src)
437 /* this removes all but one ports, and connects that one port
438 to the specified source.
441 if (_input_minimum.get_total() > 1) {
442 /* sorry, you can't do this */
446 if (other_port == 0) {
447 if (_input_minimum == ChanCount::ZERO) {
448 return ensure_inputs (ChanCount::ZERO, false, true, src);
454 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
458 return connect_input (_inputs.port(0), other_port->name(), src);
462 IO::remove_output_port (Port* port, void* src)
464 IOChange change (NoChange);
467 Glib::Mutex::Lock em(_session.engine().process_lock());
470 Glib::Mutex::Lock lm (io_lock);
472 if (n_outputs() <= _output_minimum) {
473 /* sorry, you can't do this */
477 if (_outputs.remove(port)) {
478 change = IOChange (change|ConfigurationChanged);
480 if (port->connected()) {
481 change = IOChange (change|ConnectionsChanged);
484 _session.engine().unregister_port (*port);
485 drop_output_connection ();
487 setup_peak_meters ();
493 if (change != NoChange) {
494 output_changed (change, src);
495 _session.set_dirty ();
502 /** Add an output port.
504 * @param destination Name of input port to connect new port to.
505 * @param src Source for emitted ConfigurationChanged signal.
506 * @param type Data type of port. Default value (NIL) will use this IO's default type.
509 IO::add_output_port (string destination, void* src, DataType type)
514 if (type == DataType::NIL)
515 type = _default_type;
518 Glib::Mutex::Lock em(_session.engine().process_lock());
521 Glib::Mutex::Lock lm (io_lock);
523 if (n_outputs() >= _output_maximum) {
527 /* Create a new output port */
529 // FIXME: naming scheme for differently typed ports?
530 if (_output_maximum.get(type) == 1) {
531 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
533 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
536 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
537 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
541 _outputs.add (our_port);
542 drop_output_connection ();
543 setup_peak_meters ();
547 MoreChannels (n_outputs()); /* EMIT SIGNAL */
550 if (destination.length()) {
551 if (_session.engine().connect (our_port->name(), destination)) {
556 // pan_changed (src); /* EMIT SIGNAL */
557 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
558 _session.set_dirty ();
564 IO::remove_input_port (Port* port, void* src)
566 IOChange change (NoChange);
569 Glib::Mutex::Lock em(_session.engine().process_lock());
572 Glib::Mutex::Lock lm (io_lock);
574 if (n_inputs() <= _input_minimum) {
575 /* sorry, you can't do this */
579 if (_inputs.remove(port)) {
580 change = IOChange (change|ConfigurationChanged);
582 if (port->connected()) {
583 change = IOChange (change|ConnectionsChanged);
586 _session.engine().unregister_port (*port);
587 drop_input_connection ();
589 setup_peak_meters ();
595 if (change != NoChange) {
596 input_changed (change, src);
597 _session.set_dirty ();
605 /** Add an input port.
607 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
608 * @param destination Name of input port to connect new port to.
609 * @param src Source for emitted ConfigurationChanged signal.
612 IO::add_input_port (string source, void* src, DataType type)
617 if (type == DataType::NIL)
618 type = _default_type;
621 Glib::Mutex::Lock em (_session.engine().process_lock());
624 Glib::Mutex::Lock lm (io_lock);
626 if (n_inputs() >= _input_maximum) {
630 /* Create a new input port */
632 // FIXME: naming scheme for differently typed ports?
633 if (_input_maximum.get(type) == 1) {
634 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
636 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
639 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
640 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
644 _inputs.add (our_port);
645 drop_input_connection ();
646 setup_peak_meters ();
650 MoreChannels (n_inputs()); /* EMIT SIGNAL */
653 if (source.length()) {
655 if (_session.engine().connect (source, our_port->name())) {
660 // pan_changed (src); /* EMIT SIGNAL */
661 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
662 _session.set_dirty ();
668 IO::disconnect_inputs (void* src)
671 Glib::Mutex::Lock em (_session.engine().process_lock());
674 Glib::Mutex::Lock lm (io_lock);
676 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
677 _session.engine().disconnect (*i);
680 drop_input_connection ();
684 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
690 IO::disconnect_outputs (void* src)
693 Glib::Mutex::Lock em (_session.engine().process_lock());
696 Glib::Mutex::Lock lm (io_lock);
698 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
699 _session.engine().disconnect (*i);
702 drop_output_connection ();
706 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
707 _session.set_dirty ();
713 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
715 Port* input_port = 0;
716 bool changed = false;
719 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
721 const size_t n = count.get(*t);
723 /* remove unused ports */
724 for (size_t i = n_inputs().get(*t); i > n; --i) {
725 input_port = _inputs.port(*t, i-1);
728 _inputs.remove(input_port);
729 _session.engine().unregister_port (*input_port);
734 /* create any necessary new ports */
735 while (n_inputs().get(*t) < n) {
739 if (_input_maximum.get(*t) == 1) {
740 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
742 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
747 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
748 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
753 catch (AudioEngine::PortRegistrationFailure& err) {
754 setup_peak_meters ();
760 _inputs.add (input_port);
766 drop_input_connection ();
767 setup_peak_meters ();
769 MoreChannels (n_inputs()); /* EMIT SIGNAL */
770 _session.set_dirty ();
774 /* disconnect all existing ports so that we get a fresh start */
775 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
776 _session.engine().disconnect (*i);
783 /** Attach output_buffers to port buffers.
785 * Connected to IO's own MoreChannels signal.
788 IO::attach_buffers(ChanCount ignored)
790 _output_buffers->attach_buffers(_outputs);
794 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
796 bool in_changed = false;
797 bool out_changed = false;
798 bool need_pan_reset = false;
800 in = min (_input_maximum, in);
802 out = min (_output_maximum, out);
804 if (in == n_inputs() && out == n_outputs() && !clear) {
809 Glib::Mutex::Lock em (_session.engine().process_lock());
810 Glib::Mutex::Lock lm (io_lock);
814 if (n_outputs() != out) {
815 need_pan_reset = true;
818 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
820 const size_t nin = in.get(*t);
821 const size_t nout = out.get(*t);
823 Port* output_port = 0;
824 Port* input_port = 0;
826 /* remove unused output ports */
827 for (size_t i = n_outputs().get(*t); i > nout; --i) {
828 output_port = _outputs.port(*t, i-1);
831 _outputs.remove(output_port);
832 _session.engine().unregister_port (*output_port);
837 /* remove unused input ports */
838 for (size_t i = n_inputs().get(*t); i > nin; --i) {
839 input_port = _inputs.port(*t, i-1);
842 _inputs.remove(input_port);
843 _session.engine().unregister_port (*input_port);
848 /* create any necessary new input ports */
850 while (n_inputs().get(*t) < nin) {
854 /* Create a new input port */
856 if (_input_maximum.get(*t) == 1) {
857 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
859 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
863 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
864 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
869 catch (AudioEngine::PortRegistrationFailure& err) {
870 setup_peak_meters ();
880 /* create any necessary new output ports */
882 while (n_outputs().get(*t) < nout) {
886 /* Create a new output port */
888 if (_output_maximum.get(*t) == 1) {
889 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
891 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
895 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
896 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
901 catch (AudioEngine::PortRegistrationFailure& err) {
902 setup_peak_meters ();
915 /* disconnect all existing ports so that we get a fresh start */
917 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
918 _session.engine().disconnect (*i);
921 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
922 _session.engine().disconnect (*i);
926 if (in_changed || out_changed) {
927 setup_peak_meters ();
933 drop_output_connection ();
934 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
938 drop_input_connection ();
939 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
942 if (in_changed || out_changed) {
943 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
944 _session.set_dirty ();
951 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
953 bool changed = false;
955 count = min (_input_maximum, count);
957 if (count == n_inputs() && !clear) {
962 Glib::Mutex::Lock em (_session.engine().process_lock());
963 Glib::Mutex::Lock im (io_lock);
964 changed = ensure_inputs_locked (count, clear, src);
966 changed = ensure_inputs_locked (count, clear, src);
970 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
971 _session.set_dirty ();
977 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
979 Port* output_port = 0;
980 bool changed = false;
981 bool need_pan_reset = false;
983 if (n_outputs() != count) {
984 need_pan_reset = true;
987 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
989 const size_t n = count.get(*t);
991 /* remove unused ports */
992 for (size_t i = n_outputs().get(*t); i > n; --i) {
993 output_port = _outputs.port(*t, i-1);
996 _outputs.remove(output_port);
997 _session.engine().unregister_port (*output_port);
1002 /* create any necessary new ports */
1003 while (n_outputs().get(*t) < n) {
1007 if (_output_maximum.get(*t) == 1) {
1008 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1010 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1013 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1014 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1018 _outputs.add (output_port);
1020 setup_peak_meters ();
1022 if (need_pan_reset) {
1029 drop_output_connection ();
1030 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1031 _session.set_dirty ();
1035 /* disconnect all existing ports so that we get a fresh start */
1036 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1037 _session.engine().disconnect (*i);
1045 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1047 bool changed = false;
1049 if (_output_maximum < ChanCount::INFINITE) {
1050 count = min (_output_maximum, count);
1051 if (count == n_outputs() && !clear) {
1056 /* XXX caller should hold io_lock, but generally doesn't */
1059 Glib::Mutex::Lock em (_session.engine().process_lock());
1060 Glib::Mutex::Lock im (io_lock);
1061 changed = ensure_outputs_locked (count, clear, src);
1063 changed = ensure_outputs_locked (count, clear, src);
1067 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1074 IO::effective_gain () const
1076 if (gain_automation_playback()) {
1077 return _effective_gain;
1079 return _desired_gain;
1086 if (panners_legal) {
1087 if (!no_panner_reset) {
1088 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1091 panner_legal_c.disconnect ();
1092 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1097 IO::panners_became_legal ()
1099 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1100 _panner->load (); // automation
1101 panner_legal_c.disconnect ();
1106 IO::defer_pan_reset ()
1108 no_panner_reset = true;
1112 IO::allow_pan_reset ()
1114 no_panner_reset = false;
1120 IO::get_state (void)
1122 return state (true);
1126 IO::state (bool full_state)
1128 XMLNode* node = new XMLNode (state_node_name);
1131 bool need_ins = true;
1132 bool need_outs = true;
1133 LocaleGuard lg (X_("POSIX"));
1134 Glib::Mutex::Lock lm (io_lock);
1136 node->add_property("name", _name);
1137 id().print (buf, sizeof (buf));
1138 node->add_property("id", buf);
1142 if (_input_connection) {
1143 node->add_property ("input-connection", _input_connection->name());
1147 if (_output_connection) {
1148 node->add_property ("output-connection", _output_connection->name());
1153 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1155 const char **connections = i->get_connections();
1157 if (connections && connections[0]) {
1160 for (int n = 0; connections && connections[n]; ++n) {
1165 /* if its a connection to our own port,
1166 return only the port name, not the
1167 whole thing. this allows connections
1168 to be re-established even when our
1169 client name is different.
1172 str += _session.engine().make_port_name_relative (connections[n]);
1184 node->add_property ("inputs", str);
1190 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1192 const char **connections = i->get_connections();
1194 if (connections && connections[0]) {
1198 for (int n = 0; connections[n]; ++n) {
1203 str += _session.engine().make_port_name_relative (connections[n]);
1215 node->add_property ("outputs", str);
1218 node->add_child_nocopy (_panner->state (full_state));
1219 node->add_child_nocopy (_gain_control.get_state ());
1221 snprintf (buf, sizeof(buf), "%2.12f", gain());
1222 node->add_property ("gain", buf);
1224 // FIXME: this is NOT sufficient!
1225 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1226 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1227 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1228 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1230 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1232 node->add_property ("iolimits", buf);
1237 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1239 /* never store anything except Off for automation state in a template */
1240 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1242 node->add_property ("automation-state", buf);
1243 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1244 node->add_property ("automation-style", buf);
1246 /* XXX same for pan etc. */
1252 IO::connecting_became_legal ()
1256 if (pending_state_node == 0) {
1257 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1262 connection_legal_c.disconnect ();
1264 ret = make_connections (*pending_state_node);
1267 delete pending_state_node;
1268 pending_state_node = 0;
1275 IO::ports_became_legal ()
1279 if (pending_state_node == 0) {
1280 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1285 port_legal_c.disconnect ();
1287 ret = create_ports (*pending_state_node);
1289 if (connecting_legal) {
1290 delete pending_state_node;
1291 pending_state_node = 0;
1298 IO::set_state (const XMLNode& node)
1300 const XMLProperty* prop;
1301 XMLNodeConstIterator iter;
1302 LocaleGuard lg (X_("POSIX"));
1304 /* force use of non-localized representation of decimal point,
1305 since we use it a lot in XML files and so forth.
1308 if (node.name() != state_node_name) {
1309 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1313 if ((prop = node.property ("name")) != 0) {
1314 _name = prop->value();
1315 _panner->set_name (_name);
1318 if ((prop = node.property ("id")) != 0) {
1319 _id = prop->value ();
1324 size_t out_min = -1;
1325 size_t out_max = -1;
1327 if ((prop = node.property ("iolimits")) != 0) {
1328 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1329 &in_min, &in_max, &out_min, &out_max);
1330 _input_minimum = ChanCount(_default_type, in_min);
1331 _input_maximum = ChanCount(_default_type, in_max);
1332 _output_minimum = ChanCount(_default_type, out_min);
1333 _output_maximum = ChanCount(_default_type, out_max);
1336 if ((prop = node.property ("gain")) != 0) {
1337 set_gain (atof (prop->value().c_str()), this);
1338 _gain = _desired_gain;
1341 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1343 if ((*iter)->name() == "Panner") {
1344 _panner->set_state (**iter);
1347 if ((*iter)->name() == X_("gaincontrol")) {
1348 _gain_control.set_state (**iter);
1349 _session.add_controllable (&_gain_control);
1353 if ((prop = node.property ("automation-state")) != 0) {
1356 x = strtol (prop->value().c_str(), 0, 16);
1357 set_gain_automation_state (AutoState (x));
1360 if ((prop = node.property ("automation-style")) != 0) {
1363 x = strtol (prop->value().c_str(), 0, 16);
1364 set_gain_automation_style (AutoStyle (x));
1369 if (create_ports (node)) {
1375 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1378 if (panners_legal) {
1381 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1384 if (connecting_legal) {
1386 if (make_connections (node)) {
1392 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1395 if (!ports_legal || !connecting_legal) {
1396 pending_state_node = new XMLNode (node);
1403 IO::create_ports (const XMLNode& node)
1405 const XMLProperty* prop;
1407 int num_outputs = 0;
1409 if ((prop = node.property ("input-connection")) != 0) {
1411 Connection* c = _session.connection_by_name (prop->value());
1414 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1416 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1417 error << _("No input connections available as a replacement")
1421 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1426 num_inputs = c->nports();
1428 } else if ((prop = node.property ("inputs")) != 0) {
1430 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1433 if ((prop = node.property ("output-connection")) != 0) {
1434 Connection* c = _session.connection_by_name (prop->value());
1437 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1439 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1440 error << _("No output connections available as a replacement")
1444 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1449 num_outputs = c->nports ();
1451 } else if ((prop = node.property ("outputs")) != 0) {
1452 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1455 no_panner_reset = true;
1457 // FIXME: audio-only
1458 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1459 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1463 no_panner_reset = false;
1465 set_deferred_state ();
1473 IO::make_connections (const XMLNode& node)
1475 const XMLProperty* prop;
1477 if ((prop = node.property ("input-connection")) != 0) {
1478 Connection* c = _session.connection_by_name (prop->value());
1481 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1483 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1484 error << _("No input connections available as a replacement")
1488 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1493 use_input_connection (*c, this);
1495 } else if ((prop = node.property ("inputs")) != 0) {
1496 if (set_inputs (prop->value())) {
1497 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1502 if ((prop = node.property ("output-connection")) != 0) {
1503 Connection* c = _session.connection_by_name (prop->value());
1506 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1508 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1509 error << _("No output connections available as a replacement")
1513 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1518 use_output_connection (*c, this);
1520 } else if ((prop = node.property ("outputs")) != 0) {
1521 if (set_outputs (prop->value())) {
1522 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1531 IO::set_inputs (const string& str)
1533 vector<string> ports;
1538 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1542 // FIXME: audio-only
1543 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1547 string::size_type start, end, ostart;
1554 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1557 if ((end = str.find_first_of ('}', start)) == string::npos) {
1558 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1562 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1563 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1569 for (int x = 0; x < n; ++x) {
1570 connect_input (input (i), ports[x], this);
1582 IO::set_outputs (const string& str)
1584 vector<string> ports;
1589 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1593 // FIXME: audio-only
1594 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1598 string::size_type start, end, ostart;
1605 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1608 if ((end = str.find_first_of ('}', start)) == string::npos) {
1609 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1613 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1614 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1620 for (int x = 0; x < n; ++x) {
1621 connect_output (output (i), ports[x], this);
1633 IO::parse_io_string (const string& str, vector<string>& ports)
1635 string::size_type pos, opos;
1637 if (str.length() == 0) {
1646 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1647 ports.push_back (str.substr (opos, pos - opos));
1651 if (opos < str.length()) {
1652 ports.push_back (str.substr(opos));
1655 return ports.size();
1659 IO::parse_gain_string (const string& str, vector<string>& ports)
1661 string::size_type pos, opos;
1667 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1668 ports.push_back (str.substr (opos, pos - opos));
1672 if (opos < str.length()) {
1673 ports.push_back (str.substr(opos));
1676 return ports.size();
1680 IO::set_name (string name, void* src)
1682 if (name == _name) {
1686 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1687 string current_name = i->short_name();
1688 current_name.replace (current_name.find (_name), _name.length(), name);
1689 i->set_name (current_name);
1692 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1693 string current_name = i->short_name();
1694 current_name.replace (current_name.find (_name), _name.length(), name);
1695 i->set_name (current_name);
1699 name_changed (src); /* EMIT SIGNAL */
1705 IO::set_input_minimum (int n)
1708 _input_minimum = ChanCount::ZERO;
1710 _input_minimum = ChanCount(_default_type, n);
1714 IO::set_input_maximum (int n)
1717 _input_maximum = ChanCount::INFINITE;
1719 _input_maximum = ChanCount(_default_type, n);
1723 IO::set_output_minimum (int n)
1726 _output_minimum = ChanCount::ZERO;
1728 _output_minimum = ChanCount(_default_type, n);
1732 IO::set_output_maximum (int n)
1735 _output_maximum = ChanCount::INFINITE;
1737 _output_maximum = ChanCount(_default_type, n);
1741 IO::set_input_minimum (ChanCount n)
1747 IO::set_input_maximum (ChanCount n)
1753 IO::set_output_minimum (ChanCount n)
1755 _output_minimum = n;
1759 IO::set_output_maximum (ChanCount n)
1761 _output_maximum = n;
1765 IO::set_port_latency (nframes_t nframes)
1767 Glib::Mutex::Lock lm (io_lock);
1769 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1770 i->set_latency (nframes);
1775 IO::output_latency () const
1777 nframes_t max_latency;
1782 /* io lock not taken - must be protected by other means */
1784 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1785 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1786 max_latency = latency;
1794 IO::input_latency () const
1796 nframes_t max_latency;
1801 /* io lock not taken - must be protected by other means */
1803 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1804 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1805 max_latency = latency;
1813 IO::use_input_connection (Connection& c, void* src)
1818 Glib::Mutex::Lock lm (_session.engine().process_lock());
1819 Glib::Mutex::Lock lm2 (io_lock);
1823 drop_input_connection ();
1825 // FIXME connections only work for audio-only
1826 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1830 /* first pass: check the current state to see what's correctly
1831 connected, and drop anything that we don't want.
1834 for (uint32_t n = 0; n < limit; ++n) {
1835 const Connection::PortList& pl = c.port_connections (n);
1837 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1839 if (!_inputs.port(n)->connected_to ((*i))) {
1841 /* clear any existing connections */
1843 _session.engine().disconnect (*_inputs.port(n));
1845 } else if (_inputs.port(n)->connected() > 1) {
1847 /* OK, it is connected to the port we want,
1848 but its also connected to other ports.
1849 Change that situation.
1852 /* XXX could be optimized to not drop
1856 _session.engine().disconnect (*_inputs.port(n));
1862 /* second pass: connect all requested ports where necessary */
1864 for (uint32_t n = 0; n < limit; ++n) {
1865 const Connection::PortList& pl = c.port_connections (n);
1867 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1869 if (!_inputs.port(n)->connected_to ((*i))) {
1871 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1879 _input_connection = &c;
1881 input_connection_configuration_connection = c.ConfigurationChanged.connect
1882 (mem_fun (*this, &IO::input_connection_configuration_changed));
1883 input_connection_connection_connection = c.ConnectionsChanged.connect
1884 (mem_fun (*this, &IO::input_connection_connection_changed));
1887 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1892 IO::use_output_connection (Connection& c, void* src)
1897 Glib::Mutex::Lock lm (_session.engine().process_lock());
1898 Glib::Mutex::Lock lm2 (io_lock);
1902 drop_output_connection ();
1904 // FIXME: audio-only
1905 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1909 /* first pass: check the current state to see what's correctly
1910 connected, and drop anything that we don't want.
1913 for (uint32_t n = 0; n < limit; ++n) {
1915 const Connection::PortList& pl = c.port_connections (n);
1917 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1919 if (!_outputs.port(n)->connected_to ((*i))) {
1921 /* clear any existing connections */
1923 _session.engine().disconnect (*_outputs.port(n));
1925 } else if (_outputs.port(n)->connected() > 1) {
1927 /* OK, it is connected to the port we want,
1928 but its also connected to other ports.
1929 Change that situation.
1932 /* XXX could be optimized to not drop
1936 _session.engine().disconnect (*_outputs.port(n));
1941 /* second pass: connect all requested ports where necessary */
1943 for (uint32_t n = 0; n < limit; ++n) {
1945 const Connection::PortList& pl = c.port_connections (n);
1947 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1949 if (!_outputs.port(n)->connected_to ((*i))) {
1951 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
1958 _output_connection = &c;
1960 output_connection_configuration_connection = c.ConfigurationChanged.connect
1961 (mem_fun (*this, &IO::output_connection_configuration_changed));
1962 output_connection_connection_connection = c.ConnectionsChanged.connect
1963 (mem_fun (*this, &IO::output_connection_connection_changed));
1966 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
1972 IO::disable_connecting ()
1974 connecting_legal = false;
1979 IO::enable_connecting ()
1981 connecting_legal = true;
1982 return ConnectingLegal ();
1986 IO::disable_ports ()
1988 ports_legal = false;
1996 return PortsLegal ();
2000 IO::disable_panners (void)
2002 panners_legal = false;
2007 IO::reset_panners ()
2009 panners_legal = true;
2010 return PannersLegal ();
2014 IO::input_connection_connection_changed (int ignored)
2016 use_input_connection (*_input_connection, this);
2020 IO::input_connection_configuration_changed ()
2022 use_input_connection (*_input_connection, this);
2026 IO::output_connection_connection_changed (int ignored)
2028 use_output_connection (*_output_connection, this);
2032 IO::output_connection_configuration_changed ()
2034 use_output_connection (*_output_connection, this);
2038 IO::GainControllable::set_value (float val)
2040 io.set_gain (direct_control_to_gain (val), this);
2044 IO::GainControllable::get_value (void) const
2046 return direct_gain_to_control (io.effective_gain());
2050 IO::get_memento() const
2052 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2056 IO::restore_state (StateManager::State& state)
2061 StateManager::State*
2062 IO::state_factory (std::string why) const
2064 StateManager::State* state = new StateManager::State (why);
2069 IO::setup_peak_meters()
2071 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2075 Update the peak meters.
2077 The meter signal lock is taken to prevent modification of the
2078 Meter signal while updating the meters, taking the meter signal
2079 lock prior to taking the io_lock ensures that all IO will remain
2080 valid while metering.
2085 Glib::Mutex::Lock guard (m_meter_signal_lock);
2087 Meter(); /* EMIT SIGNAL */
2093 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2095 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2100 IO::save_automation (const string& path)
2105 fullpath = _session.automation_dir();
2108 out.open (fullpath.c_str());
2111 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2115 out << X_("version ") << current_automation_version_number << endl;
2117 /* XXX use apply_to_points to get thread safety */
2119 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2120 out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2129 IO::load_automation (const string& path)
2134 uint32_t linecnt = 0;
2136 LocaleGuard lg (X_("POSIX"));
2138 fullpath = _session.automation_dir();
2141 in.open (fullpath.c_str());
2144 fullpath = _session.automation_dir();
2145 fullpath += _session.snap_name();
2148 in.open (fullpath.c_str());
2150 error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
2155 clear_automation ();
2157 while (in.getline (line, sizeof(line), '\n')) {
2162 if (++linecnt == 1) {
2163 if (memcmp (line, "version", 7) == 0) {
2164 if (sscanf (line, "version %f", &version) != 1) {
2165 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2169 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2173 if (version != current_automation_version_number) {
2174 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2181 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2182 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2188 _gain_automation_curve.add (when, value, true);
2198 /* older (pre-1.0) versions of ardour used this */
2202 warning << _("dubious automation event found (and ignored)") << endmsg;
2206 _gain_automation_curve.save_state (_("loaded from disk"));
2212 IO::clear_automation ()
2214 Glib::Mutex::Lock lm (automation_lock);
2215 _gain_automation_curve.clear ();
2216 _panner->clear_automation ();
2220 IO::set_gain_automation_state (AutoState state)
2222 bool changed = false;
2225 Glib::Mutex::Lock lm (automation_lock);
2227 if (state != _gain_automation_curve.automation_state()) {
2229 _gain_automation_curve.set_automation_state (state);
2232 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2238 _session.set_dirty ();
2239 gain_automation_state_changed (); /* EMIT SIGNAL */
2244 IO::set_gain_automation_style (AutoStyle style)
2246 bool changed = false;
2249 Glib::Mutex::Lock lm (automation_lock);
2251 if (style != _gain_automation_curve.automation_style()) {
2253 _gain_automation_curve.set_automation_style (style);
2258 gain_automation_style_changed (); /* EMIT SIGNAL */
2262 IO::inc_gain (gain_t factor, void *src)
2264 if (_desired_gain == 0.0f)
2265 set_gain (0.000001f + (0.000001f * factor), src);
2267 set_gain (_desired_gain + (_desired_gain * factor), src);
2271 IO::set_gain (gain_t val, void *src)
2273 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2274 if (val>1.99526231f) val=1.99526231f;
2277 Glib::Mutex::Lock dm (declick_lock);
2278 _desired_gain = val;
2281 if (_session.transport_stopped()) {
2282 _effective_gain = val;
2287 _gain_control.Changed (); /* EMIT SIGNAL */
2289 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2290 _gain_automation_curve.add (_session.transport_frame(), val);
2294 _session.set_dirty();
2298 IO::start_gain_touch ()
2300 _gain_automation_curve.start_touch ();
2304 IO::end_gain_touch ()
2306 _gain_automation_curve.stop_touch ();
2310 IO::start_pan_touch (uint32_t which)
2312 if (which < _panner->size()) {
2313 (*_panner)[which]->automation().start_touch();
2318 IO::end_pan_touch (uint32_t which)
2320 if (which < _panner->size()) {
2321 (*_panner)[which]->automation().stop_touch();
2327 IO::transport_stopped (nframes_t frame)
2329 _gain_automation_curve.reposition_for_rt_add (frame);
2331 if (_gain_automation_curve.automation_state() != Off) {
2333 if (gain_automation_recording()) {
2334 _gain_automation_curve.save_state (_("automation write/touch"));
2337 /* the src=0 condition is a special signal to not propagate
2338 automation gain changes into the mix group when locating.
2341 set_gain (_gain_automation_curve.eval (frame), 0);
2344 _panner->transport_stopped (frame);
2348 IO::find_input_port_hole ()
2350 /* CALLER MUST HOLD IO LOCK */
2354 if (_inputs.empty()) {
2358 for (n = 1; n < UINT_MAX; ++n) {
2359 char buf[jack_port_name_size()];
2360 PortSet::iterator i = _inputs.begin();
2362 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2364 for ( ; i != _inputs.end(); ++i) {
2365 if (i->short_name() == buf) {
2370 if (i == _inputs.end()) {
2378 IO::find_output_port_hole ()
2380 /* CALLER MUST HOLD IO LOCK */
2384 if (_outputs.empty()) {
2388 for (n = 1; n < UINT_MAX; ++n) {
2389 char buf[jack_port_name_size()];
2390 PortSet::iterator i = _outputs.begin();
2392 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2394 for ( ; i != _outputs.end(); ++i) {
2395 if (i->short_name() == buf) {
2400 if (i == _outputs.end()) {
2409 IO::audio_input(uint32_t n) const
2411 return dynamic_cast<AudioPort*>(input(n));
2415 IO::audio_output(uint32_t n) const
2417 return dynamic_cast<AudioPort*>(output(n));
2421 IO::midi_input(uint32_t n) const
2423 return dynamic_cast<MidiPort*>(input(n));
2427 IO::midi_output(uint32_t n) const
2429 return dynamic_cast<MidiPort*>(output(n));
2433 IO::set_phase_invert (bool yn, void *src)
2435 if (_phase_invert != yn) {
2438 // phase_invert_changed (src); /* EMIT SIGNAL */