2 Copyright (C) 2000 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.
26 #include <sigc++/bind.h>
28 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/connection.h>
36 #include <ardour/session.h>
37 #include <ardour/cycle_timer.h>
38 #include <ardour/panner.h>
39 #include <ardour/dB.h>
46 A bug in OS X's cmath that causes isnan() and isinf() to be
47 "undeclared". the following works around that
50 #if defined(__APPLE__) && defined(__MACH__)
51 extern "C" int isnan (double);
52 extern "C" int isinf (double);
55 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
58 using namespace ARDOUR;
61 nframes_t IO::_automation_interval = 0;
62 const string IO::state_node_name = "IO";
63 bool IO::connecting_legal = false;
64 bool IO::ports_legal = false;
65 bool IO::panners_legal = false;
66 sigc::signal<void> IO::Meter;
67 sigc::signal<int> IO::ConnectingLegal;
68 sigc::signal<int> IO::PortsLegal;
69 sigc::signal<int> IO::PannersLegal;
70 sigc::signal<void,uint32_t> IO::MoreOutputs;
71 sigc::signal<int> IO::PortsCreated;
73 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
75 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
76 others can be imagined.
79 static gain_t direct_control_to_gain (double fract) {
80 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
81 /* this maxes at +6dB */
82 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
85 static double direct_gain_to_control (gain_t gain) {
86 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
87 if (gain == 0) return 0.0;
89 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
92 static bool sort_ports_by_name (Port* a, Port* b)
94 return a->name() < b->name();
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)
106 _default_type(default_type),
107 _gain_control (X_("gaincontrol"), *this),
108 _gain_automation_curve (0.0, 2.0, 1.0),
109 _input_minimum (input_min),
110 _input_maximum (input_max),
111 _output_minimum (output_min),
112 _output_maximum (output_max)
114 _panner = new Panner (name, _session);
117 _input_connection = 0;
118 _output_connection = 0;
119 pending_state_node = 0;
122 no_panner_reset = false;
125 apply_gain_automation = false;
126 _ignore_gain_on_deliver = false;
128 last_automation_snapshot = 0;
130 _gain_automation_state = Off;
131 _gain_automation_style = Absolute;
134 // IO::Meter is emitted from another thread so the
135 // Meter signal must be protected.
136 Glib::Mutex::Lock guard (m_meter_signal_lock);
137 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
140 _session.add_controllable (&_gain_control);
143 IO::IO (Session& s, const XMLNode& node, DataType dt)
146 _gain_control (X_("gaincontrol"), *this),
147 _gain_automation_curve (0, 0, 0) // all reset in set_state()
151 no_panner_reset = false;
154 _input_connection = 0;
155 _output_connection = 0;
159 apply_gain_automation = false;
160 _ignore_gain_on_deliver = false;
165 // IO::Meter is emitted from another thread so the
166 // Meter signal must be protected.
167 Glib::Mutex::Lock guard (m_meter_signal_lock);
168 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
171 _session.add_controllable (&_gain_control);
176 Glib::Mutex::Lock guard (m_meter_signal_lock);
178 Glib::Mutex::Lock lm (io_lock);
179 vector<Port *>::iterator i;
181 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
182 _session.engine().unregister_port (*i);
185 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
186 _session.engine().unregister_port (*i);
189 m_meter_connection.disconnect();
193 IO::silence (nframes_t nframes, nframes_t offset)
195 /* io_lock, not taken: function must be called from Session::process() calltree */
197 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
198 (*i)->silence (nframes, offset);
203 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
205 nframes_t declick = min ((nframes_t)128, nframes);
208 double fractional_shift;
209 double fractional_pos;
210 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
212 if (nframes == 0) return;
214 fractional_shift = -1.0/declick;
216 if (target < initial) {
217 /* fade out: remove more and more of delta from initial */
218 delta = -(initial - target);
220 /* fade in: add more and more of delta from initial */
221 delta = target - initial;
224 for (uint32_t n = 0; n < nbufs; ++n) {
227 fractional_pos = 1.0;
229 for (nframes_t nx = 0; nx < declick; ++nx) {
230 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
231 fractional_pos += fractional_shift;
234 /* now ensure the rest of the buffer has the target value
235 applied, if necessary.
238 if (declick != nframes) {
241 if (invert_polarity) {
242 this_target = -target;
244 this_target = target;
247 if (this_target == 0.0) {
248 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
249 } else if (this_target != 1.0) {
250 for (nframes_t nx = declick; nx < nframes; ++nx) {
251 buffer[nx] *= this_target;
259 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
263 /* io_lock, not taken: function must be called from Session::process() calltree */
265 if (_noutputs == 0) {
269 if (_noutputs == 1) {
271 dst = output(0)->get_buffer (nframes) + offset;
273 for (uint32_t n = 0; n < nbufs; ++n) {
274 if (bufs[n] != dst) {
275 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
279 output(0)->mark_silence (false);
285 vector<Port *>::iterator out;
286 vector<Sample *>::iterator in;
287 Panner::iterator pan;
288 Sample* obufs[_noutputs];
290 /* the terrible silence ... */
292 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
293 obufs[o] = (*out)->get_buffer (nframes) + offset;
294 memset (obufs[o], 0, sizeof (Sample) * nframes);
295 (*out)->mark_silence (false);
300 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
301 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
306 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
311 /* io_lock, not taken: function must be called from Session::process() calltree */
313 if (_noutputs == 0) {
317 /* the panner can be empty if there are no inputs to the
318 route, but still outputs
321 if (_panner->bypassed() || _panner->empty()) {
322 deliver_output_no_pan (bufs, nbufs, nframes, offset);
326 if (_noutputs == 1) {
328 dst = output(0)->get_buffer (nframes) + offset;
330 if (gain_coeff == 0.0f) {
332 /* only one output, and gain was zero, so make it silent */
334 memset (dst, 0, sizeof (Sample) * nframes);
336 } else if (gain_coeff == 1.0f){
338 /* mix all buffers into the output */
342 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
344 for (n = 1; n < nbufs; ++n) {
347 for (nframes_t n = 0; n < nframes; ++n) {
352 output(0)->mark_silence (false);
356 /* mix all buffers into the output, scaling them all by the gain */
362 for (nframes_t n = 0; n < nframes; ++n) {
363 dst[n] = src[n] * gain_coeff;
366 for (n = 1; n < nbufs; ++n) {
369 for (nframes_t n = 0; n < nframes; ++n) {
370 dst[n] += src[n] * gain_coeff;
374 output(0)->mark_silence (false);
381 vector<Port *>::iterator out;
382 vector<Sample *>::iterator in;
383 Panner::iterator pan;
384 Sample* obufs[_noutputs];
386 /* the terrible silence ... */
388 /* XXX this is wasteful but i see no way to avoid it */
390 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
391 obufs[o] = (*out)->get_buffer (nframes) + offset;
392 memset (obufs[o], 0, sizeof (Sample) * nframes);
393 (*out)->mark_silence (false);
398 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
399 Panner::iterator tmp;
404 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
406 if (tmp != _panner->end()) {
413 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
415 /* io_lock, not taken: function must be called from Session::process() calltree */
417 if (_noutputs == 0) {
421 if (_panner->bypassed() || _panner->empty()) {
422 deliver_output_no_pan (bufs, nbufs, nframes, offset);
428 gain_t pangain = _gain;
431 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
441 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
446 /* simple, non-automation panning to outputs */
448 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
449 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
451 pan (bufs, nbufs, nframes, offset, pangain);
456 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
458 /* io_lock, not taken: function must be called from Session::process() calltree */
460 if (_noutputs == 0) {
465 gain_t old_gain = _gain;
467 if (apply_gain_automation || _ignore_gain_on_deliver) {
469 /* gain has already been applied by automation code. do nothing here except
478 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
490 vector<Port*>::iterator o;
491 vector<Sample*> outs;
495 /* unlikely condition */
496 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
497 outs.push_back ((*o)->get_buffer (nframes) + offset);
501 /* reduce nbufs to the index of the last input buffer */
505 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
506 actual_gain = _gain * speed_quietning;
511 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
513 dst = (*o)->get_buffer (nframes) + offset;
514 src = bufs[min(nbufs,i)];
516 if (dg != _gain || actual_gain == 1.0f) {
517 memcpy (dst, src, sizeof (Sample) * nframes);
518 } else if (actual_gain == 0.0f) {
519 memset (dst, 0, sizeof (Sample) * nframes);
521 for (nframes_t x = 0; x < nframes; ++x) {
522 dst[x] = src[x] * actual_gain;
526 (*o)->mark_silence (false);
530 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
534 if (apply_gain_automation || _ignore_gain_on_deliver) {
540 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
542 /* io_lock, not taken: function must be called from Session::process() calltree */
544 vector<Port *>::iterator i;
548 /* we require that bufs.size() >= 1 */
550 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
551 if (i == _inputs.end()) {
555 /* XXX always read the full extent of the port buffer that
556 we need. One day, we may use jack_port_get_buffer_at_offset()
557 or something similar. For now, this simple hack will
560 Hack? Why yes .. we only need to read nframes-worth of
561 data, but the data we want is at `offset' within the
565 last = (*i)->get_buffer (nframes+offset) + offset;
566 // the dest buffer's offset has already been applied
567 memcpy (bufs[n], last, sizeof (Sample) * nframes);
570 /* fill any excess outputs with the last input */
574 // the dest buffer's offset has already been applied
575 memcpy (bufs[n], last, sizeof (Sample) * nframes);
580 memset (bufs[n], 0, sizeof (Sample) * nframes);
587 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
588 nframes_t nframes, nframes_t offset)
590 vector<Sample*>& bufs = _session.get_passthru_buffers ();
591 uint32_t nbufs = n_process_buffers ();
593 collect_input (bufs, nbufs, nframes, offset);
595 for (uint32_t n = 0; n < nbufs; ++n) {
596 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
601 IO::drop_input_connection ()
603 _input_connection = 0;
604 input_connection_configuration_connection.disconnect();
605 input_connection_connection_connection.disconnect();
606 _session.set_dirty ();
610 IO::drop_output_connection ()
612 _output_connection = 0;
613 output_connection_configuration_connection.disconnect();
614 output_connection_connection_connection.disconnect();
615 _session.set_dirty ();
619 IO::disconnect_input (Port* our_port, string other_port, void* src)
621 if (other_port.length() == 0 || our_port == 0) {
626 BLOCK_PROCESS_CALLBACK ();
629 Glib::Mutex::Lock lm (io_lock);
631 /* check that our_port is really one of ours */
633 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
637 /* disconnect it from the source */
639 if (_session.engine().disconnect (other_port, our_port->name())) {
640 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
644 drop_input_connection();
648 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
649 _session.set_dirty ();
655 IO::connect_input (Port* our_port, string other_port, void* src)
657 if (other_port.length() == 0 || our_port == 0) {
662 BLOCK_PROCESS_CALLBACK ();
665 Glib::Mutex::Lock lm (io_lock);
667 /* check that our_port is really one of ours */
669 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
673 /* connect it to the source */
675 if (_session.engine().connect (other_port, our_port->name())) {
679 drop_input_connection ();
683 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
684 _session.set_dirty ();
689 IO::disconnect_output (Port* our_port, string other_port, void* src)
691 if (other_port.length() == 0 || our_port == 0) {
696 BLOCK_PROCESS_CALLBACK ();
699 Glib::Mutex::Lock lm (io_lock);
701 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
705 /* disconnect it from the destination */
707 if (_session.engine().disconnect (our_port->name(), other_port)) {
708 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
712 drop_output_connection ();
716 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
717 _session.set_dirty ();
722 IO::connect_output (Port* our_port, string other_port, void* src)
724 if (other_port.length() == 0 || our_port == 0) {
729 BLOCK_PROCESS_CALLBACK ();
733 Glib::Mutex::Lock lm (io_lock);
735 /* check that our_port is really one of ours */
737 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
741 /* connect it to the destination */
743 if (_session.engine().connect (our_port->name(), other_port)) {
747 drop_output_connection ();
751 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
752 _session.set_dirty ();
757 IO::set_input (Port* other_port, void* src)
759 /* this removes all but one ports, and connects that one port
760 to the specified source.
763 if (_input_minimum > 1 || _input_minimum == 0) {
764 /* sorry, you can't do this */
768 if (other_port == 0) {
769 if (_input_minimum < 0) {
770 return ensure_inputs (0, false, true, src);
776 if (ensure_inputs (1, true, true, src)) {
780 return connect_input (_inputs.front(), other_port->name(), src);
784 IO::remove_output_port (Port* port, void* src)
786 IOChange change (NoChange);
789 BLOCK_PROCESS_CALLBACK ();
793 Glib::Mutex::Lock lm (io_lock);
795 if (_noutputs - 1 == (uint32_t) _output_minimum) {
796 /* sorry, you can't do this */
800 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
802 change = IOChange (change|ConfigurationChanged);
803 if (port->connected()) {
804 change = IOChange (change|ConnectionsChanged);
807 _session.engine().unregister_port (*i);
810 drop_output_connection ();
816 if (change != NoChange) {
817 setup_peak_meters ();
823 if (change != NoChange) {
824 output_changed (change, src); /* EMIT SIGNAL */
825 _session.set_dirty ();
832 /** Add an output port.
834 * @param destination Name of input port to connect new port to.
835 * @param src Source for emitted ConfigurationChanged signal.
836 * @param type Data type of port. Default value (NIL) will use this IO's default type.
839 IO::add_output_port (string destination, void* src, DataType type)
844 if (type == DataType::NIL)
845 type = _default_type;
848 BLOCK_PROCESS_CALLBACK ();
852 Glib::Mutex::Lock lm (io_lock);
854 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
858 /* Create a new output port */
860 // FIXME: naming scheme for differently typed ports?
861 if (_output_maximum == 1) {
862 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
864 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
867 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
868 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
872 _outputs.push_back (our_port);
873 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
875 drop_output_connection ();
876 setup_peak_meters ();
880 MoreOutputs (_noutputs); /* EMIT SIGNAL */
883 if (destination.length()) {
884 if (_session.engine().connect (our_port->name(), destination)) {
889 // pan_changed (src); /* EMIT SIGNAL */
890 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
891 _session.set_dirty ();
896 IO::remove_input_port (Port* port, void* src)
898 IOChange change (NoChange);
901 BLOCK_PROCESS_CALLBACK ();
905 Glib::Mutex::Lock lm (io_lock);
907 if (((int)_ninputs - 1) < _input_minimum) {
908 /* sorry, you can't do this */
911 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
914 change = IOChange (change|ConfigurationChanged);
916 if (port->connected()) {
917 change = IOChange (change|ConnectionsChanged);
920 _session.engine().unregister_port (*i);
923 drop_input_connection ();
929 if (change != NoChange) {
930 setup_peak_meters ();
936 if (change != NoChange) {
937 input_changed (change, src);
938 _session.set_dirty ();
946 /** Add an input port.
948 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
949 * @param destination Name of input port to connect new port to.
950 * @param src Source for emitted ConfigurationChanged signal.
953 IO::add_input_port (string source, void* src, DataType type)
958 if (type == DataType::NIL)
959 type = _default_type;
962 BLOCK_PROCESS_CALLBACK ();
965 Glib::Mutex::Lock lm (io_lock);
967 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
971 /* Create a new input port */
973 // FIXME: naming scheme for differently typed ports?
974 if (_input_maximum == 1) {
975 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
977 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
980 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
981 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
985 _inputs.push_back (our_port);
986 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
988 drop_input_connection ();
989 setup_peak_meters ();
993 MoreOutputs (_ninputs); /* EMIT SIGNAL */
996 if (source.length()) {
998 if (_session.engine().connect (source, our_port->name())) {
1003 // pan_changed (src); /* EMIT SIGNAL */
1004 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1005 _session.set_dirty ();
1011 IO::disconnect_inputs (void* src)
1014 BLOCK_PROCESS_CALLBACK ();
1017 Glib::Mutex::Lock lm (io_lock);
1019 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1020 _session.engine().disconnect (*i);
1023 drop_input_connection ();
1026 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1031 IO::disconnect_outputs (void* src)
1034 BLOCK_PROCESS_CALLBACK ();
1037 Glib::Mutex::Lock lm (io_lock);
1039 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1040 _session.engine().disconnect (*i);
1043 drop_output_connection ();
1047 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1048 _session.set_dirty ();
1053 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1056 bool changed = false;
1057 bool reduced = false;
1059 /* remove unused ports */
1061 while (_ninputs > n) {
1062 _session.engine().unregister_port (_inputs.back());
1069 /* create any necessary new ports */
1071 while (_ninputs < n) {
1075 /* Create a new input port (of the default type) */
1077 if (_input_maximum == 1) {
1078 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1081 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1086 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1087 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1092 catch (AudioEngine::PortRegistrationFailure& err) {
1093 setup_peak_meters ();
1096 throw AudioEngine::PortRegistrationFailure();
1099 _inputs.push_back (input_port);
1100 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1106 drop_input_connection ();
1107 setup_peak_meters ();
1109 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1110 _session.set_dirty ();
1114 /* disconnect all existing ports so that we get a fresh start */
1116 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1117 _session.engine().disconnect (*i);
1125 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1127 bool in_changed = false;
1128 bool out_changed = false;
1129 bool in_reduced = false;
1130 bool out_reduced = false;
1131 bool need_pan_reset;
1133 if (_input_maximum >= 0) {
1134 nin = min (_input_maximum, (int) nin);
1137 if (_output_maximum >= 0) {
1138 nout = min (_output_maximum, (int) nout);
1141 if (nin == _ninputs && nout == _noutputs && !clear) {
1146 BLOCK_PROCESS_CALLBACK ();
1147 Glib::Mutex::Lock lm (io_lock);
1151 if (_noutputs == nout) {
1152 need_pan_reset = false;
1154 need_pan_reset = true;
1157 /* remove unused ports */
1159 while (_ninputs > nin) {
1160 _session.engine().unregister_port (_inputs.back());
1167 while (_noutputs > nout) {
1168 _session.engine().unregister_port (_outputs.back());
1169 _outputs.pop_back();
1175 /* create any necessary new ports (of the default type) */
1177 while (_ninputs < nin) {
1181 /* Create a new input port */
1183 if (_input_maximum == 1) {
1184 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1187 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1191 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1192 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1197 catch (AudioEngine::PortRegistrationFailure& err) {
1198 setup_peak_meters ();
1201 throw AudioEngine::PortRegistrationFailure();
1204 _inputs.push_back (port);
1209 /* create any necessary new ports */
1211 while (_noutputs < nout) {
1215 /* Create a new output port */
1217 if (_output_maximum == 1) {
1218 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1220 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1224 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1225 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1230 catch (AudioEngine::PortRegistrationFailure& err) {
1231 setup_peak_meters ();
1234 throw AudioEngine::PortRegistrationFailure ();
1237 _outputs.push_back (port);
1244 /* disconnect all existing ports so that we get a fresh start */
1246 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1247 _session.engine().disconnect (*i);
1250 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1251 _session.engine().disconnect (*i);
1255 if (in_changed || out_changed) {
1256 setup_peak_meters ();
1262 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1263 drop_output_connection ();
1264 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1268 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1269 drop_input_connection ();
1270 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1273 if (in_changed || out_changed) {
1274 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1275 _session.set_dirty ();
1282 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1284 bool changed = false;
1286 if (_input_maximum >= 0) {
1287 n = min (_input_maximum, (int) n);
1289 if (n == _ninputs && !clear) {
1295 BLOCK_PROCESS_CALLBACK ();
1296 Glib::Mutex::Lock im (io_lock);
1297 changed = ensure_inputs_locked (n, clear, src);
1299 changed = ensure_inputs_locked (n, clear, src);
1303 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1304 _session.set_dirty ();
1311 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1314 bool changed = false;
1315 bool reduced = false;
1316 bool need_pan_reset;
1318 if (_noutputs == n) {
1319 need_pan_reset = false;
1321 need_pan_reset = true;
1324 /* remove unused ports */
1326 while (_noutputs > n) {
1328 _session.engine().unregister_port (_outputs.back());
1329 _outputs.pop_back();
1335 /* create any necessary new ports */
1337 while (_noutputs < n) {
1341 /* Create a new output port */
1343 if (_output_maximum == 1) {
1344 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1346 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1349 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1350 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1354 _outputs.push_back (output_port);
1355 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1358 setup_peak_meters ();
1360 if (need_pan_reset) {
1366 drop_output_connection ();
1367 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1368 _session.set_dirty ();
1372 /* disconnect all existing ports so that we get a fresh start */
1374 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1375 _session.engine().disconnect (*i);
1383 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1385 bool changed = false;
1387 if (_output_maximum >= 0) {
1388 n = min (_output_maximum, (int) n);
1389 if (n == _noutputs && !clear) {
1394 /* XXX caller should hold io_lock, but generally doesn't */
1397 BLOCK_PROCESS_CALLBACK ();
1398 Glib::Mutex::Lock im (io_lock);
1399 changed = ensure_outputs_locked (n, clear, src);
1401 changed = ensure_outputs_locked (n, clear, src);
1405 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1412 IO::effective_gain () const
1414 if (gain_automation_playback()) {
1415 return _effective_gain;
1417 return _desired_gain;
1424 if (panners_legal) {
1425 if (!no_panner_reset) {
1426 _panner->reset (_noutputs, pans_required());
1429 panner_legal_c.disconnect ();
1430 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1435 IO::panners_became_legal ()
1437 _panner->reset (_noutputs, pans_required());
1438 _panner->load (); // automation
1439 panner_legal_c.disconnect ();
1444 IO::defer_pan_reset ()
1446 no_panner_reset = true;
1450 IO::allow_pan_reset ()
1452 no_panner_reset = false;
1458 IO::get_state (void)
1460 return state (true);
1464 IO::state (bool full_state)
1466 XMLNode* node = new XMLNode (state_node_name);
1469 bool need_ins = true;
1470 bool need_outs = true;
1471 LocaleGuard lg (X_("POSIX"));
1472 Glib::Mutex::Lock lm (io_lock);
1474 node->add_property("name", _name);
1475 id().print (buf, sizeof (buf));
1476 node->add_property("id", buf);
1480 if (_input_connection) {
1481 node->add_property ("input-connection", _input_connection->name());
1485 if (_output_connection) {
1486 node->add_property ("output-connection", _output_connection->name());
1491 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1493 const char **connections = (*i)->get_connections();
1495 if (connections && connections[0]) {
1498 for (int n = 0; connections && connections[n]; ++n) {
1503 /* if its a connection to our own port,
1504 return only the port name, not the
1505 whole thing. this allows connections
1506 to be re-established even when our
1507 client name is different.
1510 str += _session.engine().make_port_name_relative (connections[n]);
1522 node->add_property ("inputs", str);
1528 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1530 const char **connections = (*i)->get_connections();
1532 if (connections && connections[0]) {
1536 for (int n = 0; connections[n]; ++n) {
1541 str += _session.engine().make_port_name_relative (connections[n]);
1553 node->add_property ("outputs", str);
1556 node->add_child_nocopy (_panner->state (full_state));
1557 node->add_child_nocopy (_gain_control.get_state ());
1559 snprintf (buf, sizeof(buf), "%2.12f", gain());
1560 node->add_property ("gain", buf);
1562 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1568 node->add_property ("iolimits", buf);
1574 XMLNode* autonode = new XMLNode (X_("Automation"));
1575 autonode->add_child_nocopy (get_automation_state());
1576 node->add_child_nocopy (*autonode);
1578 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1580 /* never store anything except Off for automation state in a template */
1581 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1588 IO::set_state (const XMLNode& node)
1590 const XMLProperty* prop;
1591 XMLNodeConstIterator iter;
1592 LocaleGuard lg (X_("POSIX"));
1594 /* force use of non-localized representation of decimal point,
1595 since we use it a lot in XML files and so forth.
1598 if (node.name() != state_node_name) {
1599 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1603 if ((prop = node.property ("name")) != 0) {
1604 _name = prop->value();
1605 /* used to set panner name with this, but no more */
1608 if ((prop = node.property ("id")) != 0) {
1609 _id = prop->value ();
1612 if ((prop = node.property ("iolimits")) != 0) {
1613 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1620 if ((prop = node.property ("gain")) != 0) {
1621 set_gain (atof (prop->value().c_str()), this);
1622 _gain = _desired_gain;
1625 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1626 /* old school automation handling */
1629 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1631 if ((*iter)->name() == "Panner") {
1633 _panner = new Panner (_name, _session);
1635 _panner->set_state (**iter);
1638 if ((*iter)->name() == X_("Automation")) {
1640 set_automation_state (*(*iter)->children().front());
1643 if ((*iter)->name() == X_("controllable")) {
1644 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1645 _gain_control.set_state (**iter);
1652 if (create_ports (node)) {
1658 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1661 if (panners_legal) {
1664 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1667 if (connecting_legal) {
1669 if (make_connections (node)) {
1675 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1678 if (!ports_legal || !connecting_legal) {
1679 pending_state_node = new XMLNode (node);
1682 last_automation_snapshot = 0;
1688 IO::set_automation_state (const XMLNode& node)
1690 return _gain_automation_curve.set_state (node);
1694 IO::get_automation_state ()
1696 return (_gain_automation_curve.get_state ());
1700 IO::load_automation (string path)
1705 uint32_t linecnt = 0;
1707 LocaleGuard lg (X_("POSIX"));
1709 fullpath = _session.automation_dir();
1712 in.open (fullpath.c_str());
1715 fullpath = _session.automation_dir();
1716 fullpath += _session.snap_name();
1720 in.open (fullpath.c_str());
1723 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1728 clear_automation ();
1730 while (in.getline (line, sizeof(line), '\n')) {
1732 jack_nframes_t when;
1735 if (++linecnt == 1) {
1736 if (memcmp (line, "version", 7) == 0) {
1737 if (sscanf (line, "version %f", &version) != 1) {
1738 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1742 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1749 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1750 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1756 _gain_automation_curve.fast_simple_add (when, value);
1766 /* older (pre-1.0) versions of ardour used this */
1770 warning << _("dubious automation event found (and ignored)") << endmsg;
1778 IO::connecting_became_legal ()
1782 if (pending_state_node == 0) {
1783 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1788 connection_legal_c.disconnect ();
1790 ret = make_connections (*pending_state_node);
1793 delete pending_state_node;
1794 pending_state_node = 0;
1800 IO::ports_became_legal ()
1804 if (pending_state_node == 0) {
1805 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1810 port_legal_c.disconnect ();
1812 ret = create_ports (*pending_state_node);
1814 if (connecting_legal) {
1815 delete pending_state_node;
1816 pending_state_node = 0;
1823 IO::create_ports (const XMLNode& node)
1825 const XMLProperty* prop;
1827 int num_outputs = 0;
1829 if ((prop = node.property ("input-connection")) != 0) {
1831 Connection* c = _session.connection_by_name (prop->value());
1834 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1836 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1837 error << _("No input connections available as a replacement")
1841 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1846 num_inputs = c->nports();
1848 } else if ((prop = node.property ("inputs")) != 0) {
1850 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1853 if ((prop = node.property ("output-connection")) != 0) {
1854 Connection* c = _session.connection_by_name (prop->value());
1857 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1859 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1860 error << _("No output connections available as a replacement")
1864 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1869 num_outputs = c->nports ();
1871 } else if ((prop = node.property ("outputs")) != 0) {
1872 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1875 no_panner_reset = true;
1877 if (ensure_io (num_inputs, num_outputs, true, this)) {
1878 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1882 no_panner_reset = false;
1884 set_deferred_state ();
1892 IO::make_connections (const XMLNode& node)
1894 const XMLProperty* prop;
1896 if ((prop = node.property ("input-connection")) != 0) {
1897 Connection* c = _session.connection_by_name (prop->value());
1900 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1902 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1903 error << _("No input connections available as a replacement")
1907 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1912 use_input_connection (*c, this);
1914 } else if ((prop = node.property ("inputs")) != 0) {
1915 if (set_inputs (prop->value())) {
1916 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1921 if ((prop = node.property ("output-connection")) != 0) {
1922 Connection* c = _session.connection_by_name (prop->value());
1925 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1927 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1928 error << _("No output connections available as a replacement")
1932 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1937 use_output_connection (*c, this);
1939 } else if ((prop = node.property ("outputs")) != 0) {
1940 if (set_outputs (prop->value())) {
1941 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1950 IO::set_inputs (const string& str)
1952 vector<string> ports;
1957 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1961 if (ensure_inputs (nports, true, true, this)) {
1965 string::size_type start, end, ostart;
1972 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1975 if ((end = str.find_first_of ('}', start)) == string::npos) {
1976 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1980 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1981 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1987 for (int x = 0; x < n; ++x) {
1988 connect_input (input (i), ports[x], this);
2000 IO::set_outputs (const string& str)
2002 vector<string> ports;
2007 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2011 if (ensure_outputs (nports, true, true, this)) {
2015 string::size_type start, end, ostart;
2022 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2025 if ((end = str.find_first_of ('}', start)) == string::npos) {
2026 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2030 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2031 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2037 for (int x = 0; x < n; ++x) {
2038 connect_output (output (i), ports[x], this);
2050 IO::parse_io_string (const string& str, vector<string>& ports)
2052 string::size_type pos, opos;
2054 if (str.length() == 0) {
2063 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2064 ports.push_back (str.substr (opos, pos - opos));
2068 if (opos < str.length()) {
2069 ports.push_back (str.substr(opos));
2072 return ports.size();
2076 IO::parse_gain_string (const string& str, vector<string>& ports)
2078 string::size_type pos, opos;
2084 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2085 ports.push_back (str.substr (opos, pos - opos));
2089 if (opos < str.length()) {
2090 ports.push_back (str.substr(opos));
2093 return ports.size();
2097 IO::set_name (string name, void* src)
2099 if (name == _name) {
2103 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2104 string current_name = (*i)->short_name();
2105 current_name.replace (current_name.find (_name), _name.length(), name);
2106 (*i)->set_name (current_name);
2109 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2110 string current_name = (*i)->short_name();
2111 current_name.replace (current_name.find (_name), _name.length(), name);
2112 (*i)->set_name (current_name);
2116 name_changed (src); /* EMIT SIGNAL */
2122 IO::set_input_minimum (int n)
2128 IO::set_input_maximum (int n)
2134 IO::set_output_minimum (int n)
2136 _output_minimum = n;
2140 IO::set_output_maximum (int n)
2142 _output_maximum = n;
2146 IO::set_port_latency (nframes_t nframes)
2148 Glib::Mutex::Lock lm (io_lock);
2150 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2151 (*i)->set_latency (nframes);
2156 IO::output_latency () const
2158 nframes_t max_latency;
2163 /* io lock not taken - must be protected by other means */
2165 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2166 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2167 max_latency = latency;
2175 IO::input_latency () const
2177 nframes_t max_latency;
2182 /* io lock not taken - must be protected by other means */
2184 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2185 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2186 max_latency = latency;
2194 IO::use_input_connection (Connection& c, void* src)
2199 BLOCK_PROCESS_CALLBACK ();
2200 Glib::Mutex::Lock lm2 (io_lock);
2204 drop_input_connection ();
2206 if (ensure_inputs (limit, false, false, src)) {
2210 /* first pass: check the current state to see what's correctly
2211 connected, and drop anything that we don't want.
2214 for (uint32_t n = 0; n < limit; ++n) {
2215 const Connection::PortList& pl = c.port_connections (n);
2217 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2219 if (!_inputs[n]->connected_to ((*i))) {
2221 /* clear any existing connections */
2223 _session.engine().disconnect (_inputs[n]);
2225 } else if (_inputs[n]->connected() > 1) {
2227 /* OK, it is connected to the port we want,
2228 but its also connected to other ports.
2229 Change that situation.
2232 /* XXX could be optimized to not drop
2236 _session.engine().disconnect (_inputs[n]);
2242 /* second pass: connect all requested ports where necessary */
2244 for (uint32_t n = 0; n < limit; ++n) {
2245 const Connection::PortList& pl = c.port_connections (n);
2247 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2249 if (!_inputs[n]->connected_to ((*i))) {
2251 if (_session.engine().connect (*i, _inputs[n]->name())) {
2259 _input_connection = &c;
2261 input_connection_configuration_connection = c.ConfigurationChanged.connect
2262 (mem_fun (*this, &IO::input_connection_configuration_changed));
2263 input_connection_connection_connection = c.ConnectionsChanged.connect
2264 (mem_fun (*this, &IO::input_connection_connection_changed));
2267 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2272 IO::use_output_connection (Connection& c, void* src)
2277 BLOCK_PROCESS_CALLBACK ();
2278 Glib::Mutex::Lock lm2 (io_lock);
2282 drop_output_connection ();
2284 if (ensure_outputs (limit, false, false, src)) {
2288 /* first pass: check the current state to see what's correctly
2289 connected, and drop anything that we don't want.
2292 for (uint32_t n = 0; n < limit; ++n) {
2294 const Connection::PortList& pl = c.port_connections (n);
2296 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2298 if (!_outputs[n]->connected_to ((*i))) {
2300 /* clear any existing connections */
2302 _session.engine().disconnect (_outputs[n]);
2304 } else if (_outputs[n]->connected() > 1) {
2306 /* OK, it is connected to the port we want,
2307 but its also connected to other ports.
2308 Change that situation.
2311 /* XXX could be optimized to not drop
2315 _session.engine().disconnect (_outputs[n]);
2320 /* second pass: connect all requested ports where necessary */
2322 for (uint32_t n = 0; n < limit; ++n) {
2324 const Connection::PortList& pl = c.port_connections (n);
2326 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2328 if (!_outputs[n]->connected_to ((*i))) {
2330 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2337 _output_connection = &c;
2339 output_connection_configuration_connection = c.ConfigurationChanged.connect
2340 (mem_fun (*this, &IO::output_connection_configuration_changed));
2341 output_connection_connection_connection = c.ConnectionsChanged.connect
2342 (mem_fun (*this, &IO::output_connection_connection_changed));
2345 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2351 IO::disable_connecting ()
2353 connecting_legal = false;
2358 IO::enable_connecting ()
2360 connecting_legal = true;
2361 return ConnectingLegal ();
2365 IO::disable_ports ()
2367 ports_legal = false;
2375 return PortsLegal ();
2379 IO::disable_panners (void)
2381 panners_legal = false;
2386 IO::reset_panners ()
2388 panners_legal = true;
2389 return PannersLegal ();
2393 IO::input_connection_connection_changed (int ignored)
2395 use_input_connection (*_input_connection, this);
2399 IO::input_connection_configuration_changed ()
2401 use_input_connection (*_input_connection, this);
2405 IO::output_connection_connection_changed (int ignored)
2407 use_output_connection (*_output_connection, this);
2411 IO::output_connection_configuration_changed ()
2413 use_output_connection (*_output_connection, this);
2417 IO::GainControllable::set_value (float val)
2419 io.set_gain (direct_control_to_gain (val), this);
2423 IO::GainControllable::get_value (void) const
2425 return direct_gain_to_control (io.effective_gain());
2429 IO::reset_peak_meters ()
2431 uint32_t limit = max (_ninputs, _noutputs);
2433 for (uint32_t i = 0; i < limit; ++i) {
2439 IO::reset_max_peak_meters ()
2441 uint32_t limit = max (_ninputs, _noutputs);
2443 for (uint32_t i = 0; i < limit; ++i) {
2444 _max_peak_power[i] = -INFINITY;
2449 IO::setup_peak_meters ()
2451 uint32_t limit = max (_ninputs, _noutputs);
2453 while (_peak_power.size() < limit) {
2454 _peak_power.push_back (0);
2455 _visible_peak_power.push_back (-INFINITY);
2456 _max_peak_power.push_back (-INFINITY);
2461 Update the peak meters.
2463 The meter signal lock is taken to prevent modification of the
2464 Meter signal while updating the meters, taking the meter signal
2465 lock prior to taking the io_lock ensures that all IO will remain
2466 valid while metering.
2471 Glib::Mutex::Lock guard (m_meter_signal_lock);
2479 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2480 uint32_t limit = max (_ninputs, _noutputs);
2482 for (uint32_t n = 0; n < limit; ++n) {
2484 /* XXX we should use atomic exchange here */
2486 /* grab peak since last read */
2488 float new_peak = _peak_power[n];
2491 /* compute new visible value using falloff */
2493 if (new_peak > 0.0f) {
2494 new_peak = coefficient_to_dB (new_peak);
2496 new_peak = -INFINITY;
2499 /* update max peak */
2501 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2504 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2505 _visible_peak_power[n] = new_peak;
2507 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2508 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2509 _visible_peak_power[n] = max (new_peak, -INFINITY);
2515 IO::clear_automation ()
2517 Glib::Mutex::Lock lm (automation_lock);
2518 _gain_automation_curve.clear ();
2519 _panner->clear_automation ();
2523 IO::set_gain_automation_state (AutoState state)
2525 bool changed = false;
2528 Glib::Mutex::Lock lm (automation_lock);
2530 if (state != _gain_automation_curve.automation_state()) {
2532 last_automation_snapshot = 0;
2533 _gain_automation_curve.set_automation_state (state);
2536 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2542 _session.set_dirty ();
2543 gain_automation_state_changed (); /* EMIT SIGNAL */
2548 IO::set_gain_automation_style (AutoStyle style)
2550 bool changed = false;
2553 Glib::Mutex::Lock lm (automation_lock);
2555 if (style != _gain_automation_curve.automation_style()) {
2557 _gain_automation_curve.set_automation_style (style);
2562 gain_automation_style_changed (); /* EMIT SIGNAL */
2566 IO::inc_gain (gain_t factor, void *src)
2568 if (_desired_gain == 0.0f)
2569 set_gain (0.000001f + (0.000001f * factor), src);
2571 set_gain (_desired_gain + (_desired_gain * factor), src);
2575 IO::set_gain (gain_t val, void *src)
2577 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2578 if (val>1.99526231f) val=1.99526231f;
2581 Glib::Mutex::Lock dm (declick_lock);
2582 _desired_gain = val;
2585 if (_session.transport_stopped()) {
2586 _effective_gain = val;
2591 _gain_control.Changed (); /* EMIT SIGNAL */
2593 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2594 _gain_automation_curve.add (_session.transport_frame(), val);
2598 _session.set_dirty();
2602 IO::start_gain_touch ()
2604 _gain_automation_curve.start_touch ();
2608 IO::end_gain_touch ()
2610 _gain_automation_curve.stop_touch ();
2614 IO::start_pan_touch (uint32_t which)
2616 if (which < _panner->size()) {
2617 (*_panner)[which]->automation().start_touch();
2622 IO::end_pan_touch (uint32_t which)
2624 if (which < _panner->size()) {
2625 (*_panner)[which]->automation().stop_touch();
2631 IO::automation_snapshot (nframes_t now)
2633 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2635 if (gain_automation_recording()) {
2636 _gain_automation_curve.rt_add (now, gain());
2639 _panner->snapshot (now);
2641 last_automation_snapshot = now;
2646 IO::transport_stopped (nframes_t frame)
2648 _gain_automation_curve.reposition_for_rt_add (frame);
2650 if (_gain_automation_curve.automation_state() != Off) {
2652 /* the src=0 condition is a special signal to not propagate
2653 automation gain changes into the mix group when locating.
2656 set_gain (_gain_automation_curve.eval (frame), 0);
2659 _panner->transport_stopped (frame);
2663 IO::find_input_port_hole ()
2665 /* CALLER MUST HOLD IO LOCK */
2669 if (_inputs.empty()) {
2673 for (n = 1; n < UINT_MAX; ++n) {
2674 char buf[jack_port_name_size()];
2675 vector<Port*>::iterator i;
2677 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2679 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2680 if ((*i)->short_name() == buf) {
2685 if (i == _inputs.end()) {
2693 IO::find_output_port_hole ()
2695 /* CALLER MUST HOLD IO LOCK */
2699 if (_outputs.empty()) {
2703 for (n = 1; n < UINT_MAX; ++n) {
2704 char buf[jack_port_name_size()];
2705 vector<Port*>::iterator i;
2707 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2709 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2710 if ((*i)->short_name() == buf) {
2715 if (i == _outputs.end()) {