2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <sigc++/bind.h>
27 #include <glibmm/thread.h>
29 #include <pbd/xml++.h>
30 #include <pbd/replace_all.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/audio_port.h>
36 #include <ardour/midi_port.h>
37 #include <ardour/connection.h>
38 #include <ardour/session.h>
39 #include <ardour/cycle_timer.h>
40 #include <ardour/panner.h>
41 #include <ardour/buffer_set.h>
42 #include <ardour/meter.h>
43 #include <ardour/amp.h>
50 A bug in OS X's cmath that causes isnan() and isinf() to be
51 "undeclared". the following works around that
54 #if defined(__APPLE__) && defined(__MACH__)
55 extern "C" int isnan (double);
56 extern "C" int isinf (double);
59 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
62 using namespace ARDOUR;
65 nframes_t IO::_automation_interval = 0;
67 const string IO::state_node_name = "IO";
68 bool IO::connecting_legal = false;
69 bool IO::ports_legal = false;
70 bool IO::panners_legal = false;
71 sigc::signal<void> IO::Meter;
72 sigc::signal<int> IO::ConnectingLegal;
73 sigc::signal<int> IO::PortsLegal;
74 sigc::signal<int> IO::PannersLegal;
75 sigc::signal<void,ChanCount> IO::MoreChannels;
76 sigc::signal<int> IO::PortsCreated;
78 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
80 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
81 others can be imagined.
84 static gain_t direct_control_to_gain (double fract) {
85 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
86 /* this maxes at +6dB */
87 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
90 static double direct_gain_to_control (gain_t gain) {
91 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
92 if (gain == 0) return 0.0;
94 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
98 /** @param default_type The type of port that will be created by ensure_io
99 * and friends if no type is explicitly requested (to avoid breakage).
101 IO::IO (Session& s, string name,
102 int input_min, int input_max, int output_min, int output_max,
103 DataType default_type)
105 _output_buffers(new BufferSet()),
107 _default_type(default_type),
108 _gain_control (X_("gaincontrol"), *this),
109 _gain_automation_curve (0.0, 2.0, 1.0),
110 _input_minimum (ChanCount::ZERO),
111 _input_maximum (ChanCount::INFINITE),
112 _output_minimum (ChanCount::ZERO),
113 _output_maximum (ChanCount::INFINITE)
115 _panner = new Panner (name, _session);
116 _meter = new PeakMeter (_session);
119 _input_minimum = ChanCount(_default_type, input_min);
121 if (input_max >= 0) {
122 _input_maximum = ChanCount(_default_type, input_max);
124 if (output_min > 0) {
125 _output_minimum = ChanCount(_default_type, output_min);
127 if (output_max >= 0) {
128 _output_maximum = ChanCount(_default_type, output_max);
133 _input_connection = 0;
134 _output_connection = 0;
135 pending_state_node = 0;
136 no_panner_reset = false;
137 _phase_invert = false;
140 apply_gain_automation = false;
142 last_automation_snapshot = 0;
144 _gain_automation_state = Off;
145 _gain_automation_style = Absolute;
148 // IO::Meter is emitted from another thread so the
149 // Meter signal must be protected.
150 Glib::Mutex::Lock guard (m_meter_signal_lock);
151 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
154 // Connect to our own MoreChannels signal to connect output buffers
155 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
157 _session.add_controllable (&_gain_control);
160 IO::IO (Session& s, const XMLNode& node, DataType dt)
162 _output_buffers(new BufferSet()),
164 _gain_control (X_("gaincontrol"), *this),
165 _gain_automation_curve (0, 0, 0) // all reset in set_state()
168 _meter = new PeakMeter (_session);
172 no_panner_reset = false;
175 _input_connection = 0;
176 _output_connection = 0;
178 apply_gain_automation = false;
183 // IO::Meter is emitted from another thread so the
184 // Meter signal must be protected.
185 Glib::Mutex::Lock guard (m_meter_signal_lock);
186 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
189 // Connect to our own MoreChannels signal to connect output buffers
190 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
192 _session.add_controllable (&_gain_control);
197 Glib::Mutex::Lock guard (m_meter_signal_lock);
199 Glib::Mutex::Lock lm (io_lock);
201 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
202 _session.engine().unregister_port (*i);
205 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
206 _session.engine().unregister_port (*i);
209 m_meter_connection.disconnect();
213 delete _output_buffers;
217 IO::silence (nframes_t nframes, nframes_t offset)
219 /* io_lock, not taken: function must be called from Session::process() calltree */
221 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
222 i->get_buffer().silence (nframes, offset);
226 /** Deliver bufs to the IO's Jack outputs.
228 * This function should automatically do whatever it necessary to correctly deliver bufs
229 * to the outputs, eg applying gain or pan or whatever else needs to be done.
232 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
234 // FIXME: type specific code doesn't actually need to be here, it will go away in time
236 /* ********** AUDIO ********** */
238 // Apply gain if gain automation isn't playing
239 if ( ! apply_gain_automation) {
241 gain_t dg = _gain; // desired gain
244 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
252 if (dg != _gain || dg != 1.0)
253 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
256 // Use the panner to distribute audio to output port buffers
257 if (_panner && !_panner->empty() && !_panner->bypassed()) {
258 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
260 const DataType type = DataType::AUDIO;
262 // Copy any audio 1:1 to outputs
263 assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
264 BufferSet::iterator o = output_buffers().begin(type);
265 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
266 o->read_from(*i, nframes, offset);
271 /* ********** MIDI ********** */
273 // No MIDI, we're done here
274 if (bufs.count().get(DataType::MIDI) == 0) {
278 const DataType type = DataType::MIDI;
280 // Copy any MIDI 1:1 to outputs
281 assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
282 BufferSet::iterator o = output_buffers().begin(type);
283 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
284 o->read_from(*i, nframes, offset);
289 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
291 assert(outs.available() >= n_inputs());
293 outs.set_count(n_inputs());
295 if (outs.count() == ChanCount::ZERO)
298 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
300 BufferSet::iterator o = outs.begin(*t);
301 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
302 o->read_from(i->get_buffer(), nframes, offset);
309 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
310 nframes_t nframes, nframes_t offset)
312 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
314 collect_input (bufs, nframes, offset);
316 _meter->run(bufs, nframes);
320 IO::drop_input_connection ()
322 _input_connection = 0;
323 input_connection_configuration_connection.disconnect();
324 input_connection_connection_connection.disconnect();
325 _session.set_dirty ();
329 IO::drop_output_connection ()
331 _output_connection = 0;
332 output_connection_configuration_connection.disconnect();
333 output_connection_connection_connection.disconnect();
334 _session.set_dirty ();
338 IO::disconnect_input (Port* our_port, string other_port, void* src)
340 if (other_port.length() == 0 || our_port == 0) {
345 BLOCK_PROCESS_CALLBACK ();
348 Glib::Mutex::Lock lm (io_lock);
350 /* check that our_port is really one of ours */
352 if ( ! _inputs.contains(our_port)) {
356 /* disconnect it from the source */
358 if (_session.engine().disconnect (other_port, our_port->name())) {
359 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
363 drop_input_connection();
367 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
368 _session.set_dirty ();
374 IO::connect_input (Port* our_port, string other_port, void* src)
376 if (other_port.length() == 0 || our_port == 0) {
381 BLOCK_PROCESS_CALLBACK ();
384 Glib::Mutex::Lock lm (io_lock);
386 /* check that our_port is really one of ours */
388 if ( ! _inputs.contains(our_port) ) {
392 /* connect it to the source */
394 if (_session.engine().connect (other_port, our_port->name())) {
398 drop_input_connection ();
402 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
403 _session.set_dirty ();
408 IO::disconnect_output (Port* our_port, string other_port, void* src)
410 if (other_port.length() == 0 || our_port == 0) {
415 BLOCK_PROCESS_CALLBACK ();
418 Glib::Mutex::Lock lm (io_lock);
420 /* check that our_port is really one of ours */
422 if ( ! _outputs.contains(our_port) ) {
426 /* disconnect it from the destination */
428 if (_session.engine().disconnect (our_port->name(), other_port)) {
429 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
433 drop_output_connection ();
437 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
438 _session.set_dirty ();
443 IO::connect_output (Port* our_port, string other_port, void* src)
445 if (other_port.length() == 0 || our_port == 0) {
450 BLOCK_PROCESS_CALLBACK ();
454 Glib::Mutex::Lock lm (io_lock);
456 /* check that our_port is really one of ours */
458 if ( ! _outputs.contains(our_port) ) {
462 /* connect it to the destination */
464 if (_session.engine().connect (our_port->name(), other_port)) {
468 drop_output_connection ();
472 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
473 _session.set_dirty ();
478 IO::set_input (Port* other_port, void* src)
480 /* this removes all but one ports, and connects that one port
481 to the specified source.
484 if (_input_minimum.get_total() > 1) {
485 /* sorry, you can't do this */
489 if (other_port == 0) {
490 if (_input_minimum == ChanCount::ZERO) {
491 return ensure_inputs (ChanCount::ZERO, false, true, src);
497 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
501 return connect_input (_inputs.port(0), other_port->name(), src);
505 IO::remove_output_port (Port* port, void* src)
507 IOChange change (NoChange);
510 BLOCK_PROCESS_CALLBACK ();
514 Glib::Mutex::Lock lm (io_lock);
516 if (n_outputs() <= _output_minimum) {
517 /* sorry, you can't do this */
521 if (_outputs.remove(port)) {
522 change = IOChange (change|ConfigurationChanged);
524 if (port->connected()) {
525 change = IOChange (change|ConnectionsChanged);
528 _session.engine().unregister_port (*port);
529 drop_output_connection ();
531 setup_peak_meters ();
537 if (change != NoChange) {
538 output_changed (change, src);
539 _session.set_dirty ();
546 /** Add an output port.
548 * @param destination Name of input port to connect new port to.
549 * @param src Source for emitted ConfigurationChanged signal.
550 * @param type Data type of port. Default value (NIL) will use this IO's default type.
553 IO::add_output_port (string destination, void* src, DataType type)
558 if (type == DataType::NIL)
559 type = _default_type;
562 BLOCK_PROCESS_CALLBACK ();
566 Glib::Mutex::Lock lm (io_lock);
568 if (n_outputs() >= _output_maximum) {
572 /* Create a new output port */
574 // FIXME: naming scheme for differently typed ports?
575 if (_output_maximum.get(type) == 1) {
576 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
578 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
581 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
582 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
586 _outputs.add (our_port);
587 drop_output_connection ();
588 setup_peak_meters ();
592 MoreChannels (n_outputs()); /* EMIT SIGNAL */
595 if (destination.length()) {
596 if (_session.engine().connect (our_port->name(), destination)) {
601 // pan_changed (src); /* EMIT SIGNAL */
602 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
603 _session.set_dirty ();
609 IO::remove_input_port (Port* port, void* src)
611 IOChange change (NoChange);
614 BLOCK_PROCESS_CALLBACK ();
618 Glib::Mutex::Lock lm (io_lock);
620 if (n_inputs() <= _input_minimum) {
621 /* sorry, you can't do this */
625 if (_inputs.remove(port)) {
626 change = IOChange (change|ConfigurationChanged);
628 if (port->connected()) {
629 change = IOChange (change|ConnectionsChanged);
632 _session.engine().unregister_port (*port);
633 drop_input_connection ();
635 setup_peak_meters ();
641 if (change != NoChange) {
642 input_changed (change, src);
643 _session.set_dirty ();
651 /** Add an input port.
653 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
654 * @param destination Name of input port to connect new port to.
655 * @param src Source for emitted ConfigurationChanged signal.
658 IO::add_input_port (string source, void* src, DataType type)
663 if (type == DataType::NIL)
664 type = _default_type;
667 BLOCK_PROCESS_CALLBACK ();
670 Glib::Mutex::Lock lm (io_lock);
672 if (n_inputs() >= _input_maximum) {
676 /* Create a new input port */
678 // FIXME: naming scheme for differently typed ports?
679 if (_input_maximum.get(type) == 1) {
680 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
682 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
685 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
686 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
690 _inputs.add (our_port);
691 drop_input_connection ();
692 setup_peak_meters ();
696 MoreChannels (n_inputs()); /* EMIT SIGNAL */
699 if (source.length()) {
701 if (_session.engine().connect (source, our_port->name())) {
706 // pan_changed (src); /* EMIT SIGNAL */
707 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
708 _session.set_dirty ();
714 IO::disconnect_inputs (void* src)
717 BLOCK_PROCESS_CALLBACK ();
720 Glib::Mutex::Lock lm (io_lock);
722 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
723 _session.engine().disconnect (*i);
726 drop_input_connection ();
730 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
736 IO::disconnect_outputs (void* src)
739 BLOCK_PROCESS_CALLBACK ();
742 Glib::Mutex::Lock lm (io_lock);
744 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
745 _session.engine().disconnect (*i);
748 drop_output_connection ();
752 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
753 _session.set_dirty ();
759 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
761 Port* input_port = 0;
762 bool changed = false;
765 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
767 const size_t n = count.get(*t);
769 /* remove unused ports */
770 for (size_t i = n_inputs().get(*t); i > n; --i) {
771 input_port = _inputs.port(*t, i-1);
774 _inputs.remove(input_port);
775 _session.engine().unregister_port (*input_port);
780 /* create any necessary new ports */
781 while (n_inputs().get(*t) < n) {
785 if (_input_maximum.get(*t) == 1) {
786 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
788 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
793 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
794 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
799 catch (AudioEngine::PortRegistrationFailure& err) {
800 setup_peak_meters ();
803 throw AudioEngine::PortRegistrationFailure();
806 _inputs.add (input_port);
812 drop_input_connection ();
813 setup_peak_meters ();
815 MoreChannels (n_inputs()); /* EMIT SIGNAL */
816 _session.set_dirty ();
820 /* disconnect all existing ports so that we get a fresh start */
821 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
822 _session.engine().disconnect (*i);
829 /** Attach output_buffers to port buffers.
831 * Connected to IO's own MoreChannels signal.
834 IO::attach_buffers(ChanCount ignored)
836 _output_buffers->attach_buffers(_outputs);
840 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
842 bool in_changed = false;
843 bool out_changed = false;
844 bool need_pan_reset = false;
846 in = min (_input_maximum, in);
848 out = min (_output_maximum, out);
850 if (in == n_inputs() && out == n_outputs() && !clear) {
855 BLOCK_PROCESS_CALLBACK ();
856 Glib::Mutex::Lock lm (io_lock);
860 if (n_outputs() != out) {
861 need_pan_reset = true;
864 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
866 const size_t nin = in.get(*t);
867 const size_t nout = out.get(*t);
869 Port* output_port = 0;
870 Port* input_port = 0;
872 /* remove unused output ports */
873 for (size_t i = n_outputs().get(*t); i > nout; --i) {
874 output_port = _outputs.port(*t, i-1);
877 _outputs.remove(output_port);
878 _session.engine().unregister_port (*output_port);
883 /* remove unused input ports */
884 for (size_t i = n_inputs().get(*t); i > nin; --i) {
885 input_port = _inputs.port(*t, i-1);
888 _inputs.remove(input_port);
889 _session.engine().unregister_port (*input_port);
894 /* create any necessary new input ports */
896 while (n_inputs().get(*t) < nin) {
900 /* Create a new input port */
902 if (_input_maximum.get(*t) == 1) {
903 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
905 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
909 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
910 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
915 catch (AudioEngine::PortRegistrationFailure& err) {
916 setup_peak_meters ();
919 throw AudioEngine::PortRegistrationFailure();
926 /* create any necessary new output ports */
928 while (n_outputs().get(*t) < nout) {
932 /* Create a new output port */
934 if (_output_maximum.get(*t) == 1) {
935 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
937 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
941 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
942 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
947 catch (AudioEngine::PortRegistrationFailure& err) {
948 setup_peak_meters ();
951 throw AudioEngine::PortRegistrationFailure ();
961 /* disconnect all existing ports so that we get a fresh start */
963 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
964 _session.engine().disconnect (*i);
967 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
968 _session.engine().disconnect (*i);
972 if (in_changed || out_changed) {
973 setup_peak_meters ();
979 drop_output_connection ();
980 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
984 drop_input_connection ();
985 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
988 if (in_changed || out_changed) {
989 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
990 _session.set_dirty ();
997 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
999 bool changed = false;
1001 count = min (_input_maximum, count);
1003 if (count == n_inputs() && !clear) {
1008 BLOCK_PROCESS_CALLBACK ();
1009 Glib::Mutex::Lock im (io_lock);
1010 changed = ensure_inputs_locked (count, clear, src);
1012 changed = ensure_inputs_locked (count, clear, src);
1016 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1017 _session.set_dirty ();
1023 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1025 Port* output_port = 0;
1026 bool changed = false;
1027 bool need_pan_reset = false;
1029 if (n_outputs() != count) {
1030 need_pan_reset = true;
1033 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1035 const size_t n = count.get(*t);
1037 /* remove unused ports */
1038 for (size_t i = n_outputs().get(*t); i > n; --i) {
1039 output_port = _outputs.port(*t, i-1);
1041 assert(output_port);
1042 _outputs.remove(output_port);
1043 _session.engine().unregister_port (*output_port);
1048 /* create any necessary new ports */
1049 while (n_outputs().get(*t) < n) {
1053 if (_output_maximum.get(*t) == 1) {
1054 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1056 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1059 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1060 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1064 _outputs.add (output_port);
1066 setup_peak_meters ();
1068 if (need_pan_reset) {
1075 drop_output_connection ();
1076 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1077 _session.set_dirty ();
1081 /* disconnect all existing ports so that we get a fresh start */
1082 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1083 _session.engine().disconnect (*i);
1091 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1093 bool changed = false;
1095 if (_output_maximum < ChanCount::INFINITE) {
1096 count = min (_output_maximum, count);
1097 if (count == n_outputs() && !clear) {
1102 /* XXX caller should hold io_lock, but generally doesn't */
1105 BLOCK_PROCESS_CALLBACK ();
1106 Glib::Mutex::Lock im (io_lock);
1107 changed = ensure_outputs_locked (count, clear, src);
1109 changed = ensure_outputs_locked (count, clear, src);
1113 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1120 IO::effective_gain () const
1122 if (gain_automation_playback()) {
1123 return _effective_gain;
1125 return _desired_gain;
1132 if (panners_legal) {
1133 if (!no_panner_reset) {
1134 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1137 panner_legal_c.disconnect ();
1138 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1143 IO::panners_became_legal ()
1145 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1146 _panner->load (); // automation
1147 panner_legal_c.disconnect ();
1152 IO::defer_pan_reset ()
1154 no_panner_reset = true;
1158 IO::allow_pan_reset ()
1160 no_panner_reset = false;
1166 IO::get_state (void)
1168 return state (true);
1172 IO::state (bool full_state)
1174 XMLNode* node = new XMLNode (state_node_name);
1177 bool need_ins = true;
1178 bool need_outs = true;
1179 LocaleGuard lg (X_("POSIX"));
1180 Glib::Mutex::Lock lm (io_lock);
1182 node->add_property("name", _name);
1183 id().print (buf, sizeof (buf));
1184 node->add_property("id", buf);
1188 if (_input_connection) {
1189 node->add_property ("input-connection", _input_connection->name());
1193 if (_output_connection) {
1194 node->add_property ("output-connection", _output_connection->name());
1199 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1201 const char **connections = i->get_connections();
1203 if (connections && connections[0]) {
1206 for (int n = 0; connections && connections[n]; ++n) {
1211 /* if its a connection to our own port,
1212 return only the port name, not the
1213 whole thing. this allows connections
1214 to be re-established even when our
1215 client name is different.
1218 str += _session.engine().make_port_name_relative (connections[n]);
1230 node->add_property ("inputs", str);
1236 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1238 const char **connections = i->get_connections();
1240 if (connections && connections[0]) {
1244 for (int n = 0; connections[n]; ++n) {
1249 str += _session.engine().make_port_name_relative (connections[n]);
1261 node->add_property ("outputs", str);
1264 node->add_child_nocopy (_panner->state (full_state));
1265 node->add_child_nocopy (_gain_control.get_state ());
1267 snprintf (buf, sizeof(buf), "%2.12f", gain());
1268 node->add_property ("gain", buf);
1270 // FIXME: this is NOT sufficient!
1271 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1272 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1273 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1274 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1276 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1278 node->add_property ("iolimits", buf);
1284 XMLNode* autonode = new XMLNode (X_("Automation"));
1285 autonode->add_child_nocopy (get_automation_state());
1286 node->add_child_nocopy (*autonode);
1288 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1290 /* never store anything except Off for automation state in a template */
1291 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
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 /* used to set panner name with this, but no more */
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 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1342 /* old school automation handling */
1345 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1347 if ((*iter)->name() == "Panner") {
1349 _panner = new Panner (_name, _session);
1351 _panner->set_state (**iter);
1354 if ((*iter)->name() == X_("Automation")) {
1356 set_automation_state (*(*iter)->children().front());
1359 if ((*iter)->name() == X_("controllable")) {
1360 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1361 _gain_control.set_state (**iter);
1368 if (create_ports (node)) {
1374 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1377 if (panners_legal) {
1380 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1383 if (connecting_legal) {
1385 if (make_connections (node)) {
1391 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1394 if (!ports_legal || !connecting_legal) {
1395 pending_state_node = new XMLNode (node);
1398 last_automation_snapshot = 0;
1404 IO::set_automation_state (const XMLNode& node)
1406 return _gain_automation_curve.set_state (node);
1410 IO::get_automation_state ()
1412 return (_gain_automation_curve.get_state ());
1416 IO::load_automation (string path)
1421 uint32_t linecnt = 0;
1423 LocaleGuard lg (X_("POSIX"));
1425 fullpath = _session.automation_dir();
1428 in.open (fullpath.c_str());
1431 fullpath = _session.automation_dir();
1432 fullpath += _session.snap_name();
1436 in.open (fullpath.c_str());
1439 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1444 clear_automation ();
1446 while (in.getline (line, sizeof(line), '\n')) {
1451 if (++linecnt == 1) {
1452 if (memcmp (line, "version", 7) == 0) {
1453 if (sscanf (line, "version %f", &version) != 1) {
1454 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1458 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1465 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1466 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1472 _gain_automation_curve.fast_simple_add (when, value);
1482 /* older (pre-1.0) versions of ardour used this */
1486 warning << _("dubious automation event found (and ignored)") << endmsg;
1494 IO::connecting_became_legal ()
1498 if (pending_state_node == 0) {
1499 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1504 connection_legal_c.disconnect ();
1506 ret = make_connections (*pending_state_node);
1509 delete pending_state_node;
1510 pending_state_node = 0;
1516 IO::ports_became_legal ()
1520 if (pending_state_node == 0) {
1521 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1526 port_legal_c.disconnect ();
1528 ret = create_ports (*pending_state_node);
1530 if (connecting_legal) {
1531 delete pending_state_node;
1532 pending_state_node = 0;
1539 IO::create_ports (const XMLNode& node)
1541 const XMLProperty* prop;
1543 int num_outputs = 0;
1545 if ((prop = node.property ("input-connection")) != 0) {
1547 Connection* c = _session.connection_by_name (prop->value());
1550 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1552 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1553 error << _("No input connections available as a replacement")
1557 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1562 num_inputs = c->nports();
1564 } else if ((prop = node.property ("inputs")) != 0) {
1566 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1569 if ((prop = node.property ("output-connection")) != 0) {
1570 Connection* c = _session.connection_by_name (prop->value());
1573 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1575 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1576 error << _("No output connections available as a replacement")
1580 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1585 num_outputs = c->nports ();
1587 } else if ((prop = node.property ("outputs")) != 0) {
1588 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1591 no_panner_reset = true;
1593 // FIXME: audio-only
1594 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1595 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1599 no_panner_reset = false;
1601 set_deferred_state ();
1609 IO::make_connections (const XMLNode& node)
1611 const XMLProperty* prop;
1613 if ((prop = node.property ("input-connection")) != 0) {
1614 Connection* c = _session.connection_by_name (prop->value());
1617 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1619 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1620 error << _("No input connections available as a replacement")
1624 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1629 use_input_connection (*c, this);
1631 } else if ((prop = node.property ("inputs")) != 0) {
1632 if (set_inputs (prop->value())) {
1633 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1638 if ((prop = node.property ("output-connection")) != 0) {
1639 Connection* c = _session.connection_by_name (prop->value());
1642 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1644 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1645 error << _("No output connections available as a replacement")
1649 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1654 use_output_connection (*c, this);
1656 } else if ((prop = node.property ("outputs")) != 0) {
1657 if (set_outputs (prop->value())) {
1658 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1667 IO::set_inputs (const string& str)
1669 vector<string> ports;
1674 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1678 // FIXME: audio-only
1679 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1683 string::size_type start, end, ostart;
1690 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1693 if ((end = str.find_first_of ('}', start)) == string::npos) {
1694 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1698 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1699 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1705 for (int x = 0; x < n; ++x) {
1706 connect_input (input (i), ports[x], this);
1718 IO::set_outputs (const string& str)
1720 vector<string> ports;
1725 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1729 // FIXME: audio-only
1730 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1734 string::size_type start, end, ostart;
1741 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1744 if ((end = str.find_first_of ('}', start)) == string::npos) {
1745 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1749 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1750 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1756 for (int x = 0; x < n; ++x) {
1757 connect_output (output (i), ports[x], this);
1769 IO::parse_io_string (const string& str, vector<string>& ports)
1771 string::size_type pos, opos;
1773 if (str.length() == 0) {
1782 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1783 ports.push_back (str.substr (opos, pos - opos));
1787 if (opos < str.length()) {
1788 ports.push_back (str.substr(opos));
1791 return ports.size();
1795 IO::parse_gain_string (const string& str, vector<string>& ports)
1797 string::size_type pos, opos;
1803 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1804 ports.push_back (str.substr (opos, pos - opos));
1808 if (opos < str.length()) {
1809 ports.push_back (str.substr(opos));
1812 return ports.size();
1816 IO::set_name (string name, void* src)
1818 if (name == _name) {
1822 /* replace all colons in the name. i wish we didn't have to do this */
1824 if (replace_all (name, ":", "-")) {
1825 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1828 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1829 string current_name = i->short_name();
1830 current_name.replace (current_name.find (_name), _name.length(), name);
1831 i->set_name (current_name);
1834 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1835 string current_name = i->short_name();
1836 current_name.replace (current_name.find (_name), _name.length(), name);
1837 i->set_name (current_name);
1841 name_changed (src); /* EMIT SIGNAL */
1847 IO::set_input_minimum (ChanCount n)
1853 IO::set_input_maximum (ChanCount n)
1859 IO::set_output_minimum (ChanCount n)
1861 _output_minimum = n;
1865 IO::set_output_maximum (ChanCount n)
1867 _output_maximum = n;
1871 IO::set_port_latency (nframes_t nframes)
1873 Glib::Mutex::Lock lm (io_lock);
1875 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1876 i->set_latency (nframes);
1881 IO::output_latency () const
1883 nframes_t max_latency;
1888 /* io lock not taken - must be protected by other means */
1890 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1891 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1892 max_latency = latency;
1900 IO::input_latency () const
1902 nframes_t max_latency;
1907 /* io lock not taken - must be protected by other means */
1909 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1910 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1911 max_latency = latency;
1919 IO::use_input_connection (Connection& c, void* src)
1924 BLOCK_PROCESS_CALLBACK ();
1925 Glib::Mutex::Lock lm2 (io_lock);
1929 drop_input_connection ();
1931 // FIXME connections only work for audio-only
1932 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1936 /* first pass: check the current state to see what's correctly
1937 connected, and drop anything that we don't want.
1940 for (uint32_t n = 0; n < limit; ++n) {
1941 const Connection::PortList& pl = c.port_connections (n);
1943 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1945 if (!_inputs.port(n)->connected_to ((*i))) {
1947 /* clear any existing connections */
1949 _session.engine().disconnect (*_inputs.port(n));
1951 } else if (_inputs.port(n)->connected() > 1) {
1953 /* OK, it is connected to the port we want,
1954 but its also connected to other ports.
1955 Change that situation.
1958 /* XXX could be optimized to not drop
1962 _session.engine().disconnect (*_inputs.port(n));
1968 /* second pass: connect all requested ports where necessary */
1970 for (uint32_t n = 0; n < limit; ++n) {
1971 const Connection::PortList& pl = c.port_connections (n);
1973 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1975 if (!_inputs.port(n)->connected_to ((*i))) {
1977 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1985 _input_connection = &c;
1987 input_connection_configuration_connection = c.ConfigurationChanged.connect
1988 (mem_fun (*this, &IO::input_connection_configuration_changed));
1989 input_connection_connection_connection = c.ConnectionsChanged.connect
1990 (mem_fun (*this, &IO::input_connection_connection_changed));
1993 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1998 IO::use_output_connection (Connection& c, void* src)
2003 BLOCK_PROCESS_CALLBACK ();
2004 Glib::Mutex::Lock lm2 (io_lock);
2008 drop_output_connection ();
2010 // FIXME: audio-only
2011 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2015 /* first pass: check the current state to see what's correctly
2016 connected, and drop anything that we don't want.
2019 for (uint32_t n = 0; n < limit; ++n) {
2021 const Connection::PortList& pl = c.port_connections (n);
2023 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2025 if (!_outputs.port(n)->connected_to ((*i))) {
2027 /* clear any existing connections */
2029 _session.engine().disconnect (*_outputs.port(n));
2031 } else if (_outputs.port(n)->connected() > 1) {
2033 /* OK, it is connected to the port we want,
2034 but its also connected to other ports.
2035 Change that situation.
2038 /* XXX could be optimized to not drop
2042 _session.engine().disconnect (*_outputs.port(n));
2047 /* second pass: connect all requested ports where necessary */
2049 for (uint32_t n = 0; n < limit; ++n) {
2051 const Connection::PortList& pl = c.port_connections (n);
2053 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2055 if (!_outputs.port(n)->connected_to ((*i))) {
2057 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2064 _output_connection = &c;
2066 output_connection_configuration_connection = c.ConfigurationChanged.connect
2067 (mem_fun (*this, &IO::output_connection_configuration_changed));
2068 output_connection_connection_connection = c.ConnectionsChanged.connect
2069 (mem_fun (*this, &IO::output_connection_connection_changed));
2072 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2078 IO::disable_connecting ()
2080 connecting_legal = false;
2085 IO::enable_connecting ()
2087 connecting_legal = true;
2088 return ConnectingLegal ();
2092 IO::disable_ports ()
2094 ports_legal = false;
2102 return PortsLegal ();
2106 IO::disable_panners (void)
2108 panners_legal = false;
2113 IO::reset_panners ()
2115 panners_legal = true;
2116 return PannersLegal ();
2120 IO::input_connection_connection_changed (int ignored)
2122 use_input_connection (*_input_connection, this);
2126 IO::input_connection_configuration_changed ()
2128 use_input_connection (*_input_connection, this);
2132 IO::output_connection_connection_changed (int ignored)
2134 use_output_connection (*_output_connection, this);
2138 IO::output_connection_configuration_changed ()
2140 use_output_connection (*_output_connection, this);
2144 IO::GainControllable::set_value (float val)
2146 io.set_gain (direct_control_to_gain (val), this);
2150 IO::GainControllable::get_value (void) const
2152 return direct_gain_to_control (io.effective_gain());
2156 IO::setup_peak_meters()
2158 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2162 Update the peak meters.
2164 The meter signal lock is taken to prevent modification of the
2165 Meter signal while updating the meters, taking the meter signal
2166 lock prior to taking the io_lock ensures that all IO will remain
2167 valid while metering.
2172 Glib::Mutex::Lock guard (m_meter_signal_lock);
2174 Meter(); /* EMIT SIGNAL */
2180 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2182 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2187 IO::clear_automation ()
2189 Glib::Mutex::Lock lm (automation_lock);
2190 _gain_automation_curve.clear ();
2191 _panner->clear_automation ();
2195 IO::set_gain_automation_state (AutoState state)
2197 bool changed = false;
2200 Glib::Mutex::Lock lm (automation_lock);
2202 if (state != _gain_automation_curve.automation_state()) {
2204 last_automation_snapshot = 0;
2205 _gain_automation_curve.set_automation_state (state);
2208 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2214 _session.set_dirty ();
2215 gain_automation_state_changed (); /* EMIT SIGNAL */
2220 IO::set_gain_automation_style (AutoStyle style)
2222 bool changed = false;
2225 Glib::Mutex::Lock lm (automation_lock);
2227 if (style != _gain_automation_curve.automation_style()) {
2229 _gain_automation_curve.set_automation_style (style);
2234 gain_automation_style_changed (); /* EMIT SIGNAL */
2238 IO::inc_gain (gain_t factor, void *src)
2240 if (_desired_gain == 0.0f)
2241 set_gain (0.000001f + (0.000001f * factor), src);
2243 set_gain (_desired_gain + (_desired_gain * factor), src);
2247 IO::set_gain (gain_t val, void *src)
2249 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2250 if (val>1.99526231f) val=1.99526231f;
2253 Glib::Mutex::Lock dm (declick_lock);
2254 _desired_gain = val;
2257 if (_session.transport_stopped()) {
2258 _effective_gain = val;
2263 _gain_control.Changed (); /* EMIT SIGNAL */
2265 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2266 _gain_automation_curve.add (_session.transport_frame(), val);
2270 _session.set_dirty();
2274 IO::start_gain_touch ()
2276 _gain_automation_curve.start_touch ();
2280 IO::end_gain_touch ()
2282 _gain_automation_curve.stop_touch ();
2286 IO::start_pan_touch (uint32_t which)
2288 if (which < _panner->size()) {
2289 (*_panner)[which]->automation().start_touch();
2294 IO::end_pan_touch (uint32_t which)
2296 if (which < _panner->size()) {
2297 (*_panner)[which]->automation().stop_touch();
2303 IO::automation_snapshot (nframes_t now)
2305 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2307 if (gain_automation_recording()) {
2308 _gain_automation_curve.rt_add (now, gain());
2311 _panner->snapshot (now);
2313 last_automation_snapshot = now;
2318 IO::transport_stopped (nframes_t frame)
2320 _gain_automation_curve.reposition_for_rt_add (frame);
2322 if (_gain_automation_curve.automation_state() != Off) {
2324 /* the src=0 condition is a special signal to not propagate
2325 automation gain changes into the mix group when locating.
2328 set_gain (_gain_automation_curve.eval (frame), 0);
2331 _panner->transport_stopped (frame);
2335 IO::find_input_port_hole ()
2337 /* CALLER MUST HOLD IO LOCK */
2341 if (_inputs.empty()) {
2345 for (n = 1; n < UINT_MAX; ++n) {
2346 char buf[jack_port_name_size()];
2347 PortSet::iterator i = _inputs.begin();
2349 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2351 for ( ; i != _inputs.end(); ++i) {
2352 if (i->short_name() == buf) {
2357 if (i == _inputs.end()) {
2365 IO::find_output_port_hole ()
2367 /* CALLER MUST HOLD IO LOCK */
2371 if (_outputs.empty()) {
2375 for (n = 1; n < UINT_MAX; ++n) {
2376 char buf[jack_port_name_size()];
2377 PortSet::iterator i = _outputs.begin();
2379 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2381 for ( ; i != _outputs.end(); ++i) {
2382 if (i->short_name() == buf) {
2387 if (i == _outputs.end()) {
2396 IO::audio_input(uint32_t n) const
2398 return dynamic_cast<AudioPort*>(input(n));
2402 IO::audio_output(uint32_t n) const
2404 return dynamic_cast<AudioPort*>(output(n));
2408 IO::midi_input(uint32_t n) const
2410 return dynamic_cast<MidiPort*>(input(n));
2414 IO::midi_output(uint32_t n) const
2416 return dynamic_cast<MidiPort*>(output(n));
2420 IO::set_phase_invert (bool yn, void *src)
2422 if (_phase_invert != yn) {
2425 // phase_invert_changed (src); /* EMIT SIGNAL */