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);
176 Glib::Mutex::Lock guard (m_meter_signal_lock);
178 Glib::Mutex::Lock lm (io_lock);
179 vector<Port *>::iterator i;
181 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
182 _session.engine().unregister_port (*i);
185 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
186 _session.engine().unregister_port (*i);
189 m_meter_connection.disconnect();
193 IO::silence (nframes_t nframes, nframes_t offset)
195 /* io_lock, not taken: function must be called from Session::process() calltree */
197 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
198 (*i)->silence (nframes, offset);
203 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
205 nframes_t declick = min ((nframes_t)128, nframes);
208 double fractional_shift;
209 double fractional_pos;
210 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
212 if (nframes == 0) return;
214 fractional_shift = -1.0/declick;
216 if (target < initial) {
217 /* fade out: remove more and more of delta from initial */
218 delta = -(initial - target);
220 /* fade in: add more and more of delta from initial */
221 delta = target - initial;
224 for (uint32_t n = 0; n < nbufs; ++n) {
227 fractional_pos = 1.0;
229 for (nframes_t nx = 0; nx < declick; ++nx) {
230 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
231 fractional_pos += fractional_shift;
234 /* now ensure the rest of the buffer has the target value
235 applied, if necessary.
238 if (declick != nframes) {
241 if (invert_polarity) {
242 this_target = -target;
244 this_target = target;
247 if (this_target == 0.0) {
248 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
249 } else if (this_target != 1.0) {
250 for (nframes_t nx = declick; nx < nframes; ++nx) {
251 buffer[nx] *= this_target;
259 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
263 /* io_lock, not taken: function must be called from Session::process() calltree */
265 if (_noutputs == 0) {
269 if (_noutputs == 1) {
271 dst = output(0)->get_buffer (nframes) + offset;
273 for (uint32_t n = 0; n < nbufs; ++n) {
274 if (bufs[n] != dst) {
275 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
279 output(0)->mark_silence (false);
285 vector<Port *>::iterator out;
286 vector<Sample *>::iterator in;
287 Panner::iterator pan;
288 Sample* obufs[_noutputs];
290 /* the terrible silence ... */
292 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
293 obufs[o] = (*out)->get_buffer (nframes) + offset;
294 memset (obufs[o], 0, sizeof (Sample) * nframes);
295 (*out)->mark_silence (false);
300 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
301 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
306 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
311 /* io_lock, not taken: function must be called from Session::process() calltree */
313 if (_noutputs == 0) {
317 /* the panner can be empty if there are no inputs to the
318 route, but still outputs
321 if (_panner->bypassed() || _panner->empty()) {
322 deliver_output_no_pan (bufs, nbufs, nframes, offset);
326 if (_noutputs == 1) {
328 dst = output(0)->get_buffer (nframes) + offset;
330 if (gain_coeff == 0.0f) {
332 /* only one output, and gain was zero, so make it silent */
334 memset (dst, 0, sizeof (Sample) * nframes);
336 } else if (gain_coeff == 1.0f){
338 /* mix all buffers into the output */
342 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
344 for (n = 1; n < nbufs; ++n) {
347 for (nframes_t n = 0; n < nframes; ++n) {
352 output(0)->mark_silence (false);
356 /* mix all buffers into the output, scaling them all by the gain */
362 for (nframes_t n = 0; n < nframes; ++n) {
363 dst[n] = src[n] * gain_coeff;
366 for (n = 1; n < nbufs; ++n) {
369 for (nframes_t n = 0; n < nframes; ++n) {
370 dst[n] += src[n] * gain_coeff;
374 output(0)->mark_silence (false);
381 vector<Port *>::iterator out;
382 vector<Sample *>::iterator in;
383 Panner::iterator pan;
384 Sample* obufs[_noutputs];
386 /* the terrible silence ... */
388 /* XXX this is wasteful but i see no way to avoid it */
390 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
391 obufs[o] = (*out)->get_buffer (nframes) + offset;
392 memset (obufs[o], 0, sizeof (Sample) * nframes);
393 (*out)->mark_silence (false);
398 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
399 Panner::iterator tmp;
404 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
406 if (tmp != _panner->end()) {
413 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
415 /* io_lock, not taken: function must be called from Session::process() calltree */
417 if (_noutputs == 0) {
421 if (_panner->bypassed() || _panner->empty()) {
422 deliver_output_no_pan (bufs, nbufs, nframes, offset);
428 gain_t pangain = _gain;
431 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
441 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
446 /* simple, non-automation panning to outputs */
448 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
449 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
451 pan (bufs, nbufs, nframes, offset, pangain);
456 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
458 /* io_lock, not taken: function must be called from Session::process() calltree */
460 if (_noutputs == 0) {
465 gain_t old_gain = _gain;
467 if (apply_gain_automation || _ignore_gain_on_deliver) {
469 /* gain has already been applied by automation code. do nothing here except
478 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
490 vector<Port*>::iterator o;
491 vector<Sample*> outs;
495 /* unlikely condition */
496 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
497 outs.push_back ((*o)->get_buffer (nframes) + offset);
501 /* reduce nbufs to the index of the last input buffer */
505 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
506 actual_gain = _gain * speed_quietning;
511 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
513 dst = (*o)->get_buffer (nframes) + offset;
514 src = bufs[min(nbufs,i)];
516 if (dg != _gain || actual_gain == 1.0f) {
517 memcpy (dst, src, sizeof (Sample) * nframes);
518 } else if (actual_gain == 0.0f) {
519 memset (dst, 0, sizeof (Sample) * nframes);
521 for (nframes_t x = 0; x < nframes; ++x) {
522 dst[x] = src[x] * actual_gain;
526 (*o)->mark_silence (false);
530 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
534 if (apply_gain_automation || _ignore_gain_on_deliver) {
540 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
542 /* io_lock, not taken: function must be called from Session::process() calltree */
544 vector<Port *>::iterator i;
548 /* we require that bufs.size() >= 1 */
550 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
551 if (i == _inputs.end()) {
555 /* XXX always read the full extent of the port buffer that
556 we need. One day, we may use jack_port_get_buffer_at_offset()
557 or something similar. For now, this simple hack will
560 Hack? Why yes .. we only need to read nframes-worth of
561 data, but the data we want is at `offset' within the
565 last = (*i)->get_buffer (nframes+offset) + offset;
566 // the dest buffer's offset has already been applied
567 memcpy (bufs[n], last, sizeof (Sample) * nframes);
570 /* fill any excess outputs with the last input */
572 while (n < nbufs && last) {
573 // the dest buffer's offset has already been applied
574 memcpy (bufs[n], last, sizeof (Sample) * nframes);
580 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
581 nframes_t nframes, nframes_t offset)
583 vector<Sample*>& bufs = _session.get_passthru_buffers ();
584 uint32_t nbufs = n_process_buffers ();
586 collect_input (bufs, nbufs, nframes, offset);
588 for (uint32_t n = 0; n < nbufs; ++n) {
589 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
594 IO::drop_input_connection ()
596 _input_connection = 0;
597 input_connection_configuration_connection.disconnect();
598 input_connection_connection_connection.disconnect();
599 _session.set_dirty ();
603 IO::drop_output_connection ()
605 _output_connection = 0;
606 output_connection_configuration_connection.disconnect();
607 output_connection_connection_connection.disconnect();
608 _session.set_dirty ();
612 IO::disconnect_input (Port* our_port, string other_port, void* src)
614 if (other_port.length() == 0 || our_port == 0) {
619 Glib::Mutex::Lock em (_session.engine().process_lock());
622 Glib::Mutex::Lock lm (io_lock);
624 /* check that our_port is really one of ours */
626 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
630 /* disconnect it from the source */
632 if (_session.engine().disconnect (other_port, our_port->name())) {
633 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
637 drop_input_connection();
641 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
642 _session.set_dirty ();
648 IO::connect_input (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 /* check that our_port is really one of ours */
662 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
666 /* connect it to the source */
668 if (_session.engine().connect (other_port, our_port->name())) {
672 drop_input_connection ();
676 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
677 _session.set_dirty ();
682 IO::disconnect_output (Port* our_port, string other_port, void* src)
684 if (other_port.length() == 0 || our_port == 0) {
689 Glib::Mutex::Lock em(_session.engine().process_lock());
692 Glib::Mutex::Lock lm (io_lock);
694 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
698 /* disconnect it from the destination */
700 if (_session.engine().disconnect (our_port->name(), other_port)) {
701 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
705 drop_output_connection ();
709 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
710 _session.set_dirty ();
715 IO::connect_output (Port* our_port, string other_port, void* src)
717 if (other_port.length() == 0 || our_port == 0) {
722 Glib::Mutex::Lock em(_session.engine().process_lock());
725 Glib::Mutex::Lock lm (io_lock);
727 /* check that our_port is really one of ours */
729 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
733 /* connect it to the destination */
735 if (_session.engine().connect (our_port->name(), other_port)) {
739 drop_output_connection ();
743 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
744 _session.set_dirty ();
749 IO::set_input (Port* other_port, void* src)
751 /* this removes all but one ports, and connects that one port
752 to the specified source.
755 if (_input_minimum > 1 || _input_minimum == 0) {
756 /* sorry, you can't do this */
760 if (other_port == 0) {
761 if (_input_minimum < 0) {
762 return ensure_inputs (0, false, true, src);
768 if (ensure_inputs (1, true, true, src)) {
772 return connect_input (_inputs.front(), other_port->name(), src);
776 IO::remove_output_port (Port* port, void* src)
778 IOChange change (NoChange);
781 Glib::Mutex::Lock em(_session.engine().process_lock());
784 Glib::Mutex::Lock lm (io_lock);
786 if (_noutputs - 1 == (uint32_t) _output_minimum) {
787 /* sorry, you can't do this */
791 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
793 change = IOChange (change|ConfigurationChanged);
794 if (port->connected()) {
795 change = IOChange (change|ConnectionsChanged);
798 _session.engine().unregister_port (*i);
801 drop_output_connection ();
807 if (change != NoChange) {
808 setup_peak_meters ();
814 if (change != NoChange) {
815 output_changed (change, src); /* EMIT SIGNAL */
816 _session.set_dirty ();
823 /** Add an output port.
825 * @param destination Name of input port to connect new port to.
826 * @param src Source for emitted ConfigurationChanged signal.
827 * @param type Data type of port. Default value (NIL) will use this IO's default type.
830 IO::add_output_port (string destination, void* src, DataType type)
835 if (type == DataType::NIL)
836 type = _default_type;
839 Glib::Mutex::Lock em(_session.engine().process_lock());
842 Glib::Mutex::Lock lm (io_lock);
844 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
848 /* Create a new output port */
850 // FIXME: naming scheme for differently typed ports?
851 if (_output_maximum == 1) {
852 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
854 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
857 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
858 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
862 _outputs.push_back (our_port);
863 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
865 drop_output_connection ();
866 setup_peak_meters ();
870 MoreOutputs (_noutputs); /* EMIT SIGNAL */
873 if (destination.length()) {
874 if (_session.engine().connect (our_port->name(), destination)) {
879 // pan_changed (src); /* EMIT SIGNAL */
880 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
881 _session.set_dirty ();
886 IO::remove_input_port (Port* port, void* src)
888 IOChange change (NoChange);
891 Glib::Mutex::Lock em(_session.engine().process_lock());
894 Glib::Mutex::Lock lm (io_lock);
896 if (((int)_ninputs - 1) < _input_minimum) {
897 /* sorry, you can't do this */
900 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
903 change = IOChange (change|ConfigurationChanged);
905 if (port->connected()) {
906 change = IOChange (change|ConnectionsChanged);
909 _session.engine().unregister_port (*i);
912 drop_input_connection ();
918 if (change != NoChange) {
919 setup_peak_meters ();
925 if (change != NoChange) {
926 input_changed (change, src);
927 _session.set_dirty ();
935 /** Add an input port.
937 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
938 * @param destination Name of input port to connect new port to.
939 * @param src Source for emitted ConfigurationChanged signal.
942 IO::add_input_port (string source, void* src, DataType type)
947 if (type == DataType::NIL)
948 type = _default_type;
951 Glib::Mutex::Lock em (_session.engine().process_lock());
954 Glib::Mutex::Lock lm (io_lock);
956 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
960 /* Create a new input port */
962 // FIXME: naming scheme for differently typed ports?
963 if (_input_maximum == 1) {
964 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
966 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
969 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
970 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
974 _inputs.push_back (our_port);
975 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
977 drop_input_connection ();
978 setup_peak_meters ();
982 MoreOutputs (_ninputs); /* EMIT SIGNAL */
985 if (source.length()) {
987 if (_session.engine().connect (source, our_port->name())) {
992 // pan_changed (src); /* EMIT SIGNAL */
993 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
994 _session.set_dirty ();
1000 IO::disconnect_inputs (void* src)
1003 Glib::Mutex::Lock em (_session.engine().process_lock());
1006 Glib::Mutex::Lock lm (io_lock);
1008 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1009 _session.engine().disconnect (*i);
1012 drop_input_connection ();
1015 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1020 IO::disconnect_outputs (void* src)
1023 Glib::Mutex::Lock em (_session.engine().process_lock());
1026 Glib::Mutex::Lock lm (io_lock);
1028 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1029 _session.engine().disconnect (*i);
1032 drop_output_connection ();
1036 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1037 _session.set_dirty ();
1042 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1045 bool changed = false;
1046 bool reduced = false;
1048 /* remove unused ports */
1050 while (_ninputs > n) {
1051 _session.engine().unregister_port (_inputs.back());
1058 /* create any necessary new ports */
1060 while (_ninputs < n) {
1064 /* Create a new input port (of the default type) */
1066 if (_input_maximum == 1) {
1067 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1070 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1075 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1076 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1081 catch (AudioEngine::PortRegistrationFailure& err) {
1082 setup_peak_meters ();
1088 _inputs.push_back (input_port);
1089 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1095 drop_input_connection ();
1096 setup_peak_meters ();
1098 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1099 _session.set_dirty ();
1103 /* disconnect all existing ports so that we get a fresh start */
1105 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1106 _session.engine().disconnect (*i);
1114 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1116 bool in_changed = false;
1117 bool out_changed = false;
1118 bool in_reduced = false;
1119 bool out_reduced = false;
1120 bool need_pan_reset;
1122 if (_input_maximum >= 0) {
1123 nin = min (_input_maximum, (int) nin);
1126 if (_output_maximum >= 0) {
1127 nout = min (_output_maximum, (int) nout);
1130 if (nin == _ninputs && nout == _noutputs && !clear) {
1135 Glib::Mutex::Lock em (_session.engine().process_lock());
1136 Glib::Mutex::Lock lm (io_lock);
1140 if (_noutputs == nout) {
1141 need_pan_reset = false;
1143 need_pan_reset = true;
1146 /* remove unused ports */
1148 while (_ninputs > nin) {
1149 _session.engine().unregister_port (_inputs.back());
1156 while (_noutputs > nout) {
1157 _session.engine().unregister_port (_outputs.back());
1158 _outputs.pop_back();
1164 /* create any necessary new ports (of the default type) */
1166 while (_ninputs < nin) {
1170 /* Create a new input port */
1172 if (_input_maximum == 1) {
1173 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1176 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1180 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1181 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1186 catch (AudioEngine::PortRegistrationFailure& err) {
1187 setup_peak_meters ();
1193 _inputs.push_back (port);
1198 /* create any necessary new ports */
1200 while (_noutputs < nout) {
1204 /* Create a new output port */
1206 if (_output_maximum == 1) {
1207 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1209 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1213 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1214 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1219 catch (AudioEngine::PortRegistrationFailure& err) {
1220 setup_peak_meters ();
1226 _outputs.push_back (port);
1233 /* disconnect all existing ports so that we get a fresh start */
1235 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1236 _session.engine().disconnect (*i);
1239 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1240 _session.engine().disconnect (*i);
1244 if (in_changed || out_changed) {
1245 setup_peak_meters ();
1251 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1252 drop_output_connection ();
1253 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1257 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1258 drop_input_connection ();
1259 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1262 if (in_changed || out_changed) {
1263 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1264 _session.set_dirty ();
1271 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1273 bool changed = false;
1275 if (_input_maximum >= 0) {
1276 n = min (_input_maximum, (int) n);
1278 if (n == _ninputs && !clear) {
1284 Glib::Mutex::Lock em (_session.engine().process_lock());
1285 Glib::Mutex::Lock im (io_lock);
1286 changed = ensure_inputs_locked (n, clear, src);
1288 changed = ensure_inputs_locked (n, clear, src);
1292 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1293 _session.set_dirty ();
1300 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1303 bool changed = false;
1304 bool reduced = false;
1305 bool need_pan_reset;
1307 if (_noutputs == n) {
1308 need_pan_reset = false;
1310 need_pan_reset = true;
1313 /* remove unused ports */
1315 while (_noutputs > n) {
1317 _session.engine().unregister_port (_outputs.back());
1318 _outputs.pop_back();
1324 /* create any necessary new ports */
1326 while (_noutputs < n) {
1330 /* Create a new output port */
1332 if (_output_maximum == 1) {
1333 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1335 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1338 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1339 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1343 _outputs.push_back (output_port);
1344 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1347 setup_peak_meters ();
1349 if (need_pan_reset) {
1355 drop_output_connection ();
1356 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1357 _session.set_dirty ();
1361 /* disconnect all existing ports so that we get a fresh start */
1363 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1364 _session.engine().disconnect (*i);
1372 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1374 bool changed = false;
1376 if (_output_maximum >= 0) {
1377 n = min (_output_maximum, (int) n);
1378 if (n == _noutputs && !clear) {
1383 /* XXX caller should hold io_lock, but generally doesn't */
1386 Glib::Mutex::Lock em (_session.engine().process_lock());
1387 Glib::Mutex::Lock im (io_lock);
1388 changed = ensure_outputs_locked (n, clear, src);
1390 changed = ensure_outputs_locked (n, clear, src);
1394 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1401 IO::effective_gain () const
1403 if (gain_automation_playback()) {
1404 return _effective_gain;
1406 return _desired_gain;
1413 if (panners_legal) {
1414 if (!no_panner_reset) {
1415 _panner->reset (_noutputs, pans_required());
1418 panner_legal_c.disconnect ();
1419 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1424 IO::panners_became_legal ()
1426 _panner->reset (_noutputs, pans_required());
1427 _panner->load (); // automation
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 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1615 /* old school automation handling */
1618 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1620 if ((*iter)->name() == "Panner") {
1622 _panner = new Panner (_name, _session);
1624 _panner->set_state (**iter);
1627 if ((*iter)->name() == X_("Automation")) {
1629 set_automation_state (*(*iter)->children().front());
1632 if ((*iter)->name() == X_("gaincontrol")) {
1633 _gain_control.set_state (**iter);
1639 if (create_ports (node)) {
1645 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1648 if (panners_legal) {
1651 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1654 if (connecting_legal) {
1656 if (make_connections (node)) {
1662 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1665 if (!ports_legal || !connecting_legal) {
1666 pending_state_node = new XMLNode (node);
1669 last_automation_snapshot = 0;
1675 IO::set_automation_state (const XMLNode& node)
1677 return _gain_automation_curve.set_state (node);
1681 IO::get_automation_state ()
1683 return (_gain_automation_curve.get_state ());
1687 IO::load_automation (string path)
1692 uint32_t linecnt = 0;
1694 LocaleGuard lg (X_("POSIX"));
1696 fullpath = _session.automation_dir();
1699 in.open (fullpath.c_str());
1702 fullpath = _session.automation_dir();
1703 fullpath += _session.snap_name();
1707 in.open (fullpath.c_str());
1710 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1715 clear_automation ();
1717 while (in.getline (line, sizeof(line), '\n')) {
1719 jack_nframes_t when;
1722 if (++linecnt == 1) {
1723 if (memcmp (line, "version", 7) == 0) {
1724 if (sscanf (line, "version %f", &version) != 1) {
1725 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1729 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1736 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1737 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1743 _gain_automation_curve.fast_simple_add (when, value);
1753 /* older (pre-1.0) versions of ardour used this */
1757 warning << _("dubious automation event found (and ignored)") << endmsg;
1765 IO::connecting_became_legal ()
1769 if (pending_state_node == 0) {
1770 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1775 connection_legal_c.disconnect ();
1777 ret = make_connections (*pending_state_node);
1780 delete pending_state_node;
1781 pending_state_node = 0;
1787 IO::ports_became_legal ()
1791 if (pending_state_node == 0) {
1792 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1797 port_legal_c.disconnect ();
1799 ret = create_ports (*pending_state_node);
1801 if (connecting_legal) {
1802 delete pending_state_node;
1803 pending_state_node = 0;
1810 IO::create_ports (const XMLNode& node)
1812 const XMLProperty* prop;
1814 int num_outputs = 0;
1816 if ((prop = node.property ("input-connection")) != 0) {
1818 Connection* c = _session.connection_by_name (prop->value());
1821 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1823 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1824 error << _("No input connections available as a replacement")
1828 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1833 num_inputs = c->nports();
1835 } else if ((prop = node.property ("inputs")) != 0) {
1837 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1840 if ((prop = node.property ("output-connection")) != 0) {
1841 Connection* c = _session.connection_by_name (prop->value());
1844 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1846 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1847 error << _("No output connections available as a replacement")
1851 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1856 num_outputs = c->nports ();
1858 } else if ((prop = node.property ("outputs")) != 0) {
1859 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1862 no_panner_reset = true;
1864 if (ensure_io (num_inputs, num_outputs, true, this)) {
1865 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1869 no_panner_reset = false;
1871 set_deferred_state ();
1879 IO::make_connections (const XMLNode& node)
1881 const XMLProperty* prop;
1883 if ((prop = node.property ("input-connection")) != 0) {
1884 Connection* c = _session.connection_by_name (prop->value());
1887 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1889 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1890 error << _("No input connections available as a replacement")
1894 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1899 use_input_connection (*c, this);
1901 } else if ((prop = node.property ("inputs")) != 0) {
1902 if (set_inputs (prop->value())) {
1903 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1908 if ((prop = node.property ("output-connection")) != 0) {
1909 Connection* c = _session.connection_by_name (prop->value());
1912 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1914 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1915 error << _("No output connections available as a replacement")
1919 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1924 use_output_connection (*c, this);
1926 } else if ((prop = node.property ("outputs")) != 0) {
1927 if (set_outputs (prop->value())) {
1928 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1937 IO::set_inputs (const string& str)
1939 vector<string> ports;
1944 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1948 if (ensure_inputs (nports, true, true, this)) {
1952 string::size_type start, end, ostart;
1959 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1962 if ((end = str.find_first_of ('}', start)) == string::npos) {
1963 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1967 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1968 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1974 for (int x = 0; x < n; ++x) {
1975 connect_input (input (i), ports[x], this);
1987 IO::set_outputs (const string& str)
1989 vector<string> ports;
1994 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1998 if (ensure_outputs (nports, true, true, this)) {
2002 string::size_type start, end, ostart;
2009 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2012 if ((end = str.find_first_of ('}', start)) == string::npos) {
2013 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2017 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2018 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2024 for (int x = 0; x < n; ++x) {
2025 connect_output (output (i), ports[x], this);
2037 IO::parse_io_string (const string& str, vector<string>& ports)
2039 string::size_type pos, opos;
2041 if (str.length() == 0) {
2050 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2051 ports.push_back (str.substr (opos, pos - opos));
2055 if (opos < str.length()) {
2056 ports.push_back (str.substr(opos));
2059 return ports.size();
2063 IO::parse_gain_string (const string& str, vector<string>& ports)
2065 string::size_type pos, opos;
2071 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2072 ports.push_back (str.substr (opos, pos - opos));
2076 if (opos < str.length()) {
2077 ports.push_back (str.substr(opos));
2080 return ports.size();
2084 IO::set_name (string name, void* src)
2086 if (name == _name) {
2090 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2091 string current_name = (*i)->short_name();
2092 current_name.replace (current_name.find (_name), _name.length(), name);
2093 (*i)->set_name (current_name);
2096 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2097 string current_name = (*i)->short_name();
2098 current_name.replace (current_name.find (_name), _name.length(), name);
2099 (*i)->set_name (current_name);
2103 name_changed (src); /* EMIT SIGNAL */
2109 IO::set_input_minimum (int n)
2115 IO::set_input_maximum (int n)
2121 IO::set_output_minimum (int n)
2123 _output_minimum = n;
2127 IO::set_output_maximum (int n)
2129 _output_maximum = n;
2133 IO::set_port_latency (nframes_t nframes)
2135 Glib::Mutex::Lock lm (io_lock);
2137 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2138 (*i)->set_latency (nframes);
2143 IO::output_latency () const
2145 nframes_t max_latency;
2150 /* io lock not taken - must be protected by other means */
2152 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2153 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2154 max_latency = latency;
2162 IO::input_latency () const
2164 nframes_t max_latency;
2169 /* io lock not taken - must be protected by other means */
2171 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2172 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2173 max_latency = latency;
2181 IO::use_input_connection (Connection& c, void* src)
2186 Glib::Mutex::Lock lm (_session.engine().process_lock());
2187 Glib::Mutex::Lock lm2 (io_lock);
2191 drop_input_connection ();
2193 if (ensure_inputs (limit, false, false, src)) {
2197 /* first pass: check the current state to see what's correctly
2198 connected, and drop anything that we don't want.
2201 for (uint32_t n = 0; n < limit; ++n) {
2202 const Connection::PortList& pl = c.port_connections (n);
2204 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2206 if (!_inputs[n]->connected_to ((*i))) {
2208 /* clear any existing connections */
2210 _session.engine().disconnect (_inputs[n]);
2212 } else if (_inputs[n]->connected() > 1) {
2214 /* OK, it is connected to the port we want,
2215 but its also connected to other ports.
2216 Change that situation.
2219 /* XXX could be optimized to not drop
2223 _session.engine().disconnect (_inputs[n]);
2229 /* second pass: connect all requested ports where necessary */
2231 for (uint32_t n = 0; n < limit; ++n) {
2232 const Connection::PortList& pl = c.port_connections (n);
2234 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2236 if (!_inputs[n]->connected_to ((*i))) {
2238 if (_session.engine().connect (*i, _inputs[n]->name())) {
2246 _input_connection = &c;
2248 input_connection_configuration_connection = c.ConfigurationChanged.connect
2249 (mem_fun (*this, &IO::input_connection_configuration_changed));
2250 input_connection_connection_connection = c.ConnectionsChanged.connect
2251 (mem_fun (*this, &IO::input_connection_connection_changed));
2254 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2259 IO::use_output_connection (Connection& c, void* src)
2264 Glib::Mutex::Lock lm (_session.engine().process_lock());
2265 Glib::Mutex::Lock lm2 (io_lock);
2269 drop_output_connection ();
2271 if (ensure_outputs (limit, false, false, src)) {
2275 /* first pass: check the current state to see what's correctly
2276 connected, and drop anything that we don't want.
2279 for (uint32_t n = 0; n < limit; ++n) {
2281 const Connection::PortList& pl = c.port_connections (n);
2283 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2285 if (!_outputs[n]->connected_to ((*i))) {
2287 /* clear any existing connections */
2289 _session.engine().disconnect (_outputs[n]);
2291 } else if (_outputs[n]->connected() > 1) {
2293 /* OK, it is connected to the port we want,
2294 but its also connected to other ports.
2295 Change that situation.
2298 /* XXX could be optimized to not drop
2302 _session.engine().disconnect (_outputs[n]);
2307 /* second pass: connect all requested ports where necessary */
2309 for (uint32_t n = 0; n < limit; ++n) {
2311 const Connection::PortList& pl = c.port_connections (n);
2313 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2315 if (!_outputs[n]->connected_to ((*i))) {
2317 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2324 _output_connection = &c;
2326 output_connection_configuration_connection = c.ConfigurationChanged.connect
2327 (mem_fun (*this, &IO::output_connection_configuration_changed));
2328 output_connection_connection_connection = c.ConnectionsChanged.connect
2329 (mem_fun (*this, &IO::output_connection_connection_changed));
2332 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2338 IO::disable_connecting ()
2340 connecting_legal = false;
2345 IO::enable_connecting ()
2347 connecting_legal = true;
2348 return ConnectingLegal ();
2352 IO::disable_ports ()
2354 ports_legal = false;
2362 return PortsLegal ();
2366 IO::disable_panners (void)
2368 panners_legal = false;
2373 IO::reset_panners ()
2375 panners_legal = true;
2376 return PannersLegal ();
2380 IO::input_connection_connection_changed (int ignored)
2382 use_input_connection (*_input_connection, this);
2386 IO::input_connection_configuration_changed ()
2388 use_input_connection (*_input_connection, this);
2392 IO::output_connection_connection_changed (int ignored)
2394 use_output_connection (*_output_connection, this);
2398 IO::output_connection_configuration_changed ()
2400 use_output_connection (*_output_connection, this);
2404 IO::GainControllable::set_value (float val)
2406 io.set_gain (direct_control_to_gain (val), this);
2410 IO::GainControllable::get_value (void) const
2412 return direct_gain_to_control (io.effective_gain());
2416 IO::reset_peak_meters ()
2418 uint32_t limit = max (_ninputs, _noutputs);
2420 for (uint32_t i = 0; i < limit; ++i) {
2426 IO::setup_peak_meters ()
2428 uint32_t limit = max (_ninputs, _noutputs);
2430 while (_peak_power.size() < limit) {
2431 _peak_power.push_back (0);
2432 _visible_peak_power.push_back (0);
2437 Update the peak meters.
2439 The meter signal lock is taken to prevent modification of the
2440 Meter signal while updating the meters, taking the meter signal
2441 lock prior to taking the io_lock ensures that all IO will remain
2442 valid while metering.
2447 Glib::Mutex::Lock guard (m_meter_signal_lock);
2455 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2456 uint32_t limit = max (_ninputs, _noutputs);
2458 for (uint32_t n = 0; n < limit; ++n) {
2460 /* XXX we should use atomic exchange here */
2462 /* grab peak since last read */
2464 float new_peak = _peak_power[n];
2467 /* compute new visible value using falloff */
2469 if (new_peak > 0.0) {
2470 new_peak = coefficient_to_dB (new_peak);
2472 new_peak = minus_infinity();
2475 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2476 _visible_peak_power[n] = new_peak;
2479 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2480 _visible_peak_power[n] = max (new_peak, -INFINITY);
2486 IO::clear_automation ()
2488 Glib::Mutex::Lock lm (automation_lock);
2489 _gain_automation_curve.clear ();
2490 _panner->clear_automation ();
2494 IO::set_gain_automation_state (AutoState state)
2496 bool changed = false;
2499 Glib::Mutex::Lock lm (automation_lock);
2501 if (state != _gain_automation_curve.automation_state()) {
2503 last_automation_snapshot = 0;
2504 _gain_automation_curve.set_automation_state (state);
2507 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2513 _session.set_dirty ();
2514 gain_automation_state_changed (); /* EMIT SIGNAL */
2519 IO::set_gain_automation_style (AutoStyle style)
2521 bool changed = false;
2524 Glib::Mutex::Lock lm (automation_lock);
2526 if (style != _gain_automation_curve.automation_style()) {
2528 _gain_automation_curve.set_automation_style (style);
2533 gain_automation_style_changed (); /* EMIT SIGNAL */
2537 IO::inc_gain (gain_t factor, void *src)
2539 if (_desired_gain == 0.0f)
2540 set_gain (0.000001f + (0.000001f * factor), src);
2542 set_gain (_desired_gain + (_desired_gain * factor), src);
2546 IO::set_gain (gain_t val, void *src)
2548 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2549 if (val>1.99526231f) val=1.99526231f;
2552 Glib::Mutex::Lock dm (declick_lock);
2553 _desired_gain = val;
2556 if (_session.transport_stopped()) {
2557 _effective_gain = val;
2562 _gain_control.Changed (); /* EMIT SIGNAL */
2564 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2565 _gain_automation_curve.add (_session.transport_frame(), val);
2569 _session.set_dirty();
2573 IO::start_gain_touch ()
2575 _gain_automation_curve.start_touch ();
2579 IO::end_gain_touch ()
2581 _gain_automation_curve.stop_touch ();
2585 IO::start_pan_touch (uint32_t which)
2587 if (which < _panner->size()) {
2588 (*_panner)[which]->automation().start_touch();
2593 IO::end_pan_touch (uint32_t which)
2595 if (which < _panner->size()) {
2596 (*_panner)[which]->automation().stop_touch();
2602 IO::automation_snapshot (nframes_t now)
2604 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2606 if (gain_automation_recording()) {
2607 _gain_automation_curve.rt_add (now, gain());
2610 _panner->snapshot (now);
2612 last_automation_snapshot = now;
2617 IO::transport_stopped (nframes_t frame)
2619 _gain_automation_curve.reposition_for_rt_add (frame);
2621 if (_gain_automation_curve.automation_state() != Off) {
2623 /* the src=0 condition is a special signal to not propagate
2624 automation gain changes into the mix group when locating.
2627 set_gain (_gain_automation_curve.eval (frame), 0);
2630 _panner->transport_stopped (frame);
2634 IO::find_input_port_hole ()
2636 /* CALLER MUST HOLD IO LOCK */
2640 if (_inputs.empty()) {
2644 for (n = 1; n < UINT_MAX; ++n) {
2645 char buf[jack_port_name_size()];
2646 vector<Port*>::iterator i;
2648 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2650 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2651 if ((*i)->short_name() == buf) {
2656 if (i == _inputs.end()) {
2664 IO::find_output_port_hole ()
2666 /* CALLER MUST HOLD IO LOCK */
2670 if (_outputs.empty()) {
2674 for (n = 1; n < UINT_MAX; ++n) {
2675 char buf[jack_port_name_size()];
2676 vector<Port*>::iterator i;
2678 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2680 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2681 if ((*i)->short_name() == buf) {
2686 if (i == _outputs.end()) {