2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
31 #include <pbd/replace_all.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 */
575 // the dest buffer's offset has already been applied
576 memcpy (bufs[n], last, sizeof (Sample) * nframes);
581 memset (bufs[n], 0, sizeof (Sample) * nframes);
588 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
589 nframes_t nframes, nframes_t offset)
591 vector<Sample*>& bufs = _session.get_passthru_buffers ();
592 uint32_t nbufs = n_process_buffers ();
594 collect_input (bufs, nbufs, nframes, offset);
596 for (uint32_t n = 0; n < nbufs; ++n) {
597 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
602 IO::drop_input_connection ()
604 _input_connection = 0;
605 input_connection_configuration_connection.disconnect();
606 input_connection_connection_connection.disconnect();
607 _session.set_dirty ();
611 IO::drop_output_connection ()
613 _output_connection = 0;
614 output_connection_configuration_connection.disconnect();
615 output_connection_connection_connection.disconnect();
616 _session.set_dirty ();
620 IO::disconnect_input (Port* our_port, string other_port, void* src)
622 if (other_port.length() == 0 || our_port == 0) {
627 BLOCK_PROCESS_CALLBACK ();
630 Glib::Mutex::Lock lm (io_lock);
632 /* check that our_port is really one of ours */
634 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
638 /* disconnect it from the source */
640 if (_session.engine().disconnect (other_port, our_port->name())) {
641 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
645 drop_input_connection();
649 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
650 _session.set_dirty ();
656 IO::connect_input (Port* our_port, string other_port, void* src)
658 if (other_port.length() == 0 || our_port == 0) {
663 BLOCK_PROCESS_CALLBACK ();
666 Glib::Mutex::Lock lm (io_lock);
668 /* check that our_port is really one of ours */
670 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
674 /* connect it to the source */
676 if (_session.engine().connect (other_port, our_port->name())) {
680 drop_input_connection ();
684 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
685 _session.set_dirty ();
690 IO::disconnect_output (Port* our_port, string other_port, void* src)
692 if (other_port.length() == 0 || our_port == 0) {
697 BLOCK_PROCESS_CALLBACK ();
700 Glib::Mutex::Lock lm (io_lock);
702 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
706 /* disconnect it from the destination */
708 if (_session.engine().disconnect (our_port->name(), other_port)) {
709 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
713 drop_output_connection ();
717 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
718 _session.set_dirty ();
723 IO::connect_output (Port* our_port, string other_port, void* src)
725 if (other_port.length() == 0 || our_port == 0) {
730 BLOCK_PROCESS_CALLBACK ();
734 Glib::Mutex::Lock lm (io_lock);
736 /* check that our_port is really one of ours */
738 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
742 /* connect it to the destination */
744 if (_session.engine().connect (our_port->name(), other_port)) {
748 drop_output_connection ();
752 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
753 _session.set_dirty ();
758 IO::set_input (Port* other_port, void* src)
760 /* this removes all but one ports, and connects that one port
761 to the specified source.
764 if (_input_minimum > 1 || _input_minimum == 0) {
765 /* sorry, you can't do this */
769 if (other_port == 0) {
770 if (_input_minimum < 0) {
771 return ensure_inputs (0, false, true, src);
777 if (ensure_inputs (1, true, true, src)) {
781 return connect_input (_inputs.front(), other_port->name(), src);
785 IO::remove_output_port (Port* port, void* src)
787 IOChange change (NoChange);
790 BLOCK_PROCESS_CALLBACK ();
794 Glib::Mutex::Lock lm (io_lock);
796 if (_noutputs - 1 == (uint32_t) _output_minimum) {
797 /* sorry, you can't do this */
801 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
803 change = IOChange (change|ConfigurationChanged);
804 if (port->connected()) {
805 change = IOChange (change|ConnectionsChanged);
808 _session.engine().unregister_port (*i);
811 drop_output_connection ();
817 if (change != NoChange) {
818 setup_peak_meters ();
824 if (change != NoChange) {
825 output_changed (change, src); /* EMIT SIGNAL */
826 _session.set_dirty ();
833 /** Add an output port.
835 * @param destination Name of input port to connect new port to.
836 * @param src Source for emitted ConfigurationChanged signal.
837 * @param type Data type of port. Default value (NIL) will use this IO's default type.
840 IO::add_output_port (string destination, void* src, DataType type)
845 if (type == DataType::NIL)
846 type = _default_type;
849 BLOCK_PROCESS_CALLBACK ();
853 Glib::Mutex::Lock lm (io_lock);
855 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
859 /* Create a new output port */
861 // FIXME: naming scheme for differently typed ports?
862 if (_output_maximum == 1) {
863 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
865 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
868 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
869 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
873 _outputs.push_back (our_port);
874 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
876 drop_output_connection ();
877 setup_peak_meters ();
881 MoreOutputs (_noutputs); /* EMIT SIGNAL */
884 if (destination.length()) {
885 if (_session.engine().connect (our_port->name(), destination)) {
890 // pan_changed (src); /* EMIT SIGNAL */
891 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
892 _session.set_dirty ();
897 IO::remove_input_port (Port* port, void* src)
899 IOChange change (NoChange);
902 BLOCK_PROCESS_CALLBACK ();
906 Glib::Mutex::Lock lm (io_lock);
908 if (((int)_ninputs - 1) < _input_minimum) {
909 /* sorry, you can't do this */
912 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
915 change = IOChange (change|ConfigurationChanged);
917 if (port->connected()) {
918 change = IOChange (change|ConnectionsChanged);
921 _session.engine().unregister_port (*i);
924 drop_input_connection ();
930 if (change != NoChange) {
931 setup_peak_meters ();
937 if (change != NoChange) {
938 input_changed (change, src);
939 _session.set_dirty ();
947 /** Add an input port.
949 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
950 * @param destination Name of input port to connect new port to.
951 * @param src Source for emitted ConfigurationChanged signal.
954 IO::add_input_port (string source, void* src, DataType type)
959 if (type == DataType::NIL)
960 type = _default_type;
963 BLOCK_PROCESS_CALLBACK ();
966 Glib::Mutex::Lock lm (io_lock);
968 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
972 /* Create a new input port */
974 // FIXME: naming scheme for differently typed ports?
975 if (_input_maximum == 1) {
976 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
978 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
981 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
982 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
986 _inputs.push_back (our_port);
987 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
989 drop_input_connection ();
990 setup_peak_meters ();
994 MoreOutputs (_ninputs); /* EMIT SIGNAL */
997 if (source.length()) {
999 if (_session.engine().connect (source, our_port->name())) {
1004 // pan_changed (src); /* EMIT SIGNAL */
1005 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1006 _session.set_dirty ();
1012 IO::disconnect_inputs (void* src)
1015 BLOCK_PROCESS_CALLBACK ();
1018 Glib::Mutex::Lock lm (io_lock);
1020 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1021 _session.engine().disconnect (*i);
1024 drop_input_connection ();
1027 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1032 IO::disconnect_outputs (void* src)
1035 BLOCK_PROCESS_CALLBACK ();
1038 Glib::Mutex::Lock lm (io_lock);
1040 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1041 _session.engine().disconnect (*i);
1044 drop_output_connection ();
1048 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1049 _session.set_dirty ();
1054 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1057 bool changed = false;
1058 bool reduced = false;
1060 /* remove unused ports */
1062 while (_ninputs > n) {
1063 _session.engine().unregister_port (_inputs.back());
1070 /* create any necessary new ports */
1072 while (_ninputs < n) {
1076 /* Create a new input port (of the default type) */
1078 if (_input_maximum == 1) {
1079 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1082 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1087 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1088 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1093 catch (AudioEngine::PortRegistrationFailure& err) {
1094 setup_peak_meters ();
1097 throw AudioEngine::PortRegistrationFailure();
1100 _inputs.push_back (input_port);
1101 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1107 drop_input_connection ();
1108 setup_peak_meters ();
1110 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1111 _session.set_dirty ();
1115 /* disconnect all existing ports so that we get a fresh start */
1117 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1118 _session.engine().disconnect (*i);
1126 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1128 bool in_changed = false;
1129 bool out_changed = false;
1130 bool in_reduced = false;
1131 bool out_reduced = false;
1132 bool need_pan_reset;
1134 if (_input_maximum >= 0) {
1135 nin = min (_input_maximum, (int) nin);
1138 if (_output_maximum >= 0) {
1139 nout = min (_output_maximum, (int) nout);
1142 if (nin == _ninputs && nout == _noutputs && !clear) {
1147 BLOCK_PROCESS_CALLBACK ();
1148 Glib::Mutex::Lock lm (io_lock);
1152 if (_noutputs == nout) {
1153 need_pan_reset = false;
1155 need_pan_reset = true;
1158 /* remove unused ports */
1160 while (_ninputs > nin) {
1161 _session.engine().unregister_port (_inputs.back());
1168 while (_noutputs > nout) {
1169 _session.engine().unregister_port (_outputs.back());
1170 _outputs.pop_back();
1176 /* create any necessary new ports (of the default type) */
1178 while (_ninputs < nin) {
1182 /* Create a new input port */
1184 if (_input_maximum == 1) {
1185 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1188 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1192 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1193 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1198 catch (AudioEngine::PortRegistrationFailure& err) {
1199 setup_peak_meters ();
1202 throw AudioEngine::PortRegistrationFailure();
1205 _inputs.push_back (port);
1210 /* create any necessary new ports */
1212 while (_noutputs < nout) {
1216 /* Create a new output port */
1218 if (_output_maximum == 1) {
1219 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1221 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1225 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1226 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1231 catch (AudioEngine::PortRegistrationFailure& err) {
1232 setup_peak_meters ();
1235 throw AudioEngine::PortRegistrationFailure ();
1238 _outputs.push_back (port);
1245 /* disconnect all existing ports so that we get a fresh start */
1247 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1248 _session.engine().disconnect (*i);
1251 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1252 _session.engine().disconnect (*i);
1256 if (in_changed || out_changed) {
1257 setup_peak_meters ();
1263 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1264 drop_output_connection ();
1265 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1269 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1270 drop_input_connection ();
1271 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1274 if (in_changed || out_changed) {
1275 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1276 _session.set_dirty ();
1283 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1285 bool changed = false;
1287 if (_input_maximum >= 0) {
1288 n = min (_input_maximum, (int) n);
1290 if (n == _ninputs && !clear) {
1296 BLOCK_PROCESS_CALLBACK ();
1297 Glib::Mutex::Lock im (io_lock);
1298 changed = ensure_inputs_locked (n, clear, src);
1300 changed = ensure_inputs_locked (n, clear, src);
1304 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1305 _session.set_dirty ();
1312 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1315 bool changed = false;
1316 bool reduced = false;
1317 bool need_pan_reset;
1319 if (_noutputs == n) {
1320 need_pan_reset = false;
1322 need_pan_reset = true;
1325 /* remove unused ports */
1327 while (_noutputs > n) {
1329 _session.engine().unregister_port (_outputs.back());
1330 _outputs.pop_back();
1336 /* create any necessary new ports */
1338 while (_noutputs < n) {
1342 /* Create a new output port */
1344 if (_output_maximum == 1) {
1345 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1347 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1350 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1351 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1355 _outputs.push_back (output_port);
1356 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1359 setup_peak_meters ();
1361 if (need_pan_reset) {
1367 drop_output_connection ();
1368 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1369 _session.set_dirty ();
1373 /* disconnect all existing ports so that we get a fresh start */
1375 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1376 _session.engine().disconnect (*i);
1384 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1386 bool changed = false;
1388 if (_output_maximum >= 0) {
1389 n = min (_output_maximum, (int) n);
1390 if (n == _noutputs && !clear) {
1395 /* XXX caller should hold io_lock, but generally doesn't */
1398 BLOCK_PROCESS_CALLBACK ();
1399 Glib::Mutex::Lock im (io_lock);
1400 changed = ensure_outputs_locked (n, clear, src);
1402 changed = ensure_outputs_locked (n, clear, src);
1406 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1413 IO::effective_gain () const
1415 if (gain_automation_playback()) {
1416 return _effective_gain;
1418 return _desired_gain;
1425 if (panners_legal) {
1426 if (!no_panner_reset) {
1427 _panner->reset (_noutputs, pans_required());
1430 panner_legal_c.disconnect ();
1431 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1436 IO::panners_became_legal ()
1438 _panner->reset (_noutputs, pans_required());
1439 _panner->load (); // automation
1440 panner_legal_c.disconnect ();
1445 IO::defer_pan_reset ()
1447 no_panner_reset = true;
1451 IO::allow_pan_reset ()
1453 no_panner_reset = false;
1459 IO::get_state (void)
1461 return state (true);
1465 IO::state (bool full_state)
1467 XMLNode* node = new XMLNode (state_node_name);
1470 bool need_ins = true;
1471 bool need_outs = true;
1472 LocaleGuard lg (X_("POSIX"));
1473 Glib::Mutex::Lock lm (io_lock);
1475 node->add_property("name", _name);
1476 id().print (buf, sizeof (buf));
1477 node->add_property("id", buf);
1481 if (_input_connection) {
1482 node->add_property ("input-connection", _input_connection->name());
1486 if (_output_connection) {
1487 node->add_property ("output-connection", _output_connection->name());
1492 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1494 const char **connections = (*i)->get_connections();
1496 if (connections && connections[0]) {
1499 for (int n = 0; connections && connections[n]; ++n) {
1504 /* if its a connection to our own port,
1505 return only the port name, not the
1506 whole thing. this allows connections
1507 to be re-established even when our
1508 client name is different.
1511 str += _session.engine().make_port_name_relative (connections[n]);
1523 node->add_property ("inputs", str);
1529 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1531 const char **connections = (*i)->get_connections();
1533 if (connections && connections[0]) {
1537 for (int n = 0; connections[n]; ++n) {
1542 str += _session.engine().make_port_name_relative (connections[n]);
1554 node->add_property ("outputs", str);
1557 node->add_child_nocopy (_panner->state (full_state));
1558 node->add_child_nocopy (_gain_control.get_state ());
1560 snprintf (buf, sizeof(buf), "%2.12f", gain());
1561 node->add_property ("gain", buf);
1563 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1569 node->add_property ("iolimits", buf);
1575 XMLNode* autonode = new XMLNode (X_("Automation"));
1576 autonode->add_child_nocopy (get_automation_state());
1577 node->add_child_nocopy (*autonode);
1579 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1581 /* never store anything except Off for automation state in a template */
1582 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1589 IO::set_state (const XMLNode& node)
1591 const XMLProperty* prop;
1592 XMLNodeConstIterator iter;
1593 LocaleGuard lg (X_("POSIX"));
1595 /* force use of non-localized representation of decimal point,
1596 since we use it a lot in XML files and so forth.
1599 if (node.name() != state_node_name) {
1600 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1604 if ((prop = node.property ("name")) != 0) {
1605 _name = prop->value();
1606 /* used to set panner name with this, but no more */
1609 if ((prop = node.property ("id")) != 0) {
1610 _id = prop->value ();
1613 if ((prop = node.property ("iolimits")) != 0) {
1614 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1621 if ((prop = node.property ("gain")) != 0) {
1622 set_gain (atof (prop->value().c_str()), this);
1623 _gain = _desired_gain;
1626 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1627 /* old school automation handling */
1630 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1632 if ((*iter)->name() == "Panner") {
1634 _panner = new Panner (_name, _session);
1636 _panner->set_state (**iter);
1639 if ((*iter)->name() == X_("Automation")) {
1641 set_automation_state (*(*iter)->children().front());
1644 if ((*iter)->name() == X_("controllable")) {
1645 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1646 _gain_control.set_state (**iter);
1653 if (create_ports (node)) {
1659 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1662 if (panners_legal) {
1665 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1668 if (connecting_legal) {
1670 if (make_connections (node)) {
1676 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1679 if (!ports_legal || !connecting_legal) {
1680 pending_state_node = new XMLNode (node);
1683 last_automation_snapshot = 0;
1689 IO::set_automation_state (const XMLNode& node)
1691 return _gain_automation_curve.set_state (node);
1695 IO::get_automation_state ()
1697 return (_gain_automation_curve.get_state ());
1701 IO::load_automation (string path)
1706 uint32_t linecnt = 0;
1708 LocaleGuard lg (X_("POSIX"));
1710 fullpath = _session.automation_dir();
1713 in.open (fullpath.c_str());
1716 fullpath = _session.automation_dir();
1717 fullpath += _session.snap_name();
1721 in.open (fullpath.c_str());
1724 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1729 clear_automation ();
1731 while (in.getline (line, sizeof(line), '\n')) {
1733 jack_nframes_t when;
1736 if (++linecnt == 1) {
1737 if (memcmp (line, "version", 7) == 0) {
1738 if (sscanf (line, "version %f", &version) != 1) {
1739 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1743 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1750 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1751 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1757 _gain_automation_curve.fast_simple_add (when, value);
1767 /* older (pre-1.0) versions of ardour used this */
1771 warning << _("dubious automation event found (and ignored)") << endmsg;
1779 IO::connecting_became_legal ()
1783 if (pending_state_node == 0) {
1784 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1789 connection_legal_c.disconnect ();
1791 ret = make_connections (*pending_state_node);
1794 delete pending_state_node;
1795 pending_state_node = 0;
1801 IO::ports_became_legal ()
1805 if (pending_state_node == 0) {
1806 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1811 port_legal_c.disconnect ();
1813 ret = create_ports (*pending_state_node);
1815 if (connecting_legal) {
1816 delete pending_state_node;
1817 pending_state_node = 0;
1824 IO::create_ports (const XMLNode& node)
1826 const XMLProperty* prop;
1828 int num_outputs = 0;
1830 if ((prop = node.property ("input-connection")) != 0) {
1832 Connection* c = _session.connection_by_name (prop->value());
1835 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1837 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1838 error << _("No input connections available as a replacement")
1842 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1847 num_inputs = c->nports();
1849 } else if ((prop = node.property ("inputs")) != 0) {
1851 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1854 if ((prop = node.property ("output-connection")) != 0) {
1855 Connection* c = _session.connection_by_name (prop->value());
1858 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1860 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1861 error << _("No output connections available as a replacement")
1865 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1870 num_outputs = c->nports ();
1872 } else if ((prop = node.property ("outputs")) != 0) {
1873 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1876 no_panner_reset = true;
1878 if (ensure_io (num_inputs, num_outputs, true, this)) {
1879 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1883 no_panner_reset = false;
1885 set_deferred_state ();
1893 IO::make_connections (const XMLNode& node)
1895 const XMLProperty* prop;
1897 if ((prop = node.property ("input-connection")) != 0) {
1898 Connection* c = _session.connection_by_name (prop->value());
1901 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1903 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1904 error << _("No input connections available as a replacement")
1908 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1913 use_input_connection (*c, this);
1915 } else if ((prop = node.property ("inputs")) != 0) {
1916 if (set_inputs (prop->value())) {
1917 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1922 if ((prop = node.property ("output-connection")) != 0) {
1923 Connection* c = _session.connection_by_name (prop->value());
1926 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1928 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1929 error << _("No output connections available as a replacement")
1933 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1938 use_output_connection (*c, this);
1940 } else if ((prop = node.property ("outputs")) != 0) {
1941 if (set_outputs (prop->value())) {
1942 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1951 IO::set_inputs (const string& str)
1953 vector<string> ports;
1958 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1962 if (ensure_inputs (nports, true, true, this)) {
1966 string::size_type start, end, ostart;
1973 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1976 if ((end = str.find_first_of ('}', start)) == string::npos) {
1977 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1981 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1982 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1988 for (int x = 0; x < n; ++x) {
1989 connect_input (input (i), ports[x], this);
2001 IO::set_outputs (const string& str)
2003 vector<string> ports;
2008 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2012 if (ensure_outputs (nports, true, true, this)) {
2016 string::size_type start, end, ostart;
2023 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2026 if ((end = str.find_first_of ('}', start)) == string::npos) {
2027 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2031 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2032 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2038 for (int x = 0; x < n; ++x) {
2039 connect_output (output (i), ports[x], this);
2051 IO::parse_io_string (const string& str, vector<string>& ports)
2053 string::size_type pos, opos;
2055 if (str.length() == 0) {
2064 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2065 ports.push_back (str.substr (opos, pos - opos));
2069 if (opos < str.length()) {
2070 ports.push_back (str.substr(opos));
2073 return ports.size();
2077 IO::parse_gain_string (const string& str, vector<string>& ports)
2079 string::size_type pos, opos;
2085 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2086 ports.push_back (str.substr (opos, pos - opos));
2090 if (opos < str.length()) {
2091 ports.push_back (str.substr(opos));
2094 return ports.size();
2098 IO::set_name (string name, void* src)
2100 if (name == _name) {
2104 /* replace all colons in the name. i wish we didn't have to do this */
2106 if (replace_all (name, ":", "-")) {
2107 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
2110 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2111 string current_name = (*i)->short_name();
2112 current_name.replace (current_name.find (_name), _name.length(), name);
2113 (*i)->set_name (current_name);
2116 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2117 string current_name = (*i)->short_name();
2118 current_name.replace (current_name.find (_name), _name.length(), name);
2119 (*i)->set_name (current_name);
2123 name_changed (src); /* EMIT SIGNAL */
2129 IO::set_input_minimum (int n)
2135 IO::set_input_maximum (int n)
2141 IO::set_output_minimum (int n)
2143 _output_minimum = n;
2147 IO::set_output_maximum (int n)
2149 _output_maximum = n;
2153 IO::set_port_latency (nframes_t nframes)
2155 Glib::Mutex::Lock lm (io_lock);
2157 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2158 (*i)->set_latency (nframes);
2163 IO::output_latency () const
2165 nframes_t max_latency;
2170 /* io lock not taken - must be protected by other means */
2172 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2173 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2174 max_latency = latency;
2182 IO::input_latency () const
2184 nframes_t max_latency;
2189 /* io lock not taken - must be protected by other means */
2191 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2192 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2193 max_latency = latency;
2201 IO::use_input_connection (Connection& c, void* src)
2206 BLOCK_PROCESS_CALLBACK ();
2207 Glib::Mutex::Lock lm2 (io_lock);
2211 drop_input_connection ();
2213 if (ensure_inputs (limit, false, false, src)) {
2217 /* first pass: check the current state to see what's correctly
2218 connected, and drop anything that we don't want.
2221 for (uint32_t n = 0; n < limit; ++n) {
2222 const Connection::PortList& pl = c.port_connections (n);
2224 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2226 if (!_inputs[n]->connected_to ((*i))) {
2228 /* clear any existing connections */
2230 _session.engine().disconnect (_inputs[n]);
2232 } else if (_inputs[n]->connected() > 1) {
2234 /* OK, it is connected to the port we want,
2235 but its also connected to other ports.
2236 Change that situation.
2239 /* XXX could be optimized to not drop
2243 _session.engine().disconnect (_inputs[n]);
2249 /* second pass: connect all requested ports where necessary */
2251 for (uint32_t n = 0; n < limit; ++n) {
2252 const Connection::PortList& pl = c.port_connections (n);
2254 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2256 if (!_inputs[n]->connected_to ((*i))) {
2258 if (_session.engine().connect (*i, _inputs[n]->name())) {
2266 _input_connection = &c;
2268 input_connection_configuration_connection = c.ConfigurationChanged.connect
2269 (mem_fun (*this, &IO::input_connection_configuration_changed));
2270 input_connection_connection_connection = c.ConnectionsChanged.connect
2271 (mem_fun (*this, &IO::input_connection_connection_changed));
2274 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2279 IO::use_output_connection (Connection& c, void* src)
2284 BLOCK_PROCESS_CALLBACK ();
2285 Glib::Mutex::Lock lm2 (io_lock);
2289 drop_output_connection ();
2291 if (ensure_outputs (limit, false, false, src)) {
2295 /* first pass: check the current state to see what's correctly
2296 connected, and drop anything that we don't want.
2299 for (uint32_t n = 0; n < limit; ++n) {
2301 const Connection::PortList& pl = c.port_connections (n);
2303 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2305 if (!_outputs[n]->connected_to ((*i))) {
2307 /* clear any existing connections */
2309 _session.engine().disconnect (_outputs[n]);
2311 } else if (_outputs[n]->connected() > 1) {
2313 /* OK, it is connected to the port we want,
2314 but its also connected to other ports.
2315 Change that situation.
2318 /* XXX could be optimized to not drop
2322 _session.engine().disconnect (_outputs[n]);
2327 /* second pass: connect all requested ports where necessary */
2329 for (uint32_t n = 0; n < limit; ++n) {
2331 const Connection::PortList& pl = c.port_connections (n);
2333 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2335 if (!_outputs[n]->connected_to ((*i))) {
2337 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2344 _output_connection = &c;
2346 output_connection_configuration_connection = c.ConfigurationChanged.connect
2347 (mem_fun (*this, &IO::output_connection_configuration_changed));
2348 output_connection_connection_connection = c.ConnectionsChanged.connect
2349 (mem_fun (*this, &IO::output_connection_connection_changed));
2352 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2358 IO::disable_connecting ()
2360 connecting_legal = false;
2365 IO::enable_connecting ()
2367 connecting_legal = true;
2368 return ConnectingLegal ();
2372 IO::disable_ports ()
2374 ports_legal = false;
2382 return PortsLegal ();
2386 IO::disable_panners (void)
2388 panners_legal = false;
2393 IO::reset_panners ()
2395 panners_legal = true;
2396 return PannersLegal ();
2400 IO::input_connection_connection_changed (int ignored)
2402 use_input_connection (*_input_connection, this);
2406 IO::input_connection_configuration_changed ()
2408 use_input_connection (*_input_connection, this);
2412 IO::output_connection_connection_changed (int ignored)
2414 use_output_connection (*_output_connection, this);
2418 IO::output_connection_configuration_changed ()
2420 use_output_connection (*_output_connection, this);
2424 IO::GainControllable::set_value (float val)
2426 io.set_gain (direct_control_to_gain (val), this);
2430 IO::GainControllable::get_value (void) const
2432 return direct_gain_to_control (io.effective_gain());
2436 IO::reset_peak_meters ()
2438 uint32_t limit = max (_ninputs, _noutputs);
2440 for (uint32_t i = 0; i < limit; ++i) {
2446 IO::reset_max_peak_meters ()
2448 uint32_t limit = max (_ninputs, _noutputs);
2450 for (uint32_t i = 0; i < limit; ++i) {
2451 _max_peak_power[i] = -INFINITY;
2456 IO::setup_peak_meters ()
2458 uint32_t limit = max (_ninputs, _noutputs);
2460 while (_peak_power.size() < limit) {
2461 _peak_power.push_back (0);
2462 _visible_peak_power.push_back (-INFINITY);
2463 _max_peak_power.push_back (-INFINITY);
2468 Update the peak meters.
2470 The meter signal lock is taken to prevent modification of the
2471 Meter signal while updating the meters, taking the meter signal
2472 lock prior to taking the io_lock ensures that all IO will remain
2473 valid while metering.
2478 Glib::Mutex::Lock guard (m_meter_signal_lock);
2486 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2487 uint32_t limit = max (_ninputs, _noutputs);
2489 for (uint32_t n = 0; n < limit; ++n) {
2491 /* XXX we should use atomic exchange here */
2493 /* grab peak since last read */
2495 float new_peak = _peak_power[n];
2498 /* compute new visible value using falloff */
2500 if (new_peak > 0.0f) {
2501 new_peak = coefficient_to_dB (new_peak);
2503 new_peak = -INFINITY;
2506 /* update max peak */
2508 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2511 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2512 _visible_peak_power[n] = new_peak;
2514 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2515 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2516 _visible_peak_power[n] = max (new_peak, -INFINITY);
2522 IO::clear_automation ()
2524 Glib::Mutex::Lock lm (automation_lock);
2525 _gain_automation_curve.clear ();
2526 _panner->clear_automation ();
2530 IO::set_gain_automation_state (AutoState state)
2532 bool changed = false;
2535 Glib::Mutex::Lock lm (automation_lock);
2537 if (state != _gain_automation_curve.automation_state()) {
2539 last_automation_snapshot = 0;
2540 _gain_automation_curve.set_automation_state (state);
2543 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2549 _session.set_dirty ();
2550 gain_automation_state_changed (); /* EMIT SIGNAL */
2555 IO::set_gain_automation_style (AutoStyle style)
2557 bool changed = false;
2560 Glib::Mutex::Lock lm (automation_lock);
2562 if (style != _gain_automation_curve.automation_style()) {
2564 _gain_automation_curve.set_automation_style (style);
2569 gain_automation_style_changed (); /* EMIT SIGNAL */
2573 IO::inc_gain (gain_t factor, void *src)
2575 if (_desired_gain == 0.0f)
2576 set_gain (0.000001f + (0.000001f * factor), src);
2578 set_gain (_desired_gain + (_desired_gain * factor), src);
2582 IO::set_gain (gain_t val, void *src)
2584 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2585 if (val>1.99526231f) val=1.99526231f;
2588 Glib::Mutex::Lock dm (declick_lock);
2589 _desired_gain = val;
2592 if (_session.transport_stopped()) {
2593 _effective_gain = val;
2598 _gain_control.Changed (); /* EMIT SIGNAL */
2600 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2601 _gain_automation_curve.add (_session.transport_frame(), val);
2605 _session.set_dirty();
2609 IO::start_gain_touch ()
2611 _gain_automation_curve.start_touch ();
2615 IO::end_gain_touch ()
2617 _gain_automation_curve.stop_touch ();
2621 IO::start_pan_touch (uint32_t which)
2623 if (which < _panner->size()) {
2624 (*_panner)[which]->automation().start_touch();
2629 IO::end_pan_touch (uint32_t which)
2631 if (which < _panner->size()) {
2632 (*_panner)[which]->automation().stop_touch();
2638 IO::automation_snapshot (nframes_t now)
2640 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2642 if (gain_automation_recording()) {
2643 _gain_automation_curve.rt_add (now, gain());
2646 _panner->snapshot (now);
2648 last_automation_snapshot = now;
2653 IO::transport_stopped (nframes_t frame)
2655 _gain_automation_curve.reposition_for_rt_add (frame);
2657 if (_gain_automation_curve.automation_state() != Off) {
2659 /* the src=0 condition is a special signal to not propagate
2660 automation gain changes into the mix group when locating.
2663 set_gain (_gain_automation_curve.eval (frame), 0);
2666 _panner->transport_stopped (frame);
2670 IO::find_input_port_hole ()
2672 /* CALLER MUST HOLD IO LOCK */
2676 if (_inputs.empty()) {
2680 for (n = 1; n < UINT_MAX; ++n) {
2681 char buf[jack_port_name_size()];
2682 vector<Port*>::iterator i;
2684 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2686 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2687 if ((*i)->short_name() == buf) {
2692 if (i == _inputs.end()) {
2700 IO::find_output_port_hole ()
2702 /* CALLER MUST HOLD IO LOCK */
2706 if (_outputs.empty()) {
2710 for (n = 1; n < UINT_MAX; ++n) {
2711 char buf[jack_port_name_size()];
2712 vector<Port*>::iterator i;
2714 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2716 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2717 if ((*i)->short_name() == buf) {
2722 if (i == _outputs.end()) {