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) {
346 Session::mix_buffers_no_gain(dst,bufs[n],nframes);
349 output(0)->mark_silence (false);
353 /* mix all buffers into the output, scaling them all by the gain */
359 for (nframes_t n = 0; n < nframes; ++n) {
360 dst[n] = src[n] * gain_coeff;
363 for (n = 1; n < nbufs; ++n) {
364 Session::mix_buffers_with_gain(dst,bufs[n],nframes,gain_coeff);
367 output(0)->mark_silence (false);
374 vector<Port *>::iterator out;
375 vector<Sample *>::iterator in;
376 Panner::iterator pan;
377 Sample* obufs[_noutputs];
379 /* the terrible silence ... */
381 /* XXX this is wasteful but i see no way to avoid it */
383 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
384 obufs[o] = (*out)->get_buffer (nframes) + offset;
385 memset (obufs[o], 0, sizeof (Sample) * nframes);
386 (*out)->mark_silence (false);
391 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
392 Panner::iterator tmp;
397 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
399 if (tmp != _panner->end()) {
406 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
408 /* io_lock, not taken: function must be called from Session::process() calltree */
410 if (_noutputs == 0) {
414 if (_panner->bypassed() || _panner->empty()) {
415 deliver_output_no_pan (bufs, nbufs, nframes, offset);
421 gain_t pangain = _gain;
424 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
434 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
439 /* simple, non-automation panning to outputs */
441 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
442 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
444 pan (bufs, nbufs, nframes, offset, pangain);
449 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
451 /* io_lock, not taken: function must be called from Session::process() calltree */
453 if (_noutputs == 0) {
458 gain_t old_gain = _gain;
460 if (apply_gain_automation || _ignore_gain_on_deliver) {
462 /* gain has already been applied by automation code. do nothing here except
471 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
483 vector<Port*>::iterator o;
484 vector<Sample*> outs;
487 /* reduce nbufs to the index of the last input buffer */
491 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
492 actual_gain = _gain * speed_quietning;
497 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
499 dst = (*o)->get_buffer (nframes) + offset;
500 src = bufs[min(nbufs,i)];
503 /* unlikely condition */
504 outs.push_back (dst);
507 if (dg != _gain || actual_gain == 1.0f) {
508 memcpy (dst, src, sizeof (Sample) * nframes);
509 } else if (actual_gain == 0.0f) {
510 memset (dst, 0, sizeof (Sample) * nframes);
512 for (nframes_t x = 0; x < nframes; ++x) {
513 dst[x] = src[x] * actual_gain;
517 (*o)->mark_silence (false);
521 apply_declick (outs, i, nframes, _gain, dg, false);
525 if (apply_gain_automation || _ignore_gain_on_deliver) {
531 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
533 /* io_lock, not taken: function must be called from Session::process() calltree */
535 vector<Port *>::iterator i;
539 /* we require that bufs.size() >= 1 */
541 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
542 if (i == _inputs.end()) {
546 /* XXX always read the full extent of the port buffer that
547 we need. One day, we may use jack_port_get_buffer_at_offset()
548 or something similar. For now, this simple hack will
551 Hack? Why yes .. we only need to read nframes-worth of
552 data, but the data we want is at `offset' within the
556 last = (*i)->get_buffer (nframes+offset) + offset;
557 // the dest buffer's offset has already been applied
558 memcpy (bufs[n], last, sizeof (Sample) * nframes);
561 /* fill any excess outputs with the last input */
565 // the dest buffer's offset has already been applied
566 memcpy (bufs[n], last, sizeof (Sample) * nframes);
571 memset (bufs[n], 0, sizeof (Sample) * nframes);
578 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
579 nframes_t nframes, nframes_t offset)
581 vector<Sample*>& bufs = _session.get_passthru_buffers ();
582 uint32_t nbufs = n_process_buffers ();
584 collect_input (bufs, nbufs, nframes, offset);
586 for (uint32_t n = 0; n < nbufs; ++n) {
587 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
592 IO::drop_input_connection ()
594 _input_connection = 0;
595 input_connection_configuration_connection.disconnect();
596 input_connection_connection_connection.disconnect();
597 _session.set_dirty ();
601 IO::drop_output_connection ()
603 _output_connection = 0;
604 output_connection_configuration_connection.disconnect();
605 output_connection_connection_connection.disconnect();
606 _session.set_dirty ();
610 IO::disconnect_input (Port* our_port, string other_port, void* src)
612 if (other_port.length() == 0 || our_port == 0) {
617 BLOCK_PROCESS_CALLBACK ();
620 Glib::Mutex::Lock lm (io_lock);
622 /* check that our_port is really one of ours */
624 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
628 /* disconnect it from the source */
630 if (_session.engine().disconnect (other_port, our_port->name())) {
631 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
635 drop_input_connection();
639 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
640 _session.set_dirty ();
646 IO::connect_input (Port* our_port, string other_port, void* src)
648 if (other_port.length() == 0 || our_port == 0) {
653 BLOCK_PROCESS_CALLBACK ();
656 Glib::Mutex::Lock lm (io_lock);
658 /* check that our_port is really one of ours */
660 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
664 /* connect it to the source */
666 if (_session.engine().connect (other_port, our_port->name())) {
670 drop_input_connection ();
674 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
675 _session.set_dirty ();
680 IO::disconnect_output (Port* our_port, string other_port, void* src)
682 if (other_port.length() == 0 || our_port == 0) {
687 BLOCK_PROCESS_CALLBACK ();
690 Glib::Mutex::Lock lm (io_lock);
692 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
696 /* disconnect it from the destination */
698 if (_session.engine().disconnect (our_port->name(), other_port)) {
699 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
703 drop_output_connection ();
707 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
708 _session.set_dirty ();
713 IO::connect_output (Port* our_port, string other_port, void* src)
715 if (other_port.length() == 0 || our_port == 0) {
720 BLOCK_PROCESS_CALLBACK ();
724 Glib::Mutex::Lock lm (io_lock);
726 /* check that our_port is really one of ours */
728 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
732 /* connect it to the destination */
734 if (_session.engine().connect (our_port->name(), other_port)) {
738 drop_output_connection ();
742 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
743 _session.set_dirty ();
748 IO::set_input (Port* other_port, void* src)
750 /* this removes all but one ports, and connects that one port
751 to the specified source.
754 if (_input_minimum > 1 || _input_minimum == 0) {
755 /* sorry, you can't do this */
759 if (other_port == 0) {
760 if (_input_minimum < 0) {
761 return ensure_inputs (0, false, true, src);
767 if (ensure_inputs (1, true, true, src)) {
771 return connect_input (_inputs.front(), other_port->name(), src);
775 IO::remove_output_port (Port* port, void* src)
777 IOChange change (NoChange);
780 BLOCK_PROCESS_CALLBACK ();
784 Glib::Mutex::Lock lm (io_lock);
786 if (_noutputs - 1 == (uint32_t) _output_minimum) {
787 /* sorry, you can't do this */
791 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
793 change = IOChange (change|ConfigurationChanged);
794 if (port->connected()) {
795 change = IOChange (change|ConnectionsChanged);
798 _session.engine().unregister_port (*i);
801 drop_output_connection ();
807 if (change != NoChange) {
808 setup_peak_meters ();
814 if (change != NoChange) {
815 output_changed (change, src); /* EMIT SIGNAL */
816 _session.set_dirty ();
823 /** Add an output port.
825 * @param destination Name of input port to connect new port to.
826 * @param src Source for emitted ConfigurationChanged signal.
827 * @param type Data type of port. Default value (NIL) will use this IO's default type.
830 IO::add_output_port (string destination, void* src, DataType type)
835 if (type == DataType::NIL)
836 type = _default_type;
839 BLOCK_PROCESS_CALLBACK ();
843 Glib::Mutex::Lock lm (io_lock);
845 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
849 /* Create a new output port */
851 // FIXME: naming scheme for differently typed ports?
852 if (_output_maximum == 1) {
853 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
855 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
858 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
859 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
863 _outputs.push_back (our_port);
864 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
866 drop_output_connection ();
867 setup_peak_meters ();
871 MoreOutputs (_noutputs); /* EMIT SIGNAL */
874 if (destination.length()) {
875 if (_session.engine().connect (our_port->name(), destination)) {
880 // pan_changed (src); /* EMIT SIGNAL */
881 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
882 _session.set_dirty ();
887 IO::remove_input_port (Port* port, void* src)
889 IOChange change (NoChange);
892 BLOCK_PROCESS_CALLBACK ();
896 Glib::Mutex::Lock lm (io_lock);
898 if (((int)_ninputs - 1) < _input_minimum) {
899 /* sorry, you can't do this */
902 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
905 change = IOChange (change|ConfigurationChanged);
907 if (port->connected()) {
908 change = IOChange (change|ConnectionsChanged);
911 _session.engine().unregister_port (*i);
914 drop_input_connection ();
920 if (change != NoChange) {
921 setup_peak_meters ();
927 if (change != NoChange) {
928 input_changed (change, src);
929 _session.set_dirty ();
937 /** Add an input port.
939 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
940 * @param destination Name of input port to connect new port to.
941 * @param src Source for emitted ConfigurationChanged signal.
944 IO::add_input_port (string source, void* src, DataType type)
949 if (type == DataType::NIL)
950 type = _default_type;
953 BLOCK_PROCESS_CALLBACK ();
956 Glib::Mutex::Lock lm (io_lock);
958 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
962 /* Create a new input port */
964 // FIXME: naming scheme for differently typed ports?
965 if (_input_maximum == 1) {
966 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
968 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
971 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
972 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
976 _inputs.push_back (our_port);
977 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
979 drop_input_connection ();
980 setup_peak_meters ();
984 MoreOutputs (_ninputs); /* EMIT SIGNAL */
987 if (source.length()) {
989 if (_session.engine().connect (source, our_port->name())) {
994 // pan_changed (src); /* EMIT SIGNAL */
995 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
996 _session.set_dirty ();
1002 IO::disconnect_inputs (void* src)
1005 BLOCK_PROCESS_CALLBACK ();
1008 Glib::Mutex::Lock lm (io_lock);
1010 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1011 _session.engine().disconnect (*i);
1014 drop_input_connection ();
1017 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1022 IO::disconnect_outputs (void* src)
1025 BLOCK_PROCESS_CALLBACK ();
1028 Glib::Mutex::Lock lm (io_lock);
1030 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1031 _session.engine().disconnect (*i);
1034 drop_output_connection ();
1038 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1039 _session.set_dirty ();
1044 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1047 bool changed = false;
1048 bool reduced = false;
1050 /* remove unused ports */
1052 while (_ninputs > n) {
1053 _session.engine().unregister_port (_inputs.back());
1060 /* create any necessary new ports */
1062 while (_ninputs < n) {
1066 /* Create a new input port (of the default type) */
1068 if (_input_maximum == 1) {
1069 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1072 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1077 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1078 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1083 catch (AudioEngine::PortRegistrationFailure& err) {
1084 setup_peak_meters ();
1087 throw AudioEngine::PortRegistrationFailure();
1090 _inputs.push_back (input_port);
1091 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1097 drop_input_connection ();
1098 setup_peak_meters ();
1100 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1101 _session.set_dirty ();
1105 /* disconnect all existing ports so that we get a fresh start */
1107 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1108 _session.engine().disconnect (*i);
1116 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1118 bool in_changed = false;
1119 bool out_changed = false;
1120 bool in_reduced = false;
1121 bool out_reduced = false;
1122 bool need_pan_reset;
1124 if (_input_maximum >= 0) {
1125 nin = min (_input_maximum, (int) nin);
1128 if (_output_maximum >= 0) {
1129 nout = min (_output_maximum, (int) nout);
1132 if (nin == _ninputs && nout == _noutputs && !clear) {
1137 BLOCK_PROCESS_CALLBACK ();
1138 Glib::Mutex::Lock lm (io_lock);
1142 if (_noutputs == nout) {
1143 need_pan_reset = false;
1145 need_pan_reset = true;
1148 /* remove unused ports */
1150 while (_ninputs > nin) {
1151 _session.engine().unregister_port (_inputs.back());
1158 while (_noutputs > nout) {
1159 _session.engine().unregister_port (_outputs.back());
1160 _outputs.pop_back();
1166 /* create any necessary new ports (of the default type) */
1168 while (_ninputs < nin) {
1172 /* Create a new input port */
1174 if (_input_maximum == 1) {
1175 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1178 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1182 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1183 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1188 catch (AudioEngine::PortRegistrationFailure& err) {
1189 setup_peak_meters ();
1192 throw AudioEngine::PortRegistrationFailure();
1195 _inputs.push_back (port);
1200 /* create any necessary new ports */
1202 while (_noutputs < nout) {
1206 /* Create a new output port */
1208 if (_output_maximum == 1) {
1209 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1211 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1215 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1216 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1221 catch (AudioEngine::PortRegistrationFailure& err) {
1222 setup_peak_meters ();
1225 throw AudioEngine::PortRegistrationFailure ();
1228 _outputs.push_back (port);
1235 /* disconnect all existing ports so that we get a fresh start */
1237 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1238 _session.engine().disconnect (*i);
1241 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1242 _session.engine().disconnect (*i);
1246 if (in_changed || out_changed) {
1247 setup_peak_meters ();
1253 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1254 drop_output_connection ();
1255 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1259 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1260 drop_input_connection ();
1261 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1264 if (in_changed || out_changed) {
1265 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1266 _session.set_dirty ();
1273 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1275 bool changed = false;
1277 if (_input_maximum >= 0) {
1278 n = min (_input_maximum, (int) n);
1280 if (n == _ninputs && !clear) {
1286 BLOCK_PROCESS_CALLBACK ();
1287 Glib::Mutex::Lock im (io_lock);
1288 changed = ensure_inputs_locked (n, clear, src);
1290 changed = ensure_inputs_locked (n, clear, src);
1294 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1295 _session.set_dirty ();
1302 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1305 bool changed = false;
1306 bool reduced = false;
1307 bool need_pan_reset;
1309 if (_noutputs == n) {
1310 need_pan_reset = false;
1312 need_pan_reset = true;
1315 /* remove unused ports */
1317 while (_noutputs > n) {
1319 _session.engine().unregister_port (_outputs.back());
1320 _outputs.pop_back();
1326 /* create any necessary new ports */
1328 while (_noutputs < n) {
1332 /* Create a new output port */
1334 if (_output_maximum == 1) {
1335 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1337 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1340 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1341 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1345 _outputs.push_back (output_port);
1346 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1349 setup_peak_meters ();
1351 if (need_pan_reset) {
1357 drop_output_connection ();
1358 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1359 _session.set_dirty ();
1363 /* disconnect all existing ports so that we get a fresh start */
1365 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1366 _session.engine().disconnect (*i);
1374 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1376 bool changed = false;
1378 if (_output_maximum >= 0) {
1379 n = min (_output_maximum, (int) n);
1380 if (n == _noutputs && !clear) {
1385 /* XXX caller should hold io_lock, but generally doesn't */
1388 BLOCK_PROCESS_CALLBACK ();
1389 Glib::Mutex::Lock im (io_lock);
1390 changed = ensure_outputs_locked (n, clear, src);
1392 changed = ensure_outputs_locked (n, clear, src);
1396 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1403 IO::effective_gain () const
1405 if (gain_automation_playback()) {
1406 return _effective_gain;
1408 return _desired_gain;
1415 if (panners_legal) {
1416 if (!no_panner_reset) {
1417 _panner->reset (_noutputs, pans_required());
1420 panner_legal_c.disconnect ();
1421 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1426 IO::panners_became_legal ()
1428 _panner->reset (_noutputs, pans_required());
1429 _panner->load (); // automation
1430 panner_legal_c.disconnect ();
1435 IO::defer_pan_reset ()
1437 no_panner_reset = true;
1441 IO::allow_pan_reset ()
1443 no_panner_reset = false;
1449 IO::get_state (void)
1451 return state (true);
1455 IO::state (bool full_state)
1457 XMLNode* node = new XMLNode (state_node_name);
1460 bool need_ins = true;
1461 bool need_outs = true;
1462 LocaleGuard lg (X_("POSIX"));
1463 Glib::Mutex::Lock lm (io_lock);
1465 node->add_property("name", _name);
1466 id().print (buf, sizeof (buf));
1467 node->add_property("id", buf);
1471 if (_input_connection) {
1472 node->add_property ("input-connection", _input_connection->name());
1476 if (_output_connection) {
1477 node->add_property ("output-connection", _output_connection->name());
1482 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1484 const char **connections = (*i)->get_connections();
1486 if (connections && connections[0]) {
1489 for (int n = 0; connections && connections[n]; ++n) {
1494 /* if its a connection to our own port,
1495 return only the port name, not the
1496 whole thing. this allows connections
1497 to be re-established even when our
1498 client name is different.
1501 str += _session.engine().make_port_name_relative (connections[n]);
1513 node->add_property ("inputs", str);
1519 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1521 const char **connections = (*i)->get_connections();
1523 if (connections && connections[0]) {
1527 for (int n = 0; connections[n]; ++n) {
1532 str += _session.engine().make_port_name_relative (connections[n]);
1544 node->add_property ("outputs", str);
1547 node->add_child_nocopy (_panner->state (full_state));
1548 node->add_child_nocopy (_gain_control.get_state ());
1550 snprintf (buf, sizeof(buf), "%2.12f", gain());
1551 node->add_property ("gain", buf);
1553 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1559 node->add_property ("iolimits", buf);
1565 XMLNode* autonode = new XMLNode (X_("Automation"));
1566 autonode->add_child_nocopy (get_automation_state());
1567 node->add_child_nocopy (*autonode);
1569 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1571 /* never store anything except Off for automation state in a template */
1572 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1579 IO::set_state (const XMLNode& node)
1581 const XMLProperty* prop;
1582 XMLNodeConstIterator iter;
1583 LocaleGuard lg (X_("POSIX"));
1585 /* force use of non-localized representation of decimal point,
1586 since we use it a lot in XML files and so forth.
1589 if (node.name() != state_node_name) {
1590 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1594 if ((prop = node.property ("name")) != 0) {
1595 _name = prop->value();
1596 /* used to set panner name with this, but no more */
1599 if ((prop = node.property ("id")) != 0) {
1600 _id = prop->value ();
1603 if ((prop = node.property ("iolimits")) != 0) {
1604 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1611 if ((prop = node.property ("gain")) != 0) {
1612 set_gain (atof (prop->value().c_str()), this);
1613 _gain = _desired_gain;
1616 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1617 /* old school automation handling */
1620 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1622 if ((*iter)->name() == "Panner") {
1624 _panner = new Panner (_name, _session);
1626 _panner->set_state (**iter);
1629 if ((*iter)->name() == X_("Automation")) {
1631 set_automation_state (*(*iter)->children().front());
1634 if ((*iter)->name() == X_("controllable")) {
1635 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1636 _gain_control.set_state (**iter);
1643 if (create_ports (node)) {
1649 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1652 if (panners_legal) {
1655 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1658 if (connecting_legal) {
1660 if (make_connections (node)) {
1666 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1669 if (!ports_legal || !connecting_legal) {
1670 pending_state_node = new XMLNode (node);
1673 last_automation_snapshot = 0;
1679 IO::set_automation_state (const XMLNode& node)
1681 return _gain_automation_curve.set_state (node);
1685 IO::get_automation_state ()
1687 return (_gain_automation_curve.get_state ());
1691 IO::load_automation (string path)
1696 uint32_t linecnt = 0;
1698 LocaleGuard lg (X_("POSIX"));
1700 fullpath = _session.automation_dir();
1703 in.open (fullpath.c_str());
1706 fullpath = _session.automation_dir();
1707 fullpath += _session.snap_name();
1711 in.open (fullpath.c_str());
1714 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1719 clear_automation ();
1721 while (in.getline (line, sizeof(line), '\n')) {
1723 jack_nframes_t when;
1726 if (++linecnt == 1) {
1727 if (memcmp (line, "version", 7) == 0) {
1728 if (sscanf (line, "version %f", &version) != 1) {
1729 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1733 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1740 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1741 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1747 _gain_automation_curve.fast_simple_add (when, value);
1757 /* older (pre-1.0) versions of ardour used this */
1761 warning << _("dubious automation event found (and ignored)") << endmsg;
1769 IO::connecting_became_legal ()
1773 if (pending_state_node == 0) {
1774 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1779 connection_legal_c.disconnect ();
1781 ret = make_connections (*pending_state_node);
1784 delete pending_state_node;
1785 pending_state_node = 0;
1791 IO::ports_became_legal ()
1795 if (pending_state_node == 0) {
1796 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1801 port_legal_c.disconnect ();
1803 ret = create_ports (*pending_state_node);
1805 if (connecting_legal) {
1806 delete pending_state_node;
1807 pending_state_node = 0;
1814 IO::create_ports (const XMLNode& node)
1816 const XMLProperty* prop;
1818 int num_outputs = 0;
1820 if ((prop = node.property ("input-connection")) != 0) {
1822 Connection* c = _session.connection_by_name (prop->value());
1825 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1827 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1828 error << _("No input connections available as a replacement")
1832 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1837 num_inputs = c->nports();
1839 } else if ((prop = node.property ("inputs")) != 0) {
1841 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1844 if ((prop = node.property ("output-connection")) != 0) {
1845 Connection* c = _session.connection_by_name (prop->value());
1848 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1850 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1851 error << _("No output connections available as a replacement")
1855 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1860 num_outputs = c->nports ();
1862 } else if ((prop = node.property ("outputs")) != 0) {
1863 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1866 no_panner_reset = true;
1868 if (ensure_io (num_inputs, num_outputs, true, this)) {
1869 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1873 no_panner_reset = false;
1875 set_deferred_state ();
1883 IO::make_connections (const XMLNode& node)
1885 const XMLProperty* prop;
1887 if ((prop = node.property ("input-connection")) != 0) {
1888 Connection* c = _session.connection_by_name (prop->value());
1891 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1893 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1894 error << _("No input connections available as a replacement")
1898 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1903 use_input_connection (*c, this);
1905 } else if ((prop = node.property ("inputs")) != 0) {
1906 if (set_inputs (prop->value())) {
1907 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1912 if ((prop = node.property ("output-connection")) != 0) {
1913 Connection* c = _session.connection_by_name (prop->value());
1916 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1918 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1919 error << _("No output connections available as a replacement")
1923 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1928 use_output_connection (*c, this);
1930 } else if ((prop = node.property ("outputs")) != 0) {
1931 if (set_outputs (prop->value())) {
1932 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1941 IO::set_inputs (const string& str)
1943 vector<string> ports;
1948 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1952 if (ensure_inputs (nports, true, true, this)) {
1956 string::size_type start, end, ostart;
1963 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1966 if ((end = str.find_first_of ('}', start)) == string::npos) {
1967 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1971 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1972 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1978 for (int x = 0; x < n; ++x) {
1979 connect_input (input (i), ports[x], this);
1991 IO::set_outputs (const string& str)
1993 vector<string> ports;
1998 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2002 if (ensure_outputs (nports, true, true, this)) {
2006 string::size_type start, end, ostart;
2013 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2016 if ((end = str.find_first_of ('}', start)) == string::npos) {
2017 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2021 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2022 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2028 for (int x = 0; x < n; ++x) {
2029 connect_output (output (i), ports[x], this);
2041 IO::parse_io_string (const string& str, vector<string>& ports)
2043 string::size_type pos, opos;
2045 if (str.length() == 0) {
2054 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2055 ports.push_back (str.substr (opos, pos - opos));
2059 if (opos < str.length()) {
2060 ports.push_back (str.substr(opos));
2063 return ports.size();
2067 IO::parse_gain_string (const string& str, vector<string>& ports)
2069 string::size_type pos, opos;
2075 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2076 ports.push_back (str.substr (opos, pos - opos));
2080 if (opos < str.length()) {
2081 ports.push_back (str.substr(opos));
2084 return ports.size();
2088 IO::set_name (string name, void* src)
2090 if (name == _name) {
2094 /* replace all colons in the name. i wish we didn't have to do this */
2096 if (replace_all (name, ":", "-")) {
2097 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
2100 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2101 string current_name = (*i)->short_name();
2102 current_name.replace (current_name.find (_name), _name.length(), name);
2103 (*i)->set_name (current_name);
2106 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2107 string current_name = (*i)->short_name();
2108 current_name.replace (current_name.find (_name), _name.length(), name);
2109 (*i)->set_name (current_name);
2113 name_changed (src); /* EMIT SIGNAL */
2119 IO::set_input_minimum (int n)
2125 IO::set_input_maximum (int n)
2131 IO::set_output_minimum (int n)
2133 _output_minimum = n;
2137 IO::set_output_maximum (int n)
2139 _output_maximum = n;
2143 IO::set_port_latency (nframes_t nframes)
2145 Glib::Mutex::Lock lm (io_lock);
2147 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2148 (*i)->set_latency (nframes);
2153 IO::output_latency () const
2155 nframes_t max_latency;
2160 /* io lock not taken - must be protected by other means */
2162 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2163 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2164 max_latency = latency;
2172 IO::input_latency () const
2174 nframes_t max_latency;
2179 /* io lock not taken - must be protected by other means */
2181 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2182 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2183 max_latency = latency;
2191 IO::use_input_connection (Connection& c, void* src)
2196 BLOCK_PROCESS_CALLBACK ();
2197 Glib::Mutex::Lock lm2 (io_lock);
2201 drop_input_connection ();
2203 if (ensure_inputs (limit, false, false, src)) {
2207 /* first pass: check the current state to see what's correctly
2208 connected, and drop anything that we don't want.
2211 for (uint32_t n = 0; n < limit; ++n) {
2212 const Connection::PortList& pl = c.port_connections (n);
2214 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2216 if (!_inputs[n]->connected_to ((*i))) {
2218 /* clear any existing connections */
2220 _session.engine().disconnect (_inputs[n]);
2222 } else if (_inputs[n]->connected() > 1) {
2224 /* OK, it is connected to the port we want,
2225 but its also connected to other ports.
2226 Change that situation.
2229 /* XXX could be optimized to not drop
2233 _session.engine().disconnect (_inputs[n]);
2239 /* second pass: connect all requested ports where necessary */
2241 for (uint32_t n = 0; n < limit; ++n) {
2242 const Connection::PortList& pl = c.port_connections (n);
2244 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2246 if (!_inputs[n]->connected_to ((*i))) {
2248 if (_session.engine().connect (*i, _inputs[n]->name())) {
2256 _input_connection = &c;
2258 input_connection_configuration_connection = c.ConfigurationChanged.connect
2259 (mem_fun (*this, &IO::input_connection_configuration_changed));
2260 input_connection_connection_connection = c.ConnectionsChanged.connect
2261 (mem_fun (*this, &IO::input_connection_connection_changed));
2264 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2269 IO::use_output_connection (Connection& c, void* src)
2274 BLOCK_PROCESS_CALLBACK ();
2275 Glib::Mutex::Lock lm2 (io_lock);
2279 drop_output_connection ();
2281 if (ensure_outputs (limit, false, false, src)) {
2285 /* first pass: check the current state to see what's correctly
2286 connected, and drop anything that we don't want.
2289 for (uint32_t n = 0; n < limit; ++n) {
2291 const Connection::PortList& pl = c.port_connections (n);
2293 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2295 if (!_outputs[n]->connected_to ((*i))) {
2297 /* clear any existing connections */
2299 _session.engine().disconnect (_outputs[n]);
2301 } else if (_outputs[n]->connected() > 1) {
2303 /* OK, it is connected to the port we want,
2304 but its also connected to other ports.
2305 Change that situation.
2308 /* XXX could be optimized to not drop
2312 _session.engine().disconnect (_outputs[n]);
2317 /* second pass: connect all requested ports where necessary */
2319 for (uint32_t n = 0; n < limit; ++n) {
2321 const Connection::PortList& pl = c.port_connections (n);
2323 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2325 if (!_outputs[n]->connected_to ((*i))) {
2327 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2334 _output_connection = &c;
2336 output_connection_configuration_connection = c.ConfigurationChanged.connect
2337 (mem_fun (*this, &IO::output_connection_configuration_changed));
2338 output_connection_connection_connection = c.ConnectionsChanged.connect
2339 (mem_fun (*this, &IO::output_connection_connection_changed));
2342 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2348 IO::disable_connecting ()
2350 connecting_legal = false;
2355 IO::enable_connecting ()
2357 connecting_legal = true;
2358 return ConnectingLegal ();
2362 IO::disable_ports ()
2364 ports_legal = false;
2372 return PortsLegal ();
2376 IO::disable_panners (void)
2378 panners_legal = false;
2383 IO::reset_panners ()
2385 panners_legal = true;
2386 return PannersLegal ();
2390 IO::input_connection_connection_changed (int ignored)
2392 use_input_connection (*_input_connection, this);
2396 IO::input_connection_configuration_changed ()
2398 use_input_connection (*_input_connection, this);
2402 IO::output_connection_connection_changed (int ignored)
2404 use_output_connection (*_output_connection, this);
2408 IO::output_connection_configuration_changed ()
2410 use_output_connection (*_output_connection, this);
2414 IO::GainControllable::set_value (float val)
2416 io.set_gain (direct_control_to_gain (val), this);
2420 IO::GainControllable::get_value (void) const
2422 return direct_gain_to_control (io.effective_gain());
2426 IO::reset_peak_meters ()
2428 uint32_t limit = max (_ninputs, _noutputs);
2430 for (uint32_t i = 0; i < limit; ++i) {
2436 IO::reset_max_peak_meters ()
2438 uint32_t limit = max (_ninputs, _noutputs);
2440 for (uint32_t i = 0; i < limit; ++i) {
2441 _max_peak_power[i] = -INFINITY;
2446 IO::setup_peak_meters ()
2448 uint32_t limit = max (_ninputs, _noutputs);
2450 while (_peak_power.size() < limit) {
2451 _peak_power.push_back (0);
2452 _visible_peak_power.push_back (-INFINITY);
2453 _max_peak_power.push_back (-INFINITY);
2458 Update the peak meters.
2460 The meter signal lock is taken to prevent modification of the
2461 Meter signal while updating the meters, taking the meter signal
2462 lock prior to taking the io_lock ensures that all IO will remain
2463 valid while metering.
2468 Glib::Mutex::Lock guard (m_meter_signal_lock);
2476 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2477 uint32_t limit = max (_ninputs, _noutputs);
2479 for (uint32_t n = 0; n < limit; ++n) {
2481 /* XXX we should use atomic exchange here */
2483 /* grab peak since last read */
2485 float new_peak = _peak_power[n];
2488 /* compute new visible value using falloff */
2490 if (new_peak > 0.0f) {
2491 new_peak = coefficient_to_dB (new_peak);
2493 new_peak = -INFINITY;
2496 /* update max peak */
2498 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2501 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2502 _visible_peak_power[n] = new_peak;
2504 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2505 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2506 _visible_peak_power[n] = max (new_peak, -INFINITY);
2512 IO::clear_automation ()
2514 Glib::Mutex::Lock lm (automation_lock);
2515 _gain_automation_curve.clear ();
2516 _panner->clear_automation ();
2520 IO::set_gain_automation_state (AutoState state)
2522 bool changed = false;
2525 Glib::Mutex::Lock lm (automation_lock);
2527 if (state != _gain_automation_curve.automation_state()) {
2529 last_automation_snapshot = 0;
2530 _gain_automation_curve.set_automation_state (state);
2533 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2539 _session.set_dirty ();
2540 gain_automation_state_changed (); /* EMIT SIGNAL */
2545 IO::set_gain_automation_style (AutoStyle style)
2547 bool changed = false;
2550 Glib::Mutex::Lock lm (automation_lock);
2552 if (style != _gain_automation_curve.automation_style()) {
2554 _gain_automation_curve.set_automation_style (style);
2559 gain_automation_style_changed (); /* EMIT SIGNAL */
2563 IO::inc_gain (gain_t factor, void *src)
2565 if (_desired_gain == 0.0f)
2566 set_gain (0.000001f + (0.000001f * factor), src);
2568 set_gain (_desired_gain + (_desired_gain * factor), src);
2572 IO::set_gain (gain_t val, void *src)
2574 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2575 if (val>1.99526231f) val=1.99526231f;
2578 Glib::Mutex::Lock dm (declick_lock);
2579 _desired_gain = val;
2582 if (_session.transport_stopped()) {
2583 _effective_gain = val;
2588 _gain_control.Changed (); /* EMIT SIGNAL */
2590 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2591 _gain_automation_curve.add (_session.transport_frame(), val);
2595 _session.set_dirty();
2599 IO::start_gain_touch ()
2601 _gain_automation_curve.start_touch ();
2605 IO::end_gain_touch ()
2607 _gain_automation_curve.stop_touch ();
2611 IO::start_pan_touch (uint32_t which)
2613 if (which < _panner->size()) {
2614 (*_panner)[which]->automation().start_touch();
2619 IO::end_pan_touch (uint32_t which)
2621 if (which < _panner->size()) {
2622 (*_panner)[which]->automation().stop_touch();
2628 IO::automation_snapshot (nframes_t now)
2630 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2632 if (gain_automation_recording()) {
2633 _gain_automation_curve.rt_add (now, gain());
2636 _panner->snapshot (now);
2638 last_automation_snapshot = now;
2643 IO::transport_stopped (nframes_t frame)
2645 _gain_automation_curve.reposition_for_rt_add (frame);
2647 if (_gain_automation_curve.automation_state() != Off) {
2649 /* the src=0 condition is a special signal to not propagate
2650 automation gain changes into the mix group when locating.
2653 set_gain (_gain_automation_curve.eval (frame), 0);
2656 _panner->transport_stopped (frame);
2660 IO::find_input_port_hole ()
2662 /* CALLER MUST HOLD IO LOCK */
2666 if (_inputs.empty()) {
2670 for (n = 1; n < UINT_MAX; ++n) {
2671 char buf[jack_port_name_size()];
2672 vector<Port*>::iterator i;
2674 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2676 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2677 if ((*i)->short_name() == buf) {
2682 if (i == _inputs.end()) {
2690 IO::find_output_port_hole ()
2692 /* CALLER MUST HOLD IO LOCK */
2696 if (_outputs.empty()) {
2700 for (n = 1; n < UINT_MAX; ++n) {
2701 char buf[jack_port_name_size()];
2702 vector<Port*>::iterator i;
2704 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2706 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2707 if ((*i)->short_name() == buf) {
2712 if (i == _outputs.end()) {