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;
488 /* unlikely condition */
489 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
490 outs.push_back ((*o)->get_buffer (nframes) + offset);
494 /* reduce nbufs to the index of the last input buffer */
498 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
499 actual_gain = _gain * speed_quietning;
504 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
506 dst = (*o)->get_buffer (nframes) + offset;
507 src = bufs[min(nbufs,i)];
509 if (dg != _gain || actual_gain == 1.0f) {
510 memcpy (dst, src, sizeof (Sample) * nframes);
511 } else if (actual_gain == 0.0f) {
512 memset (dst, 0, sizeof (Sample) * nframes);
514 for (nframes_t x = 0; x < nframes; ++x) {
515 dst[x] = src[x] * actual_gain;
519 (*o)->mark_silence (false);
523 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
527 if (apply_gain_automation || _ignore_gain_on_deliver) {
533 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
535 /* io_lock, not taken: function must be called from Session::process() calltree */
537 vector<Port *>::iterator i;
541 /* we require that bufs.size() >= 1 */
543 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
544 if (i == _inputs.end()) {
548 /* XXX always read the full extent of the port buffer that
549 we need. One day, we may use jack_port_get_buffer_at_offset()
550 or something similar. For now, this simple hack will
553 Hack? Why yes .. we only need to read nframes-worth of
554 data, but the data we want is at `offset' within the
558 last = (*i)->get_buffer (nframes+offset) + offset;
559 // the dest buffer's offset has already been applied
560 memcpy (bufs[n], last, sizeof (Sample) * nframes);
563 /* fill any excess outputs with the last input */
567 // the dest buffer's offset has already been applied
568 memcpy (bufs[n], last, sizeof (Sample) * nframes);
573 memset (bufs[n], 0, sizeof (Sample) * nframes);
580 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
581 nframes_t nframes, nframes_t offset)
583 vector<Sample*>& bufs = _session.get_passthru_buffers ();
584 uint32_t nbufs = n_process_buffers ();
586 collect_input (bufs, nbufs, nframes, offset);
588 for (uint32_t n = 0; n < nbufs; ++n) {
589 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
594 IO::drop_input_connection ()
596 _input_connection = 0;
597 input_connection_configuration_connection.disconnect();
598 input_connection_connection_connection.disconnect();
599 _session.set_dirty ();
603 IO::drop_output_connection ()
605 _output_connection = 0;
606 output_connection_configuration_connection.disconnect();
607 output_connection_connection_connection.disconnect();
608 _session.set_dirty ();
612 IO::disconnect_input (Port* our_port, string other_port, void* src)
614 if (other_port.length() == 0 || our_port == 0) {
619 BLOCK_PROCESS_CALLBACK ();
622 Glib::Mutex::Lock lm (io_lock);
624 /* check that our_port is really one of ours */
626 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
630 /* disconnect it from the source */
632 if (_session.engine().disconnect (other_port, our_port->name())) {
633 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
637 drop_input_connection();
641 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
642 _session.set_dirty ();
648 IO::connect_input (Port* our_port, string other_port, void* src)
650 if (other_port.length() == 0 || our_port == 0) {
655 BLOCK_PROCESS_CALLBACK ();
658 Glib::Mutex::Lock lm (io_lock);
660 /* check that our_port is really one of ours */
662 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
666 /* connect it to the source */
668 if (_session.engine().connect (other_port, our_port->name())) {
672 drop_input_connection ();
676 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
677 _session.set_dirty ();
682 IO::disconnect_output (Port* our_port, string other_port, void* src)
684 if (other_port.length() == 0 || our_port == 0) {
689 BLOCK_PROCESS_CALLBACK ();
692 Glib::Mutex::Lock lm (io_lock);
694 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
698 /* disconnect it from the destination */
700 if (_session.engine().disconnect (our_port->name(), other_port)) {
701 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
705 drop_output_connection ();
709 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
710 _session.set_dirty ();
715 IO::connect_output (Port* our_port, string other_port, void* src)
717 if (other_port.length() == 0 || our_port == 0) {
722 BLOCK_PROCESS_CALLBACK ();
726 Glib::Mutex::Lock lm (io_lock);
728 /* check that our_port is really one of ours */
730 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
734 /* connect it to the destination */
736 if (_session.engine().connect (our_port->name(), other_port)) {
740 drop_output_connection ();
744 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
745 _session.set_dirty ();
750 IO::set_input (Port* other_port, void* src)
752 /* this removes all but one ports, and connects that one port
753 to the specified source.
756 if (_input_minimum > 1 || _input_minimum == 0) {
757 /* sorry, you can't do this */
761 if (other_port == 0) {
762 if (_input_minimum < 0) {
763 return ensure_inputs (0, false, true, src);
769 if (ensure_inputs (1, true, true, src)) {
773 return connect_input (_inputs.front(), other_port->name(), src);
777 IO::remove_output_port (Port* port, void* src)
779 IOChange change (NoChange);
782 BLOCK_PROCESS_CALLBACK ();
786 Glib::Mutex::Lock lm (io_lock);
788 if (_noutputs - 1 == (uint32_t) _output_minimum) {
789 /* sorry, you can't do this */
793 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
795 change = IOChange (change|ConfigurationChanged);
796 if (port->connected()) {
797 change = IOChange (change|ConnectionsChanged);
800 _session.engine().unregister_port (*i);
803 drop_output_connection ();
809 if (change != NoChange) {
810 setup_peak_meters ();
816 if (change != NoChange) {
817 output_changed (change, src); /* EMIT SIGNAL */
818 _session.set_dirty ();
825 /** Add an output port.
827 * @param destination Name of input port to connect new port to.
828 * @param src Source for emitted ConfigurationChanged signal.
829 * @param type Data type of port. Default value (NIL) will use this IO's default type.
832 IO::add_output_port (string destination, void* src, DataType type)
837 if (type == DataType::NIL)
838 type = _default_type;
841 BLOCK_PROCESS_CALLBACK ();
845 Glib::Mutex::Lock lm (io_lock);
847 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
851 /* Create a new output port */
853 // FIXME: naming scheme for differently typed ports?
854 if (_output_maximum == 1) {
855 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
857 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
860 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
861 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
865 _outputs.push_back (our_port);
866 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
868 drop_output_connection ();
869 setup_peak_meters ();
873 MoreOutputs (_noutputs); /* EMIT SIGNAL */
876 if (destination.length()) {
877 if (_session.engine().connect (our_port->name(), destination)) {
882 // pan_changed (src); /* EMIT SIGNAL */
883 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
884 _session.set_dirty ();
889 IO::remove_input_port (Port* port, void* src)
891 IOChange change (NoChange);
894 BLOCK_PROCESS_CALLBACK ();
898 Glib::Mutex::Lock lm (io_lock);
900 if (((int)_ninputs - 1) < _input_minimum) {
901 /* sorry, you can't do this */
904 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
907 change = IOChange (change|ConfigurationChanged);
909 if (port->connected()) {
910 change = IOChange (change|ConnectionsChanged);
913 _session.engine().unregister_port (*i);
916 drop_input_connection ();
922 if (change != NoChange) {
923 setup_peak_meters ();
929 if (change != NoChange) {
930 input_changed (change, src);
931 _session.set_dirty ();
939 /** Add an input port.
941 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
942 * @param destination Name of input port to connect new port to.
943 * @param src Source for emitted ConfigurationChanged signal.
946 IO::add_input_port (string source, void* src, DataType type)
951 if (type == DataType::NIL)
952 type = _default_type;
955 BLOCK_PROCESS_CALLBACK ();
958 Glib::Mutex::Lock lm (io_lock);
960 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
964 /* Create a new input port */
966 // FIXME: naming scheme for differently typed ports?
967 if (_input_maximum == 1) {
968 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
970 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
973 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
974 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
978 _inputs.push_back (our_port);
979 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
981 drop_input_connection ();
982 setup_peak_meters ();
986 MoreOutputs (_ninputs); /* EMIT SIGNAL */
989 if (source.length()) {
991 if (_session.engine().connect (source, our_port->name())) {
996 // pan_changed (src); /* EMIT SIGNAL */
997 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
998 _session.set_dirty ();
1004 IO::disconnect_inputs (void* src)
1007 BLOCK_PROCESS_CALLBACK ();
1010 Glib::Mutex::Lock lm (io_lock);
1012 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1013 _session.engine().disconnect (*i);
1016 drop_input_connection ();
1019 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1024 IO::disconnect_outputs (void* src)
1027 BLOCK_PROCESS_CALLBACK ();
1030 Glib::Mutex::Lock lm (io_lock);
1032 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1033 _session.engine().disconnect (*i);
1036 drop_output_connection ();
1040 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1041 _session.set_dirty ();
1046 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1049 bool changed = false;
1050 bool reduced = false;
1052 /* remove unused ports */
1054 while (_ninputs > n) {
1055 _session.engine().unregister_port (_inputs.back());
1062 /* create any necessary new ports */
1064 while (_ninputs < n) {
1068 /* Create a new input port (of the default type) */
1070 if (_input_maximum == 1) {
1071 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1074 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1079 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1080 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1085 catch (AudioEngine::PortRegistrationFailure& err) {
1086 setup_peak_meters ();
1089 throw AudioEngine::PortRegistrationFailure();
1092 _inputs.push_back (input_port);
1093 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1099 drop_input_connection ();
1100 setup_peak_meters ();
1102 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1103 _session.set_dirty ();
1107 /* disconnect all existing ports so that we get a fresh start */
1109 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1110 _session.engine().disconnect (*i);
1118 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1120 bool in_changed = false;
1121 bool out_changed = false;
1122 bool in_reduced = false;
1123 bool out_reduced = false;
1124 bool need_pan_reset;
1126 if (_input_maximum >= 0) {
1127 nin = min (_input_maximum, (int) nin);
1130 if (_output_maximum >= 0) {
1131 nout = min (_output_maximum, (int) nout);
1134 if (nin == _ninputs && nout == _noutputs && !clear) {
1139 BLOCK_PROCESS_CALLBACK ();
1140 Glib::Mutex::Lock lm (io_lock);
1144 if (_noutputs == nout) {
1145 need_pan_reset = false;
1147 need_pan_reset = true;
1150 /* remove unused ports */
1152 while (_ninputs > nin) {
1153 _session.engine().unregister_port (_inputs.back());
1160 while (_noutputs > nout) {
1161 _session.engine().unregister_port (_outputs.back());
1162 _outputs.pop_back();
1168 /* create any necessary new ports (of the default type) */
1170 while (_ninputs < nin) {
1174 /* Create a new input port */
1176 if (_input_maximum == 1) {
1177 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1180 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1184 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1185 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1190 catch (AudioEngine::PortRegistrationFailure& err) {
1191 setup_peak_meters ();
1194 throw AudioEngine::PortRegistrationFailure();
1197 _inputs.push_back (port);
1202 /* create any necessary new ports */
1204 while (_noutputs < nout) {
1208 /* Create a new output port */
1210 if (_output_maximum == 1) {
1211 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1213 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1217 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1218 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1223 catch (AudioEngine::PortRegistrationFailure& err) {
1224 setup_peak_meters ();
1227 throw AudioEngine::PortRegistrationFailure ();
1230 _outputs.push_back (port);
1237 /* disconnect all existing ports so that we get a fresh start */
1239 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1240 _session.engine().disconnect (*i);
1243 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1244 _session.engine().disconnect (*i);
1248 if (in_changed || out_changed) {
1249 setup_peak_meters ();
1255 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1256 drop_output_connection ();
1257 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1261 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1262 drop_input_connection ();
1263 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1266 if (in_changed || out_changed) {
1267 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1268 _session.set_dirty ();
1275 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1277 bool changed = false;
1279 if (_input_maximum >= 0) {
1280 n = min (_input_maximum, (int) n);
1282 if (n == _ninputs && !clear) {
1288 BLOCK_PROCESS_CALLBACK ();
1289 Glib::Mutex::Lock im (io_lock);
1290 changed = ensure_inputs_locked (n, clear, src);
1292 changed = ensure_inputs_locked (n, clear, src);
1296 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1297 _session.set_dirty ();
1304 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1307 bool changed = false;
1308 bool reduced = false;
1309 bool need_pan_reset;
1311 if (_noutputs == n) {
1312 need_pan_reset = false;
1314 need_pan_reset = true;
1317 /* remove unused ports */
1319 while (_noutputs > n) {
1321 _session.engine().unregister_port (_outputs.back());
1322 _outputs.pop_back();
1328 /* create any necessary new ports */
1330 while (_noutputs < n) {
1334 /* Create a new output port */
1336 if (_output_maximum == 1) {
1337 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1339 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1342 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1343 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1347 _outputs.push_back (output_port);
1348 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1351 setup_peak_meters ();
1353 if (need_pan_reset) {
1359 drop_output_connection ();
1360 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1361 _session.set_dirty ();
1365 /* disconnect all existing ports so that we get a fresh start */
1367 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1368 _session.engine().disconnect (*i);
1376 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1378 bool changed = false;
1380 if (_output_maximum >= 0) {
1381 n = min (_output_maximum, (int) n);
1382 if (n == _noutputs && !clear) {
1387 /* XXX caller should hold io_lock, but generally doesn't */
1390 BLOCK_PROCESS_CALLBACK ();
1391 Glib::Mutex::Lock im (io_lock);
1392 changed = ensure_outputs_locked (n, clear, src);
1394 changed = ensure_outputs_locked (n, clear, src);
1398 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1405 IO::effective_gain () const
1407 if (gain_automation_playback()) {
1408 return _effective_gain;
1410 return _desired_gain;
1417 if (panners_legal) {
1418 if (!no_panner_reset) {
1419 _panner->reset (_noutputs, pans_required());
1422 panner_legal_c.disconnect ();
1423 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1428 IO::panners_became_legal ()
1430 _panner->reset (_noutputs, pans_required());
1431 _panner->load (); // automation
1432 panner_legal_c.disconnect ();
1437 IO::defer_pan_reset ()
1439 no_panner_reset = true;
1443 IO::allow_pan_reset ()
1445 no_panner_reset = false;
1451 IO::get_state (void)
1453 return state (true);
1457 IO::state (bool full_state)
1459 XMLNode* node = new XMLNode (state_node_name);
1462 bool need_ins = true;
1463 bool need_outs = true;
1464 LocaleGuard lg (X_("POSIX"));
1465 Glib::Mutex::Lock lm (io_lock);
1467 node->add_property("name", _name);
1468 id().print (buf, sizeof (buf));
1469 node->add_property("id", buf);
1473 if (_input_connection) {
1474 node->add_property ("input-connection", _input_connection->name());
1478 if (_output_connection) {
1479 node->add_property ("output-connection", _output_connection->name());
1484 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1486 const char **connections = (*i)->get_connections();
1488 if (connections && connections[0]) {
1491 for (int n = 0; connections && connections[n]; ++n) {
1496 /* if its a connection to our own port,
1497 return only the port name, not the
1498 whole thing. this allows connections
1499 to be re-established even when our
1500 client name is different.
1503 str += _session.engine().make_port_name_relative (connections[n]);
1515 node->add_property ("inputs", str);
1521 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1523 const char **connections = (*i)->get_connections();
1525 if (connections && connections[0]) {
1529 for (int n = 0; connections[n]; ++n) {
1534 str += _session.engine().make_port_name_relative (connections[n]);
1546 node->add_property ("outputs", str);
1549 node->add_child_nocopy (_panner->state (full_state));
1550 node->add_child_nocopy (_gain_control.get_state ());
1552 snprintf (buf, sizeof(buf), "%2.12f", gain());
1553 node->add_property ("gain", buf);
1555 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1561 node->add_property ("iolimits", buf);
1567 XMLNode* autonode = new XMLNode (X_("Automation"));
1568 autonode->add_child_nocopy (get_automation_state());
1569 node->add_child_nocopy (*autonode);
1571 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1573 /* never store anything except Off for automation state in a template */
1574 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1581 IO::set_state (const XMLNode& node)
1583 const XMLProperty* prop;
1584 XMLNodeConstIterator iter;
1585 LocaleGuard lg (X_("POSIX"));
1587 /* force use of non-localized representation of decimal point,
1588 since we use it a lot in XML files and so forth.
1591 if (node.name() != state_node_name) {
1592 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1596 if ((prop = node.property ("name")) != 0) {
1597 _name = prop->value();
1598 /* used to set panner name with this, but no more */
1601 if ((prop = node.property ("id")) != 0) {
1602 _id = prop->value ();
1605 if ((prop = node.property ("iolimits")) != 0) {
1606 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1613 if ((prop = node.property ("gain")) != 0) {
1614 set_gain (atof (prop->value().c_str()), this);
1615 _gain = _desired_gain;
1618 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1619 /* old school automation handling */
1622 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1624 if ((*iter)->name() == "Panner") {
1626 _panner = new Panner (_name, _session);
1628 _panner->set_state (**iter);
1631 if ((*iter)->name() == X_("Automation")) {
1633 set_automation_state (*(*iter)->children().front());
1636 if ((*iter)->name() == X_("controllable")) {
1637 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1638 _gain_control.set_state (**iter);
1645 if (create_ports (node)) {
1651 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1654 if (panners_legal) {
1657 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1660 if (connecting_legal) {
1662 if (make_connections (node)) {
1668 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1671 if (!ports_legal || !connecting_legal) {
1672 pending_state_node = new XMLNode (node);
1675 last_automation_snapshot = 0;
1681 IO::set_automation_state (const XMLNode& node)
1683 return _gain_automation_curve.set_state (node);
1687 IO::get_automation_state ()
1689 return (_gain_automation_curve.get_state ());
1693 IO::load_automation (string path)
1698 uint32_t linecnt = 0;
1700 LocaleGuard lg (X_("POSIX"));
1702 fullpath = _session.automation_dir();
1705 in.open (fullpath.c_str());
1708 fullpath = _session.automation_dir();
1709 fullpath += _session.snap_name();
1713 in.open (fullpath.c_str());
1716 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1721 clear_automation ();
1723 while (in.getline (line, sizeof(line), '\n')) {
1725 jack_nframes_t when;
1728 if (++linecnt == 1) {
1729 if (memcmp (line, "version", 7) == 0) {
1730 if (sscanf (line, "version %f", &version) != 1) {
1731 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1735 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1742 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1743 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1749 _gain_automation_curve.fast_simple_add (when, value);
1759 /* older (pre-1.0) versions of ardour used this */
1763 warning << _("dubious automation event found (and ignored)") << endmsg;
1771 IO::connecting_became_legal ()
1775 if (pending_state_node == 0) {
1776 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1781 connection_legal_c.disconnect ();
1783 ret = make_connections (*pending_state_node);
1786 delete pending_state_node;
1787 pending_state_node = 0;
1793 IO::ports_became_legal ()
1797 if (pending_state_node == 0) {
1798 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1803 port_legal_c.disconnect ();
1805 ret = create_ports (*pending_state_node);
1807 if (connecting_legal) {
1808 delete pending_state_node;
1809 pending_state_node = 0;
1816 IO::create_ports (const XMLNode& node)
1818 const XMLProperty* prop;
1820 int num_outputs = 0;
1822 if ((prop = node.property ("input-connection")) != 0) {
1824 Connection* c = _session.connection_by_name (prop->value());
1827 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1829 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1830 error << _("No input connections available as a replacement")
1834 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1839 num_inputs = c->nports();
1841 } else if ((prop = node.property ("inputs")) != 0) {
1843 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1846 if ((prop = node.property ("output-connection")) != 0) {
1847 Connection* c = _session.connection_by_name (prop->value());
1850 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1852 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1853 error << _("No output connections available as a replacement")
1857 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1862 num_outputs = c->nports ();
1864 } else if ((prop = node.property ("outputs")) != 0) {
1865 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1868 no_panner_reset = true;
1870 if (ensure_io (num_inputs, num_outputs, true, this)) {
1871 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1875 no_panner_reset = false;
1877 set_deferred_state ();
1885 IO::make_connections (const XMLNode& node)
1887 const XMLProperty* prop;
1889 if ((prop = node.property ("input-connection")) != 0) {
1890 Connection* c = _session.connection_by_name (prop->value());
1893 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1895 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1896 error << _("No input connections available as a replacement")
1900 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1905 use_input_connection (*c, this);
1907 } else if ((prop = node.property ("inputs")) != 0) {
1908 if (set_inputs (prop->value())) {
1909 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1914 if ((prop = node.property ("output-connection")) != 0) {
1915 Connection* c = _session.connection_by_name (prop->value());
1918 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1920 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1921 error << _("No output connections available as a replacement")
1925 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1930 use_output_connection (*c, this);
1932 } else if ((prop = node.property ("outputs")) != 0) {
1933 if (set_outputs (prop->value())) {
1934 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1943 IO::set_inputs (const string& str)
1945 vector<string> ports;
1950 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1954 if (ensure_inputs (nports, true, true, this)) {
1958 string::size_type start, end, ostart;
1965 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1968 if ((end = str.find_first_of ('}', start)) == string::npos) {
1969 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1973 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1974 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1980 for (int x = 0; x < n; ++x) {
1981 connect_input (input (i), ports[x], this);
1993 IO::set_outputs (const string& str)
1995 vector<string> ports;
2000 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2004 if (ensure_outputs (nports, true, true, this)) {
2008 string::size_type start, end, ostart;
2015 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2018 if ((end = str.find_first_of ('}', start)) == string::npos) {
2019 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2023 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2024 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2030 for (int x = 0; x < n; ++x) {
2031 connect_output (output (i), ports[x], this);
2043 IO::parse_io_string (const string& str, vector<string>& ports)
2045 string::size_type pos, opos;
2047 if (str.length() == 0) {
2056 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2057 ports.push_back (str.substr (opos, pos - opos));
2061 if (opos < str.length()) {
2062 ports.push_back (str.substr(opos));
2065 return ports.size();
2069 IO::parse_gain_string (const string& str, vector<string>& ports)
2071 string::size_type pos, opos;
2077 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2078 ports.push_back (str.substr (opos, pos - opos));
2082 if (opos < str.length()) {
2083 ports.push_back (str.substr(opos));
2086 return ports.size();
2090 IO::set_name (string name, void* src)
2092 if (name == _name) {
2096 /* replace all colons in the name. i wish we didn't have to do this */
2098 if (replace_all (name, ":", "-")) {
2099 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
2102 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2103 string current_name = (*i)->short_name();
2104 current_name.replace (current_name.find (_name), _name.length(), name);
2105 (*i)->set_name (current_name);
2108 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2109 string current_name = (*i)->short_name();
2110 current_name.replace (current_name.find (_name), _name.length(), name);
2111 (*i)->set_name (current_name);
2115 name_changed (src); /* EMIT SIGNAL */
2121 IO::set_input_minimum (int n)
2127 IO::set_input_maximum (int n)
2133 IO::set_output_minimum (int n)
2135 _output_minimum = n;
2139 IO::set_output_maximum (int n)
2141 _output_maximum = n;
2145 IO::set_port_latency (nframes_t nframes)
2147 Glib::Mutex::Lock lm (io_lock);
2149 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2150 (*i)->set_latency (nframes);
2155 IO::output_latency () const
2157 nframes_t max_latency;
2162 /* io lock not taken - must be protected by other means */
2164 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2165 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2166 max_latency = latency;
2174 IO::input_latency () const
2176 nframes_t max_latency;
2181 /* io lock not taken - must be protected by other means */
2183 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2184 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2185 max_latency = latency;
2193 IO::use_input_connection (Connection& c, void* src)
2198 BLOCK_PROCESS_CALLBACK ();
2199 Glib::Mutex::Lock lm2 (io_lock);
2203 drop_input_connection ();
2205 if (ensure_inputs (limit, false, false, src)) {
2209 /* first pass: check the current state to see what's correctly
2210 connected, and drop anything that we don't want.
2213 for (uint32_t n = 0; n < limit; ++n) {
2214 const Connection::PortList& pl = c.port_connections (n);
2216 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2218 if (!_inputs[n]->connected_to ((*i))) {
2220 /* clear any existing connections */
2222 _session.engine().disconnect (_inputs[n]);
2224 } else if (_inputs[n]->connected() > 1) {
2226 /* OK, it is connected to the port we want,
2227 but its also connected to other ports.
2228 Change that situation.
2231 /* XXX could be optimized to not drop
2235 _session.engine().disconnect (_inputs[n]);
2241 /* second pass: connect all requested ports where necessary */
2243 for (uint32_t n = 0; n < limit; ++n) {
2244 const Connection::PortList& pl = c.port_connections (n);
2246 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2248 if (!_inputs[n]->connected_to ((*i))) {
2250 if (_session.engine().connect (*i, _inputs[n]->name())) {
2258 _input_connection = &c;
2260 input_connection_configuration_connection = c.ConfigurationChanged.connect
2261 (mem_fun (*this, &IO::input_connection_configuration_changed));
2262 input_connection_connection_connection = c.ConnectionsChanged.connect
2263 (mem_fun (*this, &IO::input_connection_connection_changed));
2266 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2271 IO::use_output_connection (Connection& c, void* src)
2276 BLOCK_PROCESS_CALLBACK ();
2277 Glib::Mutex::Lock lm2 (io_lock);
2281 drop_output_connection ();
2283 if (ensure_outputs (limit, false, false, src)) {
2287 /* first pass: check the current state to see what's correctly
2288 connected, and drop anything that we don't want.
2291 for (uint32_t n = 0; n < limit; ++n) {
2293 const Connection::PortList& pl = c.port_connections (n);
2295 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2297 if (!_outputs[n]->connected_to ((*i))) {
2299 /* clear any existing connections */
2301 _session.engine().disconnect (_outputs[n]);
2303 } else if (_outputs[n]->connected() > 1) {
2305 /* OK, it is connected to the port we want,
2306 but its also connected to other ports.
2307 Change that situation.
2310 /* XXX could be optimized to not drop
2314 _session.engine().disconnect (_outputs[n]);
2319 /* second pass: connect all requested ports where necessary */
2321 for (uint32_t n = 0; n < limit; ++n) {
2323 const Connection::PortList& pl = c.port_connections (n);
2325 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2327 if (!_outputs[n]->connected_to ((*i))) {
2329 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2336 _output_connection = &c;
2338 output_connection_configuration_connection = c.ConfigurationChanged.connect
2339 (mem_fun (*this, &IO::output_connection_configuration_changed));
2340 output_connection_connection_connection = c.ConnectionsChanged.connect
2341 (mem_fun (*this, &IO::output_connection_connection_changed));
2344 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2350 IO::disable_connecting ()
2352 connecting_legal = false;
2357 IO::enable_connecting ()
2359 connecting_legal = true;
2360 return ConnectingLegal ();
2364 IO::disable_ports ()
2366 ports_legal = false;
2374 return PortsLegal ();
2378 IO::disable_panners (void)
2380 panners_legal = false;
2385 IO::reset_panners ()
2387 panners_legal = true;
2388 return PannersLegal ();
2392 IO::input_connection_connection_changed (int ignored)
2394 use_input_connection (*_input_connection, this);
2398 IO::input_connection_configuration_changed ()
2400 use_input_connection (*_input_connection, this);
2404 IO::output_connection_connection_changed (int ignored)
2406 use_output_connection (*_output_connection, this);
2410 IO::output_connection_configuration_changed ()
2412 use_output_connection (*_output_connection, this);
2416 IO::GainControllable::set_value (float val)
2418 io.set_gain (direct_control_to_gain (val), this);
2422 IO::GainControllable::get_value (void) const
2424 return direct_gain_to_control (io.effective_gain());
2428 IO::reset_peak_meters ()
2430 uint32_t limit = max (_ninputs, _noutputs);
2432 for (uint32_t i = 0; i < limit; ++i) {
2438 IO::reset_max_peak_meters ()
2440 uint32_t limit = max (_ninputs, _noutputs);
2442 for (uint32_t i = 0; i < limit; ++i) {
2443 _max_peak_power[i] = -INFINITY;
2448 IO::setup_peak_meters ()
2450 uint32_t limit = max (_ninputs, _noutputs);
2452 while (_peak_power.size() < limit) {
2453 _peak_power.push_back (0);
2454 _visible_peak_power.push_back (-INFINITY);
2455 _max_peak_power.push_back (-INFINITY);
2460 Update the peak meters.
2462 The meter signal lock is taken to prevent modification of the
2463 Meter signal while updating the meters, taking the meter signal
2464 lock prior to taking the io_lock ensures that all IO will remain
2465 valid while metering.
2470 Glib::Mutex::Lock guard (m_meter_signal_lock);
2478 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2479 uint32_t limit = max (_ninputs, _noutputs);
2481 for (uint32_t n = 0; n < limit; ++n) {
2483 /* XXX we should use atomic exchange here */
2485 /* grab peak since last read */
2487 float new_peak = _peak_power[n];
2490 /* compute new visible value using falloff */
2492 if (new_peak > 0.0f) {
2493 new_peak = coefficient_to_dB (new_peak);
2495 new_peak = -INFINITY;
2498 /* update max peak */
2500 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2503 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2504 _visible_peak_power[n] = new_peak;
2506 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2507 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2508 _visible_peak_power[n] = max (new_peak, -INFINITY);
2514 IO::clear_automation ()
2516 Glib::Mutex::Lock lm (automation_lock);
2517 _gain_automation_curve.clear ();
2518 _panner->clear_automation ();
2522 IO::set_gain_automation_state (AutoState state)
2524 bool changed = false;
2527 Glib::Mutex::Lock lm (automation_lock);
2529 if (state != _gain_automation_curve.automation_state()) {
2531 last_automation_snapshot = 0;
2532 _gain_automation_curve.set_automation_state (state);
2535 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2541 _session.set_dirty ();
2542 gain_automation_state_changed (); /* EMIT SIGNAL */
2547 IO::set_gain_automation_style (AutoStyle style)
2549 bool changed = false;
2552 Glib::Mutex::Lock lm (automation_lock);
2554 if (style != _gain_automation_curve.automation_style()) {
2556 _gain_automation_curve.set_automation_style (style);
2561 gain_automation_style_changed (); /* EMIT SIGNAL */
2565 IO::inc_gain (gain_t factor, void *src)
2567 if (_desired_gain == 0.0f)
2568 set_gain (0.000001f + (0.000001f * factor), src);
2570 set_gain (_desired_gain + (_desired_gain * factor), src);
2574 IO::set_gain (gain_t val, void *src)
2576 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2577 if (val>1.99526231f) val=1.99526231f;
2580 Glib::Mutex::Lock dm (declick_lock);
2581 _desired_gain = val;
2584 if (_session.transport_stopped()) {
2585 _effective_gain = val;
2590 _gain_control.Changed (); /* EMIT SIGNAL */
2592 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2593 _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()) {