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.
27 #include <sigc++/bind.h>
29 #include <glibmm/thread.h>
31 #include <pbd/xml++.h>
33 #include <ardour/audioengine.h>
34 #include <ardour/io.h>
35 #include <ardour/port.h>
36 #include <ardour/connection.h>
37 #include <ardour/session.h>
38 #include <ardour/cycle_timer.h>
39 #include <ardour/panner.h>
40 #include <ardour/dB.h>
47 A bug in OS X's cmath that causes isnan() and isinf() to be
48 "undeclared". the following works around that
51 #if defined(__APPLE__) && defined(__MACH__)
52 extern "C" int isnan (double);
53 extern "C" int isinf (double);
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);
177 Glib::Mutex::Lock guard (m_meter_signal_lock);
179 Glib::Mutex::Lock lm (io_lock);
180 vector<Port *>::iterator i;
182 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
183 _session.engine().unregister_port (*i);
186 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
187 _session.engine().unregister_port (*i);
190 m_meter_connection.disconnect();
194 IO::silence (nframes_t nframes, nframes_t offset)
196 /* io_lock, not taken: function must be called from Session::process() calltree */
198 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
199 (*i)->silence (nframes, offset);
204 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
206 nframes_t declick = min ((nframes_t)128, nframes);
209 double fractional_shift;
210 double fractional_pos;
211 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
213 if (nframes == 0) return;
215 fractional_shift = -1.0/declick;
217 if (target < initial) {
218 /* fade out: remove more and more of delta from initial */
219 delta = -(initial - target);
221 /* fade in: add more and more of delta from initial */
222 delta = target - initial;
225 for (uint32_t n = 0; n < nbufs; ++n) {
228 fractional_pos = 1.0;
230 for (nframes_t nx = 0; nx < declick; ++nx) {
231 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
232 fractional_pos += fractional_shift;
235 /* now ensure the rest of the buffer has the target value
236 applied, if necessary.
239 if (declick != nframes) {
242 if (invert_polarity) {
243 this_target = -target;
245 this_target = target;
248 if (this_target == 0.0) {
249 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
250 } else if (this_target != 1.0) {
251 for (nframes_t nx = declick; nx < nframes; ++nx) {
252 buffer[nx] *= this_target;
260 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
264 /* io_lock, not taken: function must be called from Session::process() calltree */
266 if (_noutputs == 0) {
270 if (_noutputs == 1) {
272 dst = output(0)->get_buffer (nframes) + offset;
274 for (uint32_t n = 0; n < nbufs; ++n) {
275 if (bufs[n] != dst) {
276 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
280 output(0)->mark_silence (false);
286 vector<Port *>::iterator out;
287 vector<Sample *>::iterator in;
288 Panner::iterator pan;
289 Sample* obufs[_noutputs];
291 /* the terrible silence ... */
293 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
294 obufs[o] = (*out)->get_buffer (nframes) + offset;
295 memset (obufs[o], 0, sizeof (Sample) * nframes);
296 (*out)->mark_silence (false);
301 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
302 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
307 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
312 /* io_lock, not taken: function must be called from Session::process() calltree */
314 if (_noutputs == 0) {
318 /* the panner can be empty if there are no inputs to the
319 route, but still outputs
322 if (_panner->bypassed() || _panner->empty()) {
323 deliver_output_no_pan (bufs, nbufs, nframes, offset);
327 if (_noutputs == 1) {
329 dst = output(0)->get_buffer (nframes) + offset;
331 if (gain_coeff == 0.0f) {
333 /* only one output, and gain was zero, so make it silent */
335 memset (dst, 0, sizeof (Sample) * nframes);
337 } else if (gain_coeff == 1.0f){
339 /* mix all buffers into the output */
343 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
345 for (n = 1; n < nbufs; ++n) {
348 for (nframes_t n = 0; n < nframes; ++n) {
353 output(0)->mark_silence (false);
357 /* mix all buffers into the output, scaling them all by the gain */
363 for (nframes_t n = 0; n < nframes; ++n) {
364 dst[n] = src[n] * gain_coeff;
367 for (n = 1; n < nbufs; ++n) {
370 for (nframes_t n = 0; n < nframes; ++n) {
371 dst[n] += src[n] * gain_coeff;
375 output(0)->mark_silence (false);
382 vector<Port *>::iterator out;
383 vector<Sample *>::iterator in;
384 Panner::iterator pan;
385 Sample* obufs[_noutputs];
387 /* the terrible silence ... */
389 /* XXX this is wasteful but i see no way to avoid it */
391 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
392 obufs[o] = (*out)->get_buffer (nframes) + offset;
393 memset (obufs[o], 0, sizeof (Sample) * nframes);
394 (*out)->mark_silence (false);
399 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
400 Panner::iterator tmp;
405 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
407 if (tmp != _panner->end()) {
414 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
416 /* io_lock, not taken: function must be called from Session::process() calltree */
418 if (_noutputs == 0) {
422 if (_panner->bypassed() || _panner->empty()) {
423 deliver_output_no_pan (bufs, nbufs, nframes, offset);
429 gain_t pangain = _gain;
432 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
442 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
447 /* simple, non-automation panning to outputs */
449 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
450 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
452 pan (bufs, nbufs, nframes, offset, pangain);
457 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
459 /* io_lock, not taken: function must be called from Session::process() calltree */
461 if (_noutputs == 0) {
466 gain_t old_gain = _gain;
468 if (apply_gain_automation || _ignore_gain_on_deliver) {
470 /* gain has already been applied by automation code. do nothing here except
479 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
491 vector<Port*>::iterator o;
492 vector<Sample*> outs;
496 /* unlikely condition */
497 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
498 outs.push_back ((*o)->get_buffer (nframes) + offset);
502 /* reduce nbufs to the index of the last input buffer */
506 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
507 actual_gain = _gain * speed_quietning;
512 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
514 dst = (*o)->get_buffer (nframes) + offset;
515 src = bufs[min(nbufs,i)];
517 if (dg != _gain || actual_gain == 1.0f) {
518 memcpy (dst, src, sizeof (Sample) * nframes);
519 } else if (actual_gain == 0.0f) {
520 memset (dst, 0, sizeof (Sample) * nframes);
522 for (nframes_t x = 0; x < nframes; ++x) {
523 dst[x] = src[x] * actual_gain;
527 (*o)->mark_silence (false);
531 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
535 if (apply_gain_automation || _ignore_gain_on_deliver) {
541 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
543 /* io_lock, not taken: function must be called from Session::process() calltree */
545 vector<Port *>::iterator i;
549 /* we require that bufs.size() >= 1 */
551 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
552 if (i == _inputs.end()) {
556 /* XXX always read the full extent of the port buffer that
557 we need. One day, we may use jack_port_get_buffer_at_offset()
558 or something similar. For now, this simple hack will
561 Hack? Why yes .. we only need to read nframes-worth of
562 data, but the data we want is at `offset' within the
566 last = (*i)->get_buffer (nframes+offset) + offset;
567 // the dest buffer's offset has already been applied
568 memcpy (bufs[n], last, sizeof (Sample) * nframes);
571 /* fill any excess outputs with the last input */
573 while (n < nbufs && last) {
574 // the dest buffer's offset has already been applied
575 memcpy (bufs[n], last, sizeof (Sample) * nframes);
581 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
582 nframes_t nframes, nframes_t offset)
584 vector<Sample*>& bufs = _session.get_passthru_buffers ();
585 uint32_t nbufs = n_process_buffers ();
587 collect_input (bufs, nbufs, nframes, offset);
589 for (uint32_t n = 0; n < nbufs; ++n) {
590 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
595 IO::drop_input_connection ()
597 _input_connection = 0;
598 input_connection_configuration_connection.disconnect();
599 input_connection_connection_connection.disconnect();
600 _session.set_dirty ();
604 IO::drop_output_connection ()
606 _output_connection = 0;
607 output_connection_configuration_connection.disconnect();
608 output_connection_connection_connection.disconnect();
609 _session.set_dirty ();
613 IO::disconnect_input (Port* our_port, string other_port, void* src)
615 if (other_port.length() == 0 || our_port == 0) {
620 Glib::Mutex::Lock em (_session.engine().process_lock());
623 Glib::Mutex::Lock lm (io_lock);
625 /* check that our_port is really one of ours */
627 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
631 /* disconnect it from the source */
633 if (_session.engine().disconnect (other_port, our_port->name())) {
634 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
638 drop_input_connection();
642 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
643 _session.set_dirty ();
649 IO::connect_input (Port* our_port, string other_port, void* src)
651 if (other_port.length() == 0 || our_port == 0) {
656 Glib::Mutex::Lock em(_session.engine().process_lock());
659 Glib::Mutex::Lock lm (io_lock);
661 /* check that our_port is really one of ours */
663 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
667 /* connect it to the source */
669 if (_session.engine().connect (other_port, our_port->name())) {
673 drop_input_connection ();
677 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
678 _session.set_dirty ();
683 IO::disconnect_output (Port* our_port, string other_port, void* src)
685 if (other_port.length() == 0 || our_port == 0) {
690 Glib::Mutex::Lock em(_session.engine().process_lock());
693 Glib::Mutex::Lock lm (io_lock);
695 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
699 /* disconnect it from the destination */
701 if (_session.engine().disconnect (our_port->name(), other_port)) {
702 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
706 drop_output_connection ();
710 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
711 _session.set_dirty ();
716 IO::connect_output (Port* our_port, string other_port, void* src)
718 if (other_port.length() == 0 || our_port == 0) {
723 Glib::Mutex::Lock em(_session.engine().process_lock());
726 Glib::Mutex::Lock lm (io_lock);
728 /* check that our_port is really one of ours */
730 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
734 /* connect it to the destination */
736 if (_session.engine().connect (our_port->name(), other_port)) {
740 drop_output_connection ();
744 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
745 _session.set_dirty ();
750 IO::set_input (Port* other_port, void* src)
752 /* this removes all but one ports, and connects that one port
753 to the specified source.
756 if (_input_minimum > 1 || _input_minimum == 0) {
757 /* sorry, you can't do this */
761 if (other_port == 0) {
762 if (_input_minimum < 0) {
763 return ensure_inputs (0, false, true, src);
769 if (ensure_inputs (1, true, true, src)) {
773 return connect_input (_inputs.front(), other_port->name(), src);
777 IO::remove_output_port (Port* port, void* src)
779 IOChange change (NoChange);
782 Glib::Mutex::Lock em(_session.engine().process_lock());
785 Glib::Mutex::Lock lm (io_lock);
787 if (_noutputs - 1 == (uint32_t) _output_minimum) {
788 /* sorry, you can't do this */
792 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
794 change = IOChange (change|ConfigurationChanged);
795 if (port->connected()) {
796 change = IOChange (change|ConnectionsChanged);
799 _session.engine().unregister_port (*i);
802 drop_output_connection ();
808 if (change != NoChange) {
809 setup_peak_meters ();
815 if (change != NoChange) {
816 output_changed (change, src); /* EMIT SIGNAL */
817 _session.set_dirty ();
824 /** Add an output port.
826 * @param destination Name of input port to connect new port to.
827 * @param src Source for emitted ConfigurationChanged signal.
828 * @param type Data type of port. Default value (NIL) will use this IO's default type.
831 IO::add_output_port (string destination, void* src, DataType type)
836 if (type == DataType::NIL)
837 type = _default_type;
840 Glib::Mutex::Lock em(_session.engine().process_lock());
843 Glib::Mutex::Lock lm (io_lock);
845 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
849 /* Create a new output port */
851 // FIXME: naming scheme for differently typed ports?
852 if (_output_maximum == 1) {
853 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
855 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
858 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
859 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
863 _outputs.push_back (our_port);
864 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
866 drop_output_connection ();
867 setup_peak_meters ();
871 MoreOutputs (_noutputs); /* EMIT SIGNAL */
874 if (destination.length()) {
875 if (_session.engine().connect (our_port->name(), destination)) {
880 // pan_changed (src); /* EMIT SIGNAL */
881 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
882 _session.set_dirty ();
887 IO::remove_input_port (Port* port, void* src)
889 IOChange change (NoChange);
892 Glib::Mutex::Lock em(_session.engine().process_lock());
895 Glib::Mutex::Lock lm (io_lock);
897 if (((int)_ninputs - 1) < _input_minimum) {
898 /* sorry, you can't do this */
901 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
904 change = IOChange (change|ConfigurationChanged);
906 if (port->connected()) {
907 change = IOChange (change|ConnectionsChanged);
910 _session.engine().unregister_port (*i);
913 drop_input_connection ();
919 if (change != NoChange) {
920 setup_peak_meters ();
926 if (change != NoChange) {
927 input_changed (change, src);
928 _session.set_dirty ();
936 /** Add an input port.
938 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
939 * @param destination Name of input port to connect new port to.
940 * @param src Source for emitted ConfigurationChanged signal.
943 IO::add_input_port (string source, void* src, DataType type)
948 if (type == DataType::NIL)
949 type = _default_type;
952 Glib::Mutex::Lock em (_session.engine().process_lock());
955 Glib::Mutex::Lock lm (io_lock);
957 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
961 /* Create a new input port */
963 // FIXME: naming scheme for differently typed ports?
964 if (_input_maximum == 1) {
965 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
967 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
970 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
971 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
975 _inputs.push_back (our_port);
976 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
978 drop_input_connection ();
979 setup_peak_meters ();
983 MoreOutputs (_ninputs); /* EMIT SIGNAL */
986 if (source.length()) {
988 if (_session.engine().connect (source, our_port->name())) {
993 // pan_changed (src); /* EMIT SIGNAL */
994 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
995 _session.set_dirty ();
1001 IO::disconnect_inputs (void* src)
1004 Glib::Mutex::Lock em (_session.engine().process_lock());
1007 Glib::Mutex::Lock lm (io_lock);
1009 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1010 _session.engine().disconnect (*i);
1013 drop_input_connection ();
1016 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1021 IO::disconnect_outputs (void* src)
1024 Glib::Mutex::Lock em (_session.engine().process_lock());
1027 Glib::Mutex::Lock lm (io_lock);
1029 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1030 _session.engine().disconnect (*i);
1033 drop_output_connection ();
1037 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1038 _session.set_dirty ();
1043 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1046 bool changed = false;
1047 bool reduced = false;
1049 /* remove unused ports */
1051 while (_ninputs > n) {
1052 _session.engine().unregister_port (_inputs.back());
1059 /* create any necessary new ports */
1061 while (_ninputs < n) {
1065 /* Create a new input port (of the default type) */
1067 if (_input_maximum == 1) {
1068 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1071 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1076 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1077 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1082 catch (AudioEngine::PortRegistrationFailure& err) {
1083 setup_peak_meters ();
1089 _inputs.push_back (input_port);
1090 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1096 drop_input_connection ();
1097 setup_peak_meters ();
1099 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1100 _session.set_dirty ();
1104 /* disconnect all existing ports so that we get a fresh start */
1106 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1107 _session.engine().disconnect (*i);
1115 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1117 bool in_changed = false;
1118 bool out_changed = false;
1119 bool in_reduced = false;
1120 bool out_reduced = false;
1121 bool need_pan_reset;
1123 if (_input_maximum >= 0) {
1124 nin = min (_input_maximum, (int) nin);
1127 if (_output_maximum >= 0) {
1128 nout = min (_output_maximum, (int) nout);
1131 if (nin == _ninputs && nout == _noutputs && !clear) {
1136 Glib::Mutex::Lock em (_session.engine().process_lock());
1137 Glib::Mutex::Lock lm (io_lock);
1141 if (_noutputs == nout) {
1142 need_pan_reset = false;
1144 need_pan_reset = true;
1147 /* remove unused ports */
1149 while (_ninputs > nin) {
1150 _session.engine().unregister_port (_inputs.back());
1157 while (_noutputs > nout) {
1158 _session.engine().unregister_port (_outputs.back());
1159 _outputs.pop_back();
1165 /* create any necessary new ports (of the default type) */
1167 while (_ninputs < nin) {
1171 /* Create a new input port */
1173 if (_input_maximum == 1) {
1174 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1177 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1181 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1182 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1187 catch (AudioEngine::PortRegistrationFailure& err) {
1188 setup_peak_meters ();
1194 _inputs.push_back (port);
1199 /* create any necessary new ports */
1201 while (_noutputs < nout) {
1205 /* Create a new output port */
1207 if (_output_maximum == 1) {
1208 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1210 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1214 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1215 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1220 catch (AudioEngine::PortRegistrationFailure& err) {
1221 setup_peak_meters ();
1227 _outputs.push_back (port);
1234 /* disconnect all existing ports so that we get a fresh start */
1236 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1237 _session.engine().disconnect (*i);
1240 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1241 _session.engine().disconnect (*i);
1245 if (in_changed || out_changed) {
1246 setup_peak_meters ();
1252 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1253 drop_output_connection ();
1254 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1258 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1259 drop_input_connection ();
1260 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1263 if (in_changed || out_changed) {
1264 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1265 _session.set_dirty ();
1272 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1274 bool changed = false;
1276 if (_input_maximum >= 0) {
1277 n = min (_input_maximum, (int) n);
1279 if (n == _ninputs && !clear) {
1285 Glib::Mutex::Lock em (_session.engine().process_lock());
1286 Glib::Mutex::Lock im (io_lock);
1287 changed = ensure_inputs_locked (n, clear, src);
1289 changed = ensure_inputs_locked (n, clear, src);
1293 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1294 _session.set_dirty ();
1301 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1304 bool changed = false;
1305 bool reduced = false;
1306 bool need_pan_reset;
1308 if (_noutputs == n) {
1309 need_pan_reset = false;
1311 need_pan_reset = true;
1314 /* remove unused ports */
1316 while (_noutputs > n) {
1318 _session.engine().unregister_port (_outputs.back());
1319 _outputs.pop_back();
1325 /* create any necessary new ports */
1327 while (_noutputs < n) {
1331 /* Create a new output port */
1333 if (_output_maximum == 1) {
1334 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1336 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1339 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1340 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1344 _outputs.push_back (output_port);
1345 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1348 setup_peak_meters ();
1350 if (need_pan_reset) {
1356 drop_output_connection ();
1357 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1358 _session.set_dirty ();
1362 /* disconnect all existing ports so that we get a fresh start */
1364 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1365 _session.engine().disconnect (*i);
1373 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1375 bool changed = false;
1377 if (_output_maximum >= 0) {
1378 n = min (_output_maximum, (int) n);
1379 if (n == _noutputs && !clear) {
1384 /* XXX caller should hold io_lock, but generally doesn't */
1387 Glib::Mutex::Lock em (_session.engine().process_lock());
1388 Glib::Mutex::Lock im (io_lock);
1389 changed = ensure_outputs_locked (n, clear, src);
1391 changed = ensure_outputs_locked (n, clear, src);
1395 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1402 IO::effective_gain () const
1404 if (gain_automation_playback()) {
1405 return _effective_gain;
1407 return _desired_gain;
1414 if (panners_legal) {
1415 if (!no_panner_reset) {
1416 _panner->reset (_noutputs, pans_required());
1419 panner_legal_c.disconnect ();
1420 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1425 IO::panners_became_legal ()
1427 _panner->reset (_noutputs, pans_required());
1428 panner_legal_c.disconnect ();
1433 IO::defer_pan_reset ()
1435 no_panner_reset = true;
1439 IO::allow_pan_reset ()
1441 no_panner_reset = false;
1447 IO::get_state (void)
1449 return state (true);
1453 IO::state (bool full_state)
1455 XMLNode* node = new XMLNode (state_node_name);
1458 bool need_ins = true;
1459 bool need_outs = true;
1460 LocaleGuard lg (X_("POSIX"));
1461 Glib::Mutex::Lock lm (io_lock);
1463 node->add_property("name", _name);
1464 id().print (buf, sizeof (buf));
1465 node->add_property("id", buf);
1469 if (_input_connection) {
1470 node->add_property ("input-connection", _input_connection->name());
1474 if (_output_connection) {
1475 node->add_property ("output-connection", _output_connection->name());
1480 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1482 const char **connections = (*i)->get_connections();
1484 if (connections && connections[0]) {
1487 for (int n = 0; connections && connections[n]; ++n) {
1492 /* if its a connection to our own port,
1493 return only the port name, not the
1494 whole thing. this allows connections
1495 to be re-established even when our
1496 client name is different.
1499 str += _session.engine().make_port_name_relative (connections[n]);
1511 node->add_property ("inputs", str);
1517 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1519 const char **connections = (*i)->get_connections();
1521 if (connections && connections[0]) {
1525 for (int n = 0; connections[n]; ++n) {
1530 str += _session.engine().make_port_name_relative (connections[n]);
1542 node->add_property ("outputs", str);
1545 node->add_child_nocopy (_panner->state (full_state));
1546 node->add_child_nocopy (_gain_control.get_state ());
1548 snprintf (buf, sizeof(buf), "%2.12f", gain());
1549 node->add_property ("gain", buf);
1551 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1557 node->add_property ("iolimits", buf);
1563 XMLNode* autonode = new XMLNode (X_("Automation"));
1564 autonode->add_child_nocopy (get_automation_state());
1565 node->add_child_nocopy (*autonode);
1567 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1569 /* never store anything except Off for automation state in a template */
1570 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1577 IO::set_state (const XMLNode& node)
1579 const XMLProperty* prop;
1580 XMLNodeConstIterator iter;
1581 LocaleGuard lg (X_("POSIX"));
1583 /* force use of non-localized representation of decimal point,
1584 since we use it a lot in XML files and so forth.
1587 if (node.name() != state_node_name) {
1588 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1592 if ((prop = node.property ("name")) != 0) {
1593 _name = prop->value();
1594 /* used to set panner name with this, but no more */
1597 if ((prop = node.property ("id")) != 0) {
1598 _id = prop->value ();
1601 if ((prop = node.property ("iolimits")) != 0) {
1602 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1609 if ((prop = node.property ("gain")) != 0) {
1610 set_gain (atof (prop->value().c_str()), this);
1611 _gain = _desired_gain;
1614 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1616 if ((*iter)->name() == "Panner") {
1618 _panner = new Panner (_name, _session);
1620 _panner->set_state (**iter);
1623 if ((*iter)->name() == X_("Automation")) {
1625 set_automation_state (*(*iter)->children().front());
1628 if ((*iter)->name() == X_("gaincontrol")) {
1629 _gain_control.set_state (**iter);
1635 if (create_ports (node)) {
1641 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1644 if (panners_legal) {
1647 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1650 if (connecting_legal) {
1652 if (make_connections (node)) {
1658 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1661 if (!ports_legal || !connecting_legal) {
1662 pending_state_node = new XMLNode (node);
1665 last_automation_snapshot = 0;
1671 IO::set_automation_state (const XMLNode& node)
1673 return _gain_automation_curve.set_state (node);
1677 IO::get_automation_state ()
1679 return (_gain_automation_curve.get_state ());
1683 IO::connecting_became_legal ()
1687 if (pending_state_node == 0) {
1688 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1693 connection_legal_c.disconnect ();
1695 ret = make_connections (*pending_state_node);
1698 delete pending_state_node;
1699 pending_state_node = 0;
1705 IO::ports_became_legal ()
1709 if (pending_state_node == 0) {
1710 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1715 port_legal_c.disconnect ();
1717 ret = create_ports (*pending_state_node);
1719 if (connecting_legal) {
1720 delete pending_state_node;
1721 pending_state_node = 0;
1728 IO::create_ports (const XMLNode& node)
1730 const XMLProperty* prop;
1732 int num_outputs = 0;
1734 if ((prop = node.property ("input-connection")) != 0) {
1736 Connection* c = _session.connection_by_name (prop->value());
1739 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1741 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1742 error << _("No input connections available as a replacement")
1746 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1751 num_inputs = c->nports();
1753 } else if ((prop = node.property ("inputs")) != 0) {
1755 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1758 if ((prop = node.property ("output-connection")) != 0) {
1759 Connection* c = _session.connection_by_name (prop->value());
1762 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1764 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1765 error << _("No output connections available as a replacement")
1769 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1774 num_outputs = c->nports ();
1776 } else if ((prop = node.property ("outputs")) != 0) {
1777 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1780 no_panner_reset = true;
1782 if (ensure_io (num_inputs, num_outputs, true, this)) {
1783 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1787 no_panner_reset = false;
1789 set_deferred_state ();
1797 IO::make_connections (const XMLNode& node)
1799 const XMLProperty* prop;
1801 if ((prop = node.property ("input-connection")) != 0) {
1802 Connection* c = _session.connection_by_name (prop->value());
1805 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1807 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1808 error << _("No input connections available as a replacement")
1812 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1817 use_input_connection (*c, this);
1819 } else if ((prop = node.property ("inputs")) != 0) {
1820 if (set_inputs (prop->value())) {
1821 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1826 if ((prop = node.property ("output-connection")) != 0) {
1827 Connection* c = _session.connection_by_name (prop->value());
1830 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1832 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1833 error << _("No output connections available as a replacement")
1837 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1842 use_output_connection (*c, this);
1844 } else if ((prop = node.property ("outputs")) != 0) {
1845 if (set_outputs (prop->value())) {
1846 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1855 IO::set_inputs (const string& str)
1857 vector<string> ports;
1862 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1866 if (ensure_inputs (nports, true, true, this)) {
1870 string::size_type start, end, ostart;
1877 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1880 if ((end = str.find_first_of ('}', start)) == string::npos) {
1881 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1885 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1886 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1892 for (int x = 0; x < n; ++x) {
1893 connect_input (input (i), ports[x], this);
1905 IO::set_outputs (const string& str)
1907 vector<string> ports;
1912 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1916 if (ensure_outputs (nports, true, true, this)) {
1920 string::size_type start, end, ostart;
1927 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1930 if ((end = str.find_first_of ('}', start)) == string::npos) {
1931 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1935 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1936 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1942 for (int x = 0; x < n; ++x) {
1943 connect_output (output (i), ports[x], this);
1955 IO::parse_io_string (const string& str, vector<string>& ports)
1957 string::size_type pos, opos;
1959 if (str.length() == 0) {
1968 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1969 ports.push_back (str.substr (opos, pos - opos));
1973 if (opos < str.length()) {
1974 ports.push_back (str.substr(opos));
1977 return ports.size();
1981 IO::parse_gain_string (const string& str, vector<string>& ports)
1983 string::size_type pos, opos;
1989 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1990 ports.push_back (str.substr (opos, pos - opos));
1994 if (opos < str.length()) {
1995 ports.push_back (str.substr(opos));
1998 return ports.size();
2002 IO::set_name (string name, void* src)
2004 if (name == _name) {
2008 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2009 string current_name = (*i)->short_name();
2010 current_name.replace (current_name.find (_name), _name.length(), name);
2011 (*i)->set_name (current_name);
2014 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2015 string current_name = (*i)->short_name();
2016 current_name.replace (current_name.find (_name), _name.length(), name);
2017 (*i)->set_name (current_name);
2021 name_changed (src); /* EMIT SIGNAL */
2027 IO::set_input_minimum (int n)
2033 IO::set_input_maximum (int n)
2039 IO::set_output_minimum (int n)
2041 _output_minimum = n;
2045 IO::set_output_maximum (int n)
2047 _output_maximum = n;
2051 IO::set_port_latency (nframes_t nframes)
2053 Glib::Mutex::Lock lm (io_lock);
2055 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2056 (*i)->set_latency (nframes);
2061 IO::output_latency () const
2063 nframes_t max_latency;
2068 /* io lock not taken - must be protected by other means */
2070 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2071 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2072 max_latency = latency;
2080 IO::input_latency () const
2082 nframes_t max_latency;
2087 /* io lock not taken - must be protected by other means */
2089 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2090 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2091 max_latency = latency;
2099 IO::use_input_connection (Connection& c, void* src)
2104 Glib::Mutex::Lock lm (_session.engine().process_lock());
2105 Glib::Mutex::Lock lm2 (io_lock);
2109 drop_input_connection ();
2111 if (ensure_inputs (limit, false, false, src)) {
2115 /* first pass: check the current state to see what's correctly
2116 connected, and drop anything that we don't want.
2119 for (uint32_t n = 0; n < limit; ++n) {
2120 const Connection::PortList& pl = c.port_connections (n);
2122 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2124 if (!_inputs[n]->connected_to ((*i))) {
2126 /* clear any existing connections */
2128 _session.engine().disconnect (_inputs[n]);
2130 } else if (_inputs[n]->connected() > 1) {
2132 /* OK, it is connected to the port we want,
2133 but its also connected to other ports.
2134 Change that situation.
2137 /* XXX could be optimized to not drop
2141 _session.engine().disconnect (_inputs[n]);
2147 /* second pass: connect all requested ports where necessary */
2149 for (uint32_t n = 0; n < limit; ++n) {
2150 const Connection::PortList& pl = c.port_connections (n);
2152 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2154 if (!_inputs[n]->connected_to ((*i))) {
2156 if (_session.engine().connect (*i, _inputs[n]->name())) {
2164 _input_connection = &c;
2166 input_connection_configuration_connection = c.ConfigurationChanged.connect
2167 (mem_fun (*this, &IO::input_connection_configuration_changed));
2168 input_connection_connection_connection = c.ConnectionsChanged.connect
2169 (mem_fun (*this, &IO::input_connection_connection_changed));
2172 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2177 IO::use_output_connection (Connection& c, void* src)
2182 Glib::Mutex::Lock lm (_session.engine().process_lock());
2183 Glib::Mutex::Lock lm2 (io_lock);
2187 drop_output_connection ();
2189 if (ensure_outputs (limit, false, false, src)) {
2193 /* first pass: check the current state to see what's correctly
2194 connected, and drop anything that we don't want.
2197 for (uint32_t n = 0; n < limit; ++n) {
2199 const Connection::PortList& pl = c.port_connections (n);
2201 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2203 if (!_outputs[n]->connected_to ((*i))) {
2205 /* clear any existing connections */
2207 _session.engine().disconnect (_outputs[n]);
2209 } else if (_outputs[n]->connected() > 1) {
2211 /* OK, it is connected to the port we want,
2212 but its also connected to other ports.
2213 Change that situation.
2216 /* XXX could be optimized to not drop
2220 _session.engine().disconnect (_outputs[n]);
2225 /* second pass: connect all requested ports where necessary */
2227 for (uint32_t n = 0; n < limit; ++n) {
2229 const Connection::PortList& pl = c.port_connections (n);
2231 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2233 if (!_outputs[n]->connected_to ((*i))) {
2235 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2242 _output_connection = &c;
2244 output_connection_configuration_connection = c.ConfigurationChanged.connect
2245 (mem_fun (*this, &IO::output_connection_configuration_changed));
2246 output_connection_connection_connection = c.ConnectionsChanged.connect
2247 (mem_fun (*this, &IO::output_connection_connection_changed));
2250 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2256 IO::disable_connecting ()
2258 connecting_legal = false;
2263 IO::enable_connecting ()
2265 connecting_legal = true;
2266 return ConnectingLegal ();
2270 IO::disable_ports ()
2272 ports_legal = false;
2280 return PortsLegal ();
2284 IO::disable_panners (void)
2286 panners_legal = false;
2291 IO::reset_panners ()
2293 panners_legal = true;
2294 return PannersLegal ();
2298 IO::input_connection_connection_changed (int ignored)
2300 use_input_connection (*_input_connection, this);
2304 IO::input_connection_configuration_changed ()
2306 use_input_connection (*_input_connection, this);
2310 IO::output_connection_connection_changed (int ignored)
2312 use_output_connection (*_output_connection, this);
2316 IO::output_connection_configuration_changed ()
2318 use_output_connection (*_output_connection, this);
2322 IO::GainControllable::set_value (float val)
2324 io.set_gain (direct_control_to_gain (val), this);
2328 IO::GainControllable::get_value (void) const
2330 return direct_gain_to_control (io.effective_gain());
2334 IO::reset_peak_meters ()
2336 uint32_t limit = max (_ninputs, _noutputs);
2338 for (uint32_t i = 0; i < limit; ++i) {
2344 IO::setup_peak_meters ()
2346 uint32_t limit = max (_ninputs, _noutputs);
2348 while (_peak_power.size() < limit) {
2349 _peak_power.push_back (0);
2350 _visible_peak_power.push_back (0);
2355 Update the peak meters.
2357 The meter signal lock is taken to prevent modification of the
2358 Meter signal while updating the meters, taking the meter signal
2359 lock prior to taking the io_lock ensures that all IO will remain
2360 valid while metering.
2365 Glib::Mutex::Lock guard (m_meter_signal_lock);
2373 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2374 uint32_t limit = max (_ninputs, _noutputs);
2376 for (uint32_t n = 0; n < limit; ++n) {
2378 /* XXX we should use atomic exchange here */
2380 /* grab peak since last read */
2382 float new_peak = _peak_power[n];
2385 /* compute new visible value using falloff */
2387 if (new_peak > 0.0) {
2388 new_peak = coefficient_to_dB (new_peak);
2390 new_peak = minus_infinity();
2393 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2394 _visible_peak_power[n] = new_peak;
2397 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2398 _visible_peak_power[n] = max (new_peak, -INFINITY);
2404 IO::clear_automation ()
2406 Glib::Mutex::Lock lm (automation_lock);
2407 _gain_automation_curve.clear ();
2408 _panner->clear_automation ();
2412 IO::set_gain_automation_state (AutoState state)
2414 bool changed = false;
2417 Glib::Mutex::Lock lm (automation_lock);
2419 if (state != _gain_automation_curve.automation_state()) {
2421 last_automation_snapshot = 0;
2422 _gain_automation_curve.set_automation_state (state);
2425 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2431 _session.set_dirty ();
2432 gain_automation_state_changed (); /* EMIT SIGNAL */
2437 IO::set_gain_automation_style (AutoStyle style)
2439 bool changed = false;
2442 Glib::Mutex::Lock lm (automation_lock);
2444 if (style != _gain_automation_curve.automation_style()) {
2446 _gain_automation_curve.set_automation_style (style);
2451 gain_automation_style_changed (); /* EMIT SIGNAL */
2455 IO::inc_gain (gain_t factor, void *src)
2457 if (_desired_gain == 0.0f)
2458 set_gain (0.000001f + (0.000001f * factor), src);
2460 set_gain (_desired_gain + (_desired_gain * factor), src);
2464 IO::set_gain (gain_t val, void *src)
2466 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2467 if (val>1.99526231f) val=1.99526231f;
2470 Glib::Mutex::Lock dm (declick_lock);
2471 _desired_gain = val;
2474 if (_session.transport_stopped()) {
2475 _effective_gain = val;
2480 _gain_control.Changed (); /* EMIT SIGNAL */
2482 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2483 _gain_automation_curve.add (_session.transport_frame(), val);
2487 _session.set_dirty();
2491 IO::start_gain_touch ()
2493 _gain_automation_curve.start_touch ();
2497 IO::end_gain_touch ()
2499 _gain_automation_curve.stop_touch ();
2503 IO::start_pan_touch (uint32_t which)
2505 if (which < _panner->size()) {
2506 (*_panner)[which]->automation().start_touch();
2511 IO::end_pan_touch (uint32_t which)
2513 if (which < _panner->size()) {
2514 (*_panner)[which]->automation().stop_touch();
2520 IO::automation_snapshot (nframes_t now)
2522 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2524 if (gain_automation_recording()) {
2525 _gain_automation_curve.rt_add (now, gain());
2528 _panner->snapshot (now);
2530 last_automation_snapshot = now;
2535 IO::transport_stopped (nframes_t frame)
2537 _gain_automation_curve.reposition_for_rt_add (frame);
2539 if (_gain_automation_curve.automation_state() != Off) {
2541 /* the src=0 condition is a special signal to not propagate
2542 automation gain changes into the mix group when locating.
2545 set_gain (_gain_automation_curve.eval (frame), 0);
2548 _panner->transport_stopped (frame);
2552 IO::find_input_port_hole ()
2554 /* CALLER MUST HOLD IO LOCK */
2558 if (_inputs.empty()) {
2562 for (n = 1; n < UINT_MAX; ++n) {
2563 char buf[jack_port_name_size()];
2564 vector<Port*>::iterator i;
2566 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2568 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2569 if ((*i)->short_name() == buf) {
2574 if (i == _inputs.end()) {
2582 IO::find_output_port_hole ()
2584 /* CALLER MUST HOLD IO LOCK */
2588 if (_outputs.empty()) {
2592 for (n = 1; n < UINT_MAX; ++n) {
2593 char buf[jack_port_name_size()];
2594 vector<Port*>::iterator i;
2596 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2598 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2599 if ((*i)->short_name() == buf) {
2604 if (i == _outputs.end()) {