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);
58 using namespace ARDOUR;
61 nframes_t IO::_automation_interval = 0;
62 const string IO::state_node_name = "IO";
63 bool IO::connecting_legal = false;
64 bool IO::ports_legal = false;
65 bool IO::panners_legal = false;
66 sigc::signal<void> IO::Meter;
67 sigc::signal<int> IO::ConnectingLegal;
68 sigc::signal<int> IO::PortsLegal;
69 sigc::signal<int> IO::PannersLegal;
70 sigc::signal<void,uint32_t> IO::MoreOutputs;
71 sigc::signal<int> IO::PortsCreated;
73 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
75 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
76 others can be imagined.
79 static gain_t direct_control_to_gain (double fract) {
80 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
81 /* this maxes at +6dB */
82 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
85 static double direct_gain_to_control (gain_t gain) {
86 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
87 if (gain == 0) return 0.0;
89 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
92 static bool sort_ports_by_name (Port* a, Port* b)
94 return a->name() < b->name();
98 /** @param default_type The type of port that will be created by ensure_io
99 * and friends if no type is explicitly requested (to avoid breakage).
101 IO::IO (Session& s, string name,
102 int input_min, int input_max, int output_min, int output_max,
103 DataType default_type)
106 _default_type(default_type),
107 _gain_control (X_("gaincontrol"), *this),
108 _gain_automation_curve (0.0, 2.0, 1.0),
109 _input_minimum (input_min),
110 _input_maximum (input_max),
111 _output_minimum (output_min),
112 _output_maximum (output_max)
114 _panner = new Panner (name, _session);
117 _input_connection = 0;
118 _output_connection = 0;
119 pending_state_node = 0;
122 no_panner_reset = false;
125 apply_gain_automation = false;
126 _ignore_gain_on_deliver = false;
128 last_automation_snapshot = 0;
130 _gain_automation_state = Off;
131 _gain_automation_style = Absolute;
134 // IO::Meter is emitted from another thread so the
135 // Meter signal must be protected.
136 Glib::Mutex::Lock guard (m_meter_signal_lock);
137 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
140 _session.add_controllable (&_gain_control);
143 IO::IO (Session& s, const XMLNode& node, DataType dt)
146 _gain_control (X_("gaincontrol"), *this),
147 _gain_automation_curve (0, 0, 0) // all reset in set_state()
151 no_panner_reset = false;
154 _input_connection = 0;
155 _output_connection = 0;
159 apply_gain_automation = false;
160 _ignore_gain_on_deliver = false;
165 // IO::Meter is emitted from another thread so the
166 // Meter signal must be protected.
167 Glib::Mutex::Lock guard (m_meter_signal_lock);
168 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
171 _session.add_controllable (&_gain_control);
176 Glib::Mutex::Lock guard (m_meter_signal_lock);
178 Glib::Mutex::Lock lm (io_lock);
179 vector<Port *>::iterator i;
181 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
182 _session.engine().unregister_port (*i);
185 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
186 _session.engine().unregister_port (*i);
189 m_meter_connection.disconnect();
193 IO::silence (nframes_t nframes, nframes_t offset)
195 /* io_lock, not taken: function must be called from Session::process() calltree */
197 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
198 (*i)->silence (nframes, offset);
203 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
205 nframes_t declick = min ((nframes_t)128, nframes);
208 double fractional_shift;
209 double fractional_pos;
210 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
212 if (nframes == 0) return;
214 fractional_shift = -1.0/declick;
216 if (target < initial) {
217 /* fade out: remove more and more of delta from initial */
218 delta = -(initial - target);
220 /* fade in: add more and more of delta from initial */
221 delta = target - initial;
224 for (uint32_t n = 0; n < nbufs; ++n) {
227 fractional_pos = 1.0;
229 for (nframes_t nx = 0; nx < declick; ++nx) {
230 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
231 fractional_pos += fractional_shift;
234 /* now ensure the rest of the buffer has the target value
235 applied, if necessary.
238 if (declick != nframes) {
241 if (invert_polarity) {
242 this_target = -target;
244 this_target = target;
247 if (this_target == 0.0) {
248 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
249 } else if (this_target != 1.0) {
250 for (nframes_t nx = declick; nx < nframes; ++nx) {
251 buffer[nx] *= this_target;
259 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
263 /* io_lock, not taken: function must be called from Session::process() calltree */
265 if (_noutputs == 0) {
269 if (_noutputs == 1) {
271 dst = output(0)->get_buffer (nframes) + offset;
273 for (uint32_t n = 0; n < nbufs; ++n) {
274 if (bufs[n] != dst) {
275 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
279 output(0)->mark_silence (false);
285 vector<Port *>::iterator out;
286 vector<Sample *>::iterator in;
287 Panner::iterator pan;
288 Sample* obufs[_noutputs];
290 /* the terrible silence ... */
292 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
293 obufs[o] = (*out)->get_buffer (nframes) + offset;
294 memset (obufs[o], 0, sizeof (Sample) * nframes);
295 (*out)->mark_silence (false);
300 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
301 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
306 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
311 /* io_lock, not taken: function must be called from Session::process() calltree */
313 if (_noutputs == 0) {
317 /* the panner can be empty if there are no inputs to the
318 route, but still outputs
321 if (_panner->bypassed() || _panner->empty()) {
322 deliver_output_no_pan (bufs, nbufs, nframes, offset);
326 if (_noutputs == 1) {
328 dst = output(0)->get_buffer (nframes) + offset;
330 if (gain_coeff == 0.0f) {
332 /* only one output, and gain was zero, so make it silent */
334 memset (dst, 0, sizeof (Sample) * nframes);
336 } else if (gain_coeff == 1.0f){
338 /* mix all buffers into the output */
342 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
344 for (n = 1; n < nbufs; ++n) {
347 for (nframes_t n = 0; n < nframes; ++n) {
352 output(0)->mark_silence (false);
356 /* mix all buffers into the output, scaling them all by the gain */
362 for (nframes_t n = 0; n < nframes; ++n) {
363 dst[n] = src[n] * gain_coeff;
366 for (n = 1; n < nbufs; ++n) {
369 for (nframes_t n = 0; n < nframes; ++n) {
370 dst[n] += src[n] * gain_coeff;
374 output(0)->mark_silence (false);
381 vector<Port *>::iterator out;
382 vector<Sample *>::iterator in;
383 Panner::iterator pan;
384 Sample* obufs[_noutputs];
386 /* the terrible silence ... */
388 /* XXX this is wasteful but i see no way to avoid it */
390 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
391 obufs[o] = (*out)->get_buffer (nframes) + offset;
392 memset (obufs[o], 0, sizeof (Sample) * nframes);
393 (*out)->mark_silence (false);
398 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
399 Panner::iterator tmp;
404 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
406 if (tmp != _panner->end()) {
413 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
415 /* io_lock, not taken: function must be called from Session::process() calltree */
417 if (_noutputs == 0) {
421 if (_panner->bypassed() || _panner->empty()) {
422 deliver_output_no_pan (bufs, nbufs, nframes, offset);
428 gain_t pangain = _gain;
431 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
441 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
446 /* simple, non-automation panning to outputs */
448 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
449 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
451 pan (bufs, nbufs, nframes, offset, pangain);
456 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
458 /* io_lock, not taken: function must be called from Session::process() calltree */
460 if (_noutputs == 0) {
465 gain_t old_gain = _gain;
467 if (apply_gain_automation || _ignore_gain_on_deliver) {
469 /* gain has already been applied by automation code. do nothing here except
478 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
490 vector<Port*>::iterator o;
491 vector<Sample*> outs;
495 /* unlikely condition */
496 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
497 outs.push_back ((*o)->get_buffer (nframes) + offset);
501 /* reduce nbufs to the index of the last input buffer */
505 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
506 actual_gain = _gain * speed_quietning;
511 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
513 dst = (*o)->get_buffer (nframes) + offset;
514 src = bufs[min(nbufs,i)];
516 if (_name == "Audio 2") {
517 for (nframes_t x = 0; x < nframes; ++x) {
523 if (dg != _gain || actual_gain == 1.0f) {
524 memcpy (dst, src, sizeof (Sample) * nframes);
525 } else if (actual_gain == 0.0f) {
526 memset (dst, 0, sizeof (Sample) * nframes);
528 for (nframes_t x = 0; x < nframes; ++x) {
529 dst[x] = src[x] * actual_gain;
534 (*o)->mark_silence (false);
538 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
542 if (apply_gain_automation || _ignore_gain_on_deliver) {
548 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
550 /* io_lock, not taken: function must be called from Session::process() calltree */
552 vector<Port *>::iterator i;
556 /* we require that bufs.size() >= 1 */
558 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
559 if (i == _inputs.end()) {
563 /* XXX always read the full extent of the port buffer that
564 we need. One day, we may use jack_port_get_buffer_at_offset()
565 or something similar. For now, this simple hack will
568 Hack? Why yes .. we only need to read nframes-worth of
569 data, but the data we want is at `offset' within the
573 last = (*i)->get_buffer (nframes+offset) + offset;
574 // the dest buffer's offset has already been applied
575 memcpy (bufs[n], last, sizeof (Sample) * nframes);
578 /* fill any excess outputs with the last input */
580 while (n < nbufs && last) {
581 // the dest buffer's offset has already been applied
582 memcpy (bufs[n], last, sizeof (Sample) * nframes);
588 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
589 nframes_t nframes, nframes_t offset)
591 vector<Sample*>& bufs = _session.get_passthru_buffers ();
592 uint32_t nbufs = n_process_buffers ();
594 collect_input (bufs, nbufs, nframes, offset);
596 for (uint32_t n = 0; n < nbufs; ++n) {
597 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
602 IO::drop_input_connection ()
604 _input_connection = 0;
605 input_connection_configuration_connection.disconnect();
606 input_connection_connection_connection.disconnect();
607 _session.set_dirty ();
611 IO::drop_output_connection ()
613 _output_connection = 0;
614 output_connection_configuration_connection.disconnect();
615 output_connection_connection_connection.disconnect();
616 _session.set_dirty ();
620 IO::disconnect_input (Port* our_port, string other_port, void* src)
622 if (other_port.length() == 0 || our_port == 0) {
627 Glib::Mutex::Lock em (_session.engine().process_lock());
630 Glib::Mutex::Lock lm (io_lock);
632 /* check that our_port is really one of ours */
634 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
638 /* disconnect it from the source */
640 if (_session.engine().disconnect (other_port, our_port->name())) {
641 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
645 drop_input_connection();
649 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
650 _session.set_dirty ();
656 IO::connect_input (Port* our_port, string other_port, void* src)
658 if (other_port.length() == 0 || our_port == 0) {
663 Glib::Mutex::Lock em(_session.engine().process_lock());
666 Glib::Mutex::Lock lm (io_lock);
668 /* check that our_port is really one of ours */
670 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
674 /* connect it to the source */
676 if (_session.engine().connect (other_port, our_port->name())) {
680 drop_input_connection ();
684 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
685 _session.set_dirty ();
690 IO::disconnect_output (Port* our_port, string other_port, void* src)
692 if (other_port.length() == 0 || our_port == 0) {
697 Glib::Mutex::Lock em(_session.engine().process_lock());
700 Glib::Mutex::Lock lm (io_lock);
702 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
706 /* disconnect it from the destination */
708 if (_session.engine().disconnect (our_port->name(), other_port)) {
709 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
713 drop_output_connection ();
717 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
718 _session.set_dirty ();
723 IO::connect_output (Port* our_port, string other_port, void* src)
725 if (other_port.length() == 0 || our_port == 0) {
730 Glib::Mutex::Lock em(_session.engine().process_lock());
733 Glib::Mutex::Lock lm (io_lock);
735 /* check that our_port is really one of ours */
737 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
741 /* connect it to the destination */
743 if (_session.engine().connect (our_port->name(), other_port)) {
747 drop_output_connection ();
751 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
752 _session.set_dirty ();
757 IO::set_input (Port* other_port, void* src)
759 /* this removes all but one ports, and connects that one port
760 to the specified source.
763 if (_input_minimum > 1 || _input_minimum == 0) {
764 /* sorry, you can't do this */
768 if (other_port == 0) {
769 if (_input_minimum < 0) {
770 return ensure_inputs (0, false, true, src);
776 if (ensure_inputs (1, true, true, src)) {
780 return connect_input (_inputs.front(), other_port->name(), src);
784 IO::remove_output_port (Port* port, void* src)
786 IOChange change (NoChange);
789 Glib::Mutex::Lock em(_session.engine().process_lock());
792 Glib::Mutex::Lock lm (io_lock);
794 if (_noutputs - 1 == (uint32_t) _output_minimum) {
795 /* sorry, you can't do this */
799 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
801 change = IOChange (change|ConfigurationChanged);
802 if (port->connected()) {
803 change = IOChange (change|ConnectionsChanged);
806 _session.engine().unregister_port (*i);
809 drop_output_connection ();
815 if (change != NoChange) {
816 setup_peak_meters ();
822 if (change != NoChange) {
823 output_changed (change, src); /* EMIT SIGNAL */
824 _session.set_dirty ();
831 /** Add an output port.
833 * @param destination Name of input port to connect new port to.
834 * @param src Source for emitted ConfigurationChanged signal.
835 * @param type Data type of port. Default value (NIL) will use this IO's default type.
838 IO::add_output_port (string destination, void* src, DataType type)
843 if (type == DataType::NIL)
844 type = _default_type;
847 Glib::Mutex::Lock em(_session.engine().process_lock());
850 Glib::Mutex::Lock lm (io_lock);
852 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
856 /* Create a new output port */
858 // FIXME: naming scheme for differently typed ports?
859 if (_output_maximum == 1) {
860 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
862 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
865 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
866 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
870 _outputs.push_back (our_port);
871 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
873 drop_output_connection ();
874 setup_peak_meters ();
878 MoreOutputs (_noutputs); /* EMIT SIGNAL */
881 if (destination.length()) {
882 if (_session.engine().connect (our_port->name(), destination)) {
887 // pan_changed (src); /* EMIT SIGNAL */
888 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
889 _session.set_dirty ();
894 IO::remove_input_port (Port* port, void* src)
896 IOChange change (NoChange);
899 Glib::Mutex::Lock em(_session.engine().process_lock());
902 Glib::Mutex::Lock lm (io_lock);
904 if (((int)_ninputs - 1) < _input_minimum) {
905 /* sorry, you can't do this */
908 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
911 change = IOChange (change|ConfigurationChanged);
913 if (port->connected()) {
914 change = IOChange (change|ConnectionsChanged);
917 _session.engine().unregister_port (*i);
920 drop_input_connection ();
926 if (change != NoChange) {
927 setup_peak_meters ();
933 if (change != NoChange) {
934 input_changed (change, src);
935 _session.set_dirty ();
943 /** Add an input port.
945 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
946 * @param destination Name of input port to connect new port to.
947 * @param src Source for emitted ConfigurationChanged signal.
950 IO::add_input_port (string source, void* src, DataType type)
955 if (type == DataType::NIL)
956 type = _default_type;
959 Glib::Mutex::Lock em (_session.engine().process_lock());
962 Glib::Mutex::Lock lm (io_lock);
964 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
968 /* Create a new input port */
970 // FIXME: naming scheme for differently typed ports?
971 if (_input_maximum == 1) {
972 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
974 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
977 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
978 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
982 _inputs.push_back (our_port);
983 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
985 drop_input_connection ();
986 setup_peak_meters ();
990 MoreOutputs (_ninputs); /* EMIT SIGNAL */
993 if (source.length()) {
995 if (_session.engine().connect (source, our_port->name())) {
1000 // pan_changed (src); /* EMIT SIGNAL */
1001 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1002 _session.set_dirty ();
1008 IO::disconnect_inputs (void* src)
1011 Glib::Mutex::Lock em (_session.engine().process_lock());
1014 Glib::Mutex::Lock lm (io_lock);
1016 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1017 _session.engine().disconnect (*i);
1020 drop_input_connection ();
1023 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1028 IO::disconnect_outputs (void* src)
1031 Glib::Mutex::Lock em (_session.engine().process_lock());
1034 Glib::Mutex::Lock lm (io_lock);
1036 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1037 _session.engine().disconnect (*i);
1040 drop_output_connection ();
1044 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1045 _session.set_dirty ();
1050 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1053 bool changed = false;
1054 bool reduced = false;
1056 /* remove unused ports */
1058 while (_ninputs > n) {
1059 _session.engine().unregister_port (_inputs.back());
1066 /* create any necessary new ports */
1068 while (_ninputs < n) {
1072 /* Create a new input port (of the default type) */
1074 if (_input_maximum == 1) {
1075 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1078 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1083 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1084 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1089 catch (AudioEngine::PortRegistrationFailure& err) {
1090 setup_peak_meters ();
1096 _inputs.push_back (input_port);
1097 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1103 drop_input_connection ();
1104 setup_peak_meters ();
1106 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1107 _session.set_dirty ();
1111 /* disconnect all existing ports so that we get a fresh start */
1113 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1114 _session.engine().disconnect (*i);
1122 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1124 bool in_changed = false;
1125 bool out_changed = false;
1126 bool in_reduced = false;
1127 bool out_reduced = false;
1128 bool need_pan_reset;
1130 if (_input_maximum >= 0) {
1131 nin = min (_input_maximum, (int) nin);
1134 if (_output_maximum >= 0) {
1135 nout = min (_output_maximum, (int) nout);
1138 if (nin == _ninputs && nout == _noutputs && !clear) {
1143 Glib::Mutex::Lock em (_session.engine().process_lock());
1144 Glib::Mutex::Lock lm (io_lock);
1148 if (_noutputs == nout) {
1149 need_pan_reset = false;
1151 need_pan_reset = true;
1154 /* remove unused ports */
1156 while (_ninputs > nin) {
1157 _session.engine().unregister_port (_inputs.back());
1164 while (_noutputs > nout) {
1165 _session.engine().unregister_port (_outputs.back());
1166 _outputs.pop_back();
1172 /* create any necessary new ports (of the default type) */
1174 while (_ninputs < nin) {
1178 /* Create a new input port */
1180 if (_input_maximum == 1) {
1181 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1184 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1188 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1189 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1194 catch (AudioEngine::PortRegistrationFailure& err) {
1195 setup_peak_meters ();
1201 _inputs.push_back (port);
1206 /* create any necessary new ports */
1208 while (_noutputs < nout) {
1212 /* Create a new output port */
1214 if (_output_maximum == 1) {
1215 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1217 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1221 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1222 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1227 catch (AudioEngine::PortRegistrationFailure& err) {
1228 setup_peak_meters ();
1234 _outputs.push_back (port);
1241 /* disconnect all existing ports so that we get a fresh start */
1243 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1244 _session.engine().disconnect (*i);
1247 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1248 _session.engine().disconnect (*i);
1252 if (in_changed || out_changed) {
1253 setup_peak_meters ();
1259 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1260 drop_output_connection ();
1261 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1265 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1266 drop_input_connection ();
1267 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1270 if (in_changed || out_changed) {
1271 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1272 _session.set_dirty ();
1279 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1281 bool changed = false;
1283 if (_input_maximum >= 0) {
1284 n = min (_input_maximum, (int) n);
1286 if (n == _ninputs && !clear) {
1292 Glib::Mutex::Lock em (_session.engine().process_lock());
1293 Glib::Mutex::Lock im (io_lock);
1294 changed = ensure_inputs_locked (n, clear, src);
1296 changed = ensure_inputs_locked (n, clear, src);
1300 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1301 _session.set_dirty ();
1308 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1311 bool changed = false;
1312 bool reduced = false;
1313 bool need_pan_reset;
1315 if (_noutputs == n) {
1316 need_pan_reset = false;
1318 need_pan_reset = true;
1321 /* remove unused ports */
1323 while (_noutputs > n) {
1325 _session.engine().unregister_port (_outputs.back());
1326 _outputs.pop_back();
1332 /* create any necessary new ports */
1334 while (_noutputs < n) {
1338 /* Create a new output port */
1340 if (_output_maximum == 1) {
1341 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1343 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1346 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1347 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1351 _outputs.push_back (output_port);
1352 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1355 setup_peak_meters ();
1357 if (need_pan_reset) {
1363 drop_output_connection ();
1364 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1365 _session.set_dirty ();
1369 /* disconnect all existing ports so that we get a fresh start */
1371 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1372 _session.engine().disconnect (*i);
1380 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1382 bool changed = false;
1384 if (_output_maximum >= 0) {
1385 n = min (_output_maximum, (int) n);
1386 if (n == _noutputs && !clear) {
1391 /* XXX caller should hold io_lock, but generally doesn't */
1394 Glib::Mutex::Lock em (_session.engine().process_lock());
1395 Glib::Mutex::Lock im (io_lock);
1396 changed = ensure_outputs_locked (n, clear, src);
1398 changed = ensure_outputs_locked (n, clear, src);
1402 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1409 IO::effective_gain () const
1411 if (gain_automation_playback()) {
1412 return _effective_gain;
1414 return _desired_gain;
1421 if (panners_legal) {
1422 if (!no_panner_reset) {
1423 _panner->reset (_noutputs, pans_required());
1426 panner_legal_c.disconnect ();
1427 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1432 IO::panners_became_legal ()
1434 _panner->reset (_noutputs, pans_required());
1435 _panner->load (); // automation
1436 panner_legal_c.disconnect ();
1441 IO::defer_pan_reset ()
1443 no_panner_reset = true;
1447 IO::allow_pan_reset ()
1449 no_panner_reset = false;
1455 IO::get_state (void)
1457 return state (true);
1461 IO::state (bool full_state)
1463 XMLNode* node = new XMLNode (state_node_name);
1466 bool need_ins = true;
1467 bool need_outs = true;
1468 LocaleGuard lg (X_("POSIX"));
1469 Glib::Mutex::Lock lm (io_lock);
1471 node->add_property("name", _name);
1472 id().print (buf, sizeof (buf));
1473 node->add_property("id", buf);
1477 if (_input_connection) {
1478 node->add_property ("input-connection", _input_connection->name());
1482 if (_output_connection) {
1483 node->add_property ("output-connection", _output_connection->name());
1488 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1490 const char **connections = (*i)->get_connections();
1492 if (connections && connections[0]) {
1495 for (int n = 0; connections && connections[n]; ++n) {
1500 /* if its a connection to our own port,
1501 return only the port name, not the
1502 whole thing. this allows connections
1503 to be re-established even when our
1504 client name is different.
1507 str += _session.engine().make_port_name_relative (connections[n]);
1519 node->add_property ("inputs", str);
1525 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1527 const char **connections = (*i)->get_connections();
1529 if (connections && connections[0]) {
1533 for (int n = 0; connections[n]; ++n) {
1538 str += _session.engine().make_port_name_relative (connections[n]);
1550 node->add_property ("outputs", str);
1553 node->add_child_nocopy (_panner->state (full_state));
1554 node->add_child_nocopy (_gain_control.get_state ());
1556 snprintf (buf, sizeof(buf), "%2.12f", gain());
1557 node->add_property ("gain", buf);
1559 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1565 node->add_property ("iolimits", buf);
1571 XMLNode* autonode = new XMLNode (X_("Automation"));
1572 autonode->add_child_nocopy (get_automation_state());
1573 node->add_child_nocopy (*autonode);
1575 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1577 /* never store anything except Off for automation state in a template */
1578 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1585 IO::set_state (const XMLNode& node)
1587 const XMLProperty* prop;
1588 XMLNodeConstIterator iter;
1589 LocaleGuard lg (X_("POSIX"));
1591 /* force use of non-localized representation of decimal point,
1592 since we use it a lot in XML files and so forth.
1595 if (node.name() != state_node_name) {
1596 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1600 if ((prop = node.property ("name")) != 0) {
1601 _name = prop->value();
1602 /* used to set panner name with this, but no more */
1605 if ((prop = node.property ("id")) != 0) {
1606 _id = prop->value ();
1609 if ((prop = node.property ("iolimits")) != 0) {
1610 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1617 if ((prop = node.property ("gain")) != 0) {
1618 set_gain (atof (prop->value().c_str()), this);
1619 _gain = _desired_gain;
1622 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1623 /* old school automation handling */
1626 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1628 if ((*iter)->name() == "Panner") {
1630 _panner = new Panner (_name, _session);
1632 _panner->set_state (**iter);
1635 if ((*iter)->name() == X_("Automation")) {
1637 set_automation_state (*(*iter)->children().front());
1640 if ((*iter)->name() == X_("gaincontrol")) {
1641 _gain_control.set_state (**iter);
1647 if (create_ports (node)) {
1653 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1656 if (panners_legal) {
1659 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1662 if (connecting_legal) {
1664 if (make_connections (node)) {
1670 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1673 if (!ports_legal || !connecting_legal) {
1674 pending_state_node = new XMLNode (node);
1677 last_automation_snapshot = 0;
1683 IO::set_automation_state (const XMLNode& node)
1685 return _gain_automation_curve.set_state (node);
1689 IO::get_automation_state ()
1691 return (_gain_automation_curve.get_state ());
1695 IO::load_automation (string path)
1700 uint32_t linecnt = 0;
1702 LocaleGuard lg (X_("POSIX"));
1704 fullpath = _session.automation_dir();
1707 in.open (fullpath.c_str());
1710 fullpath = _session.automation_dir();
1711 fullpath += _session.snap_name();
1715 in.open (fullpath.c_str());
1718 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1723 clear_automation ();
1725 while (in.getline (line, sizeof(line), '\n')) {
1727 jack_nframes_t when;
1730 if (++linecnt == 1) {
1731 if (memcmp (line, "version", 7) == 0) {
1732 if (sscanf (line, "version %f", &version) != 1) {
1733 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1737 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1744 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1745 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1751 _gain_automation_curve.fast_simple_add (when, value);
1761 /* older (pre-1.0) versions of ardour used this */
1765 warning << _("dubious automation event found (and ignored)") << endmsg;
1773 IO::connecting_became_legal ()
1777 if (pending_state_node == 0) {
1778 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1783 connection_legal_c.disconnect ();
1785 ret = make_connections (*pending_state_node);
1788 delete pending_state_node;
1789 pending_state_node = 0;
1795 IO::ports_became_legal ()
1799 if (pending_state_node == 0) {
1800 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1805 port_legal_c.disconnect ();
1807 ret = create_ports (*pending_state_node);
1809 if (connecting_legal) {
1810 delete pending_state_node;
1811 pending_state_node = 0;
1818 IO::create_ports (const XMLNode& node)
1820 const XMLProperty* prop;
1822 int num_outputs = 0;
1824 if ((prop = node.property ("input-connection")) != 0) {
1826 Connection* c = _session.connection_by_name (prop->value());
1829 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1831 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1832 error << _("No input connections available as a replacement")
1836 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1841 num_inputs = c->nports();
1843 } else if ((prop = node.property ("inputs")) != 0) {
1845 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1848 if ((prop = node.property ("output-connection")) != 0) {
1849 Connection* c = _session.connection_by_name (prop->value());
1852 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1854 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1855 error << _("No output connections available as a replacement")
1859 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1864 num_outputs = c->nports ();
1866 } else if ((prop = node.property ("outputs")) != 0) {
1867 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1870 no_panner_reset = true;
1872 if (ensure_io (num_inputs, num_outputs, true, this)) {
1873 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1877 no_panner_reset = false;
1879 set_deferred_state ();
1887 IO::make_connections (const XMLNode& node)
1889 const XMLProperty* prop;
1891 if ((prop = node.property ("input-connection")) != 0) {
1892 Connection* c = _session.connection_by_name (prop->value());
1895 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1897 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1898 error << _("No input connections available as a replacement")
1902 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1907 use_input_connection (*c, this);
1909 } else if ((prop = node.property ("inputs")) != 0) {
1910 if (set_inputs (prop->value())) {
1911 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1916 if ((prop = node.property ("output-connection")) != 0) {
1917 Connection* c = _session.connection_by_name (prop->value());
1920 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1922 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1923 error << _("No output connections available as a replacement")
1927 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1932 use_output_connection (*c, this);
1934 } else if ((prop = node.property ("outputs")) != 0) {
1935 if (set_outputs (prop->value())) {
1936 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1945 IO::set_inputs (const string& str)
1947 vector<string> ports;
1952 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1956 if (ensure_inputs (nports, true, true, this)) {
1960 string::size_type start, end, ostart;
1967 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1970 if ((end = str.find_first_of ('}', start)) == string::npos) {
1971 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1975 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1976 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1982 for (int x = 0; x < n; ++x) {
1983 connect_input (input (i), ports[x], this);
1995 IO::set_outputs (const string& str)
1997 vector<string> ports;
2002 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2006 if (ensure_outputs (nports, true, true, this)) {
2010 string::size_type start, end, ostart;
2017 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2020 if ((end = str.find_first_of ('}', start)) == string::npos) {
2021 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2025 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2026 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2032 for (int x = 0; x < n; ++x) {
2033 connect_output (output (i), ports[x], this);
2045 IO::parse_io_string (const string& str, vector<string>& ports)
2047 string::size_type pos, opos;
2049 if (str.length() == 0) {
2058 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2059 ports.push_back (str.substr (opos, pos - opos));
2063 if (opos < str.length()) {
2064 ports.push_back (str.substr(opos));
2067 return ports.size();
2071 IO::parse_gain_string (const string& str, vector<string>& ports)
2073 string::size_type pos, opos;
2079 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2080 ports.push_back (str.substr (opos, pos - opos));
2084 if (opos < str.length()) {
2085 ports.push_back (str.substr(opos));
2088 return ports.size();
2092 IO::set_name (string name, void* src)
2094 if (name == _name) {
2098 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2099 string current_name = (*i)->short_name();
2100 current_name.replace (current_name.find (_name), _name.length(), name);
2101 (*i)->set_name (current_name);
2104 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2105 string current_name = (*i)->short_name();
2106 current_name.replace (current_name.find (_name), _name.length(), name);
2107 (*i)->set_name (current_name);
2111 name_changed (src); /* EMIT SIGNAL */
2117 IO::set_input_minimum (int n)
2123 IO::set_input_maximum (int n)
2129 IO::set_output_minimum (int n)
2131 _output_minimum = n;
2135 IO::set_output_maximum (int n)
2137 _output_maximum = n;
2141 IO::set_port_latency (nframes_t nframes)
2143 Glib::Mutex::Lock lm (io_lock);
2145 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2146 (*i)->set_latency (nframes);
2151 IO::output_latency () const
2153 nframes_t max_latency;
2158 /* io lock not taken - must be protected by other means */
2160 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2161 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2162 max_latency = latency;
2170 IO::input_latency () const
2172 nframes_t max_latency;
2177 /* io lock not taken - must be protected by other means */
2179 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2180 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2181 max_latency = latency;
2189 IO::use_input_connection (Connection& c, void* src)
2194 Glib::Mutex::Lock lm (_session.engine().process_lock());
2195 Glib::Mutex::Lock lm2 (io_lock);
2199 drop_input_connection ();
2201 if (ensure_inputs (limit, false, false, src)) {
2205 /* first pass: check the current state to see what's correctly
2206 connected, and drop anything that we don't want.
2209 for (uint32_t n = 0; n < limit; ++n) {
2210 const Connection::PortList& pl = c.port_connections (n);
2212 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2214 if (!_inputs[n]->connected_to ((*i))) {
2216 /* clear any existing connections */
2218 _session.engine().disconnect (_inputs[n]);
2220 } else if (_inputs[n]->connected() > 1) {
2222 /* OK, it is connected to the port we want,
2223 but its also connected to other ports.
2224 Change that situation.
2227 /* XXX could be optimized to not drop
2231 _session.engine().disconnect (_inputs[n]);
2237 /* second pass: connect all requested ports where necessary */
2239 for (uint32_t n = 0; n < limit; ++n) {
2240 const Connection::PortList& pl = c.port_connections (n);
2242 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2244 if (!_inputs[n]->connected_to ((*i))) {
2246 if (_session.engine().connect (*i, _inputs[n]->name())) {
2254 _input_connection = &c;
2256 input_connection_configuration_connection = c.ConfigurationChanged.connect
2257 (mem_fun (*this, &IO::input_connection_configuration_changed));
2258 input_connection_connection_connection = c.ConnectionsChanged.connect
2259 (mem_fun (*this, &IO::input_connection_connection_changed));
2262 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2267 IO::use_output_connection (Connection& c, void* src)
2272 Glib::Mutex::Lock lm (_session.engine().process_lock());
2273 Glib::Mutex::Lock lm2 (io_lock);
2277 drop_output_connection ();
2279 if (ensure_outputs (limit, false, false, src)) {
2283 /* first pass: check the current state to see what's correctly
2284 connected, and drop anything that we don't want.
2287 for (uint32_t n = 0; n < limit; ++n) {
2289 const Connection::PortList& pl = c.port_connections (n);
2291 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2293 if (!_outputs[n]->connected_to ((*i))) {
2295 /* clear any existing connections */
2297 _session.engine().disconnect (_outputs[n]);
2299 } else if (_outputs[n]->connected() > 1) {
2301 /* OK, it is connected to the port we want,
2302 but its also connected to other ports.
2303 Change that situation.
2306 /* XXX could be optimized to not drop
2310 _session.engine().disconnect (_outputs[n]);
2315 /* second pass: connect all requested ports where necessary */
2317 for (uint32_t n = 0; n < limit; ++n) {
2319 const Connection::PortList& pl = c.port_connections (n);
2321 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2323 if (!_outputs[n]->connected_to ((*i))) {
2325 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2332 _output_connection = &c;
2334 output_connection_configuration_connection = c.ConfigurationChanged.connect
2335 (mem_fun (*this, &IO::output_connection_configuration_changed));
2336 output_connection_connection_connection = c.ConnectionsChanged.connect
2337 (mem_fun (*this, &IO::output_connection_connection_changed));
2340 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2346 IO::disable_connecting ()
2348 connecting_legal = false;
2353 IO::enable_connecting ()
2355 connecting_legal = true;
2356 return ConnectingLegal ();
2360 IO::disable_ports ()
2362 ports_legal = false;
2370 return PortsLegal ();
2374 IO::disable_panners (void)
2376 panners_legal = false;
2381 IO::reset_panners ()
2383 panners_legal = true;
2384 return PannersLegal ();
2388 IO::input_connection_connection_changed (int ignored)
2390 use_input_connection (*_input_connection, this);
2394 IO::input_connection_configuration_changed ()
2396 use_input_connection (*_input_connection, this);
2400 IO::output_connection_connection_changed (int ignored)
2402 use_output_connection (*_output_connection, this);
2406 IO::output_connection_configuration_changed ()
2408 use_output_connection (*_output_connection, this);
2412 IO::GainControllable::set_value (float val)
2414 io.set_gain (direct_control_to_gain (val), this);
2418 IO::GainControllable::get_value (void) const
2420 return direct_gain_to_control (io.effective_gain());
2424 IO::reset_peak_meters ()
2426 uint32_t limit = max (_ninputs, _noutputs);
2428 for (uint32_t i = 0; i < limit; ++i) {
2434 IO::setup_peak_meters ()
2436 uint32_t limit = max (_ninputs, _noutputs);
2438 while (_peak_power.size() < limit) {
2439 _peak_power.push_back (0);
2440 _visible_peak_power.push_back (0);
2445 Update the peak meters.
2447 The meter signal lock is taken to prevent modification of the
2448 Meter signal while updating the meters, taking the meter signal
2449 lock prior to taking the io_lock ensures that all IO will remain
2450 valid while metering.
2455 Glib::Mutex::Lock guard (m_meter_signal_lock);
2463 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2464 uint32_t limit = max (_ninputs, _noutputs);
2466 for (uint32_t n = 0; n < limit; ++n) {
2468 /* XXX we should use atomic exchange here */
2470 /* grab peak since last read */
2472 float new_peak = _peak_power[n];
2475 /* compute new visible value using falloff */
2477 if (new_peak > 0.0) {
2478 new_peak = coefficient_to_dB (new_peak);
2480 new_peak = minus_infinity();
2483 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2484 _visible_peak_power[n] = new_peak;
2487 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2488 _visible_peak_power[n] = max (new_peak, -INFINITY);
2494 IO::clear_automation ()
2496 Glib::Mutex::Lock lm (automation_lock);
2497 _gain_automation_curve.clear ();
2498 _panner->clear_automation ();
2502 IO::set_gain_automation_state (AutoState state)
2504 bool changed = false;
2507 Glib::Mutex::Lock lm (automation_lock);
2509 if (state != _gain_automation_curve.automation_state()) {
2511 last_automation_snapshot = 0;
2512 _gain_automation_curve.set_automation_state (state);
2515 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2521 _session.set_dirty ();
2522 gain_automation_state_changed (); /* EMIT SIGNAL */
2527 IO::set_gain_automation_style (AutoStyle style)
2529 bool changed = false;
2532 Glib::Mutex::Lock lm (automation_lock);
2534 if (style != _gain_automation_curve.automation_style()) {
2536 _gain_automation_curve.set_automation_style (style);
2541 gain_automation_style_changed (); /* EMIT SIGNAL */
2545 IO::inc_gain (gain_t factor, void *src)
2547 if (_desired_gain == 0.0f)
2548 set_gain (0.000001f + (0.000001f * factor), src);
2550 set_gain (_desired_gain + (_desired_gain * factor), src);
2554 IO::set_gain (gain_t val, void *src)
2556 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2557 if (val>1.99526231f) val=1.99526231f;
2560 Glib::Mutex::Lock dm (declick_lock);
2561 _desired_gain = val;
2564 if (_session.transport_stopped()) {
2565 _effective_gain = val;
2570 _gain_control.Changed (); /* EMIT SIGNAL */
2572 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2573 _gain_automation_curve.add (_session.transport_frame(), val);
2577 _session.set_dirty();
2581 IO::start_gain_touch ()
2583 _gain_automation_curve.start_touch ();
2587 IO::end_gain_touch ()
2589 _gain_automation_curve.stop_touch ();
2593 IO::start_pan_touch (uint32_t which)
2595 if (which < _panner->size()) {
2596 (*_panner)[which]->automation().start_touch();
2601 IO::end_pan_touch (uint32_t which)
2603 if (which < _panner->size()) {
2604 (*_panner)[which]->automation().stop_touch();
2610 IO::automation_snapshot (nframes_t now)
2612 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2614 if (gain_automation_recording()) {
2615 _gain_automation_curve.rt_add (now, gain());
2618 _panner->snapshot (now);
2620 last_automation_snapshot = now;
2625 IO::transport_stopped (nframes_t frame)
2627 _gain_automation_curve.reposition_for_rt_add (frame);
2629 if (_gain_automation_curve.automation_state() != Off) {
2631 /* the src=0 condition is a special signal to not propagate
2632 automation gain changes into the mix group when locating.
2635 set_gain (_gain_automation_curve.eval (frame), 0);
2638 _panner->transport_stopped (frame);
2642 IO::find_input_port_hole ()
2644 /* CALLER MUST HOLD IO LOCK */
2648 if (_inputs.empty()) {
2652 for (n = 1; n < UINT_MAX; ++n) {
2653 char buf[jack_port_name_size()];
2654 vector<Port*>::iterator i;
2656 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2658 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2659 if ((*i)->short_name() == buf) {
2664 if (i == _inputs.end()) {
2672 IO::find_output_port_hole ()
2674 /* CALLER MUST HOLD IO LOCK */
2678 if (_outputs.empty()) {
2682 for (n = 1; n < UINT_MAX; ++n) {
2683 char buf[jack_port_name_size()];
2684 vector<Port*>::iterator i;
2686 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2688 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2689 if ((*i)->short_name() == buf) {
2694 if (i == _outputs.end()) {