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 */
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 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2105 string current_name = (*i)->short_name();
2106 current_name.replace (current_name.find (_name), _name.length(), name);
2107 (*i)->set_name (current_name);
2110 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.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);
2117 name_changed (src); /* EMIT SIGNAL */
2123 IO::set_input_minimum (int n)
2129 IO::set_input_maximum (int n)
2135 IO::set_output_minimum (int n)
2137 _output_minimum = n;
2141 IO::set_output_maximum (int n)
2143 _output_maximum = n;
2147 IO::set_port_latency (nframes_t nframes)
2149 Glib::Mutex::Lock lm (io_lock);
2151 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2152 (*i)->set_latency (nframes);
2157 IO::output_latency () const
2159 nframes_t max_latency;
2164 /* io lock not taken - must be protected by other means */
2166 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2167 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2168 max_latency = latency;
2176 IO::input_latency () const
2178 nframes_t max_latency;
2183 /* io lock not taken - must be protected by other means */
2185 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2186 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2187 max_latency = latency;
2195 IO::use_input_connection (Connection& c, void* src)
2200 BLOCK_PROCESS_CALLBACK ();
2201 Glib::Mutex::Lock lm2 (io_lock);
2205 drop_input_connection ();
2207 if (ensure_inputs (limit, false, false, src)) {
2211 /* first pass: check the current state to see what's correctly
2212 connected, and drop anything that we don't want.
2215 for (uint32_t n = 0; n < limit; ++n) {
2216 const Connection::PortList& pl = c.port_connections (n);
2218 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2220 if (!_inputs[n]->connected_to ((*i))) {
2222 /* clear any existing connections */
2224 _session.engine().disconnect (_inputs[n]);
2226 } else if (_inputs[n]->connected() > 1) {
2228 /* OK, it is connected to the port we want,
2229 but its also connected to other ports.
2230 Change that situation.
2233 /* XXX could be optimized to not drop
2237 _session.engine().disconnect (_inputs[n]);
2243 /* second pass: connect all requested ports where necessary */
2245 for (uint32_t n = 0; n < limit; ++n) {
2246 const Connection::PortList& pl = c.port_connections (n);
2248 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2250 if (!_inputs[n]->connected_to ((*i))) {
2252 if (_session.engine().connect (*i, _inputs[n]->name())) {
2260 _input_connection = &c;
2262 input_connection_configuration_connection = c.ConfigurationChanged.connect
2263 (mem_fun (*this, &IO::input_connection_configuration_changed));
2264 input_connection_connection_connection = c.ConnectionsChanged.connect
2265 (mem_fun (*this, &IO::input_connection_connection_changed));
2268 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2273 IO::use_output_connection (Connection& c, void* src)
2278 BLOCK_PROCESS_CALLBACK ();
2279 Glib::Mutex::Lock lm2 (io_lock);
2283 drop_output_connection ();
2285 if (ensure_outputs (limit, false, false, src)) {
2289 /* first pass: check the current state to see what's correctly
2290 connected, and drop anything that we don't want.
2293 for (uint32_t n = 0; n < limit; ++n) {
2295 const Connection::PortList& pl = c.port_connections (n);
2297 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2299 if (!_outputs[n]->connected_to ((*i))) {
2301 /* clear any existing connections */
2303 _session.engine().disconnect (_outputs[n]);
2305 } else if (_outputs[n]->connected() > 1) {
2307 /* OK, it is connected to the port we want,
2308 but its also connected to other ports.
2309 Change that situation.
2312 /* XXX could be optimized to not drop
2316 _session.engine().disconnect (_outputs[n]);
2321 /* second pass: connect all requested ports where necessary */
2323 for (uint32_t n = 0; n < limit; ++n) {
2325 const Connection::PortList& pl = c.port_connections (n);
2327 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2329 if (!_outputs[n]->connected_to ((*i))) {
2331 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2338 _output_connection = &c;
2340 output_connection_configuration_connection = c.ConfigurationChanged.connect
2341 (mem_fun (*this, &IO::output_connection_configuration_changed));
2342 output_connection_connection_connection = c.ConnectionsChanged.connect
2343 (mem_fun (*this, &IO::output_connection_connection_changed));
2346 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2352 IO::disable_connecting ()
2354 connecting_legal = false;
2359 IO::enable_connecting ()
2361 connecting_legal = true;
2362 return ConnectingLegal ();
2366 IO::disable_ports ()
2368 ports_legal = false;
2376 return PortsLegal ();
2380 IO::disable_panners (void)
2382 panners_legal = false;
2387 IO::reset_panners ()
2389 panners_legal = true;
2390 return PannersLegal ();
2394 IO::input_connection_connection_changed (int ignored)
2396 use_input_connection (*_input_connection, this);
2400 IO::input_connection_configuration_changed ()
2402 use_input_connection (*_input_connection, this);
2406 IO::output_connection_connection_changed (int ignored)
2408 use_output_connection (*_output_connection, this);
2412 IO::output_connection_configuration_changed ()
2414 use_output_connection (*_output_connection, this);
2418 IO::GainControllable::set_value (float val)
2420 io.set_gain (direct_control_to_gain (val), this);
2424 IO::GainControllable::get_value (void) const
2426 return direct_gain_to_control (io.effective_gain());
2430 IO::reset_peak_meters ()
2432 uint32_t limit = max (_ninputs, _noutputs);
2434 for (uint32_t i = 0; i < limit; ++i) {
2440 IO::reset_max_peak_meters ()
2442 uint32_t limit = max (_ninputs, _noutputs);
2444 for (uint32_t i = 0; i < limit; ++i) {
2445 _max_peak_power[i] = -INFINITY;
2450 IO::setup_peak_meters ()
2452 uint32_t limit = max (_ninputs, _noutputs);
2454 while (_peak_power.size() < limit) {
2455 _peak_power.push_back (0);
2456 _visible_peak_power.push_back (-INFINITY);
2457 _max_peak_power.push_back (-INFINITY);
2462 Update the peak meters.
2464 The meter signal lock is taken to prevent modification of the
2465 Meter signal while updating the meters, taking the meter signal
2466 lock prior to taking the io_lock ensures that all IO will remain
2467 valid while metering.
2472 Glib::Mutex::Lock guard (m_meter_signal_lock);
2480 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2481 uint32_t limit = max (_ninputs, _noutputs);
2483 for (uint32_t n = 0; n < limit; ++n) {
2485 /* XXX we should use atomic exchange here */
2487 /* grab peak since last read */
2489 float new_peak = _peak_power[n];
2492 /* compute new visible value using falloff */
2494 if (new_peak > 0.0f) {
2495 new_peak = coefficient_to_dB (new_peak);
2497 new_peak = -INFINITY;
2500 /* update max peak */
2502 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2505 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2506 _visible_peak_power[n] = new_peak;
2508 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2509 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2510 _visible_peak_power[n] = max (new_peak, -INFINITY);
2516 IO::clear_automation ()
2518 Glib::Mutex::Lock lm (automation_lock);
2519 _gain_automation_curve.clear ();
2520 _panner->clear_automation ();
2524 IO::set_gain_automation_state (AutoState state)
2526 bool changed = false;
2529 Glib::Mutex::Lock lm (automation_lock);
2531 if (state != _gain_automation_curve.automation_state()) {
2533 last_automation_snapshot = 0;
2534 _gain_automation_curve.set_automation_state (state);
2537 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2543 _session.set_dirty ();
2544 gain_automation_state_changed (); /* EMIT SIGNAL */
2549 IO::set_gain_automation_style (AutoStyle style)
2551 bool changed = false;
2554 Glib::Mutex::Lock lm (automation_lock);
2556 if (style != _gain_automation_curve.automation_style()) {
2558 _gain_automation_curve.set_automation_style (style);
2563 gain_automation_style_changed (); /* EMIT SIGNAL */
2567 IO::inc_gain (gain_t factor, void *src)
2569 if (_desired_gain == 0.0f)
2570 set_gain (0.000001f + (0.000001f * factor), src);
2572 set_gain (_desired_gain + (_desired_gain * factor), src);
2576 IO::set_gain (gain_t val, void *src)
2578 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2579 if (val>1.99526231f) val=1.99526231f;
2582 Glib::Mutex::Lock dm (declick_lock);
2583 _desired_gain = val;
2586 if (_session.transport_stopped()) {
2587 _effective_gain = val;
2592 _gain_control.Changed (); /* EMIT SIGNAL */
2594 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2595 _gain_automation_curve.add (_session.transport_frame(), val);
2599 _session.set_dirty();
2603 IO::start_gain_touch ()
2605 _gain_automation_curve.start_touch ();
2609 IO::end_gain_touch ()
2611 _gain_automation_curve.stop_touch ();
2615 IO::start_pan_touch (uint32_t which)
2617 if (which < _panner->size()) {
2618 (*_panner)[which]->automation().start_touch();
2623 IO::end_pan_touch (uint32_t which)
2625 if (which < _panner->size()) {
2626 (*_panner)[which]->automation().stop_touch();
2632 IO::automation_snapshot (nframes_t now)
2634 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2636 if (gain_automation_recording()) {
2637 _gain_automation_curve.rt_add (now, gain());
2640 _panner->snapshot (now);
2642 last_automation_snapshot = now;
2647 IO::transport_stopped (nframes_t frame)
2649 _gain_automation_curve.reposition_for_rt_add (frame);
2651 if (_gain_automation_curve.automation_state() != Off) {
2653 /* the src=0 condition is a special signal to not propagate
2654 automation gain changes into the mix group when locating.
2657 set_gain (_gain_automation_curve.eval (frame), 0);
2660 _panner->transport_stopped (frame);
2664 IO::find_input_port_hole ()
2666 /* CALLER MUST HOLD IO LOCK */
2670 if (_inputs.empty()) {
2674 for (n = 1; n < UINT_MAX; ++n) {
2675 char buf[jack_port_name_size()];
2676 vector<Port*>::iterator i;
2678 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2680 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2681 if ((*i)->short_name() == buf) {
2686 if (i == _inputs.end()) {
2694 IO::find_output_port_hole ()
2696 /* CALLER MUST HOLD IO LOCK */
2700 if (_outputs.empty()) {
2704 for (n = 1; n < UINT_MAX; ++n) {
2705 char buf[jack_port_name_size()];
2706 vector<Port*>::iterator i;
2708 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2710 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2711 if ((*i)->short_name() == buf) {
2716 if (i == _outputs.end()) {