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;
183 BLOCK_PROCESS_CALLBACK ();
185 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
186 _session.engine().unregister_port (*i);
189 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
190 _session.engine().unregister_port (*i);
194 m_meter_connection.disconnect();
198 IO::silence (nframes_t nframes, nframes_t offset)
200 /* io_lock, not taken: function must be called from Session::process() calltree */
202 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
203 (*i)->silence (nframes, offset);
208 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
210 nframes_t declick = min ((nframes_t)128, nframes);
213 double fractional_shift;
214 double fractional_pos;
215 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
217 if (nframes == 0) return;
219 fractional_shift = -1.0/declick;
221 if (target < initial) {
222 /* fade out: remove more and more of delta from initial */
223 delta = -(initial - target);
225 /* fade in: add more and more of delta from initial */
226 delta = target - initial;
229 for (uint32_t n = 0; n < nbufs; ++n) {
232 fractional_pos = 1.0;
234 for (nframes_t nx = 0; nx < declick; ++nx) {
235 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
236 fractional_pos += fractional_shift;
239 /* now ensure the rest of the buffer has the target value
240 applied, if necessary.
243 if (declick != nframes) {
246 if (invert_polarity) {
247 this_target = -target;
249 this_target = target;
252 if (this_target == 0.0) {
253 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
254 } else if (this_target != 1.0) {
255 for (nframes_t nx = declick; nx < nframes; ++nx) {
256 buffer[nx] *= this_target;
264 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
268 /* io_lock, not taken: function must be called from Session::process() calltree */
270 if (_noutputs == 0) {
274 if (_noutputs == 1) {
276 dst = output(0)->get_buffer (nframes) + offset;
278 for (uint32_t n = 0; n < nbufs; ++n) {
279 if (bufs[n] != dst) {
280 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
284 output(0)->mark_silence (false);
290 vector<Port *>::iterator out;
291 vector<Sample *>::iterator in;
292 Panner::iterator pan;
293 Sample* obufs[_noutputs];
295 /* the terrible silence ... */
297 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
298 obufs[o] = (*out)->get_buffer (nframes) + offset;
299 memset (obufs[o], 0, sizeof (Sample) * nframes);
300 (*out)->mark_silence (false);
305 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
306 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
311 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
316 /* io_lock, not taken: function must be called from Session::process() calltree */
318 if (_noutputs == 0) {
322 /* the panner can be empty if there are no inputs to the
323 route, but still outputs
326 if (_panner->bypassed() || _panner->empty()) {
327 deliver_output_no_pan (bufs, nbufs, nframes, offset);
331 if (_noutputs == 1) {
333 dst = output(0)->get_buffer (nframes) + offset;
335 if (gain_coeff == 0.0f) {
337 /* only one output, and gain was zero, so make it silent */
339 memset (dst, 0, sizeof (Sample) * nframes);
341 } else if (gain_coeff == 1.0f){
343 /* mix all buffers into the output */
347 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
349 for (n = 1; n < nbufs; ++n) {
350 Session::mix_buffers_no_gain(dst,bufs[n],nframes);
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) {
368 Session::mix_buffers_with_gain(dst,bufs[n],nframes,gain_coeff);
371 output(0)->mark_silence (false);
378 vector<Port *>::iterator out;
379 vector<Sample *>::iterator in;
380 Panner::iterator pan;
381 Sample* obufs[_noutputs];
383 /* the terrible silence ... */
385 /* XXX this is wasteful but i see no way to avoid it */
387 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
388 obufs[o] = (*out)->get_buffer (nframes) + offset;
389 memset (obufs[o], 0, sizeof (Sample) * nframes);
390 (*out)->mark_silence (false);
395 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
396 Panner::iterator tmp;
401 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
403 if (tmp != _panner->end()) {
410 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
412 /* io_lock, not taken: function must be called from Session::process() calltree */
414 if (_noutputs == 0) {
418 if (_panner->bypassed() || _panner->empty()) {
419 deliver_output_no_pan (bufs, nbufs, nframes, offset);
425 gain_t pangain = _gain;
428 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
438 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
443 /* simple, non-automation panning to outputs */
445 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
446 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
448 pan (bufs, nbufs, nframes, offset, pangain);
453 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
455 /* io_lock, not taken: function must be called from Session::process() calltree */
457 if (_noutputs == 0) {
462 gain_t old_gain = _gain;
464 if (apply_gain_automation || _ignore_gain_on_deliver) {
466 /* gain has already been applied by automation code. do nothing here except
475 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
487 vector<Port*>::iterator o;
488 vector<Sample*> outs;
491 /* reduce nbufs to the index of the last input buffer */
495 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
496 actual_gain = _gain * speed_quietning;
501 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
503 dst = (*o)->get_buffer (nframes) + offset;
504 src = bufs[min(nbufs,i)];
507 /* unlikely condition */
508 outs.push_back (dst);
511 if (dg != _gain || actual_gain == 1.0f) {
512 memcpy (dst, src, sizeof (Sample) * nframes);
513 } else if (actual_gain == 0.0f) {
514 memset (dst, 0, sizeof (Sample) * nframes);
516 for (nframes_t x = 0; x < nframes; ++x) {
517 dst[x] = src[x] * actual_gain;
521 (*o)->mark_silence (false);
525 apply_declick (outs, i, nframes, _gain, dg, false);
529 if (apply_gain_automation || _ignore_gain_on_deliver) {
535 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
537 /* io_lock, not taken: function must be called from Session::process() calltree */
539 vector<Port *>::iterator i;
543 /* we require that bufs.size() >= 1 */
545 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
546 if (i == _inputs.end()) {
550 /* XXX always read the full extent of the port buffer that
551 we need. One day, we may use jack_port_get_buffer_at_offset()
552 or something similar. For now, this simple hack will
555 Hack? Why yes .. we only need to read nframes-worth of
556 data, but the data we want is at `offset' within the
560 last = (*i)->get_buffer (nframes+offset) + offset;
561 // the dest buffer's offset has already been applied
562 memcpy (bufs[n], last, sizeof (Sample) * nframes);
565 /* fill any excess outputs with the last input */
569 // the dest buffer's offset has already been applied
570 memcpy (bufs[n], last, sizeof (Sample) * nframes);
575 memset (bufs[n], 0, sizeof (Sample) * nframes);
582 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
583 nframes_t nframes, nframes_t offset)
585 vector<Sample*>& bufs = _session.get_passthru_buffers ();
586 uint32_t nbufs = n_process_buffers ();
588 collect_input (bufs, nbufs, nframes, offset);
590 for (uint32_t n = 0; n < nbufs; ++n) {
591 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
596 IO::drop_input_connection ()
598 _input_connection = 0;
599 input_connection_configuration_connection.disconnect();
600 input_connection_connection_connection.disconnect();
601 _session.set_dirty ();
605 IO::drop_output_connection ()
607 _output_connection = 0;
608 output_connection_configuration_connection.disconnect();
609 output_connection_connection_connection.disconnect();
610 _session.set_dirty ();
614 IO::disconnect_input (Port* our_port, string other_port, void* src)
616 if (other_port.length() == 0 || our_port == 0) {
621 BLOCK_PROCESS_CALLBACK ();
624 Glib::Mutex::Lock lm (io_lock);
626 /* check that our_port is really one of ours */
628 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
632 /* disconnect it from the source */
634 if (_session.engine().disconnect (other_port, our_port->name())) {
635 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
639 drop_input_connection();
643 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
644 _session.set_dirty ();
650 IO::connect_input (Port* our_port, string other_port, void* src)
652 if (other_port.length() == 0 || our_port == 0) {
657 BLOCK_PROCESS_CALLBACK ();
660 Glib::Mutex::Lock lm (io_lock);
662 /* check that our_port is really one of ours */
664 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
668 /* connect it to the source */
670 if (_session.engine().connect (other_port, our_port->name())) {
674 drop_input_connection ();
678 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
679 _session.set_dirty ();
684 IO::disconnect_output (Port* our_port, string other_port, void* src)
686 if (other_port.length() == 0 || our_port == 0) {
691 BLOCK_PROCESS_CALLBACK ();
694 Glib::Mutex::Lock lm (io_lock);
696 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
700 /* disconnect it from the destination */
702 if (_session.engine().disconnect (our_port->name(), other_port)) {
703 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
707 drop_output_connection ();
711 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
712 _session.set_dirty ();
717 IO::connect_output (Port* our_port, string other_port, void* src)
719 if (other_port.length() == 0 || our_port == 0) {
724 BLOCK_PROCESS_CALLBACK ();
728 Glib::Mutex::Lock lm (io_lock);
730 /* check that our_port is really one of ours */
732 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
736 /* connect it to the destination */
738 if (_session.engine().connect (our_port->name(), other_port)) {
742 drop_output_connection ();
746 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
747 _session.set_dirty ();
752 IO::set_input (Port* other_port, void* src)
754 /* this removes all but one ports, and connects that one port
755 to the specified source.
758 if (_input_minimum > 1 || _input_minimum == 0) {
759 /* sorry, you can't do this */
763 if (other_port == 0) {
764 if (_input_minimum < 0) {
765 return ensure_inputs (0, false, true, src);
771 if (ensure_inputs (1, true, true, src)) {
775 return connect_input (_inputs.front(), other_port->name(), src);
779 IO::remove_output_port (Port* port, void* src)
781 IOChange change (NoChange);
784 BLOCK_PROCESS_CALLBACK ();
788 Glib::Mutex::Lock lm (io_lock);
790 if (_noutputs - 1 == (uint32_t) _output_minimum) {
791 /* sorry, you can't do this */
795 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
797 change = IOChange (change|ConfigurationChanged);
798 if (port->connected()) {
799 change = IOChange (change|ConnectionsChanged);
802 _session.engine().unregister_port (*i);
805 drop_output_connection ();
811 if (change != NoChange) {
812 setup_peak_meters ();
818 if (change != NoChange) {
819 output_changed (change, src); /* EMIT SIGNAL */
820 _session.set_dirty ();
827 /** Add an output port.
829 * @param destination Name of input port to connect new port to.
830 * @param src Source for emitted ConfigurationChanged signal.
831 * @param type Data type of port. Default value (NIL) will use this IO's default type.
834 IO::add_output_port (string destination, void* src, DataType type)
839 if (type == DataType::NIL)
840 type = _default_type;
843 BLOCK_PROCESS_CALLBACK ();
847 Glib::Mutex::Lock lm (io_lock);
849 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
853 /* Create a new output port */
855 // FIXME: naming scheme for differently typed ports?
856 if (_output_maximum == 1) {
857 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
859 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
862 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
863 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
867 _outputs.push_back (our_port);
868 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
870 drop_output_connection ();
871 setup_peak_meters ();
875 MoreOutputs (_noutputs); /* EMIT SIGNAL */
878 if (destination.length()) {
879 if (_session.engine().connect (our_port->name(), destination)) {
884 // pan_changed (src); /* EMIT SIGNAL */
885 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
886 _session.set_dirty ();
891 IO::remove_input_port (Port* port, void* src)
893 IOChange change (NoChange);
896 BLOCK_PROCESS_CALLBACK ();
900 Glib::Mutex::Lock lm (io_lock);
902 if (((int)_ninputs - 1) < _input_minimum) {
903 /* sorry, you can't do this */
906 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
909 change = IOChange (change|ConfigurationChanged);
911 if (port->connected()) {
912 change = IOChange (change|ConnectionsChanged);
915 _session.engine().unregister_port (*i);
918 drop_input_connection ();
924 if (change != NoChange) {
925 setup_peak_meters ();
931 if (change != NoChange) {
932 input_changed (change, src);
933 _session.set_dirty ();
941 /** Add an input port.
943 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
944 * @param destination Name of input port to connect new port to.
945 * @param src Source for emitted ConfigurationChanged signal.
948 IO::add_input_port (string source, void* src, DataType type)
953 if (type == DataType::NIL)
954 type = _default_type;
957 BLOCK_PROCESS_CALLBACK ();
960 Glib::Mutex::Lock lm (io_lock);
962 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
966 /* Create a new input port */
968 // FIXME: naming scheme for differently typed ports?
969 if (_input_maximum == 1) {
970 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
972 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
975 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
976 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
980 _inputs.push_back (our_port);
981 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
983 drop_input_connection ();
984 setup_peak_meters ();
988 MoreOutputs (_ninputs); /* EMIT SIGNAL */
991 if (source.length()) {
993 if (_session.engine().connect (source, our_port->name())) {
998 // pan_changed (src); /* EMIT SIGNAL */
999 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1000 _session.set_dirty ();
1006 IO::disconnect_inputs (void* src)
1009 BLOCK_PROCESS_CALLBACK ();
1012 Glib::Mutex::Lock lm (io_lock);
1014 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1015 _session.engine().disconnect (*i);
1018 drop_input_connection ();
1021 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1026 IO::disconnect_outputs (void* src)
1029 BLOCK_PROCESS_CALLBACK ();
1032 Glib::Mutex::Lock lm (io_lock);
1034 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1035 _session.engine().disconnect (*i);
1038 drop_output_connection ();
1042 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1043 _session.set_dirty ();
1048 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1051 bool changed = false;
1052 bool reduced = false;
1054 /* remove unused ports */
1056 while (_ninputs > n) {
1057 _session.engine().unregister_port (_inputs.back());
1064 /* create any necessary new ports */
1066 while (_ninputs < n) {
1070 /* Create a new input port (of the default type) */
1072 if (_input_maximum == 1) {
1073 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1076 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1081 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1082 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1087 catch (AudioEngine::PortRegistrationFailure& err) {
1088 setup_peak_meters ();
1091 throw AudioEngine::PortRegistrationFailure();
1094 _inputs.push_back (input_port);
1095 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1101 drop_input_connection ();
1102 setup_peak_meters ();
1104 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1105 _session.set_dirty ();
1109 /* disconnect all existing ports so that we get a fresh start */
1111 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1112 _session.engine().disconnect (*i);
1120 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1122 bool in_changed = false;
1123 bool out_changed = false;
1124 bool in_reduced = false;
1125 bool out_reduced = false;
1126 bool need_pan_reset;
1128 if (_input_maximum >= 0) {
1129 nin = min (_input_maximum, (int) nin);
1132 if (_output_maximum >= 0) {
1133 nout = min (_output_maximum, (int) nout);
1136 if (nin == _ninputs && nout == _noutputs && !clear) {
1141 BLOCK_PROCESS_CALLBACK ();
1142 Glib::Mutex::Lock lm (io_lock);
1146 if (_noutputs == nout) {
1147 need_pan_reset = false;
1149 need_pan_reset = true;
1152 /* remove unused ports */
1154 while (_ninputs > nin) {
1155 _session.engine().unregister_port (_inputs.back());
1162 while (_noutputs > nout) {
1163 _session.engine().unregister_port (_outputs.back());
1164 _outputs.pop_back();
1170 /* create any necessary new ports (of the default type) */
1172 while (_ninputs < nin) {
1176 /* Create a new input port */
1178 if (_input_maximum == 1) {
1179 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1182 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1186 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1187 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1192 catch (AudioEngine::PortRegistrationFailure& err) {
1193 setup_peak_meters ();
1196 throw AudioEngine::PortRegistrationFailure();
1199 _inputs.push_back (port);
1204 /* create any necessary new ports */
1206 while (_noutputs < nout) {
1210 /* Create a new output port */
1212 if (_output_maximum == 1) {
1213 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1215 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1219 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1220 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1225 catch (AudioEngine::PortRegistrationFailure& err) {
1226 setup_peak_meters ();
1229 throw AudioEngine::PortRegistrationFailure ();
1232 _outputs.push_back (port);
1239 /* disconnect all existing ports so that we get a fresh start */
1241 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1242 _session.engine().disconnect (*i);
1245 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1246 _session.engine().disconnect (*i);
1250 if (in_changed || out_changed) {
1251 setup_peak_meters ();
1257 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1258 drop_output_connection ();
1259 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1263 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1264 drop_input_connection ();
1265 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1268 if (in_changed || out_changed) {
1269 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1270 _session.set_dirty ();
1277 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1279 bool changed = false;
1281 if (_input_maximum >= 0) {
1282 n = min (_input_maximum, (int) n);
1284 if (n == _ninputs && !clear) {
1290 BLOCK_PROCESS_CALLBACK ();
1291 Glib::Mutex::Lock im (io_lock);
1292 changed = ensure_inputs_locked (n, clear, src);
1294 changed = ensure_inputs_locked (n, clear, src);
1298 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1299 _session.set_dirty ();
1306 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1309 bool changed = false;
1310 bool reduced = false;
1311 bool need_pan_reset;
1313 if (_noutputs == n) {
1314 need_pan_reset = false;
1316 need_pan_reset = true;
1319 /* remove unused ports */
1321 while (_noutputs > n) {
1323 _session.engine().unregister_port (_outputs.back());
1324 _outputs.pop_back();
1330 /* create any necessary new ports */
1332 while (_noutputs < n) {
1336 /* Create a new output port */
1338 if (_output_maximum == 1) {
1339 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1341 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1344 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1345 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1349 _outputs.push_back (output_port);
1350 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1353 setup_peak_meters ();
1355 if (need_pan_reset) {
1361 drop_output_connection ();
1362 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1363 _session.set_dirty ();
1367 /* disconnect all existing ports so that we get a fresh start */
1369 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1370 _session.engine().disconnect (*i);
1378 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1380 bool changed = false;
1382 if (_output_maximum >= 0) {
1383 n = min (_output_maximum, (int) n);
1384 if (n == _noutputs && !clear) {
1389 /* XXX caller should hold io_lock, but generally doesn't */
1392 BLOCK_PROCESS_CALLBACK ();
1393 Glib::Mutex::Lock im (io_lock);
1394 changed = ensure_outputs_locked (n, clear, src);
1396 changed = ensure_outputs_locked (n, clear, src);
1400 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1407 IO::effective_gain () const
1409 if (gain_automation_playback()) {
1410 return _effective_gain;
1412 return _desired_gain;
1419 if (panners_legal) {
1420 if (!no_panner_reset) {
1421 _panner->reset (_noutputs, pans_required());
1424 panner_legal_c.disconnect ();
1425 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1430 IO::panners_became_legal ()
1432 _panner->reset (_noutputs, pans_required());
1433 _panner->load (); // automation
1434 panner_legal_c.disconnect ();
1439 IO::defer_pan_reset ()
1441 no_panner_reset = true;
1445 IO::allow_pan_reset ()
1447 no_panner_reset = false;
1453 IO::get_state (void)
1455 return state (true);
1459 IO::state (bool full_state)
1461 XMLNode* node = new XMLNode (state_node_name);
1464 bool need_ins = true;
1465 bool need_outs = true;
1466 LocaleGuard lg (X_("POSIX"));
1467 Glib::Mutex::Lock lm (io_lock);
1469 node->add_property("name", _name);
1470 id().print (buf, sizeof (buf));
1471 node->add_property("id", buf);
1475 if (_input_connection) {
1476 node->add_property ("input-connection", _input_connection->name());
1480 if (_output_connection) {
1481 node->add_property ("output-connection", _output_connection->name());
1486 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1488 const char **connections = (*i)->get_connections();
1490 if (connections && connections[0]) {
1493 for (int n = 0; connections && connections[n]; ++n) {
1498 /* if its a connection to our own port,
1499 return only the port name, not the
1500 whole thing. this allows connections
1501 to be re-established even when our
1502 client name is different.
1505 str += _session.engine().make_port_name_relative (connections[n]);
1517 node->add_property ("inputs", str);
1523 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1525 const char **connections = (*i)->get_connections();
1527 if (connections && connections[0]) {
1531 for (int n = 0; connections[n]; ++n) {
1536 str += _session.engine().make_port_name_relative (connections[n]);
1548 node->add_property ("outputs", str);
1551 node->add_child_nocopy (_panner->state (full_state));
1552 node->add_child_nocopy (_gain_control.get_state ());
1554 snprintf (buf, sizeof(buf), "%2.12f", gain());
1555 node->add_property ("gain", buf);
1557 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1563 node->add_property ("iolimits", buf);
1569 XMLNode* autonode = new XMLNode (X_("Automation"));
1570 autonode->add_child_nocopy (get_automation_state());
1571 node->add_child_nocopy (*autonode);
1573 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1575 /* never store anything except Off for automation state in a template */
1576 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1583 IO::set_state (const XMLNode& node)
1585 const XMLProperty* prop;
1586 XMLNodeConstIterator iter;
1587 LocaleGuard lg (X_("POSIX"));
1589 /* force use of non-localized representation of decimal point,
1590 since we use it a lot in XML files and so forth.
1593 if (node.name() != state_node_name) {
1594 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1598 if ((prop = node.property ("name")) != 0) {
1599 _name = prop->value();
1600 /* used to set panner name with this, but no more */
1603 if ((prop = node.property ("id")) != 0) {
1604 _id = prop->value ();
1607 if ((prop = node.property ("iolimits")) != 0) {
1608 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1615 if ((prop = node.property ("gain")) != 0) {
1616 set_gain (atof (prop->value().c_str()), this);
1617 _gain = _desired_gain;
1620 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1621 /* old school automation handling */
1624 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1626 if ((*iter)->name() == "Panner") {
1628 _panner = new Panner (_name, _session);
1630 _panner->set_state (**iter);
1633 if ((*iter)->name() == X_("Automation")) {
1635 set_automation_state (*(*iter)->children().front());
1638 if ((*iter)->name() == X_("controllable")) {
1639 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1640 _gain_control.set_state (**iter);
1647 if (create_ports (node)) {
1653 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1656 if (panners_legal) {
1659 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1662 if (connecting_legal) {
1664 if (make_connections (node)) {
1670 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1673 if (!ports_legal || !connecting_legal) {
1674 pending_state_node = new XMLNode (node);
1677 last_automation_snapshot = 0;
1683 IO::set_automation_state (const XMLNode& node)
1685 return _gain_automation_curve.set_state (node);
1689 IO::get_automation_state ()
1691 return (_gain_automation_curve.get_state ());
1695 IO::load_automation (string path)
1700 uint32_t linecnt = 0;
1702 LocaleGuard lg (X_("POSIX"));
1704 fullpath = _session.automation_dir();
1707 in.open (fullpath.c_str());
1710 fullpath = _session.automation_dir();
1711 fullpath += _session.snap_name();
1715 in.open (fullpath.c_str());
1718 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1723 clear_automation ();
1725 while (in.getline (line, sizeof(line), '\n')) {
1727 jack_nframes_t when;
1730 if (++linecnt == 1) {
1731 if (memcmp (line, "version", 7) == 0) {
1732 if (sscanf (line, "version %f", &version) != 1) {
1733 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1737 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1744 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1745 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1751 _gain_automation_curve.fast_simple_add (when, value);
1761 /* older (pre-1.0) versions of ardour used this */
1765 warning << _("dubious automation event found (and ignored)") << endmsg;
1773 IO::connecting_became_legal ()
1777 if (pending_state_node == 0) {
1778 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1783 connection_legal_c.disconnect ();
1785 ret = make_connections (*pending_state_node);
1788 delete pending_state_node;
1789 pending_state_node = 0;
1795 IO::ports_became_legal ()
1799 if (pending_state_node == 0) {
1800 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1805 port_legal_c.disconnect ();
1807 ret = create_ports (*pending_state_node);
1809 if (connecting_legal) {
1810 delete pending_state_node;
1811 pending_state_node = 0;
1818 IO::create_ports (const XMLNode& node)
1820 const XMLProperty* prop;
1822 int num_outputs = 0;
1824 if ((prop = node.property ("input-connection")) != 0) {
1826 Connection* c = _session.connection_by_name (prop->value());
1829 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1831 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1832 error << _("No input connections available as a replacement")
1836 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1841 num_inputs = c->nports();
1843 } else if ((prop = node.property ("inputs")) != 0) {
1845 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1848 if ((prop = node.property ("output-connection")) != 0) {
1849 Connection* c = _session.connection_by_name (prop->value());
1852 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1854 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1855 error << _("No output connections available as a replacement")
1859 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1864 num_outputs = c->nports ();
1866 } else if ((prop = node.property ("outputs")) != 0) {
1867 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1870 no_panner_reset = true;
1872 if (ensure_io (num_inputs, num_outputs, true, this)) {
1873 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1877 no_panner_reset = false;
1879 set_deferred_state ();
1887 IO::make_connections (const XMLNode& node)
1889 const XMLProperty* prop;
1891 if ((prop = node.property ("input-connection")) != 0) {
1892 Connection* c = _session.connection_by_name (prop->value());
1895 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1897 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1898 error << _("No input connections available as a replacement")
1902 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1907 use_input_connection (*c, this);
1909 } else if ((prop = node.property ("inputs")) != 0) {
1910 if (set_inputs (prop->value())) {
1911 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1916 if ((prop = node.property ("output-connection")) != 0) {
1917 Connection* c = _session.connection_by_name (prop->value());
1920 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1922 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1923 error << _("No output connections available as a replacement")
1927 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1932 use_output_connection (*c, this);
1934 } else if ((prop = node.property ("outputs")) != 0) {
1935 if (set_outputs (prop->value())) {
1936 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1945 IO::set_inputs (const string& str)
1947 vector<string> ports;
1952 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1956 if (ensure_inputs (nports, true, true, this)) {
1960 string::size_type start, end, ostart;
1967 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1970 if ((end = str.find_first_of ('}', start)) == string::npos) {
1971 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1975 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1976 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1982 for (int x = 0; x < n; ++x) {
1983 connect_input (input (i), ports[x], this);
1995 IO::set_outputs (const string& str)
1997 vector<string> ports;
2002 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2006 if (ensure_outputs (nports, true, true, this)) {
2010 string::size_type start, end, ostart;
2017 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2020 if ((end = str.find_first_of ('}', start)) == string::npos) {
2021 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2025 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2026 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2032 for (int x = 0; x < n; ++x) {
2033 connect_output (output (i), ports[x], this);
2045 IO::parse_io_string (const string& str, vector<string>& ports)
2047 string::size_type pos, opos;
2049 if (str.length() == 0) {
2058 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2059 ports.push_back (str.substr (opos, pos - opos));
2063 if (opos < str.length()) {
2064 ports.push_back (str.substr(opos));
2067 return ports.size();
2071 IO::parse_gain_string (const string& str, vector<string>& ports)
2073 string::size_type pos, opos;
2079 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2080 ports.push_back (str.substr (opos, pos - opos));
2084 if (opos < str.length()) {
2085 ports.push_back (str.substr(opos));
2088 return ports.size();
2092 IO::set_name (string name, void* src)
2094 if (name == _name) {
2098 /* replace all colons in the name. i wish we didn't have to do this */
2100 if (replace_all (name, ":", "-")) {
2101 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
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]);
2504 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2505 _visible_peak_power[n] = new_peak;
2507 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2508 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2509 _visible_peak_power[n] = max (new_peak, -INFINITY);
2515 IO::clear_automation ()
2517 Glib::Mutex::Lock lm (automation_lock);
2518 _gain_automation_curve.clear ();
2519 _panner->clear_automation ();
2523 IO::set_gain_automation_state (AutoState state)
2525 bool changed = false;
2528 Glib::Mutex::Lock lm (automation_lock);
2530 if (state != _gain_automation_curve.automation_state()) {
2532 last_automation_snapshot = 0;
2533 _gain_automation_curve.set_automation_state (state);
2536 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2542 _session.set_dirty ();
2543 gain_automation_state_changed (); /* EMIT SIGNAL */
2548 IO::set_gain_automation_style (AutoStyle style)
2550 bool changed = false;
2553 Glib::Mutex::Lock lm (automation_lock);
2555 if (style != _gain_automation_curve.automation_style()) {
2557 _gain_automation_curve.set_automation_style (style);
2562 gain_automation_style_changed (); /* EMIT SIGNAL */
2566 IO::inc_gain (gain_t factor, void *src)
2568 if (_desired_gain == 0.0f)
2569 set_gain (0.000001f + (0.000001f * factor), src);
2571 set_gain (_desired_gain + (_desired_gain * factor), src);
2575 IO::set_gain (gain_t val, void *src)
2577 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2578 if (val>1.99526231f) val=1.99526231f;
2581 Glib::Mutex::Lock dm (declick_lock);
2582 _desired_gain = val;
2585 if (_session.transport_stopped()) {
2586 _effective_gain = val;
2591 _gain_control.Changed (); /* EMIT SIGNAL */
2593 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2594 _gain_automation_curve.add (_session.transport_frame(), val);
2597 _session.set_dirty();
2601 IO::start_gain_touch ()
2603 _gain_automation_curve.start_touch ();
2607 IO::end_gain_touch ()
2609 _gain_automation_curve.stop_touch ();
2613 IO::start_pan_touch (uint32_t which)
2615 if (which < _panner->size()) {
2616 (*_panner)[which]->automation().start_touch();
2621 IO::end_pan_touch (uint32_t which)
2623 if (which < _panner->size()) {
2624 (*_panner)[which]->automation().stop_touch();
2630 IO::automation_snapshot (nframes_t now)
2632 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2634 if (gain_automation_recording()) {
2635 _gain_automation_curve.rt_add (now, gain());
2638 _panner->snapshot (now);
2640 last_automation_snapshot = now;
2645 IO::transport_stopped (nframes_t frame)
2647 _gain_automation_curve.reposition_for_rt_add (frame);
2649 if (_gain_automation_curve.automation_state() != Off) {
2651 /* the src=0 condition is a special signal to not propagate
2652 automation gain changes into the mix group when locating.
2655 set_gain (_gain_automation_curve.eval (frame), 0);
2658 _panner->transport_stopped (frame);
2662 IO::find_input_port_hole ()
2664 /* CALLER MUST HOLD IO LOCK */
2668 if (_inputs.empty()) {
2672 for (n = 1; n < UINT_MAX; ++n) {
2673 char buf[jack_port_name_size()];
2674 vector<Port*>::iterator i;
2676 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2678 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2679 if ((*i)->short_name() == buf) {
2684 if (i == _inputs.end()) {
2692 IO::find_output_port_hole ()
2694 /* CALLER MUST HOLD IO LOCK */
2698 if (_outputs.empty()) {
2702 for (n = 1; n < UINT_MAX; ++n) {
2703 char buf[jack_port_name_size()];
2704 vector<Port*>::iterator i;
2706 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2708 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2709 if ((*i)->short_name() == buf) {
2714 if (i == _outputs.end()) {