2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <sigc++/bind.h>
29 #include <glibmm/thread.h>
31 #include <pbd/xml++.h>
33 #include <ardour/audioengine.h>
34 #include <ardour/io.h>
35 #include <ardour/port.h>
36 #include <ardour/connection.h>
37 #include <ardour/session.h>
38 #include <ardour/cycle_timer.h>
39 #include <ardour/panner.h>
40 #include <ardour/dB.h>
47 A bug in OS X's cmath that causes isnan() and isinf() to be
48 "undeclared". the following works around that
51 #if defined(__APPLE__) && defined(__MACH__)
52 extern "C" int isnan (double);
53 extern "C" int isinf (double);
56 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
59 using namespace ARDOUR;
62 nframes_t IO::_automation_interval = 0;
63 const string IO::state_node_name = "IO";
64 bool IO::connecting_legal = false;
65 bool IO::ports_legal = false;
66 bool IO::panners_legal = false;
67 sigc::signal<void> IO::Meter;
68 sigc::signal<int> IO::ConnectingLegal;
69 sigc::signal<int> IO::PortsLegal;
70 sigc::signal<int> IO::PannersLegal;
71 sigc::signal<void,uint32_t> IO::MoreOutputs;
72 sigc::signal<int> IO::PortsCreated;
74 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
76 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
77 others can be imagined.
80 static gain_t direct_control_to_gain (double fract) {
81 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
82 /* this maxes at +6dB */
83 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
86 static double direct_gain_to_control (gain_t gain) {
87 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
88 if (gain == 0) return 0.0;
90 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
93 static bool sort_ports_by_name (Port* a, Port* b)
95 return a->name() < b->name();
99 /** @param default_type The type of port that will be created by ensure_io
100 * and friends if no type is explicitly requested (to avoid breakage).
102 IO::IO (Session& s, string name,
103 int input_min, int input_max, int output_min, int output_max,
104 DataType default_type)
107 _default_type(default_type),
108 _gain_control (X_("gaincontrol"), *this),
109 _gain_automation_curve (0.0, 2.0, 1.0),
110 _input_minimum (input_min),
111 _input_maximum (input_max),
112 _output_minimum (output_min),
113 _output_maximum (output_max)
115 _panner = new Panner (name, _session);
118 _input_connection = 0;
119 _output_connection = 0;
120 pending_state_node = 0;
123 no_panner_reset = false;
126 apply_gain_automation = false;
127 _ignore_gain_on_deliver = false;
129 last_automation_snapshot = 0;
131 _gain_automation_state = Off;
132 _gain_automation_style = Absolute;
135 // IO::Meter is emitted from another thread so the
136 // Meter signal must be protected.
137 Glib::Mutex::Lock guard (m_meter_signal_lock);
138 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
141 _session.add_controllable (&_gain_control);
144 IO::IO (Session& s, const XMLNode& node, DataType dt)
147 _gain_control (X_("gaincontrol"), *this),
148 _gain_automation_curve (0, 0, 0) // all reset in set_state()
152 no_panner_reset = false;
155 _input_connection = 0;
156 _output_connection = 0;
160 apply_gain_automation = false;
161 _ignore_gain_on_deliver = false;
166 // IO::Meter is emitted from another thread so the
167 // Meter signal must be protected.
168 Glib::Mutex::Lock guard (m_meter_signal_lock);
169 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
172 _session.add_controllable (&_gain_control);
177 Glib::Mutex::Lock guard (m_meter_signal_lock);
179 Glib::Mutex::Lock lm (io_lock);
180 vector<Port *>::iterator i;
182 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
183 _session.engine().unregister_port (*i);
186 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
187 _session.engine().unregister_port (*i);
190 m_meter_connection.disconnect();
194 IO::silence (nframes_t nframes, nframes_t offset)
196 /* io_lock, not taken: function must be called from Session::process() calltree */
198 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
199 (*i)->silence (nframes, offset);
204 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
206 nframes_t declick = min ((nframes_t)128, nframes);
209 double fractional_shift;
210 double fractional_pos;
211 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
213 if (nframes == 0) return;
215 fractional_shift = -1.0/declick;
217 if (target < initial) {
218 /* fade out: remove more and more of delta from initial */
219 delta = -(initial - target);
221 /* fade in: add more and more of delta from initial */
222 delta = target - initial;
225 for (uint32_t n = 0; n < nbufs; ++n) {
228 fractional_pos = 1.0;
230 for (nframes_t nx = 0; nx < declick; ++nx) {
231 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
232 fractional_pos += fractional_shift;
235 /* now ensure the rest of the buffer has the target value
236 applied, if necessary.
239 if (declick != nframes) {
242 if (invert_polarity) {
243 this_target = -target;
245 this_target = target;
248 if (this_target == 0.0) {
249 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
250 } else if (this_target != 1.0) {
251 for (nframes_t nx = declick; nx < nframes; ++nx) {
252 buffer[nx] *= this_target;
260 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
264 /* io_lock, not taken: function must be called from Session::process() calltree */
266 if (_noutputs == 0) {
270 if (_noutputs == 1) {
272 dst = output(0)->get_buffer (nframes) + offset;
274 for (uint32_t n = 0; n < nbufs; ++n) {
275 if (bufs[n] != dst) {
276 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
280 output(0)->mark_silence (false);
286 vector<Port *>::iterator out;
287 vector<Sample *>::iterator in;
288 Panner::iterator pan;
289 Sample* obufs[_noutputs];
291 /* the terrible silence ... */
293 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
294 obufs[o] = (*out)->get_buffer (nframes) + offset;
295 memset (obufs[o], 0, sizeof (Sample) * nframes);
296 (*out)->mark_silence (false);
301 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
302 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
307 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
312 /* io_lock, not taken: function must be called from Session::process() calltree */
314 if (_noutputs == 0) {
318 /* the panner can be empty if there are no inputs to the
319 route, but still outputs
322 if (_panner->bypassed() || _panner->empty()) {
323 deliver_output_no_pan (bufs, nbufs, nframes, offset);
327 if (_noutputs == 1) {
329 dst = output(0)->get_buffer (nframes) + offset;
331 if (gain_coeff == 0.0f) {
333 /* only one output, and gain was zero, so make it silent */
335 memset (dst, 0, sizeof (Sample) * nframes);
337 } else if (gain_coeff == 1.0f){
339 /* mix all buffers into the output */
343 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
345 for (n = 1; n < nbufs; ++n) {
348 for (nframes_t n = 0; n < nframes; ++n) {
353 output(0)->mark_silence (false);
357 /* mix all buffers into the output, scaling them all by the gain */
363 for (nframes_t n = 0; n < nframes; ++n) {
364 dst[n] = src[n] * gain_coeff;
367 for (n = 1; n < nbufs; ++n) {
370 for (nframes_t n = 0; n < nframes; ++n) {
371 dst[n] += src[n] * gain_coeff;
375 output(0)->mark_silence (false);
382 vector<Port *>::iterator out;
383 vector<Sample *>::iterator in;
384 Panner::iterator pan;
385 Sample* obufs[_noutputs];
387 /* the terrible silence ... */
389 /* XXX this is wasteful but i see no way to avoid it */
391 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
392 obufs[o] = (*out)->get_buffer (nframes) + offset;
393 memset (obufs[o], 0, sizeof (Sample) * nframes);
394 (*out)->mark_silence (false);
399 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
400 Panner::iterator tmp;
405 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
407 if (tmp != _panner->end()) {
414 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
416 /* io_lock, not taken: function must be called from Session::process() calltree */
418 if (_noutputs == 0) {
422 if (_panner->bypassed() || _panner->empty()) {
423 deliver_output_no_pan (bufs, nbufs, nframes, offset);
429 gain_t pangain = _gain;
432 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
442 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
447 /* simple, non-automation panning to outputs */
449 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
450 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
452 pan (bufs, nbufs, nframes, offset, pangain);
457 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
459 /* io_lock, not taken: function must be called from Session::process() calltree */
461 if (_noutputs == 0) {
466 gain_t old_gain = _gain;
468 if (apply_gain_automation || _ignore_gain_on_deliver) {
470 /* gain has already been applied by automation code. do nothing here except
479 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
491 vector<Port*>::iterator o;
492 vector<Sample*> outs;
496 /* unlikely condition */
497 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
498 outs.push_back ((*o)->get_buffer (nframes) + offset);
502 /* reduce nbufs to the index of the last input buffer */
506 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
507 actual_gain = _gain * speed_quietning;
512 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
514 dst = (*o)->get_buffer (nframes) + offset;
515 src = bufs[min(nbufs,i)];
517 if (_name == "Audio 2") {
518 for (nframes_t x = 0; x < nframes; ++x) {
524 if (dg != _gain || actual_gain == 1.0f) {
525 memcpy (dst, src, sizeof (Sample) * nframes);
526 } else if (actual_gain == 0.0f) {
527 memset (dst, 0, sizeof (Sample) * nframes);
529 for (nframes_t x = 0; x < nframes; ++x) {
530 dst[x] = src[x] * actual_gain;
535 (*o)->mark_silence (false);
539 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
543 if (apply_gain_automation || _ignore_gain_on_deliver) {
549 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
551 /* io_lock, not taken: function must be called from Session::process() calltree */
553 vector<Port *>::iterator i;
557 /* we require that bufs.size() >= 1 */
559 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
560 if (i == _inputs.end()) {
564 /* XXX always read the full extent of the port buffer that
565 we need. One day, we may use jack_port_get_buffer_at_offset()
566 or something similar. For now, this simple hack will
569 Hack? Why yes .. we only need to read nframes-worth of
570 data, but the data we want is at `offset' within the
574 last = (*i)->get_buffer (nframes+offset) + offset;
575 // the dest buffer's offset has already been applied
576 memcpy (bufs[n], last, sizeof (Sample) * nframes);
579 /* fill any excess outputs with the last input */
581 while (n < nbufs && last) {
582 // the dest buffer's offset has already been applied
583 memcpy (bufs[n], last, sizeof (Sample) * nframes);
589 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
590 nframes_t nframes, nframes_t offset)
592 vector<Sample*>& bufs = _session.get_passthru_buffers ();
593 uint32_t nbufs = n_process_buffers ();
595 collect_input (bufs, nbufs, nframes, offset);
597 for (uint32_t n = 0; n < nbufs; ++n) {
598 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
603 IO::drop_input_connection ()
605 _input_connection = 0;
606 input_connection_configuration_connection.disconnect();
607 input_connection_connection_connection.disconnect();
608 _session.set_dirty ();
612 IO::drop_output_connection ()
614 _output_connection = 0;
615 output_connection_configuration_connection.disconnect();
616 output_connection_connection_connection.disconnect();
617 _session.set_dirty ();
621 IO::disconnect_input (Port* our_port, string other_port, void* src)
623 if (other_port.length() == 0 || our_port == 0) {
628 BLOCK_PROCESS_CALLBACK ();
631 Glib::Mutex::Lock lm (io_lock);
633 /* check that our_port is really one of ours */
635 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
639 /* disconnect it from the source */
641 if (_session.engine().disconnect (other_port, our_port->name())) {
642 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
646 drop_input_connection();
650 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
651 _session.set_dirty ();
657 IO::connect_input (Port* our_port, string other_port, void* src)
659 if (other_port.length() == 0 || our_port == 0) {
664 BLOCK_PROCESS_CALLBACK ();
667 Glib::Mutex::Lock lm (io_lock);
669 /* check that our_port is really one of ours */
671 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
675 /* connect it to the source */
677 if (_session.engine().connect (other_port, our_port->name())) {
681 drop_input_connection ();
685 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
686 _session.set_dirty ();
691 IO::disconnect_output (Port* our_port, string other_port, void* src)
693 if (other_port.length() == 0 || our_port == 0) {
698 BLOCK_PROCESS_CALLBACK ();
701 Glib::Mutex::Lock lm (io_lock);
703 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
707 /* disconnect it from the destination */
709 if (_session.engine().disconnect (our_port->name(), other_port)) {
710 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
714 drop_output_connection ();
718 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
719 _session.set_dirty ();
724 IO::connect_output (Port* our_port, string other_port, void* src)
726 if (other_port.length() == 0 || our_port == 0) {
731 BLOCK_PROCESS_CALLBACK ();
735 Glib::Mutex::Lock lm (io_lock);
737 /* check that our_port is really one of ours */
739 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
743 /* connect it to the destination */
745 if (_session.engine().connect (our_port->name(), other_port)) {
749 drop_output_connection ();
753 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
754 _session.set_dirty ();
759 IO::set_input (Port* other_port, void* src)
761 /* this removes all but one ports, and connects that one port
762 to the specified source.
765 if (_input_minimum > 1 || _input_minimum == 0) {
766 /* sorry, you can't do this */
770 if (other_port == 0) {
771 if (_input_minimum < 0) {
772 return ensure_inputs (0, false, true, src);
778 if (ensure_inputs (1, true, true, src)) {
782 return connect_input (_inputs.front(), other_port->name(), src);
786 IO::remove_output_port (Port* port, void* src)
788 IOChange change (NoChange);
791 BLOCK_PROCESS_CALLBACK ();
795 Glib::Mutex::Lock lm (io_lock);
797 if (_noutputs - 1 == (uint32_t) _output_minimum) {
798 /* sorry, you can't do this */
802 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
804 change = IOChange (change|ConfigurationChanged);
805 if (port->connected()) {
806 change = IOChange (change|ConnectionsChanged);
809 _session.engine().unregister_port (*i);
812 drop_output_connection ();
818 if (change != NoChange) {
819 setup_peak_meters ();
825 if (change != NoChange) {
826 output_changed (change, src); /* EMIT SIGNAL */
827 _session.set_dirty ();
834 /** Add an output port.
836 * @param destination Name of input port to connect new port to.
837 * @param src Source for emitted ConfigurationChanged signal.
838 * @param type Data type of port. Default value (NIL) will use this IO's default type.
841 IO::add_output_port (string destination, void* src, DataType type)
846 if (type == DataType::NIL)
847 type = _default_type;
850 BLOCK_PROCESS_CALLBACK ();
854 Glib::Mutex::Lock lm (io_lock);
856 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
860 /* Create a new output port */
862 // FIXME: naming scheme for differently typed ports?
863 if (_output_maximum == 1) {
864 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
866 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
869 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
870 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
874 _outputs.push_back (our_port);
875 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
877 drop_output_connection ();
878 setup_peak_meters ();
882 MoreOutputs (_noutputs); /* EMIT SIGNAL */
885 if (destination.length()) {
886 if (_session.engine().connect (our_port->name(), destination)) {
891 // pan_changed (src); /* EMIT SIGNAL */
892 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
893 _session.set_dirty ();
898 IO::remove_input_port (Port* port, void* src)
900 IOChange change (NoChange);
903 BLOCK_PROCESS_CALLBACK ();
907 Glib::Mutex::Lock lm (io_lock);
909 if (((int)_ninputs - 1) < _input_minimum) {
910 /* sorry, you can't do this */
913 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
916 change = IOChange (change|ConfigurationChanged);
918 if (port->connected()) {
919 change = IOChange (change|ConnectionsChanged);
922 _session.engine().unregister_port (*i);
925 drop_input_connection ();
931 if (change != NoChange) {
932 setup_peak_meters ();
938 if (change != NoChange) {
939 input_changed (change, src);
940 _session.set_dirty ();
948 /** Add an input port.
950 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
951 * @param destination Name of input port to connect new port to.
952 * @param src Source for emitted ConfigurationChanged signal.
955 IO::add_input_port (string source, void* src, DataType type)
960 if (type == DataType::NIL)
961 type = _default_type;
964 BLOCK_PROCESS_CALLBACK ();
967 Glib::Mutex::Lock lm (io_lock);
969 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
973 /* Create a new input port */
975 // FIXME: naming scheme for differently typed ports?
976 if (_input_maximum == 1) {
977 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
979 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
982 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
983 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
987 _inputs.push_back (our_port);
988 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
990 drop_input_connection ();
991 setup_peak_meters ();
995 MoreOutputs (_ninputs); /* EMIT SIGNAL */
998 if (source.length()) {
1000 if (_session.engine().connect (source, our_port->name())) {
1005 // pan_changed (src); /* EMIT SIGNAL */
1006 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1007 _session.set_dirty ();
1013 IO::disconnect_inputs (void* src)
1016 BLOCK_PROCESS_CALLBACK ();
1019 Glib::Mutex::Lock lm (io_lock);
1021 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1022 _session.engine().disconnect (*i);
1025 drop_input_connection ();
1028 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1033 IO::disconnect_outputs (void* src)
1036 BLOCK_PROCESS_CALLBACK ();
1039 Glib::Mutex::Lock lm (io_lock);
1041 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1042 _session.engine().disconnect (*i);
1045 drop_output_connection ();
1049 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1050 _session.set_dirty ();
1055 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1058 bool changed = false;
1059 bool reduced = false;
1061 /* remove unused ports */
1063 while (_ninputs > n) {
1064 _session.engine().unregister_port (_inputs.back());
1071 /* create any necessary new ports */
1073 while (_ninputs < n) {
1077 /* Create a new input port (of the default type) */
1079 if (_input_maximum == 1) {
1080 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1083 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1088 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1089 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1094 catch (AudioEngine::PortRegistrationFailure& err) {
1095 setup_peak_meters ();
1098 throw AudioEngine::PortRegistrationFailure();
1101 _inputs.push_back (input_port);
1102 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1108 drop_input_connection ();
1109 setup_peak_meters ();
1111 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1112 _session.set_dirty ();
1116 /* disconnect all existing ports so that we get a fresh start */
1118 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1119 _session.engine().disconnect (*i);
1127 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1129 bool in_changed = false;
1130 bool out_changed = false;
1131 bool in_reduced = false;
1132 bool out_reduced = false;
1133 bool need_pan_reset;
1135 if (_input_maximum >= 0) {
1136 nin = min (_input_maximum, (int) nin);
1139 if (_output_maximum >= 0) {
1140 nout = min (_output_maximum, (int) nout);
1143 if (nin == _ninputs && nout == _noutputs && !clear) {
1148 BLOCK_PROCESS_CALLBACK ();
1149 Glib::Mutex::Lock lm (io_lock);
1153 if (_noutputs == nout) {
1154 need_pan_reset = false;
1156 need_pan_reset = true;
1159 /* remove unused ports */
1161 while (_ninputs > nin) {
1162 _session.engine().unregister_port (_inputs.back());
1169 while (_noutputs > nout) {
1170 _session.engine().unregister_port (_outputs.back());
1171 _outputs.pop_back();
1177 /* create any necessary new ports (of the default type) */
1179 while (_ninputs < nin) {
1183 /* Create a new input port */
1185 if (_input_maximum == 1) {
1186 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1189 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1193 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1194 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1199 catch (AudioEngine::PortRegistrationFailure& err) {
1200 setup_peak_meters ();
1203 throw AudioEngine::PortRegistrationFailure();
1206 _inputs.push_back (port);
1211 /* create any necessary new ports */
1213 while (_noutputs < nout) {
1217 /* Create a new output port */
1219 if (_output_maximum == 1) {
1220 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1222 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1226 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1227 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1232 catch (AudioEngine::PortRegistrationFailure& err) {
1233 setup_peak_meters ();
1236 throw AudioEngine::PortRegistrationFailure ();
1239 _outputs.push_back (port);
1246 /* disconnect all existing ports so that we get a fresh start */
1248 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1249 _session.engine().disconnect (*i);
1252 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1253 _session.engine().disconnect (*i);
1257 if (in_changed || out_changed) {
1258 setup_peak_meters ();
1264 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1265 drop_output_connection ();
1266 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1270 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1271 drop_input_connection ();
1272 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1275 if (in_changed || out_changed) {
1276 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1277 _session.set_dirty ();
1284 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1286 bool changed = false;
1288 if (_input_maximum >= 0) {
1289 n = min (_input_maximum, (int) n);
1291 if (n == _ninputs && !clear) {
1297 BLOCK_PROCESS_CALLBACK ();
1298 Glib::Mutex::Lock im (io_lock);
1299 changed = ensure_inputs_locked (n, clear, src);
1301 changed = ensure_inputs_locked (n, clear, src);
1305 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1306 _session.set_dirty ();
1313 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1316 bool changed = false;
1317 bool reduced = false;
1318 bool need_pan_reset;
1320 if (_noutputs == n) {
1321 need_pan_reset = false;
1323 need_pan_reset = true;
1326 /* remove unused ports */
1328 while (_noutputs > n) {
1330 _session.engine().unregister_port (_outputs.back());
1331 _outputs.pop_back();
1337 /* create any necessary new ports */
1339 while (_noutputs < n) {
1343 /* Create a new output port */
1345 if (_output_maximum == 1) {
1346 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1348 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1351 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1352 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1356 _outputs.push_back (output_port);
1357 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1360 setup_peak_meters ();
1362 if (need_pan_reset) {
1368 drop_output_connection ();
1369 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1370 _session.set_dirty ();
1374 /* disconnect all existing ports so that we get a fresh start */
1376 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1377 _session.engine().disconnect (*i);
1385 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1387 bool changed = false;
1389 if (_output_maximum >= 0) {
1390 n = min (_output_maximum, (int) n);
1391 if (n == _noutputs && !clear) {
1396 /* XXX caller should hold io_lock, but generally doesn't */
1399 BLOCK_PROCESS_CALLBACK ();
1400 Glib::Mutex::Lock im (io_lock);
1401 changed = ensure_outputs_locked (n, clear, src);
1403 changed = ensure_outputs_locked (n, clear, src);
1407 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1414 IO::effective_gain () const
1416 if (gain_automation_playback()) {
1417 return _effective_gain;
1419 return _desired_gain;
1426 if (panners_legal) {
1427 if (!no_panner_reset) {
1428 _panner->reset (_noutputs, pans_required());
1431 panner_legal_c.disconnect ();
1432 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1437 IO::panners_became_legal ()
1439 _panner->reset (_noutputs, pans_required());
1440 _panner->load (); // automation
1441 panner_legal_c.disconnect ();
1446 IO::defer_pan_reset ()
1448 no_panner_reset = true;
1452 IO::allow_pan_reset ()
1454 no_panner_reset = false;
1460 IO::get_state (void)
1462 return state (true);
1466 IO::state (bool full_state)
1468 XMLNode* node = new XMLNode (state_node_name);
1471 bool need_ins = true;
1472 bool need_outs = true;
1473 LocaleGuard lg (X_("POSIX"));
1474 Glib::Mutex::Lock lm (io_lock);
1476 node->add_property("name", _name);
1477 id().print (buf, sizeof (buf));
1478 node->add_property("id", buf);
1482 if (_input_connection) {
1483 node->add_property ("input-connection", _input_connection->name());
1487 if (_output_connection) {
1488 node->add_property ("output-connection", _output_connection->name());
1493 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1495 const char **connections = (*i)->get_connections();
1497 if (connections && connections[0]) {
1500 for (int n = 0; connections && connections[n]; ++n) {
1505 /* if its a connection to our own port,
1506 return only the port name, not the
1507 whole thing. this allows connections
1508 to be re-established even when our
1509 client name is different.
1512 str += _session.engine().make_port_name_relative (connections[n]);
1524 node->add_property ("inputs", str);
1530 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1532 const char **connections = (*i)->get_connections();
1534 if (connections && connections[0]) {
1538 for (int n = 0; connections[n]; ++n) {
1543 str += _session.engine().make_port_name_relative (connections[n]);
1555 node->add_property ("outputs", str);
1558 node->add_child_nocopy (_panner->state (full_state));
1559 node->add_child_nocopy (_gain_control.get_state ());
1561 snprintf (buf, sizeof(buf), "%2.12f", gain());
1562 node->add_property ("gain", buf);
1564 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1570 node->add_property ("iolimits", buf);
1576 XMLNode* autonode = new XMLNode (X_("Automation"));
1577 autonode->add_child_nocopy (get_automation_state());
1578 node->add_child_nocopy (*autonode);
1580 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1582 /* never store anything except Off for automation state in a template */
1583 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1590 IO::set_state (const XMLNode& node)
1592 const XMLProperty* prop;
1593 XMLNodeConstIterator iter;
1594 LocaleGuard lg (X_("POSIX"));
1596 /* force use of non-localized representation of decimal point,
1597 since we use it a lot in XML files and so forth.
1600 if (node.name() != state_node_name) {
1601 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1605 if ((prop = node.property ("name")) != 0) {
1606 _name = prop->value();
1607 /* used to set panner name with this, but no more */
1610 if ((prop = node.property ("id")) != 0) {
1611 _id = prop->value ();
1614 if ((prop = node.property ("iolimits")) != 0) {
1615 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1622 if ((prop = node.property ("gain")) != 0) {
1623 set_gain (atof (prop->value().c_str()), this);
1624 _gain = _desired_gain;
1627 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1628 /* old school automation handling */
1631 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1633 if ((*iter)->name() == "Panner") {
1635 _panner = new Panner (_name, _session);
1637 _panner->set_state (**iter);
1640 if ((*iter)->name() == X_("Automation")) {
1642 set_automation_state (*(*iter)->children().front());
1645 if ((*iter)->name() == X_("gaincontrol")) {
1646 _gain_control.set_state (**iter);
1652 if (create_ports (node)) {
1658 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1661 if (panners_legal) {
1664 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1667 if (connecting_legal) {
1669 if (make_connections (node)) {
1675 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1678 if (!ports_legal || !connecting_legal) {
1679 pending_state_node = new XMLNode (node);
1682 last_automation_snapshot = 0;
1688 IO::set_automation_state (const XMLNode& node)
1690 return _gain_automation_curve.set_state (node);
1694 IO::get_automation_state ()
1696 return (_gain_automation_curve.get_state ());
1700 IO::load_automation (string path)
1705 uint32_t linecnt = 0;
1707 LocaleGuard lg (X_("POSIX"));
1709 fullpath = _session.automation_dir();
1712 in.open (fullpath.c_str());
1715 fullpath = _session.automation_dir();
1716 fullpath += _session.snap_name();
1720 in.open (fullpath.c_str());
1723 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1728 clear_automation ();
1730 while (in.getline (line, sizeof(line), '\n')) {
1732 jack_nframes_t when;
1735 if (++linecnt == 1) {
1736 if (memcmp (line, "version", 7) == 0) {
1737 if (sscanf (line, "version %f", &version) != 1) {
1738 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1742 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1749 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1750 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1756 _gain_automation_curve.fast_simple_add (when, value);
1766 /* older (pre-1.0) versions of ardour used this */
1770 warning << _("dubious automation event found (and ignored)") << endmsg;
1778 IO::connecting_became_legal ()
1782 if (pending_state_node == 0) {
1783 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1788 connection_legal_c.disconnect ();
1790 ret = make_connections (*pending_state_node);
1793 delete pending_state_node;
1794 pending_state_node = 0;
1800 IO::ports_became_legal ()
1804 if (pending_state_node == 0) {
1805 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1810 port_legal_c.disconnect ();
1812 ret = create_ports (*pending_state_node);
1814 if (connecting_legal) {
1815 delete pending_state_node;
1816 pending_state_node = 0;
1823 IO::create_ports (const XMLNode& node)
1825 const XMLProperty* prop;
1827 int num_outputs = 0;
1829 if ((prop = node.property ("input-connection")) != 0) {
1831 Connection* c = _session.connection_by_name (prop->value());
1834 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1836 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1837 error << _("No input connections available as a replacement")
1841 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1846 num_inputs = c->nports();
1848 } else if ((prop = node.property ("inputs")) != 0) {
1850 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1853 if ((prop = node.property ("output-connection")) != 0) {
1854 Connection* c = _session.connection_by_name (prop->value());
1857 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1859 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1860 error << _("No output connections available as a replacement")
1864 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1869 num_outputs = c->nports ();
1871 } else if ((prop = node.property ("outputs")) != 0) {
1872 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1875 no_panner_reset = true;
1877 if (ensure_io (num_inputs, num_outputs, true, this)) {
1878 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1882 no_panner_reset = false;
1884 set_deferred_state ();
1892 IO::make_connections (const XMLNode& node)
1894 const XMLProperty* prop;
1896 if ((prop = node.property ("input-connection")) != 0) {
1897 Connection* c = _session.connection_by_name (prop->value());
1900 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1902 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1903 error << _("No input connections available as a replacement")
1907 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1912 use_input_connection (*c, this);
1914 } else if ((prop = node.property ("inputs")) != 0) {
1915 if (set_inputs (prop->value())) {
1916 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1921 if ((prop = node.property ("output-connection")) != 0) {
1922 Connection* c = _session.connection_by_name (prop->value());
1925 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1927 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1928 error << _("No output connections available as a replacement")
1932 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1937 use_output_connection (*c, this);
1939 } else if ((prop = node.property ("outputs")) != 0) {
1940 if (set_outputs (prop->value())) {
1941 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1950 IO::set_inputs (const string& str)
1952 vector<string> ports;
1957 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1961 if (ensure_inputs (nports, true, true, this)) {
1965 string::size_type start, end, ostart;
1972 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1975 if ((end = str.find_first_of ('}', start)) == string::npos) {
1976 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1980 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1981 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1987 for (int x = 0; x < n; ++x) {
1988 connect_input (input (i), ports[x], this);
2000 IO::set_outputs (const string& str)
2002 vector<string> ports;
2007 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2011 if (ensure_outputs (nports, true, true, this)) {
2015 string::size_type start, end, ostart;
2022 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2025 if ((end = str.find_first_of ('}', start)) == string::npos) {
2026 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2030 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2031 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2037 for (int x = 0; x < n; ++x) {
2038 connect_output (output (i), ports[x], this);
2050 IO::parse_io_string (const string& str, vector<string>& ports)
2052 string::size_type pos, opos;
2054 if (str.length() == 0) {
2063 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2064 ports.push_back (str.substr (opos, pos - opos));
2068 if (opos < str.length()) {
2069 ports.push_back (str.substr(opos));
2072 return ports.size();
2076 IO::parse_gain_string (const string& str, vector<string>& ports)
2078 string::size_type pos, opos;
2084 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2085 ports.push_back (str.substr (opos, pos - opos));
2089 if (opos < str.length()) {
2090 ports.push_back (str.substr(opos));
2093 return ports.size();
2097 IO::set_name (string name, void* src)
2099 if (name == _name) {
2103 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2104 string current_name = (*i)->short_name();
2105 current_name.replace (current_name.find (_name), _name.length(), name);
2106 (*i)->set_name (current_name);
2109 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2110 string current_name = (*i)->short_name();
2111 current_name.replace (current_name.find (_name), _name.length(), name);
2112 (*i)->set_name (current_name);
2116 name_changed (src); /* EMIT SIGNAL */
2122 IO::set_input_minimum (int n)
2128 IO::set_input_maximum (int n)
2134 IO::set_output_minimum (int n)
2136 _output_minimum = n;
2140 IO::set_output_maximum (int n)
2142 _output_maximum = n;
2146 IO::set_port_latency (nframes_t nframes)
2148 Glib::Mutex::Lock lm (io_lock);
2150 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2151 (*i)->set_latency (nframes);
2156 IO::output_latency () const
2158 nframes_t max_latency;
2163 /* io lock not taken - must be protected by other means */
2165 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2166 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2167 max_latency = latency;
2175 IO::input_latency () const
2177 nframes_t max_latency;
2182 /* io lock not taken - must be protected by other means */
2184 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2185 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2186 max_latency = latency;
2194 IO::use_input_connection (Connection& c, void* src)
2199 BLOCK_PROCESS_CALLBACK ();
2200 Glib::Mutex::Lock lm2 (io_lock);
2204 drop_input_connection ();
2206 if (ensure_inputs (limit, false, false, src)) {
2210 /* first pass: check the current state to see what's correctly
2211 connected, and drop anything that we don't want.
2214 for (uint32_t n = 0; n < limit; ++n) {
2215 const Connection::PortList& pl = c.port_connections (n);
2217 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2219 if (!_inputs[n]->connected_to ((*i))) {
2221 /* clear any existing connections */
2223 _session.engine().disconnect (_inputs[n]);
2225 } else if (_inputs[n]->connected() > 1) {
2227 /* OK, it is connected to the port we want,
2228 but its also connected to other ports.
2229 Change that situation.
2232 /* XXX could be optimized to not drop
2236 _session.engine().disconnect (_inputs[n]);
2242 /* second pass: connect all requested ports where necessary */
2244 for (uint32_t n = 0; n < limit; ++n) {
2245 const Connection::PortList& pl = c.port_connections (n);
2247 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2249 if (!_inputs[n]->connected_to ((*i))) {
2251 if (_session.engine().connect (*i, _inputs[n]->name())) {
2259 _input_connection = &c;
2261 input_connection_configuration_connection = c.ConfigurationChanged.connect
2262 (mem_fun (*this, &IO::input_connection_configuration_changed));
2263 input_connection_connection_connection = c.ConnectionsChanged.connect
2264 (mem_fun (*this, &IO::input_connection_connection_changed));
2267 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2272 IO::use_output_connection (Connection& c, void* src)
2277 BLOCK_PROCESS_CALLBACK ();
2278 Glib::Mutex::Lock lm2 (io_lock);
2282 drop_output_connection ();
2284 if (ensure_outputs (limit, false, false, src)) {
2288 /* first pass: check the current state to see what's correctly
2289 connected, and drop anything that we don't want.
2292 for (uint32_t n = 0; n < limit; ++n) {
2294 const Connection::PortList& pl = c.port_connections (n);
2296 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2298 if (!_outputs[n]->connected_to ((*i))) {
2300 /* clear any existing connections */
2302 _session.engine().disconnect (_outputs[n]);
2304 } else if (_outputs[n]->connected() > 1) {
2306 /* OK, it is connected to the port we want,
2307 but its also connected to other ports.
2308 Change that situation.
2311 /* XXX could be optimized to not drop
2315 _session.engine().disconnect (_outputs[n]);
2320 /* second pass: connect all requested ports where necessary */
2322 for (uint32_t n = 0; n < limit; ++n) {
2324 const Connection::PortList& pl = c.port_connections (n);
2326 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2328 if (!_outputs[n]->connected_to ((*i))) {
2330 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2337 _output_connection = &c;
2339 output_connection_configuration_connection = c.ConfigurationChanged.connect
2340 (mem_fun (*this, &IO::output_connection_configuration_changed));
2341 output_connection_connection_connection = c.ConnectionsChanged.connect
2342 (mem_fun (*this, &IO::output_connection_connection_changed));
2345 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2351 IO::disable_connecting ()
2353 connecting_legal = false;
2358 IO::enable_connecting ()
2360 connecting_legal = true;
2361 return ConnectingLegal ();
2365 IO::disable_ports ()
2367 ports_legal = false;
2375 return PortsLegal ();
2379 IO::disable_panners (void)
2381 panners_legal = false;
2386 IO::reset_panners ()
2388 panners_legal = true;
2389 return PannersLegal ();
2393 IO::input_connection_connection_changed (int ignored)
2395 use_input_connection (*_input_connection, this);
2399 IO::input_connection_configuration_changed ()
2401 use_input_connection (*_input_connection, this);
2405 IO::output_connection_connection_changed (int ignored)
2407 use_output_connection (*_output_connection, this);
2411 IO::output_connection_configuration_changed ()
2413 use_output_connection (*_output_connection, this);
2417 IO::GainControllable::set_value (float val)
2419 io.set_gain (direct_control_to_gain (val), this);
2423 IO::GainControllable::get_value (void) const
2425 return direct_gain_to_control (io.effective_gain());
2429 IO::reset_peak_meters ()
2431 uint32_t limit = max (_ninputs, _noutputs);
2433 for (uint32_t i = 0; i < limit; ++i) {
2439 IO::setup_peak_meters ()
2441 uint32_t limit = max (_ninputs, _noutputs);
2443 while (_peak_power.size() < limit) {
2444 _peak_power.push_back (0);
2445 _visible_peak_power.push_back (0);
2450 Update the peak meters.
2452 The meter signal lock is taken to prevent modification of the
2453 Meter signal while updating the meters, taking the meter signal
2454 lock prior to taking the io_lock ensures that all IO will remain
2455 valid while metering.
2460 Glib::Mutex::Lock guard (m_meter_signal_lock);
2468 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2469 uint32_t limit = max (_ninputs, _noutputs);
2471 for (uint32_t n = 0; n < limit; ++n) {
2473 /* XXX we should use atomic exchange here */
2475 /* grab peak since last read */
2477 float new_peak = _peak_power[n];
2480 /* compute new visible value using falloff */
2482 if (new_peak > 0.0) {
2483 new_peak = coefficient_to_dB (new_peak);
2485 new_peak = minus_infinity();
2488 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2489 _visible_peak_power[n] = new_peak;
2492 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2493 _visible_peak_power[n] = max (new_peak, -INFINITY);
2499 IO::clear_automation ()
2501 Glib::Mutex::Lock lm (automation_lock);
2502 _gain_automation_curve.clear ();
2503 _panner->clear_automation ();
2507 IO::set_gain_automation_state (AutoState state)
2509 bool changed = false;
2512 Glib::Mutex::Lock lm (automation_lock);
2514 if (state != _gain_automation_curve.automation_state()) {
2516 last_automation_snapshot = 0;
2517 _gain_automation_curve.set_automation_state (state);
2520 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2526 _session.set_dirty ();
2527 gain_automation_state_changed (); /* EMIT SIGNAL */
2532 IO::set_gain_automation_style (AutoStyle style)
2534 bool changed = false;
2537 Glib::Mutex::Lock lm (automation_lock);
2539 if (style != _gain_automation_curve.automation_style()) {
2541 _gain_automation_curve.set_automation_style (style);
2546 gain_automation_style_changed (); /* EMIT SIGNAL */
2550 IO::inc_gain (gain_t factor, void *src)
2552 if (_desired_gain == 0.0f)
2553 set_gain (0.000001f + (0.000001f * factor), src);
2555 set_gain (_desired_gain + (_desired_gain * factor), src);
2559 IO::set_gain (gain_t val, void *src)
2561 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2562 if (val>1.99526231f) val=1.99526231f;
2565 Glib::Mutex::Lock dm (declick_lock);
2566 _desired_gain = val;
2569 if (_session.transport_stopped()) {
2570 _effective_gain = val;
2575 _gain_control.Changed (); /* EMIT SIGNAL */
2577 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2578 _gain_automation_curve.add (_session.transport_frame(), val);
2582 _session.set_dirty();
2586 IO::start_gain_touch ()
2588 _gain_automation_curve.start_touch ();
2592 IO::end_gain_touch ()
2594 _gain_automation_curve.stop_touch ();
2598 IO::start_pan_touch (uint32_t which)
2600 if (which < _panner->size()) {
2601 (*_panner)[which]->automation().start_touch();
2606 IO::end_pan_touch (uint32_t which)
2608 if (which < _panner->size()) {
2609 (*_panner)[which]->automation().stop_touch();
2615 IO::automation_snapshot (nframes_t now)
2617 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2619 if (gain_automation_recording()) {
2620 _gain_automation_curve.rt_add (now, gain());
2623 _panner->snapshot (now);
2625 last_automation_snapshot = now;
2630 IO::transport_stopped (nframes_t frame)
2632 _gain_automation_curve.reposition_for_rt_add (frame);
2634 if (_gain_automation_curve.automation_state() != Off) {
2636 /* the src=0 condition is a special signal to not propagate
2637 automation gain changes into the mix group when locating.
2640 set_gain (_gain_automation_curve.eval (frame), 0);
2643 _panner->transport_stopped (frame);
2647 IO::find_input_port_hole ()
2649 /* CALLER MUST HOLD IO LOCK */
2653 if (_inputs.empty()) {
2657 for (n = 1; n < UINT_MAX; ++n) {
2658 char buf[jack_port_name_size()];
2659 vector<Port*>::iterator i;
2661 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2663 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2664 if ((*i)->short_name() == buf) {
2669 if (i == _inputs.end()) {
2677 IO::find_output_port_hole ()
2679 /* CALLER MUST HOLD IO LOCK */
2683 if (_outputs.empty()) {
2687 for (n = 1; n < UINT_MAX; ++n) {
2688 char buf[jack_port_name_size()];
2689 vector<Port*>::iterator i;
2691 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2693 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2694 if ((*i)->short_name() == buf) {
2699 if (i == _outputs.end()) {