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);
56 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
59 using namespace ARDOUR;
62 nframes_t IO::_automation_interval = 0;
63 const string IO::state_node_name = "IO";
64 bool IO::connecting_legal = false;
65 bool IO::ports_legal = false;
66 bool IO::panners_legal = false;
67 sigc::signal<void> IO::Meter;
68 sigc::signal<int> IO::ConnectingLegal;
69 sigc::signal<int> IO::PortsLegal;
70 sigc::signal<int> IO::PannersLegal;
71 sigc::signal<void,uint32_t> IO::MoreOutputs;
72 sigc::signal<int> IO::PortsCreated;
74 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
76 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
77 others can be imagined.
80 static gain_t direct_control_to_gain (double fract) {
81 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
82 /* this maxes at +6dB */
83 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
86 static double direct_gain_to_control (gain_t gain) {
87 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
88 if (gain == 0) return 0.0;
90 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
93 static bool sort_ports_by_name (Port* a, Port* b)
95 return a->name() < b->name();
99 /** @param default_type The type of port that will be created by ensure_io
100 * and friends if no type is explicitly requested (to avoid breakage).
102 IO::IO (Session& s, string name,
103 int input_min, int input_max, int output_min, int output_max,
104 DataType default_type)
107 _default_type(default_type),
108 _gain_control (X_("gaincontrol"), *this),
109 _gain_automation_curve (0.0, 2.0, 1.0),
110 _input_minimum (input_min),
111 _input_maximum (input_max),
112 _output_minimum (output_min),
113 _output_maximum (output_max)
115 _panner = new Panner (name, _session);
118 _input_connection = 0;
119 _output_connection = 0;
120 pending_state_node = 0;
123 no_panner_reset = false;
126 apply_gain_automation = false;
127 _ignore_gain_on_deliver = false;
129 last_automation_snapshot = 0;
131 _gain_automation_state = Off;
132 _gain_automation_style = Absolute;
135 // IO::Meter is emitted from another thread so the
136 // Meter signal must be protected.
137 Glib::Mutex::Lock guard (m_meter_signal_lock);
138 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
141 _session.add_controllable (&_gain_control);
144 IO::IO (Session& s, const XMLNode& node, DataType dt)
147 _gain_control (X_("gaincontrol"), *this),
148 _gain_automation_curve (0, 0, 0) // all reset in set_state()
152 no_panner_reset = false;
155 _input_connection = 0;
156 _output_connection = 0;
160 apply_gain_automation = false;
161 _ignore_gain_on_deliver = false;
166 // IO::Meter is emitted from another thread so the
167 // Meter signal must be protected.
168 Glib::Mutex::Lock guard (m_meter_signal_lock);
169 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
172 _session.add_controllable (&_gain_control);
177 Glib::Mutex::Lock guard (m_meter_signal_lock);
179 Glib::Mutex::Lock lm (io_lock);
180 vector<Port *>::iterator i;
182 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
183 _session.engine().unregister_port (*i);
186 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
187 _session.engine().unregister_port (*i);
190 m_meter_connection.disconnect();
194 IO::silence (nframes_t nframes, nframes_t offset)
196 /* io_lock, not taken: function must be called from Session::process() calltree */
198 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
199 (*i)->silence (nframes, offset);
204 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
206 nframes_t declick = min ((nframes_t)128, nframes);
209 double fractional_shift;
210 double fractional_pos;
211 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
213 if (nframes == 0) return;
215 fractional_shift = -1.0/declick;
217 if (target < initial) {
218 /* fade out: remove more and more of delta from initial */
219 delta = -(initial - target);
221 /* fade in: add more and more of delta from initial */
222 delta = target - initial;
225 for (uint32_t n = 0; n < nbufs; ++n) {
228 fractional_pos = 1.0;
230 for (nframes_t nx = 0; nx < declick; ++nx) {
231 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
232 fractional_pos += fractional_shift;
235 /* now ensure the rest of the buffer has the target value
236 applied, if necessary.
239 if (declick != nframes) {
242 if (invert_polarity) {
243 this_target = -target;
245 this_target = target;
248 if (this_target == 0.0) {
249 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
250 } else if (this_target != 1.0) {
251 for (nframes_t nx = declick; nx < nframes; ++nx) {
252 buffer[nx] *= this_target;
260 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
264 /* io_lock, not taken: function must be called from Session::process() calltree */
266 if (_noutputs == 0) {
270 if (_noutputs == 1) {
272 dst = output(0)->get_buffer (nframes) + offset;
274 for (uint32_t n = 0; n < nbufs; ++n) {
275 if (bufs[n] != dst) {
276 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
280 output(0)->mark_silence (false);
286 vector<Port *>::iterator out;
287 vector<Sample *>::iterator in;
288 Panner::iterator pan;
289 Sample* obufs[_noutputs];
291 /* the terrible silence ... */
293 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
294 obufs[o] = (*out)->get_buffer (nframes) + offset;
295 memset (obufs[o], 0, sizeof (Sample) * nframes);
296 (*out)->mark_silence (false);
301 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
302 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
307 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
312 /* io_lock, not taken: function must be called from Session::process() calltree */
314 if (_noutputs == 0) {
318 /* the panner can be empty if there are no inputs to the
319 route, but still outputs
322 if (_panner->bypassed() || _panner->empty()) {
323 deliver_output_no_pan (bufs, nbufs, nframes, offset);
327 if (_noutputs == 1) {
329 dst = output(0)->get_buffer (nframes) + offset;
331 if (gain_coeff == 0.0f) {
333 /* only one output, and gain was zero, so make it silent */
335 memset (dst, 0, sizeof (Sample) * nframes);
337 } else if (gain_coeff == 1.0f){
339 /* mix all buffers into the output */
343 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
345 for (n = 1; n < nbufs; ++n) {
348 for (nframes_t n = 0; n < nframes; ++n) {
353 output(0)->mark_silence (false);
357 /* mix all buffers into the output, scaling them all by the gain */
363 for (nframes_t n = 0; n < nframes; ++n) {
364 dst[n] = src[n] * gain_coeff;
367 for (n = 1; n < nbufs; ++n) {
370 for (nframes_t n = 0; n < nframes; ++n) {
371 dst[n] += src[n] * gain_coeff;
375 output(0)->mark_silence (false);
382 vector<Port *>::iterator out;
383 vector<Sample *>::iterator in;
384 Panner::iterator pan;
385 Sample* obufs[_noutputs];
387 /* the terrible silence ... */
389 /* XXX this is wasteful but i see no way to avoid it */
391 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
392 obufs[o] = (*out)->get_buffer (nframes) + offset;
393 memset (obufs[o], 0, sizeof (Sample) * nframes);
394 (*out)->mark_silence (false);
399 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
400 Panner::iterator tmp;
405 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
407 if (tmp != _panner->end()) {
414 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
416 /* io_lock, not taken: function must be called from Session::process() calltree */
418 if (_noutputs == 0) {
422 if (_panner->bypassed() || _panner->empty()) {
423 deliver_output_no_pan (bufs, nbufs, nframes, offset);
429 gain_t pangain = _gain;
432 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
442 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
447 /* simple, non-automation panning to outputs */
449 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
450 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
452 pan (bufs, nbufs, nframes, offset, pangain);
457 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
459 /* io_lock, not taken: function must be called from Session::process() calltree */
461 if (_noutputs == 0) {
466 gain_t old_gain = _gain;
468 if (apply_gain_automation || _ignore_gain_on_deliver) {
470 /* gain has already been applied by automation code. do nothing here except
479 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
491 vector<Port*>::iterator o;
492 vector<Sample*> outs;
496 /* unlikely condition */
497 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
498 outs.push_back ((*o)->get_buffer (nframes) + offset);
502 /* reduce nbufs to the index of the last input buffer */
506 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
507 actual_gain = _gain * speed_quietning;
512 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
514 dst = (*o)->get_buffer (nframes) + offset;
515 src = bufs[min(nbufs,i)];
517 if (dg != _gain || actual_gain == 1.0f) {
518 memcpy (dst, src, sizeof (Sample) * nframes);
519 } else if (actual_gain == 0.0f) {
520 memset (dst, 0, sizeof (Sample) * nframes);
522 for (nframes_t x = 0; x < nframes; ++x) {
523 dst[x] = src[x] * actual_gain;
527 (*o)->mark_silence (false);
531 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
535 if (apply_gain_automation || _ignore_gain_on_deliver) {
541 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
543 /* io_lock, not taken: function must be called from Session::process() calltree */
545 vector<Port *>::iterator i;
549 /* we require that bufs.size() >= 1 */
551 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
552 if (i == _inputs.end()) {
556 /* XXX always read the full extent of the port buffer that
557 we need. One day, we may use jack_port_get_buffer_at_offset()
558 or something similar. For now, this simple hack will
561 Hack? Why yes .. we only need to read nframes-worth of
562 data, but the data we want is at `offset' within the
566 last = (*i)->get_buffer (nframes+offset) + offset;
567 // the dest buffer's offset has already been applied
568 memcpy (bufs[n], last, sizeof (Sample) * nframes);
571 /* fill any excess outputs with the last input */
573 while (n < nbufs && last) {
574 // the dest buffer's offset has already been applied
575 memcpy (bufs[n], last, sizeof (Sample) * nframes);
581 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
582 nframes_t nframes, nframes_t offset)
584 vector<Sample*>& bufs = _session.get_passthru_buffers ();
585 uint32_t nbufs = n_process_buffers ();
587 collect_input (bufs, nbufs, nframes, offset);
589 for (uint32_t n = 0; n < nbufs; ++n) {
590 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
595 IO::drop_input_connection ()
597 _input_connection = 0;
598 input_connection_configuration_connection.disconnect();
599 input_connection_connection_connection.disconnect();
600 _session.set_dirty ();
604 IO::drop_output_connection ()
606 _output_connection = 0;
607 output_connection_configuration_connection.disconnect();
608 output_connection_connection_connection.disconnect();
609 _session.set_dirty ();
613 IO::disconnect_input (Port* our_port, string other_port, void* src)
615 if (other_port.length() == 0 || our_port == 0) {
620 BLOCK_PROCESS_CALLBACK ();
623 Glib::Mutex::Lock lm (io_lock);
625 /* check that our_port is really one of ours */
627 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
631 /* disconnect it from the source */
633 if (_session.engine().disconnect (other_port, our_port->name())) {
634 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
638 drop_input_connection();
642 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
643 _session.set_dirty ();
649 IO::connect_input (Port* our_port, string other_port, void* src)
651 if (other_port.length() == 0 || our_port == 0) {
656 BLOCK_PROCESS_CALLBACK ();
659 Glib::Mutex::Lock lm (io_lock);
661 /* check that our_port is really one of ours */
663 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
667 /* connect it to the source */
669 if (_session.engine().connect (other_port, our_port->name())) {
673 drop_input_connection ();
677 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
678 _session.set_dirty ();
683 IO::disconnect_output (Port* our_port, string other_port, void* src)
685 if (other_port.length() == 0 || our_port == 0) {
690 BLOCK_PROCESS_CALLBACK ();
693 Glib::Mutex::Lock lm (io_lock);
695 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
699 /* disconnect it from the destination */
701 if (_session.engine().disconnect (our_port->name(), other_port)) {
702 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
706 drop_output_connection ();
710 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
711 _session.set_dirty ();
716 IO::connect_output (Port* our_port, string other_port, void* src)
718 if (other_port.length() == 0 || our_port == 0) {
723 BLOCK_PROCESS_CALLBACK ();
727 Glib::Mutex::Lock lm (io_lock);
729 /* check that our_port is really one of ours */
731 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
735 /* connect it to the destination */
737 if (_session.engine().connect (our_port->name(), other_port)) {
741 drop_output_connection ();
745 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
746 _session.set_dirty ();
751 IO::set_input (Port* other_port, void* src)
753 /* this removes all but one ports, and connects that one port
754 to the specified source.
757 if (_input_minimum > 1 || _input_minimum == 0) {
758 /* sorry, you can't do this */
762 if (other_port == 0) {
763 if (_input_minimum < 0) {
764 return ensure_inputs (0, false, true, src);
770 if (ensure_inputs (1, true, true, src)) {
774 return connect_input (_inputs.front(), other_port->name(), src);
778 IO::remove_output_port (Port* port, void* src)
780 IOChange change (NoChange);
783 BLOCK_PROCESS_CALLBACK ();
787 Glib::Mutex::Lock lm (io_lock);
789 if (_noutputs - 1 == (uint32_t) _output_minimum) {
790 /* sorry, you can't do this */
794 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
796 change = IOChange (change|ConfigurationChanged);
797 if (port->connected()) {
798 change = IOChange (change|ConnectionsChanged);
801 _session.engine().unregister_port (*i);
804 drop_output_connection ();
810 if (change != NoChange) {
811 setup_peak_meters ();
817 if (change != NoChange) {
818 output_changed (change, src); /* EMIT SIGNAL */
819 _session.set_dirty ();
826 /** Add an output port.
828 * @param destination Name of input port to connect new port to.
829 * @param src Source for emitted ConfigurationChanged signal.
830 * @param type Data type of port. Default value (NIL) will use this IO's default type.
833 IO::add_output_port (string destination, void* src, DataType type)
838 if (type == DataType::NIL)
839 type = _default_type;
842 BLOCK_PROCESS_CALLBACK ();
846 Glib::Mutex::Lock lm (io_lock);
848 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
852 /* Create a new output port */
854 // FIXME: naming scheme for differently typed ports?
855 if (_output_maximum == 1) {
856 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
858 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
861 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
862 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
866 _outputs.push_back (our_port);
867 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
869 drop_output_connection ();
870 setup_peak_meters ();
874 MoreOutputs (_noutputs); /* EMIT SIGNAL */
877 if (destination.length()) {
878 if (_session.engine().connect (our_port->name(), destination)) {
883 // pan_changed (src); /* EMIT SIGNAL */
884 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
885 _session.set_dirty ();
890 IO::remove_input_port (Port* port, void* src)
892 IOChange change (NoChange);
895 BLOCK_PROCESS_CALLBACK ();
899 Glib::Mutex::Lock lm (io_lock);
901 if (((int)_ninputs - 1) < _input_minimum) {
902 /* sorry, you can't do this */
905 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
908 change = IOChange (change|ConfigurationChanged);
910 if (port->connected()) {
911 change = IOChange (change|ConnectionsChanged);
914 _session.engine().unregister_port (*i);
917 drop_input_connection ();
923 if (change != NoChange) {
924 setup_peak_meters ();
930 if (change != NoChange) {
931 input_changed (change, src);
932 _session.set_dirty ();
940 /** Add an input port.
942 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
943 * @param destination Name of input port to connect new port to.
944 * @param src Source for emitted ConfigurationChanged signal.
947 IO::add_input_port (string source, void* src, DataType type)
952 if (type == DataType::NIL)
953 type = _default_type;
956 BLOCK_PROCESS_CALLBACK ();
959 Glib::Mutex::Lock lm (io_lock);
961 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
965 /* Create a new input port */
967 // FIXME: naming scheme for differently typed ports?
968 if (_input_maximum == 1) {
969 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
971 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
974 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
975 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
979 _inputs.push_back (our_port);
980 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
982 drop_input_connection ();
983 setup_peak_meters ();
987 MoreOutputs (_ninputs); /* EMIT SIGNAL */
990 if (source.length()) {
992 if (_session.engine().connect (source, our_port->name())) {
997 // pan_changed (src); /* EMIT SIGNAL */
998 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
999 _session.set_dirty ();
1005 IO::disconnect_inputs (void* src)
1008 BLOCK_PROCESS_CALLBACK ();
1011 Glib::Mutex::Lock lm (io_lock);
1013 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1014 _session.engine().disconnect (*i);
1017 drop_input_connection ();
1020 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1025 IO::disconnect_outputs (void* src)
1028 BLOCK_PROCESS_CALLBACK ();
1031 Glib::Mutex::Lock lm (io_lock);
1033 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1034 _session.engine().disconnect (*i);
1037 drop_output_connection ();
1041 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1042 _session.set_dirty ();
1047 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1050 bool changed = false;
1051 bool reduced = false;
1053 /* remove unused ports */
1055 while (_ninputs > n) {
1056 _session.engine().unregister_port (_inputs.back());
1063 /* create any necessary new ports */
1065 while (_ninputs < n) {
1069 /* Create a new input port (of the default type) */
1071 if (_input_maximum == 1) {
1072 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1075 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1080 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1081 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1086 catch (AudioEngine::PortRegistrationFailure& err) {
1087 setup_peak_meters ();
1090 throw AudioEngine::PortRegistrationFailure();
1093 _inputs.push_back (input_port);
1094 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1100 drop_input_connection ();
1101 setup_peak_meters ();
1103 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1104 _session.set_dirty ();
1108 /* disconnect all existing ports so that we get a fresh start */
1110 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1111 _session.engine().disconnect (*i);
1119 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1121 bool in_changed = false;
1122 bool out_changed = false;
1123 bool in_reduced = false;
1124 bool out_reduced = false;
1125 bool need_pan_reset;
1127 if (_input_maximum >= 0) {
1128 nin = min (_input_maximum, (int) nin);
1131 if (_output_maximum >= 0) {
1132 nout = min (_output_maximum, (int) nout);
1135 if (nin == _ninputs && nout == _noutputs && !clear) {
1140 BLOCK_PROCESS_CALLBACK ();
1141 Glib::Mutex::Lock lm (io_lock);
1145 if (_noutputs == nout) {
1146 need_pan_reset = false;
1148 need_pan_reset = true;
1151 /* remove unused ports */
1153 while (_ninputs > nin) {
1154 _session.engine().unregister_port (_inputs.back());
1161 while (_noutputs > nout) {
1162 _session.engine().unregister_port (_outputs.back());
1163 _outputs.pop_back();
1169 /* create any necessary new ports (of the default type) */
1171 while (_ninputs < nin) {
1175 /* Create a new input port */
1177 if (_input_maximum == 1) {
1178 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1181 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1185 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1186 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1191 catch (AudioEngine::PortRegistrationFailure& err) {
1192 setup_peak_meters ();
1195 throw AudioEngine::PortRegistrationFailure();
1198 _inputs.push_back (port);
1203 /* create any necessary new ports */
1205 while (_noutputs < nout) {
1209 /* Create a new output port */
1211 if (_output_maximum == 1) {
1212 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1214 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1218 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1219 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1224 catch (AudioEngine::PortRegistrationFailure& err) {
1225 setup_peak_meters ();
1228 throw AudioEngine::PortRegistrationFailure ();
1231 _outputs.push_back (port);
1238 /* disconnect all existing ports so that we get a fresh start */
1240 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1241 _session.engine().disconnect (*i);
1244 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1245 _session.engine().disconnect (*i);
1249 if (in_changed || out_changed) {
1250 setup_peak_meters ();
1256 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1257 drop_output_connection ();
1258 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1262 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1263 drop_input_connection ();
1264 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1267 if (in_changed || out_changed) {
1268 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1269 _session.set_dirty ();
1276 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1278 bool changed = false;
1280 if (_input_maximum >= 0) {
1281 n = min (_input_maximum, (int) n);
1283 if (n == _ninputs && !clear) {
1289 BLOCK_PROCESS_CALLBACK ();
1290 Glib::Mutex::Lock im (io_lock);
1291 changed = ensure_inputs_locked (n, clear, src);
1293 changed = ensure_inputs_locked (n, clear, src);
1297 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1298 _session.set_dirty ();
1305 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1308 bool changed = false;
1309 bool reduced = false;
1310 bool need_pan_reset;
1312 if (_noutputs == n) {
1313 need_pan_reset = false;
1315 need_pan_reset = true;
1318 /* remove unused ports */
1320 while (_noutputs > n) {
1322 _session.engine().unregister_port (_outputs.back());
1323 _outputs.pop_back();
1329 /* create any necessary new ports */
1331 while (_noutputs < n) {
1335 /* Create a new output port */
1337 if (_output_maximum == 1) {
1338 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1340 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1343 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1344 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1348 _outputs.push_back (output_port);
1349 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1352 setup_peak_meters ();
1354 if (need_pan_reset) {
1360 drop_output_connection ();
1361 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1362 _session.set_dirty ();
1366 /* disconnect all existing ports so that we get a fresh start */
1368 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1369 _session.engine().disconnect (*i);
1377 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1379 bool changed = false;
1381 if (_output_maximum >= 0) {
1382 n = min (_output_maximum, (int) n);
1383 if (n == _noutputs && !clear) {
1388 /* XXX caller should hold io_lock, but generally doesn't */
1391 BLOCK_PROCESS_CALLBACK ();
1392 Glib::Mutex::Lock im (io_lock);
1393 changed = ensure_outputs_locked (n, clear, src);
1395 changed = ensure_outputs_locked (n, clear, src);
1399 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1406 IO::effective_gain () const
1408 if (gain_automation_playback()) {
1409 return _effective_gain;
1411 return _desired_gain;
1418 if (panners_legal) {
1419 if (!no_panner_reset) {
1420 _panner->reset (_noutputs, pans_required());
1423 panner_legal_c.disconnect ();
1424 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1429 IO::panners_became_legal ()
1431 _panner->reset (_noutputs, pans_required());
1432 _panner->load (); // automation
1433 panner_legal_c.disconnect ();
1438 IO::defer_pan_reset ()
1440 no_panner_reset = true;
1444 IO::allow_pan_reset ()
1446 no_panner_reset = false;
1452 IO::get_state (void)
1454 return state (true);
1458 IO::state (bool full_state)
1460 XMLNode* node = new XMLNode (state_node_name);
1463 bool need_ins = true;
1464 bool need_outs = true;
1465 LocaleGuard lg (X_("POSIX"));
1466 Glib::Mutex::Lock lm (io_lock);
1468 node->add_property("name", _name);
1469 id().print (buf, sizeof (buf));
1470 node->add_property("id", buf);
1474 if (_input_connection) {
1475 node->add_property ("input-connection", _input_connection->name());
1479 if (_output_connection) {
1480 node->add_property ("output-connection", _output_connection->name());
1485 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1487 const char **connections = (*i)->get_connections();
1489 if (connections && connections[0]) {
1492 for (int n = 0; connections && connections[n]; ++n) {
1497 /* if its a connection to our own port,
1498 return only the port name, not the
1499 whole thing. this allows connections
1500 to be re-established even when our
1501 client name is different.
1504 str += _session.engine().make_port_name_relative (connections[n]);
1516 node->add_property ("inputs", str);
1522 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1524 const char **connections = (*i)->get_connections();
1526 if (connections && connections[0]) {
1530 for (int n = 0; connections[n]; ++n) {
1535 str += _session.engine().make_port_name_relative (connections[n]);
1547 node->add_property ("outputs", str);
1550 node->add_child_nocopy (_panner->state (full_state));
1551 node->add_child_nocopy (_gain_control.get_state ());
1553 snprintf (buf, sizeof(buf), "%2.12f", gain());
1554 node->add_property ("gain", buf);
1556 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1562 node->add_property ("iolimits", buf);
1568 XMLNode* autonode = new XMLNode (X_("Automation"));
1569 autonode->add_child_nocopy (get_automation_state());
1570 node->add_child_nocopy (*autonode);
1572 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1574 /* never store anything except Off for automation state in a template */
1575 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1582 IO::set_state (const XMLNode& node)
1584 const XMLProperty* prop;
1585 XMLNodeConstIterator iter;
1586 LocaleGuard lg (X_("POSIX"));
1588 /* force use of non-localized representation of decimal point,
1589 since we use it a lot in XML files and so forth.
1592 if (node.name() != state_node_name) {
1593 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1597 if ((prop = node.property ("name")) != 0) {
1598 _name = prop->value();
1599 /* used to set panner name with this, but no more */
1602 if ((prop = node.property ("id")) != 0) {
1603 _id = prop->value ();
1606 if ((prop = node.property ("iolimits")) != 0) {
1607 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1614 if ((prop = node.property ("gain")) != 0) {
1615 set_gain (atof (prop->value().c_str()), this);
1616 _gain = _desired_gain;
1619 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1620 /* old school automation handling */
1623 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1625 if ((*iter)->name() == "Panner") {
1627 _panner = new Panner (_name, _session);
1629 _panner->set_state (**iter);
1632 if ((*iter)->name() == X_("Automation")) {
1634 set_automation_state (*(*iter)->children().front());
1637 if ((*iter)->name() == X_("gaincontrol")) {
1638 _gain_control.set_state (**iter);
1644 if (create_ports (node)) {
1650 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1653 if (panners_legal) {
1656 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1659 if (connecting_legal) {
1661 if (make_connections (node)) {
1667 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1670 if (!ports_legal || !connecting_legal) {
1671 pending_state_node = new XMLNode (node);
1674 last_automation_snapshot = 0;
1680 IO::set_automation_state (const XMLNode& node)
1682 return _gain_automation_curve.set_state (node);
1686 IO::get_automation_state ()
1688 return (_gain_automation_curve.get_state ());
1692 IO::load_automation (string path)
1697 uint32_t linecnt = 0;
1699 LocaleGuard lg (X_("POSIX"));
1701 fullpath = _session.automation_dir();
1704 in.open (fullpath.c_str());
1707 fullpath = _session.automation_dir();
1708 fullpath += _session.snap_name();
1712 in.open (fullpath.c_str());
1715 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1720 clear_automation ();
1722 while (in.getline (line, sizeof(line), '\n')) {
1724 jack_nframes_t when;
1727 if (++linecnt == 1) {
1728 if (memcmp (line, "version", 7) == 0) {
1729 if (sscanf (line, "version %f", &version) != 1) {
1730 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1734 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1741 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1742 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1748 _gain_automation_curve.fast_simple_add (when, value);
1758 /* older (pre-1.0) versions of ardour used this */
1762 warning << _("dubious automation event found (and ignored)") << endmsg;
1770 IO::connecting_became_legal ()
1774 if (pending_state_node == 0) {
1775 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1780 connection_legal_c.disconnect ();
1782 ret = make_connections (*pending_state_node);
1785 delete pending_state_node;
1786 pending_state_node = 0;
1792 IO::ports_became_legal ()
1796 if (pending_state_node == 0) {
1797 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1802 port_legal_c.disconnect ();
1804 ret = create_ports (*pending_state_node);
1806 if (connecting_legal) {
1807 delete pending_state_node;
1808 pending_state_node = 0;
1815 IO::create_ports (const XMLNode& node)
1817 const XMLProperty* prop;
1819 int num_outputs = 0;
1821 if ((prop = node.property ("input-connection")) != 0) {
1823 Connection* c = _session.connection_by_name (prop->value());
1826 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1828 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1829 error << _("No input connections available as a replacement")
1833 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1838 num_inputs = c->nports();
1840 } else if ((prop = node.property ("inputs")) != 0) {
1842 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1845 if ((prop = node.property ("output-connection")) != 0) {
1846 Connection* c = _session.connection_by_name (prop->value());
1849 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1851 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1852 error << _("No output connections available as a replacement")
1856 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1861 num_outputs = c->nports ();
1863 } else if ((prop = node.property ("outputs")) != 0) {
1864 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1867 no_panner_reset = true;
1869 if (ensure_io (num_inputs, num_outputs, true, this)) {
1870 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1874 no_panner_reset = false;
1876 set_deferred_state ();
1884 IO::make_connections (const XMLNode& node)
1886 const XMLProperty* prop;
1888 if ((prop = node.property ("input-connection")) != 0) {
1889 Connection* c = _session.connection_by_name (prop->value());
1892 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1894 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1895 error << _("No input connections available as a replacement")
1899 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1904 use_input_connection (*c, this);
1906 } else if ((prop = node.property ("inputs")) != 0) {
1907 if (set_inputs (prop->value())) {
1908 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1913 if ((prop = node.property ("output-connection")) != 0) {
1914 Connection* c = _session.connection_by_name (prop->value());
1917 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1919 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1920 error << _("No output connections available as a replacement")
1924 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1929 use_output_connection (*c, this);
1931 } else if ((prop = node.property ("outputs")) != 0) {
1932 if (set_outputs (prop->value())) {
1933 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1942 IO::set_inputs (const string& str)
1944 vector<string> ports;
1949 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1953 if (ensure_inputs (nports, true, true, this)) {
1957 string::size_type start, end, ostart;
1964 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1967 if ((end = str.find_first_of ('}', start)) == string::npos) {
1968 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1972 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1973 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1979 for (int x = 0; x < n; ++x) {
1980 connect_input (input (i), ports[x], this);
1992 IO::set_outputs (const string& str)
1994 vector<string> ports;
1999 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2003 if (ensure_outputs (nports, true, true, this)) {
2007 string::size_type start, end, ostart;
2014 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2017 if ((end = str.find_first_of ('}', start)) == string::npos) {
2018 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2022 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2023 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2029 for (int x = 0; x < n; ++x) {
2030 connect_output (output (i), ports[x], this);
2042 IO::parse_io_string (const string& str, vector<string>& ports)
2044 string::size_type pos, opos;
2046 if (str.length() == 0) {
2055 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2056 ports.push_back (str.substr (opos, pos - opos));
2060 if (opos < str.length()) {
2061 ports.push_back (str.substr(opos));
2064 return ports.size();
2068 IO::parse_gain_string (const string& str, vector<string>& ports)
2070 string::size_type pos, opos;
2076 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2077 ports.push_back (str.substr (opos, pos - opos));
2081 if (opos < str.length()) {
2082 ports.push_back (str.substr(opos));
2085 return ports.size();
2089 IO::set_name (string name, void* src)
2091 if (name == _name) {
2095 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2096 string current_name = (*i)->short_name();
2097 current_name.replace (current_name.find (_name), _name.length(), name);
2098 (*i)->set_name (current_name);
2101 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2102 string current_name = (*i)->short_name();
2103 current_name.replace (current_name.find (_name), _name.length(), name);
2104 (*i)->set_name (current_name);
2108 name_changed (src); /* EMIT SIGNAL */
2114 IO::set_input_minimum (int n)
2120 IO::set_input_maximum (int n)
2126 IO::set_output_minimum (int n)
2128 _output_minimum = n;
2132 IO::set_output_maximum (int n)
2134 _output_maximum = n;
2138 IO::set_port_latency (nframes_t nframes)
2140 Glib::Mutex::Lock lm (io_lock);
2142 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2143 (*i)->set_latency (nframes);
2148 IO::output_latency () const
2150 nframes_t max_latency;
2155 /* io lock not taken - must be protected by other means */
2157 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2158 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2159 max_latency = latency;
2167 IO::input_latency () const
2169 nframes_t max_latency;
2174 /* io lock not taken - must be protected by other means */
2176 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2177 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2178 max_latency = latency;
2186 IO::use_input_connection (Connection& c, void* src)
2191 BLOCK_PROCESS_CALLBACK ();
2192 Glib::Mutex::Lock lm2 (io_lock);
2196 drop_input_connection ();
2198 if (ensure_inputs (limit, false, false, src)) {
2202 /* first pass: check the current state to see what's correctly
2203 connected, and drop anything that we don't want.
2206 for (uint32_t n = 0; n < limit; ++n) {
2207 const Connection::PortList& pl = c.port_connections (n);
2209 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2211 if (!_inputs[n]->connected_to ((*i))) {
2213 /* clear any existing connections */
2215 _session.engine().disconnect (_inputs[n]);
2217 } else if (_inputs[n]->connected() > 1) {
2219 /* OK, it is connected to the port we want,
2220 but its also connected to other ports.
2221 Change that situation.
2224 /* XXX could be optimized to not drop
2228 _session.engine().disconnect (_inputs[n]);
2234 /* second pass: connect all requested ports where necessary */
2236 for (uint32_t n = 0; n < limit; ++n) {
2237 const Connection::PortList& pl = c.port_connections (n);
2239 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2241 if (!_inputs[n]->connected_to ((*i))) {
2243 if (_session.engine().connect (*i, _inputs[n]->name())) {
2251 _input_connection = &c;
2253 input_connection_configuration_connection = c.ConfigurationChanged.connect
2254 (mem_fun (*this, &IO::input_connection_configuration_changed));
2255 input_connection_connection_connection = c.ConnectionsChanged.connect
2256 (mem_fun (*this, &IO::input_connection_connection_changed));
2259 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2264 IO::use_output_connection (Connection& c, void* src)
2269 BLOCK_PROCESS_CALLBACK ();
2270 Glib::Mutex::Lock lm2 (io_lock);
2274 drop_output_connection ();
2276 if (ensure_outputs (limit, false, false, src)) {
2280 /* first pass: check the current state to see what's correctly
2281 connected, and drop anything that we don't want.
2284 for (uint32_t n = 0; n < limit; ++n) {
2286 const Connection::PortList& pl = c.port_connections (n);
2288 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2290 if (!_outputs[n]->connected_to ((*i))) {
2292 /* clear any existing connections */
2294 _session.engine().disconnect (_outputs[n]);
2296 } else if (_outputs[n]->connected() > 1) {
2298 /* OK, it is connected to the port we want,
2299 but its also connected to other ports.
2300 Change that situation.
2303 /* XXX could be optimized to not drop
2307 _session.engine().disconnect (_outputs[n]);
2312 /* second pass: connect all requested ports where necessary */
2314 for (uint32_t n = 0; n < limit; ++n) {
2316 const Connection::PortList& pl = c.port_connections (n);
2318 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2320 if (!_outputs[n]->connected_to ((*i))) {
2322 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2329 _output_connection = &c;
2331 output_connection_configuration_connection = c.ConfigurationChanged.connect
2332 (mem_fun (*this, &IO::output_connection_configuration_changed));
2333 output_connection_connection_connection = c.ConnectionsChanged.connect
2334 (mem_fun (*this, &IO::output_connection_connection_changed));
2337 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2343 IO::disable_connecting ()
2345 connecting_legal = false;
2350 IO::enable_connecting ()
2352 connecting_legal = true;
2353 return ConnectingLegal ();
2357 IO::disable_ports ()
2359 ports_legal = false;
2367 return PortsLegal ();
2371 IO::disable_panners (void)
2373 panners_legal = false;
2378 IO::reset_panners ()
2380 panners_legal = true;
2381 return PannersLegal ();
2385 IO::input_connection_connection_changed (int ignored)
2387 use_input_connection (*_input_connection, this);
2391 IO::input_connection_configuration_changed ()
2393 use_input_connection (*_input_connection, this);
2397 IO::output_connection_connection_changed (int ignored)
2399 use_output_connection (*_output_connection, this);
2403 IO::output_connection_configuration_changed ()
2405 use_output_connection (*_output_connection, this);
2409 IO::GainControllable::set_value (float val)
2411 io.set_gain (direct_control_to_gain (val), this);
2415 IO::GainControllable::get_value (void) const
2417 return direct_gain_to_control (io.effective_gain());
2421 IO::reset_peak_meters ()
2423 uint32_t limit = max (_ninputs, _noutputs);
2425 for (uint32_t i = 0; i < limit; ++i) {
2431 IO::reset_max_peak_meters ()
2433 uint32_t limit = max (_ninputs, _noutputs);
2435 for (uint32_t i = 0; i < limit; ++i) {
2436 _max_peak_power[i] = -INFINITY;
2441 IO::setup_peak_meters ()
2443 uint32_t limit = max (_ninputs, _noutputs);
2445 while (_peak_power.size() < limit) {
2446 _peak_power.push_back (0);
2447 _visible_peak_power.push_back (-INFINITY);
2448 _max_peak_power.push_back (-INFINITY);
2453 Update the peak meters.
2455 The meter signal lock is taken to prevent modification of the
2456 Meter signal while updating the meters, taking the meter signal
2457 lock prior to taking the io_lock ensures that all IO will remain
2458 valid while metering.
2463 Glib::Mutex::Lock guard (m_meter_signal_lock);
2471 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2472 uint32_t limit = max (_ninputs, _noutputs);
2474 for (uint32_t n = 0; n < limit; ++n) {
2476 /* XXX we should use atomic exchange here */
2478 /* grab peak since last read */
2480 float new_peak = _peak_power[n];
2483 /* compute new visible value using falloff */
2485 if (new_peak > 0.0f) {
2486 new_peak = coefficient_to_dB (new_peak);
2488 new_peak = -INFINITY;
2491 /* update max peak */
2493 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2496 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2497 _visible_peak_power[n] = new_peak;
2499 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2500 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2501 _visible_peak_power[n] = max (new_peak, -INFINITY);
2507 IO::clear_automation ()
2509 Glib::Mutex::Lock lm (automation_lock);
2510 _gain_automation_curve.clear ();
2511 _panner->clear_automation ();
2515 IO::set_gain_automation_state (AutoState state)
2517 bool changed = false;
2520 Glib::Mutex::Lock lm (automation_lock);
2522 if (state != _gain_automation_curve.automation_state()) {
2524 last_automation_snapshot = 0;
2525 _gain_automation_curve.set_automation_state (state);
2528 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2534 _session.set_dirty ();
2535 gain_automation_state_changed (); /* EMIT SIGNAL */
2540 IO::set_gain_automation_style (AutoStyle style)
2542 bool changed = false;
2545 Glib::Mutex::Lock lm (automation_lock);
2547 if (style != _gain_automation_curve.automation_style()) {
2549 _gain_automation_curve.set_automation_style (style);
2554 gain_automation_style_changed (); /* EMIT SIGNAL */
2558 IO::inc_gain (gain_t factor, void *src)
2560 if (_desired_gain == 0.0f)
2561 set_gain (0.000001f + (0.000001f * factor), src);
2563 set_gain (_desired_gain + (_desired_gain * factor), src);
2567 IO::set_gain (gain_t val, void *src)
2569 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2570 if (val>1.99526231f) val=1.99526231f;
2573 Glib::Mutex::Lock dm (declick_lock);
2574 _desired_gain = val;
2577 if (_session.transport_stopped()) {
2578 _effective_gain = val;
2583 _gain_control.Changed (); /* EMIT SIGNAL */
2585 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2586 _gain_automation_curve.add (_session.transport_frame(), val);
2590 _session.set_dirty();
2594 IO::start_gain_touch ()
2596 _gain_automation_curve.start_touch ();
2600 IO::end_gain_touch ()
2602 _gain_automation_curve.stop_touch ();
2606 IO::start_pan_touch (uint32_t which)
2608 if (which < _panner->size()) {
2609 (*_panner)[which]->automation().start_touch();
2614 IO::end_pan_touch (uint32_t which)
2616 if (which < _panner->size()) {
2617 (*_panner)[which]->automation().stop_touch();
2623 IO::automation_snapshot (nframes_t now)
2625 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2627 if (gain_automation_recording()) {
2628 _gain_automation_curve.rt_add (now, gain());
2631 _panner->snapshot (now);
2633 last_automation_snapshot = now;
2638 IO::transport_stopped (nframes_t frame)
2640 _gain_automation_curve.reposition_for_rt_add (frame);
2642 if (_gain_automation_curve.automation_state() != Off) {
2644 /* the src=0 condition is a special signal to not propagate
2645 automation gain changes into the mix group when locating.
2648 set_gain (_gain_automation_curve.eval (frame), 0);
2651 _panner->transport_stopped (frame);
2655 IO::find_input_port_hole ()
2657 /* CALLER MUST HOLD IO LOCK */
2661 if (_inputs.empty()) {
2665 for (n = 1; n < UINT_MAX; ++n) {
2666 char buf[jack_port_name_size()];
2667 vector<Port*>::iterator i;
2669 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2671 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2672 if ((*i)->short_name() == buf) {
2677 if (i == _inputs.end()) {
2685 IO::find_output_port_hole ()
2687 /* CALLER MUST HOLD IO LOCK */
2691 if (_outputs.empty()) {
2695 for (n = 1; n < UINT_MAX; ++n) {
2696 char buf[jack_port_name_size()];
2697 vector<Port*>::iterator i;
2699 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2701 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2702 if ((*i)->short_name() == buf) {
2707 if (i == _outputs.end()) {