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 const string IO::state_node_name = "IO";
62 bool IO::connecting_legal = false;
63 bool IO::ports_legal = false;
64 bool IO::panners_legal = false;
65 sigc::signal<void> IO::Meter;
66 sigc::signal<int> IO::ConnectingLegal;
67 sigc::signal<int> IO::PortsLegal;
68 sigc::signal<int> IO::PannersLegal;
69 sigc::signal<void,uint32_t> IO::MoreOutputs;
70 sigc::signal<int> IO::PortsCreated;
72 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
74 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
75 others can be imagined.
78 static gain_t direct_control_to_gain (double fract) {
79 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
80 /* this maxes at +6dB */
81 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
84 static double direct_gain_to_control (gain_t gain) {
85 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
86 if (gain == 0) return 0.0;
88 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
91 static bool sort_ports_by_name (Port* a, Port* b)
93 return a->name() < b->name();
97 /** @param default_type The type of port that will be created by ensure_io
98 * and friends if no type is explicitly requested (to avoid breakage).
100 IO::IO (Session& s, string name,
101 int input_min, int input_max, int output_min, int output_max,
102 DataType default_type)
105 _default_type(default_type),
106 _gain_control (X_("gaincontrol"), *this),
107 _gain_automation_curve (0.0, 2.0, 1.0),
108 _input_minimum (input_min),
109 _input_maximum (input_max),
110 _output_minimum (output_min),
111 _output_maximum (output_max)
113 _panner = new Panner (name, _session);
116 _input_connection = 0;
117 _output_connection = 0;
118 pending_state_node = 0;
121 no_panner_reset = false;
124 apply_gain_automation = false;
125 _ignore_gain_on_deliver = false;
127 _gain_automation_state = Off;
128 _gain_automation_style = Absolute;
131 // IO::Meter is emitted from another thread so the
132 // Meter signal must be protected.
133 Glib::Mutex::Lock guard (m_meter_signal_lock);
134 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
137 _session.add_controllable (&_gain_control);
142 Glib::Mutex::Lock guard (m_meter_signal_lock);
144 Glib::Mutex::Lock lm (io_lock);
145 vector<Port *>::iterator i;
147 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
148 _session.engine().unregister_port (*i);
151 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
152 _session.engine().unregister_port (*i);
155 m_meter_connection.disconnect();
159 IO::silence (nframes_t nframes, nframes_t offset)
161 /* io_lock, not taken: function must be called from Session::process() calltree */
163 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
164 (*i)->silence (nframes, offset);
169 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
171 nframes_t declick = min ((nframes_t)128, nframes);
174 double fractional_shift;
175 double fractional_pos;
176 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
178 if (nframes == 0) return;
180 fractional_shift = -1.0/declick;
182 if (target < initial) {
183 /* fade out: remove more and more of delta from initial */
184 delta = -(initial - target);
186 /* fade in: add more and more of delta from initial */
187 delta = target - initial;
190 for (uint32_t n = 0; n < nbufs; ++n) {
193 fractional_pos = 1.0;
195 for (nframes_t nx = 0; nx < declick; ++nx) {
196 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
197 fractional_pos += fractional_shift;
200 /* now ensure the rest of the buffer has the target value
201 applied, if necessary.
204 if (declick != nframes) {
207 if (invert_polarity) {
208 this_target = -target;
210 this_target = target;
213 if (this_target == 0.0) {
214 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
215 } else if (this_target != 1.0) {
216 for (nframes_t nx = declick; nx < nframes; ++nx) {
217 buffer[nx] *= this_target;
225 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
229 /* io_lock, not taken: function must be called from Session::process() calltree */
231 if (_noutputs == 0) {
235 if (_noutputs == 1) {
237 dst = output(0)->get_buffer (nframes) + offset;
239 for (uint32_t n = 0; n < nbufs; ++n) {
240 if (bufs[n] != dst) {
241 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
245 output(0)->mark_silence (false);
251 vector<Port *>::iterator out;
252 vector<Sample *>::iterator in;
253 Panner::iterator pan;
254 Sample* obufs[_noutputs];
256 /* the terrible silence ... */
258 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
259 obufs[o] = (*out)->get_buffer (nframes) + offset;
260 memset (obufs[o], 0, sizeof (Sample) * nframes);
261 (*out)->mark_silence (false);
266 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
267 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
272 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
277 /* io_lock, not taken: function must be called from Session::process() calltree */
279 if (_noutputs == 0) {
283 /* the panner can be empty if there are no inputs to the
284 route, but still outputs
287 if (_panner->bypassed() || _panner->empty()) {
288 deliver_output_no_pan (bufs, nbufs, nframes, offset);
292 if (_noutputs == 1) {
294 dst = output(0)->get_buffer (nframes) + offset;
296 if (gain_coeff == 0.0f) {
298 /* only one output, and gain was zero, so make it silent */
300 memset (dst, 0, sizeof (Sample) * nframes);
302 } else if (gain_coeff == 1.0f){
304 /* mix all buffers into the output */
308 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
310 for (n = 1; n < nbufs; ++n) {
313 for (nframes_t n = 0; n < nframes; ++n) {
318 output(0)->mark_silence (false);
322 /* mix all buffers into the output, scaling them all by the gain */
328 for (nframes_t n = 0; n < nframes; ++n) {
329 dst[n] = src[n] * gain_coeff;
332 for (n = 1; n < nbufs; ++n) {
335 for (nframes_t n = 0; n < nframes; ++n) {
336 dst[n] += src[n] * gain_coeff;
340 output(0)->mark_silence (false);
347 vector<Port *>::iterator out;
348 vector<Sample *>::iterator in;
349 Panner::iterator pan;
350 Sample* obufs[_noutputs];
352 /* the terrible silence ... */
354 /* XXX this is wasteful but i see no way to avoid it */
356 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
357 obufs[o] = (*out)->get_buffer (nframes) + offset;
358 memset (obufs[o], 0, sizeof (Sample) * nframes);
359 (*out)->mark_silence (false);
364 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
365 Panner::iterator tmp;
370 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
372 if (tmp != _panner->end()) {
379 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
381 /* io_lock, not taken: function must be called from Session::process() calltree */
383 if (_noutputs == 0) {
387 if (_panner->bypassed() || _panner->empty()) {
388 deliver_output_no_pan (bufs, nbufs, nframes, offset);
394 gain_t pangain = _gain;
397 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
407 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
412 /* simple, non-automation panning to outputs */
414 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
415 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
417 pan (bufs, nbufs, nframes, offset, pangain);
422 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
424 /* io_lock, not taken: function must be called from Session::process() calltree */
426 if (_noutputs == 0) {
431 gain_t old_gain = _gain;
433 if (apply_gain_automation || _ignore_gain_on_deliver) {
435 /* gain has already been applied by automation code. do nothing here except
444 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
456 vector<Port*>::iterator o;
457 vector<Sample*> outs;
461 /* unlikely condition */
462 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
463 outs.push_back ((*o)->get_buffer (nframes) + offset);
467 /* reduce nbufs to the index of the last input buffer */
471 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
472 actual_gain = _gain * speed_quietning;
477 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
479 dst = (*o)->get_buffer (nframes) + offset;
480 src = bufs[min(nbufs,i)];
482 if (dg != _gain || actual_gain == 1.0f) {
483 memcpy (dst, src, sizeof (Sample) * nframes);
484 } else if (actual_gain == 0.0f) {
485 memset (dst, 0, sizeof (Sample) * nframes);
487 for (nframes_t x = 0; x < nframes; ++x) {
488 dst[x] = src[x] * actual_gain;
492 (*o)->mark_silence (false);
496 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
500 if (apply_gain_automation || _ignore_gain_on_deliver) {
506 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
508 /* io_lock, not taken: function must be called from Session::process() calltree */
510 vector<Port *>::iterator i;
514 /* we require that bufs.size() >= 1 */
516 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
517 if (i == _inputs.end()) {
521 /* XXX always read the full extent of the port buffer that
522 we need. One day, we may use jack_port_get_buffer_at_offset()
523 or something similar. For now, this simple hack will
526 Hack? Why yes .. we only need to read nframes-worth of
527 data, but the data we want is at `offset' within the
531 last = (*i)->get_buffer (nframes+offset) + offset;
532 // the dest buffer's offset has already been applied
533 memcpy (bufs[n], last, sizeof (Sample) * nframes);
536 /* fill any excess outputs with the last input */
538 while (n < nbufs && last) {
539 // the dest buffer's offset has already been applied
540 memcpy (bufs[n], last, sizeof (Sample) * nframes);
546 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
547 nframes_t nframes, nframes_t offset)
549 vector<Sample*>& bufs = _session.get_passthru_buffers ();
550 uint32_t nbufs = n_process_buffers ();
552 collect_input (bufs, nbufs, nframes, offset);
554 for (uint32_t n = 0; n < nbufs; ++n) {
555 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
560 IO::drop_input_connection ()
562 _input_connection = 0;
563 input_connection_configuration_connection.disconnect();
564 input_connection_connection_connection.disconnect();
565 _session.set_dirty ();
569 IO::drop_output_connection ()
571 _output_connection = 0;
572 output_connection_configuration_connection.disconnect();
573 output_connection_connection_connection.disconnect();
574 _session.set_dirty ();
578 IO::disconnect_input (Port* our_port, string other_port, void* src)
580 if (other_port.length() == 0 || our_port == 0) {
585 Glib::Mutex::Lock em (_session.engine().process_lock());
588 Glib::Mutex::Lock lm (io_lock);
590 /* check that our_port is really one of ours */
592 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
596 /* disconnect it from the source */
598 if (_session.engine().disconnect (other_port, our_port->name())) {
599 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
603 drop_input_connection();
607 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
608 _session.set_dirty ();
614 IO::connect_input (Port* our_port, string other_port, void* src)
616 if (other_port.length() == 0 || our_port == 0) {
621 Glib::Mutex::Lock em(_session.engine().process_lock());
624 Glib::Mutex::Lock lm (io_lock);
626 /* check that our_port is really one of ours */
628 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
632 /* connect it to the source */
634 if (_session.engine().connect (other_port, our_port->name())) {
638 drop_input_connection ();
642 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
643 _session.set_dirty ();
648 IO::disconnect_output (Port* our_port, string other_port, void* src)
650 if (other_port.length() == 0 || our_port == 0) {
655 Glib::Mutex::Lock em(_session.engine().process_lock());
658 Glib::Mutex::Lock lm (io_lock);
660 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
664 /* disconnect it from the destination */
666 if (_session.engine().disconnect (our_port->name(), other_port)) {
667 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
671 drop_output_connection ();
675 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
676 _session.set_dirty ();
681 IO::connect_output (Port* our_port, string other_port, void* src)
683 if (other_port.length() == 0 || our_port == 0) {
688 Glib::Mutex::Lock em(_session.engine().process_lock());
691 Glib::Mutex::Lock lm (io_lock);
693 /* check that our_port is really one of ours */
695 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
699 /* connect it to the destination */
701 if (_session.engine().connect (our_port->name(), other_port)) {
705 drop_output_connection ();
709 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
710 _session.set_dirty ();
715 IO::set_input (Port* other_port, void* src)
717 /* this removes all but one ports, and connects that one port
718 to the specified source.
721 if (_input_minimum > 1 || _input_minimum == 0) {
722 /* sorry, you can't do this */
726 if (other_port == 0) {
727 if (_input_minimum < 0) {
728 return ensure_inputs (0, false, true, src);
734 if (ensure_inputs (1, true, true, src)) {
738 return connect_input (_inputs.front(), other_port->name(), src);
742 IO::remove_output_port (Port* port, void* src)
744 IOChange change (NoChange);
747 Glib::Mutex::Lock em(_session.engine().process_lock());
750 Glib::Mutex::Lock lm (io_lock);
752 if (_noutputs - 1 == (uint32_t) _output_minimum) {
753 /* sorry, you can't do this */
757 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
759 change = IOChange (change|ConfigurationChanged);
760 if (port->connected()) {
761 change = IOChange (change|ConnectionsChanged);
764 _session.engine().unregister_port (*i);
767 drop_output_connection ();
773 if (change != NoChange) {
774 setup_peak_meters ();
780 if (change != NoChange) {
781 output_changed (change, src); /* EMIT SIGNAL */
782 _session.set_dirty ();
789 /** Add an output port.
791 * @param destination Name of input port to connect new port to.
792 * @param src Source for emitted ConfigurationChanged signal.
793 * @param type Data type of port. Default value (NIL) will use this IO's default type.
796 IO::add_output_port (string destination, void* src, DataType type)
801 if (type == DataType::NIL)
802 type = _default_type;
805 Glib::Mutex::Lock em(_session.engine().process_lock());
808 Glib::Mutex::Lock lm (io_lock);
810 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
814 /* Create a new output port */
816 // FIXME: naming scheme for differently typed ports?
817 if (_output_maximum == 1) {
818 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
820 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
823 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
824 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
828 _outputs.push_back (our_port);
829 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
831 drop_output_connection ();
832 setup_peak_meters ();
836 MoreOutputs (_noutputs); /* EMIT SIGNAL */
839 if (destination.length()) {
840 if (_session.engine().connect (our_port->name(), destination)) {
845 // pan_changed (src); /* EMIT SIGNAL */
846 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
847 _session.set_dirty ();
852 IO::remove_input_port (Port* port, void* src)
854 IOChange change (NoChange);
857 Glib::Mutex::Lock em(_session.engine().process_lock());
860 Glib::Mutex::Lock lm (io_lock);
862 if (((int)_ninputs - 1) < _input_minimum) {
863 /* sorry, you can't do this */
866 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
869 change = IOChange (change|ConfigurationChanged);
871 if (port->connected()) {
872 change = IOChange (change|ConnectionsChanged);
875 _session.engine().unregister_port (*i);
878 drop_input_connection ();
884 if (change != NoChange) {
885 setup_peak_meters ();
891 if (change != NoChange) {
892 input_changed (change, src);
893 _session.set_dirty ();
901 /** Add an input port.
903 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
904 * @param destination Name of input port to connect new port to.
905 * @param src Source for emitted ConfigurationChanged signal.
908 IO::add_input_port (string source, void* src, DataType type)
913 if (type == DataType::NIL)
914 type = _default_type;
917 Glib::Mutex::Lock em (_session.engine().process_lock());
920 Glib::Mutex::Lock lm (io_lock);
922 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
926 /* Create a new input port */
928 // FIXME: naming scheme for differently typed ports?
929 if (_input_maximum == 1) {
930 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
932 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
935 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
936 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
940 _inputs.push_back (our_port);
941 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
943 drop_input_connection ();
944 setup_peak_meters ();
948 MoreOutputs (_ninputs); /* EMIT SIGNAL */
951 if (source.length()) {
953 if (_session.engine().connect (source, our_port->name())) {
958 // pan_changed (src); /* EMIT SIGNAL */
959 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
960 _session.set_dirty ();
966 IO::disconnect_inputs (void* src)
969 Glib::Mutex::Lock em (_session.engine().process_lock());
972 Glib::Mutex::Lock lm (io_lock);
974 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
975 _session.engine().disconnect (*i);
978 drop_input_connection ();
981 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
986 IO::disconnect_outputs (void* src)
989 Glib::Mutex::Lock em (_session.engine().process_lock());
992 Glib::Mutex::Lock lm (io_lock);
994 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
995 _session.engine().disconnect (*i);
998 drop_output_connection ();
1002 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1003 _session.set_dirty ();
1008 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1011 bool changed = false;
1012 bool reduced = false;
1014 /* remove unused ports */
1016 while (_ninputs > n) {
1017 _session.engine().unregister_port (_inputs.back());
1024 /* create any necessary new ports */
1026 while (_ninputs < n) {
1030 /* Create a new input port (of the default type) */
1032 if (_input_maximum == 1) {
1033 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1036 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1041 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1042 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1047 catch (AudioEngine::PortRegistrationFailure& err) {
1048 setup_peak_meters ();
1054 _inputs.push_back (input_port);
1055 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1061 drop_input_connection ();
1062 setup_peak_meters ();
1064 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1065 _session.set_dirty ();
1069 /* disconnect all existing ports so that we get a fresh start */
1071 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1072 _session.engine().disconnect (*i);
1080 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1082 bool in_changed = false;
1083 bool out_changed = false;
1084 bool in_reduced = false;
1085 bool out_reduced = false;
1086 bool need_pan_reset;
1088 if (_input_maximum >= 0) {
1089 nin = min (_input_maximum, (int) nin);
1092 if (_output_maximum >= 0) {
1093 nout = min (_output_maximum, (int) nout);
1096 if (nin == _ninputs && nout == _noutputs && !clear) {
1101 Glib::Mutex::Lock em (_session.engine().process_lock());
1102 Glib::Mutex::Lock lm (io_lock);
1106 if (_noutputs == nout) {
1107 need_pan_reset = false;
1109 need_pan_reset = true;
1112 /* remove unused ports */
1114 while (_ninputs > nin) {
1115 _session.engine().unregister_port (_inputs.back());
1122 while (_noutputs > nout) {
1123 _session.engine().unregister_port (_outputs.back());
1124 _outputs.pop_back();
1130 /* create any necessary new ports (of the default type) */
1132 while (_ninputs < nin) {
1136 /* Create a new input port */
1138 if (_input_maximum == 1) {
1139 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1142 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1146 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1147 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1152 catch (AudioEngine::PortRegistrationFailure& err) {
1153 setup_peak_meters ();
1159 _inputs.push_back (port);
1164 /* create any necessary new ports */
1166 while (_noutputs < nout) {
1170 /* Create a new output port */
1172 if (_output_maximum == 1) {
1173 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1175 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1179 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1180 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1185 catch (AudioEngine::PortRegistrationFailure& err) {
1186 setup_peak_meters ();
1192 _outputs.push_back (port);
1199 /* disconnect all existing ports so that we get a fresh start */
1201 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1202 _session.engine().disconnect (*i);
1205 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1206 _session.engine().disconnect (*i);
1210 if (in_changed || out_changed) {
1211 setup_peak_meters ();
1217 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1218 drop_output_connection ();
1219 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1223 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1224 drop_input_connection ();
1225 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1228 if (in_changed || out_changed) {
1229 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1230 _session.set_dirty ();
1237 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1239 bool changed = false;
1241 if (_input_maximum >= 0) {
1242 n = min (_input_maximum, (int) n);
1244 if (n == _ninputs && !clear) {
1250 Glib::Mutex::Lock em (_session.engine().process_lock());
1251 Glib::Mutex::Lock im (io_lock);
1252 changed = ensure_inputs_locked (n, clear, src);
1254 changed = ensure_inputs_locked (n, clear, src);
1258 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1259 _session.set_dirty ();
1266 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1269 bool changed = false;
1270 bool reduced = false;
1271 bool need_pan_reset;
1273 if (_noutputs == n) {
1274 need_pan_reset = false;
1276 need_pan_reset = true;
1279 /* remove unused ports */
1281 while (_noutputs > n) {
1283 _session.engine().unregister_port (_outputs.back());
1284 _outputs.pop_back();
1290 /* create any necessary new ports */
1292 while (_noutputs < n) {
1296 /* Create a new output port */
1298 if (_output_maximum == 1) {
1299 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1301 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1304 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1305 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1309 _outputs.push_back (output_port);
1310 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1313 setup_peak_meters ();
1315 if (need_pan_reset) {
1321 drop_output_connection ();
1322 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1323 _session.set_dirty ();
1327 /* disconnect all existing ports so that we get a fresh start */
1329 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1330 _session.engine().disconnect (*i);
1338 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1340 bool changed = false;
1342 if (_output_maximum >= 0) {
1343 n = min (_output_maximum, (int) n);
1344 if (n == _noutputs && !clear) {
1349 /* XXX caller should hold io_lock, but generally doesn't */
1352 Glib::Mutex::Lock em (_session.engine().process_lock());
1353 Glib::Mutex::Lock im (io_lock);
1354 changed = ensure_outputs_locked (n, clear, src);
1356 changed = ensure_outputs_locked (n, clear, src);
1360 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1367 IO::effective_gain () const
1369 if (gain_automation_playback()) {
1370 return _effective_gain;
1372 return _desired_gain;
1379 if (panners_legal) {
1380 if (!no_panner_reset) {
1381 _panner->reset (_noutputs, pans_required());
1384 panner_legal_c.disconnect ();
1385 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1390 IO::panners_became_legal ()
1392 _panner->reset (_noutputs, pans_required());
1393 panner_legal_c.disconnect ();
1398 IO::defer_pan_reset ()
1400 no_panner_reset = true;
1404 IO::allow_pan_reset ()
1406 no_panner_reset = false;
1412 IO::get_state (void)
1414 return state (true);
1418 IO::state (bool full_state)
1420 XMLNode* node = new XMLNode (state_node_name);
1423 bool need_ins = true;
1424 bool need_outs = true;
1425 LocaleGuard lg (X_("POSIX"));
1426 Glib::Mutex::Lock lm (io_lock);
1428 node->add_property("name", _name);
1429 id().print (buf, sizeof (buf));
1430 node->add_property("id", buf);
1434 if (_input_connection) {
1435 node->add_property ("input-connection", _input_connection->name());
1439 if (_output_connection) {
1440 node->add_property ("output-connection", _output_connection->name());
1445 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1447 const char **connections = (*i)->get_connections();
1449 if (connections && connections[0]) {
1452 for (int n = 0; connections && connections[n]; ++n) {
1457 /* if its a connection to our own port,
1458 return only the port name, not the
1459 whole thing. this allows connections
1460 to be re-established even when our
1461 client name is different.
1464 str += _session.engine().make_port_name_relative (connections[n]);
1476 node->add_property ("inputs", str);
1482 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1484 const char **connections = (*i)->get_connections();
1486 if (connections && connections[0]) {
1490 for (int n = 0; connections[n]; ++n) {
1495 str += _session.engine().make_port_name_relative (connections[n]);
1507 node->add_property ("outputs", str);
1510 node->add_child_nocopy (_panner->state (full_state));
1511 node->add_child_nocopy (_gain_control.get_state ());
1513 snprintf (buf, sizeof(buf), "%2.12f", gain());
1514 node->add_property ("gain", buf);
1516 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1522 node->add_property ("iolimits", buf);
1528 XMLNode* autonode = new XMLNode (X_("Automation"));
1529 autonode->add_child_nocopy (get_automation_state());
1530 node->add_child_nocopy (*autonode);
1532 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1534 /* never store anything except Off for automation state in a template */
1535 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1538 node->add_property ("automation-state", buf);
1539 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1540 node->add_property ("automation-style", buf);
1548 IO::set_state (const XMLNode& node)
1550 const XMLProperty* prop;
1551 XMLNodeConstIterator iter;
1552 LocaleGuard lg (X_("POSIX"));
1554 /* force use of non-localized representation of decimal point,
1555 since we use it a lot in XML files and so forth.
1558 if (node.name() != state_node_name) {
1559 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1563 if ((prop = node.property ("name")) != 0) {
1564 _name = prop->value();
1565 /* used to set panner name with this, but no more */
1568 if ((prop = node.property ("id")) != 0) {
1569 _id = prop->value ();
1572 if ((prop = node.property ("iolimits")) != 0) {
1573 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1580 if ((prop = node.property ("gain")) != 0) {
1581 set_gain (atof (prop->value().c_str()), this);
1582 _gain = _desired_gain;
1585 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1587 if ((*iter)->name() == "Panner") {
1588 _panner->set_state (**iter);
1591 if ((*iter)->name() == X_("Automation")) {
1593 set_automation_state (*(*iter)->children().front());
1596 if ((*iter)->name() == X_("gaincontrol")) {
1597 _gain_control.set_state (**iter);
1601 if ((prop = node.property ("automation-state")) != 0) {
1604 x = strtol (prop->value().c_str(), 0, 16);
1605 set_gain_automation_state (AutoState (x));
1608 if ((prop = node.property ("automation-style")) != 0) {
1611 x = strtol (prop->value().c_str(), 0, 16);
1612 set_gain_automation_style (AutoStyle (x));
1617 if (create_ports (node)) {
1623 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1626 if (panners_legal) {
1629 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1632 if (connecting_legal) {
1634 if (make_connections (node)) {
1640 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1643 if (!ports_legal || !connecting_legal) {
1644 pending_state_node = new XMLNode (node);
1651 IO::set_automation_state (const XMLNode& node)
1653 return _gain_automation_curve.set_state (node);
1657 IO::get_automation_state ()
1659 return (_gain_automation_curve.get_state ());
1663 IO::connecting_became_legal ()
1667 if (pending_state_node == 0) {
1668 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1673 connection_legal_c.disconnect ();
1675 ret = make_connections (*pending_state_node);
1678 delete pending_state_node;
1679 pending_state_node = 0;
1685 IO::ports_became_legal ()
1689 if (pending_state_node == 0) {
1690 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1695 port_legal_c.disconnect ();
1697 ret = create_ports (*pending_state_node);
1699 if (connecting_legal) {
1700 delete pending_state_node;
1701 pending_state_node = 0;
1708 IO::create_ports (const XMLNode& node)
1710 const XMLProperty* prop;
1712 int num_outputs = 0;
1714 if ((prop = node.property ("input-connection")) != 0) {
1716 Connection* c = _session.connection_by_name (prop->value());
1719 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1721 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1722 error << _("No input connections available as a replacement")
1726 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1731 num_inputs = c->nports();
1733 } else if ((prop = node.property ("inputs")) != 0) {
1735 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1738 if ((prop = node.property ("output-connection")) != 0) {
1739 Connection* c = _session.connection_by_name (prop->value());
1742 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1744 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1745 error << _("No output connections available as a replacement")
1749 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1754 num_outputs = c->nports ();
1756 } else if ((prop = node.property ("outputs")) != 0) {
1757 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1760 no_panner_reset = true;
1762 if (ensure_io (num_inputs, num_outputs, true, this)) {
1763 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1767 no_panner_reset = false;
1769 set_deferred_state ();
1777 IO::make_connections (const XMLNode& node)
1779 const XMLProperty* prop;
1781 if ((prop = node.property ("input-connection")) != 0) {
1782 Connection* c = _session.connection_by_name (prop->value());
1785 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1787 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1788 error << _("No input connections available as a replacement")
1792 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1797 use_input_connection (*c, this);
1799 } else if ((prop = node.property ("inputs")) != 0) {
1800 if (set_inputs (prop->value())) {
1801 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1806 if ((prop = node.property ("output-connection")) != 0) {
1807 Connection* c = _session.connection_by_name (prop->value());
1810 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1812 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1813 error << _("No output connections available as a replacement")
1817 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1822 use_output_connection (*c, this);
1824 } else if ((prop = node.property ("outputs")) != 0) {
1825 if (set_outputs (prop->value())) {
1826 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1835 IO::set_inputs (const string& str)
1837 vector<string> ports;
1842 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1846 if (ensure_inputs (nports, true, true, this)) {
1850 string::size_type start, end, ostart;
1857 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1860 if ((end = str.find_first_of ('}', start)) == string::npos) {
1861 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1865 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1866 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1872 for (int x = 0; x < n; ++x) {
1873 connect_input (input (i), ports[x], this);
1885 IO::set_outputs (const string& str)
1887 vector<string> ports;
1892 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1896 if (ensure_outputs (nports, true, true, this)) {
1900 string::size_type start, end, ostart;
1907 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1910 if ((end = str.find_first_of ('}', start)) == string::npos) {
1911 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1915 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1916 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1922 for (int x = 0; x < n; ++x) {
1923 connect_output (output (i), ports[x], this);
1935 IO::parse_io_string (const string& str, vector<string>& ports)
1937 string::size_type pos, opos;
1939 if (str.length() == 0) {
1948 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1949 ports.push_back (str.substr (opos, pos - opos));
1953 if (opos < str.length()) {
1954 ports.push_back (str.substr(opos));
1957 return ports.size();
1961 IO::parse_gain_string (const string& str, vector<string>& ports)
1963 string::size_type pos, opos;
1969 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1970 ports.push_back (str.substr (opos, pos - opos));
1974 if (opos < str.length()) {
1975 ports.push_back (str.substr(opos));
1978 return ports.size();
1982 IO::set_name (string name, void* src)
1984 if (name == _name) {
1988 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1989 string current_name = (*i)->short_name();
1990 current_name.replace (current_name.find (_name), _name.length(), name);
1991 (*i)->set_name (current_name);
1994 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1995 string current_name = (*i)->short_name();
1996 current_name.replace (current_name.find (_name), _name.length(), name);
1997 (*i)->set_name (current_name);
2001 name_changed (src); /* EMIT SIGNAL */
2007 IO::set_input_minimum (int n)
2013 IO::set_input_maximum (int n)
2019 IO::set_output_minimum (int n)
2021 _output_minimum = n;
2025 IO::set_output_maximum (int n)
2027 _output_maximum = n;
2031 IO::set_port_latency (nframes_t nframes)
2033 Glib::Mutex::Lock lm (io_lock);
2035 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2036 (*i)->set_latency (nframes);
2041 IO::output_latency () const
2043 nframes_t max_latency;
2048 /* io lock not taken - must be protected by other means */
2050 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2051 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2052 max_latency = latency;
2060 IO::input_latency () const
2062 nframes_t max_latency;
2067 /* io lock not taken - must be protected by other means */
2069 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2070 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2071 max_latency = latency;
2079 IO::use_input_connection (Connection& c, void* src)
2084 Glib::Mutex::Lock lm (_session.engine().process_lock());
2085 Glib::Mutex::Lock lm2 (io_lock);
2089 drop_input_connection ();
2091 if (ensure_inputs (limit, false, false, src)) {
2095 /* first pass: check the current state to see what's correctly
2096 connected, and drop anything that we don't want.
2099 for (uint32_t n = 0; n < limit; ++n) {
2100 const Connection::PortList& pl = c.port_connections (n);
2102 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2104 if (!_inputs[n]->connected_to ((*i))) {
2106 /* clear any existing connections */
2108 _session.engine().disconnect (_inputs[n]);
2110 } else if (_inputs[n]->connected() > 1) {
2112 /* OK, it is connected to the port we want,
2113 but its also connected to other ports.
2114 Change that situation.
2117 /* XXX could be optimized to not drop
2121 _session.engine().disconnect (_inputs[n]);
2127 /* second pass: connect all requested ports where necessary */
2129 for (uint32_t n = 0; n < limit; ++n) {
2130 const Connection::PortList& pl = c.port_connections (n);
2132 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2134 if (!_inputs[n]->connected_to ((*i))) {
2136 if (_session.engine().connect (*i, _inputs[n]->name())) {
2144 _input_connection = &c;
2146 input_connection_configuration_connection = c.ConfigurationChanged.connect
2147 (mem_fun (*this, &IO::input_connection_configuration_changed));
2148 input_connection_connection_connection = c.ConnectionsChanged.connect
2149 (mem_fun (*this, &IO::input_connection_connection_changed));
2152 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2157 IO::use_output_connection (Connection& c, void* src)
2162 Glib::Mutex::Lock lm (_session.engine().process_lock());
2163 Glib::Mutex::Lock lm2 (io_lock);
2167 drop_output_connection ();
2169 if (ensure_outputs (limit, false, false, src)) {
2173 /* first pass: check the current state to see what's correctly
2174 connected, and drop anything that we don't want.
2177 for (uint32_t n = 0; n < limit; ++n) {
2179 const Connection::PortList& pl = c.port_connections (n);
2181 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2183 if (!_outputs[n]->connected_to ((*i))) {
2185 /* clear any existing connections */
2187 _session.engine().disconnect (_outputs[n]);
2189 } else if (_outputs[n]->connected() > 1) {
2191 /* OK, it is connected to the port we want,
2192 but its also connected to other ports.
2193 Change that situation.
2196 /* XXX could be optimized to not drop
2200 _session.engine().disconnect (_outputs[n]);
2205 /* second pass: connect all requested ports where necessary */
2207 for (uint32_t n = 0; n < limit; ++n) {
2209 const Connection::PortList& pl = c.port_connections (n);
2211 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2213 if (!_outputs[n]->connected_to ((*i))) {
2215 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2222 _output_connection = &c;
2224 output_connection_configuration_connection = c.ConfigurationChanged.connect
2225 (mem_fun (*this, &IO::output_connection_configuration_changed));
2226 output_connection_connection_connection = c.ConnectionsChanged.connect
2227 (mem_fun (*this, &IO::output_connection_connection_changed));
2230 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2236 IO::disable_connecting ()
2238 connecting_legal = false;
2243 IO::enable_connecting ()
2245 connecting_legal = true;
2246 return ConnectingLegal ();
2250 IO::disable_ports ()
2252 ports_legal = false;
2260 return PortsLegal ();
2264 IO::disable_panners (void)
2266 panners_legal = false;
2271 IO::reset_panners ()
2273 panners_legal = true;
2274 return PannersLegal ();
2278 IO::input_connection_connection_changed (int ignored)
2280 use_input_connection (*_input_connection, this);
2284 IO::input_connection_configuration_changed ()
2286 use_input_connection (*_input_connection, this);
2290 IO::output_connection_connection_changed (int ignored)
2292 use_output_connection (*_output_connection, this);
2296 IO::output_connection_configuration_changed ()
2298 use_output_connection (*_output_connection, this);
2302 IO::GainControllable::set_value (float val)
2304 io.set_gain (direct_control_to_gain (val), this);
2308 IO::GainControllable::get_value (void) const
2310 return direct_gain_to_control (io.effective_gain());
2314 IO::reset_peak_meters ()
2316 uint32_t limit = max (_ninputs, _noutputs);
2318 for (uint32_t i = 0; i < limit; ++i) {
2324 IO::setup_peak_meters ()
2326 uint32_t limit = max (_ninputs, _noutputs);
2328 while (_peak_power.size() < limit) {
2329 _peak_power.push_back (0);
2330 _visible_peak_power.push_back (0);
2335 Update the peak meters.
2337 The meter signal lock is taken to prevent modification of the
2338 Meter signal while updating the meters, taking the meter signal
2339 lock prior to taking the io_lock ensures that all IO will remain
2340 valid while metering.
2345 Glib::Mutex::Lock guard (m_meter_signal_lock);
2353 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2354 uint32_t limit = max (_ninputs, _noutputs);
2356 for (uint32_t n = 0; n < limit; ++n) {
2358 /* XXX we should use atomic exchange here */
2360 /* grab peak since last read */
2362 float new_peak = _peak_power[n];
2365 /* compute new visible value using falloff */
2367 if (new_peak > 0.0) {
2368 new_peak = coefficient_to_dB (new_peak);
2370 new_peak = minus_infinity();
2373 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2374 _visible_peak_power[n] = new_peak;
2377 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2378 _visible_peak_power[n] = max (new_peak, -INFINITY);
2384 IO::clear_automation ()
2386 Glib::Mutex::Lock lm (automation_lock);
2387 _gain_automation_curve.clear ();
2388 _panner->clear_automation ();
2392 IO::set_gain_automation_state (AutoState state)
2394 bool changed = false;
2397 Glib::Mutex::Lock lm (automation_lock);
2399 if (state != _gain_automation_curve.automation_state()) {
2401 _gain_automation_curve.set_automation_state (state);
2404 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2410 _session.set_dirty ();
2411 gain_automation_state_changed (); /* EMIT SIGNAL */
2416 IO::set_gain_automation_style (AutoStyle style)
2418 bool changed = false;
2421 Glib::Mutex::Lock lm (automation_lock);
2423 if (style != _gain_automation_curve.automation_style()) {
2425 _gain_automation_curve.set_automation_style (style);
2430 gain_automation_style_changed (); /* EMIT SIGNAL */
2434 IO::inc_gain (gain_t factor, void *src)
2436 if (_desired_gain == 0.0f)
2437 set_gain (0.000001f + (0.000001f * factor), src);
2439 set_gain (_desired_gain + (_desired_gain * factor), src);
2443 IO::set_gain (gain_t val, void *src)
2445 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2446 if (val>1.99526231f) val=1.99526231f;
2449 Glib::Mutex::Lock dm (declick_lock);
2450 _desired_gain = val;
2453 if (_session.transport_stopped()) {
2454 _effective_gain = val;
2459 _gain_control.Changed (); /* EMIT SIGNAL */
2461 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2462 _gain_automation_curve.add (_session.transport_frame(), val);
2466 _session.set_dirty();
2470 IO::start_gain_touch ()
2472 _gain_automation_curve.start_touch ();
2476 IO::end_gain_touch ()
2478 _gain_automation_curve.stop_touch ();
2482 IO::start_pan_touch (uint32_t which)
2484 if (which < _panner->size()) {
2485 (*_panner)[which]->automation().start_touch();
2490 IO::end_pan_touch (uint32_t which)
2492 if (which < _panner->size()) {
2493 (*_panner)[which]->automation().stop_touch();
2499 IO::transport_stopped (nframes_t frame)
2501 _gain_automation_curve.reposition_for_rt_add (frame);
2503 if (_gain_automation_curve.automation_state() != Off) {
2505 /* the src=0 condition is a special signal to not propagate
2506 automation gain changes into the mix group when locating.
2509 set_gain (_gain_automation_curve.eval (frame), 0);
2512 _panner->transport_stopped (frame);
2516 IO::find_input_port_hole ()
2518 /* CALLER MUST HOLD IO LOCK */
2522 if (_inputs.empty()) {
2526 for (n = 1; n < UINT_MAX; ++n) {
2527 char buf[jack_port_name_size()];
2528 vector<Port*>::iterator i;
2530 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2532 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2533 if ((*i)->short_name() == buf) {
2538 if (i == _inputs.end()) {
2546 IO::find_output_port_hole ()
2548 /* CALLER MUST HOLD IO LOCK */
2552 if (_outputs.empty()) {
2556 for (n = 1; n < UINT_MAX; ++n) {
2557 char buf[jack_port_name_size()];
2558 vector<Port*>::iterator i;
2560 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2562 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2563 if ((*i)->short_name() == buf) {
2568 if (i == _outputs.end()) {