2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
31 #include <pbd/replace_all.h>
33 #include <ardour/audioengine.h>
34 #include <ardour/io.h>
35 #include <ardour/route.h>
36 #include <ardour/port.h>
37 #include <ardour/connection.h>
38 #include <ardour/session.h>
39 #include <ardour/cycle_timer.h>
40 #include <ardour/panner.h>
41 #include <ardour/dB.h>
48 A bug in OS X's cmath that causes isnan() and isinf() to be
49 "undeclared". the following works around that
52 #if defined(__APPLE__) && defined(__MACH__)
53 extern "C" int isnan (double);
54 extern "C" int isinf (double);
57 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
60 using namespace ARDOUR;
63 nframes_t IO::_automation_interval = 0;
64 const string IO::state_node_name = "IO";
65 bool IO::connecting_legal = false;
66 bool IO::ports_legal = false;
67 bool IO::panners_legal = false;
68 sigc::signal<void> IO::Meter;
69 sigc::signal<int> IO::ConnectingLegal;
70 sigc::signal<int> IO::PortsLegal;
71 sigc::signal<int> IO::PannersLegal;
72 sigc::signal<void,uint32_t> IO::MoreOutputs;
73 sigc::signal<int> IO::PortsCreated;
75 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
77 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
78 others can be imagined.
81 static gain_t direct_control_to_gain (double fract) {
82 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
83 /* this maxes at +6dB */
84 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
87 static double direct_gain_to_control (gain_t gain) {
88 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
89 if (gain == 0) return 0.0;
91 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
94 static bool sort_ports_by_name (Port* a, Port* b)
96 return a->name() < b->name();
100 /** @param default_type The type of port that will be created by ensure_io
101 * and friends if no type is explicitly requested (to avoid breakage).
103 IO::IO (Session& s, string name,
104 int input_min, int input_max, int output_min, int output_max,
105 DataType default_type)
108 _default_type(default_type),
109 _gain_control (X_("gaincontrol"), *this),
110 _gain_automation_curve (0.0, 2.0, 1.0),
111 _input_minimum (input_min),
112 _input_maximum (input_max),
113 _output_minimum (output_min),
114 _output_maximum (output_max)
116 _panner = new Panner (name, _session);
120 _input_connection = 0;
121 _output_connection = 0;
122 pending_state_node = 0;
125 no_panner_reset = false;
128 apply_gain_automation = false;
129 _ignore_gain_on_deliver = false;
131 last_automation_snapshot = 0;
133 _gain_automation_state = Off;
134 _gain_automation_style = Absolute;
137 // IO::Meter is emitted from another thread so the
138 // Meter signal must be protected.
139 Glib::Mutex::Lock guard (m_meter_signal_lock);
140 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
143 _session.add_controllable (&_gain_control);
146 IO::IO (Session& s, const XMLNode& node, DataType dt)
149 _gain_control (X_("gaincontrol"), *this),
150 _gain_automation_curve (0, 0, 0) // all reset in set_state()
155 no_panner_reset = false;
158 _input_connection = 0;
159 _output_connection = 0;
163 apply_gain_automation = false;
164 _ignore_gain_on_deliver = false;
169 // IO::Meter is emitted from another thread so the
170 // Meter signal must be protected.
171 Glib::Mutex::Lock guard (m_meter_signal_lock);
172 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
175 _session.add_controllable (&_gain_control);
180 Glib::Mutex::Lock guard (m_meter_signal_lock);
182 Glib::Mutex::Lock lm (io_lock);
183 vector<Port *>::iterator i;
186 BLOCK_PROCESS_CALLBACK ();
188 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
189 _session.engine().unregister_port (*i);
192 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
193 _session.engine().unregister_port (*i);
197 m_meter_connection.disconnect();
201 IO::silence (nframes_t nframes, nframes_t offset)
203 /* io_lock, not taken: function must be called from Session::process() calltree */
205 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
206 (*i)->silence (nframes, offset);
211 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
213 nframes_t declick = min ((nframes_t)128, nframes);
216 double fractional_shift;
217 double fractional_pos;
218 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
220 if (nframes == 0) return;
222 fractional_shift = -1.0/declick;
224 if (target < initial) {
225 /* fade out: remove more and more of delta from initial */
226 delta = -(initial - target);
228 /* fade in: add more and more of delta from initial */
229 delta = target - initial;
232 for (uint32_t n = 0; n < nbufs; ++n) {
235 fractional_pos = 1.0;
237 for (nframes_t nx = 0; nx < declick; ++nx) {
238 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
239 fractional_pos += fractional_shift;
242 /* now ensure the rest of the buffer has the target value
243 applied, if necessary.
246 if (declick != nframes) {
249 if (invert_polarity) {
250 this_target = -target;
252 this_target = target;
255 if (this_target == 0.0) {
256 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
257 } else if (this_target != 1.0) {
258 for (nframes_t nx = declick; nx < nframes; ++nx) {
259 buffer[nx] *= this_target;
267 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
271 /* io_lock, not taken: function must be called from Session::process() calltree */
273 if (_noutputs == 0) {
277 if (_noutputs == 1) {
279 dst = output(0)->get_buffer (nframes) + offset;
281 for (uint32_t n = 0; n < nbufs; ++n) {
282 if (bufs[n] != dst) {
283 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
287 output(0)->mark_silence (false);
293 vector<Port *>::iterator out;
294 vector<Sample *>::iterator in;
295 Panner::iterator pan;
296 Sample* obufs[_noutputs];
298 /* the terrible silence ... */
300 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
301 obufs[o] = (*out)->get_buffer (nframes) + offset;
302 memset (obufs[o], 0, sizeof (Sample) * nframes);
303 (*out)->mark_silence (false);
308 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
309 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
314 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
319 /* io_lock, not taken: function must be called from Session::process() calltree */
321 if (_noutputs == 0) {
325 /* the panner can be empty if there are no inputs to the
326 route, but still outputs
329 if (_panner->bypassed() || _panner->empty()) {
330 deliver_output_no_pan (bufs, nbufs, nframes, offset);
334 if (_noutputs == 1) {
336 dst = output(0)->get_buffer (nframes) + offset;
338 if (gain_coeff == 0.0f) {
340 /* only one output, and gain was zero, so make it silent */
342 memset (dst, 0, sizeof (Sample) * nframes);
344 } else if (gain_coeff == 1.0f){
346 /* mix all buffers into the output */
350 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
352 for (n = 1; n < nbufs; ++n) {
353 Session::mix_buffers_no_gain(dst,bufs[n],nframes);
356 output(0)->mark_silence (false);
360 /* mix all buffers into the output, scaling them all by the gain */
366 for (nframes_t n = 0; n < nframes; ++n) {
367 dst[n] = src[n] * gain_coeff;
370 for (n = 1; n < nbufs; ++n) {
371 Session::mix_buffers_with_gain(dst,bufs[n],nframes,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;
494 /* reduce nbufs to the index of the last input buffer */
498 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
499 actual_gain = _gain * speed_quietning;
504 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
506 dst = (*o)->get_buffer (nframes) + offset;
507 src = bufs[min(nbufs,i)];
510 /* unlikely condition */
511 outs.push_back (dst);
514 if (dg != _gain || actual_gain == 1.0f) {
515 memcpy (dst, src, sizeof (Sample) * nframes);
516 } else if (actual_gain == 0.0f) {
517 memset (dst, 0, sizeof (Sample) * nframes);
519 for (nframes_t x = 0; x < nframes; ++x) {
520 dst[x] = src[x] * actual_gain;
524 (*o)->mark_silence (false);
528 apply_declick (outs, i, nframes, _gain, dg, false);
532 if (apply_gain_automation || _ignore_gain_on_deliver) {
538 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
540 /* io_lock, not taken: function must be called from Session::process() calltree */
542 vector<Port *>::iterator i;
546 /* we require that bufs.size() >= 1 */
548 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
549 if (i == _inputs.end()) {
553 /* XXX always read the full extent of the port buffer that
554 we need. One day, we may use jack_port_get_buffer_at_offset()
555 or something similar. For now, this simple hack will
558 Hack? Why yes .. we only need to read nframes-worth of
559 data, but the data we want is at `offset' within the
563 last = (*i)->get_buffer (nframes+offset) + offset;
564 // the dest buffer's offset has already been applied
565 memcpy (bufs[n], last, sizeof (Sample) * nframes);
568 /* fill any excess outputs with the last input */
572 // the dest buffer's offset has already been applied
573 memcpy (bufs[n], last, sizeof (Sample) * nframes);
578 memset (bufs[n], 0, sizeof (Sample) * nframes);
585 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
586 nframes_t nframes, nframes_t offset)
588 vector<Sample*>& bufs = _session.get_passthru_buffers ();
589 uint32_t nbufs = n_process_buffers ();
591 collect_input (bufs, nbufs, nframes, offset);
593 for (uint32_t n = 0; n < nbufs; ++n) {
594 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
599 IO::drop_input_connection ()
601 _input_connection = 0;
602 input_connection_configuration_connection.disconnect();
603 input_connection_connection_connection.disconnect();
604 _session.set_dirty ();
608 IO::drop_output_connection ()
610 _output_connection = 0;
611 output_connection_configuration_connection.disconnect();
612 output_connection_connection_connection.disconnect();
613 _session.set_dirty ();
617 IO::disconnect_input (Port* our_port, string other_port, void* src)
619 if (other_port.length() == 0 || our_port == 0) {
624 BLOCK_PROCESS_CALLBACK ();
627 Glib::Mutex::Lock lm (io_lock);
629 /* check that our_port is really one of ours */
631 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
635 /* disconnect it from the source */
637 if (_session.engine().disconnect (other_port, our_port->name())) {
638 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
642 drop_input_connection();
646 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
647 _session.set_dirty ();
653 IO::connect_input (Port* our_port, string other_port, void* src)
655 if (other_port.length() == 0 || our_port == 0) {
660 BLOCK_PROCESS_CALLBACK ();
663 Glib::Mutex::Lock lm (io_lock);
665 /* check that our_port is really one of ours */
667 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
671 /* connect it to the source */
673 if (_session.engine().connect (other_port, our_port->name())) {
677 drop_input_connection ();
681 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
682 _session.set_dirty ();
687 IO::disconnect_output (Port* our_port, string other_port, void* src)
689 if (other_port.length() == 0 || our_port == 0) {
694 BLOCK_PROCESS_CALLBACK ();
697 Glib::Mutex::Lock lm (io_lock);
699 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
703 /* disconnect it from the destination */
705 if (_session.engine().disconnect (our_port->name(), other_port)) {
706 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
710 drop_output_connection ();
714 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
715 _session.set_dirty ();
720 IO::connect_output (Port* our_port, string other_port, void* src)
722 if (other_port.length() == 0 || our_port == 0) {
727 BLOCK_PROCESS_CALLBACK ();
731 Glib::Mutex::Lock lm (io_lock);
733 /* check that our_port is really one of ours */
735 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
739 /* connect it to the destination */
741 if (_session.engine().connect (our_port->name(), other_port)) {
745 drop_output_connection ();
749 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
750 _session.set_dirty ();
755 IO::set_input (Port* other_port, void* src)
757 /* this removes all but one ports, and connects that one port
758 to the specified source.
761 if (_input_minimum > 1 || _input_minimum == 0) {
762 /* sorry, you can't do this */
766 if (other_port == 0) {
767 if (_input_minimum < 0) {
768 return ensure_inputs (0, false, true, src);
774 if (ensure_inputs (1, true, true, src)) {
778 return connect_input (_inputs.front(), other_port->name(), src);
782 IO::remove_output_port (Port* port, void* src)
784 IOChange change (NoChange);
787 BLOCK_PROCESS_CALLBACK ();
791 Glib::Mutex::Lock lm (io_lock);
793 if (_noutputs - 1 == (uint32_t) _output_minimum) {
794 /* sorry, you can't do this */
798 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
800 change = IOChange (change|ConfigurationChanged);
801 if (port->connected()) {
802 change = IOChange (change|ConnectionsChanged);
805 _session.engine().unregister_port (*i);
808 drop_output_connection ();
814 if (change != NoChange) {
815 setup_peak_meters ();
821 if (change != NoChange) {
822 output_changed (change, src); /* EMIT SIGNAL */
823 _session.set_dirty ();
830 /** Add an output port.
832 * @param destination Name of input port to connect new port to.
833 * @param src Source for emitted ConfigurationChanged signal.
834 * @param type Data type of port. Default value (NIL) will use this IO's default type.
837 IO::add_output_port (string destination, void* src, DataType type)
841 if (type == DataType::NIL)
842 type = _default_type;
845 BLOCK_PROCESS_CALLBACK ();
849 Glib::Mutex::Lock lm (io_lock);
851 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
855 /* Create a new output port */
857 string portname = build_legal_port_name (false);
859 if ((our_port = _session.engine().register_output_port (type, portname)) == 0) {
860 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
864 _outputs.push_back (our_port);
865 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
867 drop_output_connection ();
868 setup_peak_meters ();
872 MoreOutputs (_noutputs); /* EMIT SIGNAL */
875 if (destination.length()) {
876 if (_session.engine().connect (our_port->name(), destination)) {
881 // pan_changed (src); /* EMIT SIGNAL */
882 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
883 _session.set_dirty ();
888 IO::remove_input_port (Port* port, void* src)
890 IOChange change (NoChange);
893 BLOCK_PROCESS_CALLBACK ();
897 Glib::Mutex::Lock lm (io_lock);
899 if (((int)_ninputs - 1) < _input_minimum) {
900 /* sorry, you can't do this */
903 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
906 change = IOChange (change|ConfigurationChanged);
908 if (port->connected()) {
909 change = IOChange (change|ConnectionsChanged);
912 _session.engine().unregister_port (*i);
915 drop_input_connection ();
921 if (change != NoChange) {
922 setup_peak_meters ();
928 if (change != NoChange) {
929 input_changed (change, src);
930 _session.set_dirty ();
938 /** Add an input port.
940 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
941 * @param destination Name of input port to connect new port to.
942 * @param src Source for emitted ConfigurationChanged signal.
945 IO::add_input_port (string source, void* src, DataType type)
949 if (type == DataType::NIL)
950 type = _default_type;
953 BLOCK_PROCESS_CALLBACK ();
956 Glib::Mutex::Lock lm (io_lock);
958 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
962 /* Create a new input port */
964 string portname = build_legal_port_name (true);
966 if ((our_port = _session.engine().register_input_port (type, portname)) == 0) {
967 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
971 _inputs.push_back (our_port);
972 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
974 drop_input_connection ();
975 setup_peak_meters ();
979 MoreOutputs (_ninputs); /* EMIT SIGNAL */
982 if (source.length()) {
984 if (_session.engine().connect (source, our_port->name())) {
989 // pan_changed (src); /* EMIT SIGNAL */
990 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
991 _session.set_dirty ();
997 IO::disconnect_inputs (void* src)
1000 BLOCK_PROCESS_CALLBACK ();
1003 Glib::Mutex::Lock lm (io_lock);
1005 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1006 _session.engine().disconnect (*i);
1009 drop_input_connection ();
1012 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1017 IO::disconnect_outputs (void* src)
1020 BLOCK_PROCESS_CALLBACK ();
1023 Glib::Mutex::Lock lm (io_lock);
1025 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1026 _session.engine().disconnect (*i);
1029 drop_output_connection ();
1033 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1034 _session.set_dirty ();
1039 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1042 bool changed = false;
1043 bool reduced = false;
1045 /* remove unused ports */
1047 while (_ninputs > n) {
1048 _session.engine().unregister_port (_inputs.back());
1055 /* create any necessary new ports */
1057 while (_ninputs < n) {
1059 /* Create a new input port (of the default type) */
1061 string portname = build_legal_port_name (true);
1065 if ((input_port = _session.engine().register_input_port (_default_type, portname)) == 0) {
1066 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
1071 catch (AudioEngine::PortRegistrationFailure& err) {
1072 setup_peak_meters ();
1078 _inputs.push_back (input_port);
1079 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1085 drop_input_connection ();
1086 setup_peak_meters ();
1088 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1089 _session.set_dirty ();
1093 /* disconnect all existing ports so that we get a fresh start */
1095 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1096 _session.engine().disconnect (*i);
1104 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1106 bool in_changed = false;
1107 bool out_changed = false;
1108 bool in_reduced = false;
1109 bool out_reduced = false;
1110 bool need_pan_reset;
1112 if (_input_maximum >= 0) {
1113 nin = min (_input_maximum, (int) nin);
1116 if (_output_maximum >= 0) {
1117 nout = min (_output_maximum, (int) nout);
1120 if (nin == _ninputs && nout == _noutputs && !clear) {
1125 BLOCK_PROCESS_CALLBACK ();
1126 Glib::Mutex::Lock lm (io_lock);
1130 if (_noutputs == nout) {
1131 need_pan_reset = false;
1133 need_pan_reset = true;
1136 /* remove unused ports */
1138 while (_ninputs > nin) {
1139 _session.engine().unregister_port (_inputs.back());
1146 while (_noutputs > nout) {
1147 _session.engine().unregister_port (_outputs.back());
1148 _outputs.pop_back();
1154 /* create any necessary new ports (of the default type) */
1156 while (_ninputs < nin) {
1158 /* Create a new input port */
1160 string portname = build_legal_port_name (true);
1163 if ((port = _session.engine().register_input_port (_default_type, portname)) == 0) {
1164 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
1169 catch (AudioEngine::PortRegistrationFailure& err) {
1170 setup_peak_meters ();
1176 _inputs.push_back (port);
1181 /* create any necessary new ports */
1183 while (_noutputs < nout) {
1185 string portname = build_legal_port_name (false);
1188 if ((port = _session.engine().register_output_port (_default_type, portname)) == 0) {
1189 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
1194 catch (AudioEngine::PortRegistrationFailure& err) {
1195 setup_peak_meters ();
1201 _outputs.push_back (port);
1208 /* disconnect all existing ports so that we get a fresh start */
1210 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1211 _session.engine().disconnect (*i);
1214 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1215 _session.engine().disconnect (*i);
1219 if (in_changed || out_changed) {
1220 setup_peak_meters ();
1226 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1227 drop_output_connection ();
1228 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1232 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1233 drop_input_connection ();
1234 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1237 if (in_changed || out_changed) {
1238 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1239 _session.set_dirty ();
1246 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1248 bool changed = false;
1250 if (_input_maximum >= 0) {
1251 n = min (_input_maximum, (int) n);
1253 if (n == _ninputs && !clear) {
1259 BLOCK_PROCESS_CALLBACK ();
1260 Glib::Mutex::Lock im (io_lock);
1261 changed = ensure_inputs_locked (n, clear, src);
1263 changed = ensure_inputs_locked (n, clear, src);
1267 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1268 _session.set_dirty ();
1275 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1278 bool changed = false;
1279 bool reduced = false;
1280 bool need_pan_reset;
1282 if (_noutputs == n) {
1283 need_pan_reset = false;
1285 need_pan_reset = true;
1288 /* remove unused ports */
1290 while (_noutputs > n) {
1292 _session.engine().unregister_port (_outputs.back());
1293 _outputs.pop_back();
1299 /* create any necessary new ports */
1301 while (_noutputs < n) {
1303 /* Create a new output port */
1305 string portname = build_legal_port_name (false);
1307 if ((output_port = _session.engine().register_output_port (_default_type, portname)) == 0) {
1308 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
1312 _outputs.push_back (output_port);
1313 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1316 setup_peak_meters ();
1318 if (need_pan_reset) {
1324 drop_output_connection ();
1325 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1326 _session.set_dirty ();
1330 /* disconnect all existing ports so that we get a fresh start */
1332 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1333 _session.engine().disconnect (*i);
1341 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1343 bool changed = false;
1345 if (_output_maximum >= 0) {
1346 n = min (_output_maximum, (int) n);
1347 if (n == _noutputs && !clear) {
1352 /* XXX caller should hold io_lock, but generally doesn't */
1355 BLOCK_PROCESS_CALLBACK ();
1356 Glib::Mutex::Lock im (io_lock);
1357 changed = ensure_outputs_locked (n, clear, src);
1359 changed = ensure_outputs_locked (n, clear, src);
1363 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1370 IO::effective_gain () const
1372 if (gain_automation_playback()) {
1373 return _effective_gain;
1375 return _desired_gain;
1382 if (panners_legal) {
1383 if (!no_panner_reset) {
1384 _panner->reset (_noutputs, pans_required());
1387 panner_legal_c.disconnect ();
1388 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1393 IO::panners_became_legal ()
1395 _panner->reset (_noutputs, pans_required());
1396 _panner->load (); // automation
1397 panner_legal_c.disconnect ();
1402 IO::defer_pan_reset ()
1404 no_panner_reset = true;
1408 IO::allow_pan_reset ()
1410 no_panner_reset = false;
1416 IO::get_state (void)
1418 return state (true);
1422 IO::state (bool full_state)
1424 XMLNode* node = new XMLNode (state_node_name);
1427 bool need_ins = true;
1428 bool need_outs = true;
1429 LocaleGuard lg (X_("POSIX"));
1430 Glib::Mutex::Lock lm (io_lock);
1432 node->add_property("name", _name);
1433 id().print (buf, sizeof (buf));
1434 node->add_property("id", buf);
1435 node->add_property("active", _active? "yes" : "no");
1439 if (_input_connection) {
1440 node->add_property ("input-connection", _input_connection->name());
1444 if (_output_connection) {
1445 node->add_property ("output-connection", _output_connection->name());
1450 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1452 const char **connections = (*i)->get_connections();
1454 if (connections && connections[0]) {
1457 for (int n = 0; connections && connections[n]; ++n) {
1462 /* if its a connection to our own port,
1463 return only the port name, not the
1464 whole thing. this allows connections
1465 to be re-established even when our
1466 client name is different.
1469 str += _session.engine().make_port_name_relative (connections[n]);
1481 node->add_property ("inputs", str);
1487 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1489 const char **connections = (*i)->get_connections();
1491 if (connections && connections[0]) {
1495 for (int n = 0; connections[n]; ++n) {
1500 str += _session.engine().make_port_name_relative (connections[n]);
1512 node->add_property ("outputs", str);
1515 node->add_child_nocopy (_panner->state (full_state));
1516 node->add_child_nocopy (_gain_control.get_state ());
1518 snprintf (buf, sizeof(buf), "%2.12f", gain());
1519 node->add_property ("gain", buf);
1521 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1527 node->add_property ("iolimits", buf);
1533 XMLNode* autonode = new XMLNode (X_("Automation"));
1534 autonode->add_child_nocopy (get_automation_state());
1535 node->add_child_nocopy (*autonode);
1537 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1539 /* never store anything except Off for automation state in a template */
1540 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1547 IO::set_state (const XMLNode& node)
1549 const XMLProperty* prop;
1550 XMLNodeConstIterator iter;
1551 LocaleGuard lg (X_("POSIX"));
1553 /* force use of non-localized representation of decimal point,
1554 since we use it a lot in XML files and so forth.
1557 if (node.name() != state_node_name) {
1558 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1562 if ((prop = node.property ("name")) != 0) {
1563 _name = prop->value();
1564 /* used to set panner name with this, but no more */
1567 if ((prop = node.property ("id")) != 0) {
1568 _id = prop->value ();
1571 if ((prop = node.property ("iolimits")) != 0) {
1572 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1579 if ((prop = node.property ("gain")) != 0) {
1580 set_gain (atof (prop->value().c_str()), this);
1581 _gain = _desired_gain;
1584 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1585 /* old school automation handling */
1588 if ((prop = node.property (X_("active"))) != 0) {
1589 set_active (prop->value() == "yes");
1592 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1594 if ((*iter)->name() == "Panner") {
1596 _panner = new Panner (_name, _session);
1598 _panner->set_state (**iter);
1601 if ((*iter)->name() == X_("Automation")) {
1603 set_automation_state (*(*iter)->children().front());
1606 if ((*iter)->name() == X_("controllable")) {
1607 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1608 _gain_control.set_state (**iter);
1615 if (create_ports (node)) {
1621 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1624 if (panners_legal) {
1627 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1630 if (connecting_legal) {
1632 if (make_connections (node)) {
1638 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1641 if (!ports_legal || !connecting_legal) {
1642 pending_state_node = new XMLNode (node);
1645 last_automation_snapshot = 0;
1651 IO::set_automation_state (const XMLNode& node)
1653 return _gain_automation_curve.set_state (node);
1657 IO::get_automation_state ()
1659 return (_gain_automation_curve.get_state ());
1663 IO::load_automation (string path)
1668 uint32_t linecnt = 0;
1670 LocaleGuard lg (X_("POSIX"));
1672 fullpath = _session.automation_dir();
1675 in.open (fullpath.c_str());
1678 fullpath = _session.automation_dir();
1679 fullpath += _session.snap_name();
1683 in.open (fullpath.c_str());
1686 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1691 clear_automation ();
1693 while (in.getline (line, sizeof(line), '\n')) {
1695 jack_nframes_t when;
1698 if (++linecnt == 1) {
1699 if (memcmp (line, "version", 7) == 0) {
1700 if (sscanf (line, "version %f", &version) != 1) {
1701 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1705 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1712 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1713 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1719 _gain_automation_curve.fast_simple_add (when, value);
1729 /* older (pre-1.0) versions of ardour used this */
1733 warning << _("dubious automation event found (and ignored)") << endmsg;
1741 IO::connecting_became_legal ()
1745 if (pending_state_node == 0) {
1746 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1751 connection_legal_c.disconnect ();
1753 ret = make_connections (*pending_state_node);
1756 delete pending_state_node;
1757 pending_state_node = 0;
1763 IO::ports_became_legal ()
1767 if (pending_state_node == 0) {
1768 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1773 port_legal_c.disconnect ();
1775 ret = create_ports (*pending_state_node);
1777 if (connecting_legal) {
1778 delete pending_state_node;
1779 pending_state_node = 0;
1786 IO::create_ports (const XMLNode& node)
1788 const XMLProperty* prop;
1790 int num_outputs = 0;
1792 if ((prop = node.property ("input-connection")) != 0) {
1794 Connection* c = _session.connection_by_name (prop->value());
1797 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1799 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1800 error << _("No input connections available as a replacement")
1804 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1809 num_inputs = c->nports();
1811 } else if ((prop = node.property ("inputs")) != 0) {
1813 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1816 if ((prop = node.property ("output-connection")) != 0) {
1817 Connection* c = _session.connection_by_name (prop->value());
1820 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1822 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1823 error << _("No output connections available as a replacement")
1827 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1832 num_outputs = c->nports ();
1834 } else if ((prop = node.property ("outputs")) != 0) {
1835 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1838 no_panner_reset = true;
1840 if (ensure_io (num_inputs, num_outputs, true, this)) {
1841 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1845 no_panner_reset = false;
1847 set_deferred_state ();
1855 IO::make_connections (const XMLNode& node)
1857 const XMLProperty* prop;
1859 if ((prop = node.property ("input-connection")) != 0) {
1860 Connection* c = _session.connection_by_name (prop->value());
1863 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1865 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1866 error << _("No input connections available as a replacement")
1870 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1875 use_input_connection (*c, this);
1877 } else if ((prop = node.property ("inputs")) != 0) {
1878 if (set_inputs (prop->value())) {
1879 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1884 if ((prop = node.property ("output-connection")) != 0) {
1885 Connection* c = _session.connection_by_name (prop->value());
1888 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1890 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1891 error << _("No output connections available as a replacement")
1895 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1900 use_output_connection (*c, this);
1902 } else if ((prop = node.property ("outputs")) != 0) {
1903 if (set_outputs (prop->value())) {
1904 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1913 IO::set_inputs (const string& str)
1915 vector<string> ports;
1920 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1924 if (ensure_inputs (nports, true, true, this)) {
1928 string::size_type start, end, ostart;
1935 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1938 if ((end = str.find_first_of ('}', start)) == string::npos) {
1939 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1943 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1944 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1950 for (int x = 0; x < n; ++x) {
1951 connect_input (input (i), ports[x], this);
1963 IO::set_outputs (const string& str)
1965 vector<string> ports;
1970 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1974 if (ensure_outputs (nports, true, true, this)) {
1978 string::size_type start, end, ostart;
1985 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1988 if ((end = str.find_first_of ('}', start)) == string::npos) {
1989 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1993 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1994 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2000 for (int x = 0; x < n; ++x) {
2001 connect_output (output (i), ports[x], this);
2013 IO::parse_io_string (const string& str, vector<string>& ports)
2015 string::size_type pos, opos;
2017 if (str.length() == 0) {
2026 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2027 ports.push_back (str.substr (opos, pos - opos));
2031 if (opos < str.length()) {
2032 ports.push_back (str.substr(opos));
2035 return ports.size();
2039 IO::parse_gain_string (const string& str, vector<string>& ports)
2041 string::size_type pos, opos;
2047 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2048 ports.push_back (str.substr (opos, pos - opos));
2052 if (opos < str.length()) {
2053 ports.push_back (str.substr(opos));
2056 return ports.size();
2060 IO::set_name (string requested_name, void* src)
2062 if (requested_name == _name) {
2068 if ( (rt = dynamic_cast<Route *>(this))) {
2069 name = Route::ensure_track_or_route_name(requested_name, _session);
2071 name = requested_name;
2075 /* replace all colons in the name. i wish we didn't have to do this */
2077 if (replace_all (name, ":", "-")) {
2078 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
2081 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2082 string current_name = (*i)->short_name();
2083 current_name.replace (current_name.find (_name), _name.length(), name);
2084 (*i)->set_name (current_name);
2087 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2088 string current_name = (*i)->short_name();
2089 current_name.replace (current_name.find (_name), _name.length(), name);
2090 (*i)->set_name (current_name);
2094 name_changed (src); /* EMIT SIGNAL */
2100 IO::set_input_minimum (int n)
2106 IO::set_input_maximum (int n)
2112 IO::set_output_minimum (int n)
2114 _output_minimum = n;
2118 IO::set_output_maximum (int n)
2120 _output_maximum = n;
2124 IO::set_port_latency (nframes_t nframes)
2126 Glib::Mutex::Lock lm (io_lock);
2128 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2129 (*i)->set_latency (nframes);
2134 IO::output_latency () const
2136 nframes_t max_latency;
2141 /* io lock not taken - must be protected by other means */
2143 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2144 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2145 max_latency = latency;
2153 IO::input_latency () const
2155 nframes_t max_latency;
2160 /* io lock not taken - must be protected by other means */
2162 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2163 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2164 max_latency = latency;
2172 IO::use_input_connection (Connection& c, void* src)
2177 BLOCK_PROCESS_CALLBACK ();
2178 Glib::Mutex::Lock lm2 (io_lock);
2182 drop_input_connection ();
2184 if (ensure_inputs (limit, false, false, src)) {
2188 /* first pass: check the current state to see what's correctly
2189 connected, and drop anything that we don't want.
2192 for (uint32_t n = 0; n < limit; ++n) {
2193 const Connection::PortList& pl = c.port_connections (n);
2195 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2197 if (!_inputs[n]->connected_to ((*i))) {
2199 /* clear any existing connections */
2201 _session.engine().disconnect (_inputs[n]);
2203 } else if (_inputs[n]->connected() > 1) {
2205 /* OK, it is connected to the port we want,
2206 but its also connected to other ports.
2207 Change that situation.
2210 /* XXX could be optimized to not drop
2214 _session.engine().disconnect (_inputs[n]);
2220 /* second pass: connect all requested ports where necessary */
2222 for (uint32_t n = 0; n < limit; ++n) {
2223 const Connection::PortList& pl = c.port_connections (n);
2225 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2227 if (!_inputs[n]->connected_to ((*i))) {
2229 if (_session.engine().connect (*i, _inputs[n]->name())) {
2237 _input_connection = &c;
2239 input_connection_configuration_connection = c.ConfigurationChanged.connect
2240 (mem_fun (*this, &IO::input_connection_configuration_changed));
2241 input_connection_connection_connection = c.ConnectionsChanged.connect
2242 (mem_fun (*this, &IO::input_connection_connection_changed));
2245 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2250 IO::use_output_connection (Connection& c, void* src)
2255 BLOCK_PROCESS_CALLBACK ();
2256 Glib::Mutex::Lock lm2 (io_lock);
2260 drop_output_connection ();
2262 if (ensure_outputs (limit, false, false, src)) {
2266 /* first pass: check the current state to see what's correctly
2267 connected, and drop anything that we don't want.
2270 for (uint32_t n = 0; n < limit; ++n) {
2272 const Connection::PortList& pl = c.port_connections (n);
2274 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2276 if (!_outputs[n]->connected_to ((*i))) {
2278 /* clear any existing connections */
2280 _session.engine().disconnect (_outputs[n]);
2282 } else if (_outputs[n]->connected() > 1) {
2284 /* OK, it is connected to the port we want,
2285 but its also connected to other ports.
2286 Change that situation.
2289 /* XXX could be optimized to not drop
2293 _session.engine().disconnect (_outputs[n]);
2298 /* second pass: connect all requested ports where necessary */
2300 for (uint32_t n = 0; n < limit; ++n) {
2302 const Connection::PortList& pl = c.port_connections (n);
2304 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2306 if (!_outputs[n]->connected_to ((*i))) {
2308 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2315 _output_connection = &c;
2317 output_connection_configuration_connection = c.ConfigurationChanged.connect
2318 (mem_fun (*this, &IO::output_connection_configuration_changed));
2319 output_connection_connection_connection = c.ConnectionsChanged.connect
2320 (mem_fun (*this, &IO::output_connection_connection_changed));
2323 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2329 IO::disable_connecting ()
2331 connecting_legal = false;
2336 IO::enable_connecting ()
2338 connecting_legal = true;
2339 return ConnectingLegal ();
2343 IO::disable_ports ()
2345 ports_legal = false;
2353 return PortsLegal ();
2357 IO::disable_panners (void)
2359 panners_legal = false;
2364 IO::reset_panners ()
2366 panners_legal = true;
2367 return PannersLegal ();
2371 IO::input_connection_connection_changed (int ignored)
2373 use_input_connection (*_input_connection, this);
2377 IO::input_connection_configuration_changed ()
2379 use_input_connection (*_input_connection, this);
2383 IO::output_connection_connection_changed (int ignored)
2385 use_output_connection (*_output_connection, this);
2389 IO::output_connection_configuration_changed ()
2391 use_output_connection (*_output_connection, this);
2395 IO::GainControllable::set_value (float val)
2397 io.set_gain (direct_control_to_gain (val), this);
2401 IO::GainControllable::get_value (void) const
2403 return direct_gain_to_control (io.effective_gain());
2407 IO::reset_peak_meters ()
2409 uint32_t limit = max (_ninputs, _noutputs);
2411 for (uint32_t i = 0; i < limit; ++i) {
2417 IO::reset_max_peak_meters ()
2419 uint32_t limit = max (_ninputs, _noutputs);
2421 for (uint32_t i = 0; i < limit; ++i) {
2422 _max_peak_power[i] = -INFINITY;
2427 IO::setup_peak_meters ()
2429 uint32_t limit = max (_ninputs, _noutputs);
2431 while (_peak_power.size() < limit) {
2432 _peak_power.push_back (0);
2433 _visible_peak_power.push_back (-INFINITY);
2434 _max_peak_power.push_back (-INFINITY);
2439 Update the peak meters.
2441 The meter signal lock is taken to prevent modification of the
2442 Meter signal while updating the meters, taking the meter signal
2443 lock prior to taking the io_lock ensures that all IO will remain
2444 valid while metering.
2449 Glib::Mutex::Lock guard (m_meter_signal_lock);
2456 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2457 uint32_t limit = max (_ninputs, _noutputs);
2459 for (uint32_t n = 0; n < limit; ++n) {
2461 /* XXX we should use atomic exchange here */
2463 /* grab peak since last read */
2465 float new_peak = _peak_power[n];
2468 /* compute new visible value using falloff */
2470 if (new_peak > 0.0f) {
2471 new_peak = coefficient_to_dB (new_peak);
2473 new_peak = -INFINITY;
2476 /* update max peak */
2478 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2480 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2481 _visible_peak_power[n] = new_peak;
2483 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2484 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2485 _visible_peak_power[n] = max (new_peak, -INFINITY);
2491 IO::clear_automation ()
2493 Glib::Mutex::Lock lm (automation_lock);
2494 _gain_automation_curve.clear ();
2495 _panner->clear_automation ();
2499 IO::set_gain_automation_state (AutoState state)
2501 bool changed = false;
2504 Glib::Mutex::Lock lm (automation_lock);
2506 if (state != _gain_automation_curve.automation_state()) {
2508 last_automation_snapshot = 0;
2509 _gain_automation_curve.set_automation_state (state);
2512 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2518 _session.set_dirty ();
2519 gain_automation_state_changed (); /* EMIT SIGNAL */
2524 IO::set_gain_automation_style (AutoStyle style)
2526 bool changed = false;
2529 Glib::Mutex::Lock lm (automation_lock);
2531 if (style != _gain_automation_curve.automation_style()) {
2533 _gain_automation_curve.set_automation_style (style);
2538 gain_automation_style_changed (); /* EMIT SIGNAL */
2542 IO::inc_gain (gain_t factor, void *src)
2544 if (_desired_gain == 0.0f)
2545 set_gain (0.000001f + (0.000001f * factor), src);
2547 set_gain (_desired_gain + (_desired_gain * factor), src);
2551 IO::set_gain (gain_t val, void *src)
2553 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2554 if (val>1.99526231f) val=1.99526231f;
2557 Glib::Mutex::Lock dm (declick_lock);
2558 _desired_gain = val;
2561 if (_session.transport_stopped()) {
2562 _effective_gain = val;
2567 _gain_control.Changed (); /* EMIT SIGNAL */
2569 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2570 _gain_automation_curve.add (_session.transport_frame(), val);
2573 _session.set_dirty();
2577 IO::start_gain_touch ()
2579 _gain_automation_curve.start_touch ();
2583 IO::end_gain_touch ()
2585 _gain_automation_curve.stop_touch ();
2589 IO::start_pan_touch (uint32_t which)
2591 if (which < _panner->size()) {
2592 (*_panner)[which]->automation().start_touch();
2597 IO::end_pan_touch (uint32_t which)
2599 if (which < _panner->size()) {
2600 (*_panner)[which]->automation().stop_touch();
2606 IO::automation_snapshot (nframes_t now, bool force)
2608 if (gain_automation_recording()) {
2609 _gain_automation_curve.rt_add (now, gain());
2612 _panner->snapshot (now);
2613 last_automation_snapshot = now;
2617 IO::transport_stopped (nframes_t frame)
2619 _gain_automation_curve.reposition_for_rt_add (frame);
2621 if (_gain_automation_curve.automation_state() != Off) {
2623 /* the src=0 condition is a special signal to not propagate
2624 automation gain changes into the mix group when locating.
2627 set_gain (_gain_automation_curve.eval (frame), 0);
2630 _panner->transport_stopped (frame);
2634 IO::build_legal_port_name (bool in)
2636 const int name_size = jack_port_name_size();
2643 maxports = _input_maximum;
2646 maxports = _output_maximum;
2649 if (maxports == 1) {
2650 // allow space for the slash + the suffix
2651 limit = name_size - _session.engine().client_name().length() - (strlen (suffix) + 1);
2652 char buf[name_size+1];
2653 snprintf (buf, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix);
2654 return string (buf);
2657 // allow up to 4 digits for the output port number, plus the slash, suffix and extra space
2659 limit = name_size - _session.engine().client_name().length() - (strlen (suffix) + 5);
2661 char buf1[name_size+1];
2662 char buf2[name_size+1];
2664 snprintf (buf1, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix);
2669 port_number = find_input_port_hole (buf1);
2671 port_number = find_output_port_hole (buf1);
2674 snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
2676 return string (buf2);
2680 IO::find_input_port_hole (const char* base)
2682 /* CALLER MUST HOLD IO LOCK */
2686 if (_inputs.empty()) {
2690 /* we only allow up to 4 characters for the port number
2693 for (n = 1; n < 9999; ++n) {
2694 char buf[jack_port_name_size()];
2695 vector<Port*>::iterator i;
2697 snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
2699 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2700 if ((*i)->short_name() == buf) {
2705 if (i == _inputs.end()) {
2713 IO::find_output_port_hole (const char* base)
2715 /* CALLER MUST HOLD IO LOCK */
2719 if (_outputs.empty()) {
2723 /* we only allow up to 4 characters for the port number
2726 for (n = 1; n < 9999; ++n) {
2727 char buf[jack_port_name_size()];
2728 vector<Port*>::iterator i;
2730 snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
2732 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2733 if ((*i)->short_name() == buf) {
2738 if (i == _outputs.end()) {
2747 IO::set_active (bool yn)
2750 active_changed(); /* EMIT SIGNAL */