2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
31 #include <pbd/replace_all.h>
33 #include <ardour/audioengine.h>
34 #include <ardour/io.h>
35 #include <ardour/port.h>
36 #include <ardour/connection.h>
37 #include <ardour/session.h>
38 #include <ardour/cycle_timer.h>
39 #include <ardour/panner.h>
40 #include <ardour/dB.h>
47 A bug in OS X's cmath that causes isnan() and isinf() to be
48 "undeclared". the following works around that
51 #if defined(__APPLE__) && defined(__MACH__)
52 extern "C" int isnan (double);
53 extern "C" int isinf (double);
56 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
59 using namespace ARDOUR;
62 nframes_t IO::_automation_interval = 0;
63 const string IO::state_node_name = "IO";
64 bool IO::connecting_legal = false;
65 bool IO::ports_legal = false;
66 bool IO::panners_legal = false;
67 sigc::signal<void> IO::Meter;
68 sigc::signal<int> IO::ConnectingLegal;
69 sigc::signal<int> IO::PortsLegal;
70 sigc::signal<int> IO::PannersLegal;
71 sigc::signal<void,uint32_t> IO::MoreOutputs;
72 sigc::signal<int> IO::PortsCreated;
74 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
76 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
77 others can be imagined.
80 static gain_t direct_control_to_gain (double fract) {
81 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
82 /* this maxes at +6dB */
83 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
86 static double direct_gain_to_control (gain_t gain) {
87 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
88 if (gain == 0) return 0.0;
90 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
93 static bool sort_ports_by_name (Port* a, Port* b)
95 return a->name() < b->name();
99 /** @param default_type The type of port that will be created by ensure_io
100 * and friends if no type is explicitly requested (to avoid breakage).
102 IO::IO (Session& s, string name,
103 int input_min, int input_max, int output_min, int output_max,
104 DataType default_type)
107 _default_type(default_type),
108 _gain_control (X_("gaincontrol"), *this),
109 _gain_automation_curve (0.0, 2.0, 1.0),
110 _input_minimum (input_min),
111 _input_maximum (input_max),
112 _output_minimum (output_min),
113 _output_maximum (output_max)
115 _panner = new Panner (name, _session);
119 _input_connection = 0;
120 _output_connection = 0;
121 pending_state_node = 0;
124 no_panner_reset = false;
127 apply_gain_automation = false;
128 _ignore_gain_on_deliver = false;
130 last_automation_snapshot = 0;
132 _gain_automation_state = Off;
133 _gain_automation_style = Absolute;
136 // IO::Meter is emitted from another thread so the
137 // Meter signal must be protected.
138 Glib::Mutex::Lock guard (m_meter_signal_lock);
139 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
142 _session.add_controllable (&_gain_control);
145 IO::IO (Session& s, const XMLNode& node, DataType dt)
148 _gain_control (X_("gaincontrol"), *this),
149 _gain_automation_curve (0, 0, 0) // all reset in set_state()
154 no_panner_reset = false;
157 _input_connection = 0;
158 _output_connection = 0;
162 apply_gain_automation = false;
163 _ignore_gain_on_deliver = false;
168 // IO::Meter is emitted from another thread so the
169 // Meter signal must be protected.
170 Glib::Mutex::Lock guard (m_meter_signal_lock);
171 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
174 _session.add_controllable (&_gain_control);
179 Glib::Mutex::Lock guard (m_meter_signal_lock);
181 Glib::Mutex::Lock lm (io_lock);
182 vector<Port *>::iterator i;
185 BLOCK_PROCESS_CALLBACK ();
187 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
188 _session.engine().unregister_port (*i);
191 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
192 _session.engine().unregister_port (*i);
196 m_meter_connection.disconnect();
200 IO::silence (nframes_t nframes, nframes_t offset)
202 /* io_lock, not taken: function must be called from Session::process() calltree */
204 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
205 (*i)->silence (nframes, offset);
210 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
212 nframes_t declick = min ((nframes_t)128, nframes);
215 double fractional_shift;
216 double fractional_pos;
217 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
219 if (nframes == 0) return;
221 fractional_shift = -1.0/declick;
223 if (target < initial) {
224 /* fade out: remove more and more of delta from initial */
225 delta = -(initial - target);
227 /* fade in: add more and more of delta from initial */
228 delta = target - initial;
231 for (uint32_t n = 0; n < nbufs; ++n) {
234 fractional_pos = 1.0;
236 for (nframes_t nx = 0; nx < declick; ++nx) {
237 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
238 fractional_pos += fractional_shift;
241 /* now ensure the rest of the buffer has the target value
242 applied, if necessary.
245 if (declick != nframes) {
248 if (invert_polarity) {
249 this_target = -target;
251 this_target = target;
254 if (this_target == 0.0) {
255 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
256 } else if (this_target != 1.0) {
257 for (nframes_t nx = declick; nx < nframes; ++nx) {
258 buffer[nx] *= this_target;
266 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
270 /* io_lock, not taken: function must be called from Session::process() calltree */
272 if (_noutputs == 0) {
276 if (_noutputs == 1) {
278 dst = output(0)->get_buffer (nframes) + offset;
280 for (uint32_t n = 0; n < nbufs; ++n) {
281 if (bufs[n] != dst) {
282 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
286 output(0)->mark_silence (false);
292 vector<Port *>::iterator out;
293 vector<Sample *>::iterator in;
294 Panner::iterator pan;
295 Sample* obufs[_noutputs];
297 /* the terrible silence ... */
299 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
300 obufs[o] = (*out)->get_buffer (nframes) + offset;
301 memset (obufs[o], 0, sizeof (Sample) * nframes);
302 (*out)->mark_silence (false);
307 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
308 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
313 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
318 /* io_lock, not taken: function must be called from Session::process() calltree */
320 if (_noutputs == 0) {
324 /* the panner can be empty if there are no inputs to the
325 route, but still outputs
328 if (_panner->bypassed() || _panner->empty()) {
329 deliver_output_no_pan (bufs, nbufs, nframes, offset);
333 if (_noutputs == 1) {
335 dst = output(0)->get_buffer (nframes) + offset;
337 if (gain_coeff == 0.0f) {
339 /* only one output, and gain was zero, so make it silent */
341 memset (dst, 0, sizeof (Sample) * nframes);
343 } else if (gain_coeff == 1.0f){
345 /* mix all buffers into the output */
349 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
351 for (n = 1; n < nbufs; ++n) {
352 Session::mix_buffers_no_gain(dst,bufs[n],nframes);
355 output(0)->mark_silence (false);
359 /* mix all buffers into the output, scaling them all by the gain */
365 for (nframes_t n = 0; n < nframes; ++n) {
366 dst[n] = src[n] * gain_coeff;
369 for (n = 1; n < nbufs; ++n) {
370 Session::mix_buffers_with_gain(dst,bufs[n],nframes,gain_coeff);
373 output(0)->mark_silence (false);
380 vector<Port *>::iterator out;
381 vector<Sample *>::iterator in;
382 Panner::iterator pan;
383 Sample* obufs[_noutputs];
385 /* the terrible silence ... */
387 /* XXX this is wasteful but i see no way to avoid it */
389 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
390 obufs[o] = (*out)->get_buffer (nframes) + offset;
391 memset (obufs[o], 0, sizeof (Sample) * nframes);
392 (*out)->mark_silence (false);
397 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
398 Panner::iterator tmp;
403 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
405 if (tmp != _panner->end()) {
412 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
414 /* io_lock, not taken: function must be called from Session::process() calltree */
416 if (_noutputs == 0) {
420 if (_panner->bypassed() || _panner->empty()) {
421 deliver_output_no_pan (bufs, nbufs, nframes, offset);
427 gain_t pangain = _gain;
430 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
440 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
445 /* simple, non-automation panning to outputs */
447 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
448 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
450 pan (bufs, nbufs, nframes, offset, pangain);
455 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
457 /* io_lock, not taken: function must be called from Session::process() calltree */
459 if (_noutputs == 0) {
464 gain_t old_gain = _gain;
466 if (apply_gain_automation || _ignore_gain_on_deliver) {
468 /* gain has already been applied by automation code. do nothing here except
477 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
489 vector<Port*>::iterator o;
490 vector<Sample*> outs;
493 /* reduce nbufs to the index of the last input buffer */
497 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
498 actual_gain = _gain * speed_quietning;
503 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
505 dst = (*o)->get_buffer (nframes) + offset;
506 src = bufs[min(nbufs,i)];
509 /* unlikely condition */
510 outs.push_back (dst);
513 if (dg != _gain || actual_gain == 1.0f) {
514 memcpy (dst, src, sizeof (Sample) * nframes);
515 } else if (actual_gain == 0.0f) {
516 memset (dst, 0, sizeof (Sample) * nframes);
518 for (nframes_t x = 0; x < nframes; ++x) {
519 dst[x] = src[x] * actual_gain;
523 (*o)->mark_silence (false);
527 apply_declick (outs, i, nframes, _gain, dg, false);
531 if (apply_gain_automation || _ignore_gain_on_deliver) {
537 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
539 /* io_lock, not taken: function must be called from Session::process() calltree */
541 vector<Port *>::iterator i;
545 /* we require that bufs.size() >= 1 */
547 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
548 if (i == _inputs.end()) {
552 /* XXX always read the full extent of the port buffer that
553 we need. One day, we may use jack_port_get_buffer_at_offset()
554 or something similar. For now, this simple hack will
557 Hack? Why yes .. we only need to read nframes-worth of
558 data, but the data we want is at `offset' within the
562 last = (*i)->get_buffer (nframes+offset) + offset;
563 // the dest buffer's offset has already been applied
564 memcpy (bufs[n], last, sizeof (Sample) * nframes);
567 /* fill any excess outputs with the last input */
571 // the dest buffer's offset has already been applied
572 memcpy (bufs[n], last, sizeof (Sample) * nframes);
577 memset (bufs[n], 0, sizeof (Sample) * nframes);
584 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
585 nframes_t nframes, nframes_t offset)
587 vector<Sample*>& bufs = _session.get_passthru_buffers ();
588 uint32_t nbufs = n_process_buffers ();
590 collect_input (bufs, nbufs, nframes, offset);
592 for (uint32_t n = 0; n < nbufs; ++n) {
593 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
598 IO::drop_input_connection ()
600 _input_connection = 0;
601 input_connection_configuration_connection.disconnect();
602 input_connection_connection_connection.disconnect();
603 _session.set_dirty ();
607 IO::drop_output_connection ()
609 _output_connection = 0;
610 output_connection_configuration_connection.disconnect();
611 output_connection_connection_connection.disconnect();
612 _session.set_dirty ();
616 IO::disconnect_input (Port* our_port, string other_port, void* src)
618 if (other_port.length() == 0 || our_port == 0) {
623 BLOCK_PROCESS_CALLBACK ();
626 Glib::Mutex::Lock lm (io_lock);
628 /* check that our_port is really one of ours */
630 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
634 /* disconnect it from the source */
636 if (_session.engine().disconnect (other_port, our_port->name())) {
637 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
641 drop_input_connection();
645 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
646 _session.set_dirty ();
652 IO::connect_input (Port* our_port, string other_port, void* src)
654 if (other_port.length() == 0 || our_port == 0) {
659 BLOCK_PROCESS_CALLBACK ();
662 Glib::Mutex::Lock lm (io_lock);
664 /* check that our_port is really one of ours */
666 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
670 /* connect it to the source */
672 if (_session.engine().connect (other_port, our_port->name())) {
676 drop_input_connection ();
680 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
681 _session.set_dirty ();
686 IO::disconnect_output (Port* our_port, string other_port, void* src)
688 if (other_port.length() == 0 || our_port == 0) {
693 BLOCK_PROCESS_CALLBACK ();
696 Glib::Mutex::Lock lm (io_lock);
698 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
702 /* disconnect it from the destination */
704 if (_session.engine().disconnect (our_port->name(), other_port)) {
705 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
709 drop_output_connection ();
713 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
714 _session.set_dirty ();
719 IO::connect_output (Port* our_port, string other_port, void* src)
721 if (other_port.length() == 0 || our_port == 0) {
726 BLOCK_PROCESS_CALLBACK ();
730 Glib::Mutex::Lock lm (io_lock);
732 /* check that our_port is really one of ours */
734 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
738 /* connect it to the destination */
740 if (_session.engine().connect (our_port->name(), other_port)) {
744 drop_output_connection ();
748 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
749 _session.set_dirty ();
754 IO::set_input (Port* other_port, void* src)
756 /* this removes all but one ports, and connects that one port
757 to the specified source.
760 if (_input_minimum > 1 || _input_minimum == 0) {
761 /* sorry, you can't do this */
765 if (other_port == 0) {
766 if (_input_minimum < 0) {
767 return ensure_inputs (0, false, true, src);
773 if (ensure_inputs (1, true, true, src)) {
777 return connect_input (_inputs.front(), other_port->name(), src);
781 IO::remove_output_port (Port* port, void* src)
783 IOChange change (NoChange);
786 BLOCK_PROCESS_CALLBACK ();
790 Glib::Mutex::Lock lm (io_lock);
792 if (_noutputs - 1 == (uint32_t) _output_minimum) {
793 /* sorry, you can't do this */
797 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
799 change = IOChange (change|ConfigurationChanged);
800 if (port->connected()) {
801 change = IOChange (change|ConnectionsChanged);
804 _session.engine().unregister_port (*i);
807 drop_output_connection ();
813 if (change != NoChange) {
814 setup_peak_meters ();
820 if (change != NoChange) {
821 output_changed (change, src); /* EMIT SIGNAL */
822 _session.set_dirty ();
829 /** Add an output port.
831 * @param destination Name of input port to connect new port to.
832 * @param src Source for emitted ConfigurationChanged signal.
833 * @param type Data type of port. Default value (NIL) will use this IO's default type.
836 IO::add_output_port (string destination, void* src, DataType type)
840 if (type == DataType::NIL)
841 type = _default_type;
844 BLOCK_PROCESS_CALLBACK ();
848 Glib::Mutex::Lock lm (io_lock);
850 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
854 /* Create a new output port */
856 string portname = build_legal_port_name (false);
858 if ((our_port = _session.engine().register_output_port (type, portname)) == 0) {
859 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
863 _outputs.push_back (our_port);
864 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
866 drop_output_connection ();
867 setup_peak_meters ();
871 MoreOutputs (_noutputs); /* EMIT SIGNAL */
874 if (destination.length()) {
875 if (_session.engine().connect (our_port->name(), destination)) {
880 // pan_changed (src); /* EMIT SIGNAL */
881 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
882 _session.set_dirty ();
887 IO::remove_input_port (Port* port, void* src)
889 IOChange change (NoChange);
892 BLOCK_PROCESS_CALLBACK ();
896 Glib::Mutex::Lock lm (io_lock);
898 if (((int)_ninputs - 1) < _input_minimum) {
899 /* sorry, you can't do this */
902 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
905 change = IOChange (change|ConfigurationChanged);
907 if (port->connected()) {
908 change = IOChange (change|ConnectionsChanged);
911 _session.engine().unregister_port (*i);
914 drop_input_connection ();
920 if (change != NoChange) {
921 setup_peak_meters ();
927 if (change != NoChange) {
928 input_changed (change, src);
929 _session.set_dirty ();
937 /** Add an input port.
939 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
940 * @param destination Name of input port to connect new port to.
941 * @param src Source for emitted ConfigurationChanged signal.
944 IO::add_input_port (string source, void* src, DataType type)
948 if (type == DataType::NIL)
949 type = _default_type;
952 BLOCK_PROCESS_CALLBACK ();
955 Glib::Mutex::Lock lm (io_lock);
957 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
961 /* Create a new input port */
963 string portname = build_legal_port_name (true);
965 if ((our_port = _session.engine().register_input_port (type, portname)) == 0) {
966 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
970 _inputs.push_back (our_port);
971 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
973 drop_input_connection ();
974 setup_peak_meters ();
978 MoreOutputs (_ninputs); /* EMIT SIGNAL */
981 if (source.length()) {
983 if (_session.engine().connect (source, our_port->name())) {
988 // pan_changed (src); /* EMIT SIGNAL */
989 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
990 _session.set_dirty ();
996 IO::disconnect_inputs (void* src)
999 BLOCK_PROCESS_CALLBACK ();
1002 Glib::Mutex::Lock lm (io_lock);
1004 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1005 _session.engine().disconnect (*i);
1008 drop_input_connection ();
1011 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1016 IO::disconnect_outputs (void* src)
1019 BLOCK_PROCESS_CALLBACK ();
1022 Glib::Mutex::Lock lm (io_lock);
1024 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1025 _session.engine().disconnect (*i);
1028 drop_output_connection ();
1032 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1033 _session.set_dirty ();
1038 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1041 bool changed = false;
1042 bool reduced = false;
1044 /* remove unused ports */
1046 while (_ninputs > n) {
1047 _session.engine().unregister_port (_inputs.back());
1054 /* create any necessary new ports */
1056 while (_ninputs < n) {
1058 /* Create a new input port (of the default type) */
1060 string portname = build_legal_port_name (true);
1064 if ((input_port = _session.engine().register_input_port (_default_type, portname)) == 0) {
1065 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
1070 catch (AudioEngine::PortRegistrationFailure& err) {
1071 setup_peak_meters ();
1077 _inputs.push_back (input_port);
1078 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1084 drop_input_connection ();
1085 setup_peak_meters ();
1087 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1088 _session.set_dirty ();
1092 /* disconnect all existing ports so that we get a fresh start */
1094 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1095 _session.engine().disconnect (*i);
1103 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1105 bool in_changed = false;
1106 bool out_changed = false;
1107 bool in_reduced = false;
1108 bool out_reduced = false;
1109 bool need_pan_reset;
1111 if (_input_maximum >= 0) {
1112 nin = min (_input_maximum, (int) nin);
1115 if (_output_maximum >= 0) {
1116 nout = min (_output_maximum, (int) nout);
1119 if (nin == _ninputs && nout == _noutputs && !clear) {
1124 BLOCK_PROCESS_CALLBACK ();
1125 Glib::Mutex::Lock lm (io_lock);
1129 if (_noutputs == nout) {
1130 need_pan_reset = false;
1132 need_pan_reset = true;
1135 /* remove unused ports */
1137 while (_ninputs > nin) {
1138 _session.engine().unregister_port (_inputs.back());
1145 while (_noutputs > nout) {
1146 _session.engine().unregister_port (_outputs.back());
1147 _outputs.pop_back();
1153 /* create any necessary new ports (of the default type) */
1155 while (_ninputs < nin) {
1157 /* Create a new input port */
1159 string portname = build_legal_port_name (true);
1162 if ((port = _session.engine().register_input_port (_default_type, portname)) == 0) {
1163 error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
1168 catch (AudioEngine::PortRegistrationFailure& err) {
1169 setup_peak_meters ();
1175 _inputs.push_back (port);
1180 /* create any necessary new ports */
1182 while (_noutputs < nout) {
1184 string portname = build_legal_port_name (false);
1187 if ((port = _session.engine().register_output_port (_default_type, portname)) == 0) {
1188 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
1193 catch (AudioEngine::PortRegistrationFailure& err) {
1194 setup_peak_meters ();
1200 _outputs.push_back (port);
1207 /* disconnect all existing ports so that we get a fresh start */
1209 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1210 _session.engine().disconnect (*i);
1213 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1214 _session.engine().disconnect (*i);
1218 if (in_changed || out_changed) {
1219 setup_peak_meters ();
1225 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1226 drop_output_connection ();
1227 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1231 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1232 drop_input_connection ();
1233 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1236 if (in_changed || out_changed) {
1237 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1238 _session.set_dirty ();
1245 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1247 bool changed = false;
1249 if (_input_maximum >= 0) {
1250 n = min (_input_maximum, (int) n);
1252 if (n == _ninputs && !clear) {
1258 BLOCK_PROCESS_CALLBACK ();
1259 Glib::Mutex::Lock im (io_lock);
1260 changed = ensure_inputs_locked (n, clear, src);
1262 changed = ensure_inputs_locked (n, clear, src);
1266 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1267 _session.set_dirty ();
1274 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1277 bool changed = false;
1278 bool reduced = false;
1279 bool need_pan_reset;
1281 if (_noutputs == n) {
1282 need_pan_reset = false;
1284 need_pan_reset = true;
1287 /* remove unused ports */
1289 while (_noutputs > n) {
1291 _session.engine().unregister_port (_outputs.back());
1292 _outputs.pop_back();
1298 /* create any necessary new ports */
1300 while (_noutputs < n) {
1302 /* Create a new output port */
1304 string portname = build_legal_port_name (false);
1306 if ((output_port = _session.engine().register_output_port (_default_type, portname)) == 0) {
1307 error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
1311 _outputs.push_back (output_port);
1312 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1315 setup_peak_meters ();
1317 if (need_pan_reset) {
1323 drop_output_connection ();
1324 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1325 _session.set_dirty ();
1329 /* disconnect all existing ports so that we get a fresh start */
1331 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1332 _session.engine().disconnect (*i);
1340 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1342 bool changed = false;
1344 if (_output_maximum >= 0) {
1345 n = min (_output_maximum, (int) n);
1346 if (n == _noutputs && !clear) {
1351 /* XXX caller should hold io_lock, but generally doesn't */
1354 BLOCK_PROCESS_CALLBACK ();
1355 Glib::Mutex::Lock im (io_lock);
1356 changed = ensure_outputs_locked (n, clear, src);
1358 changed = ensure_outputs_locked (n, clear, src);
1362 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1369 IO::effective_gain () const
1371 if (gain_automation_playback()) {
1372 return _effective_gain;
1374 return _desired_gain;
1381 if (panners_legal) {
1382 if (!no_panner_reset) {
1383 _panner->reset (_noutputs, pans_required());
1386 panner_legal_c.disconnect ();
1387 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1392 IO::panners_became_legal ()
1394 _panner->reset (_noutputs, pans_required());
1395 _panner->load (); // automation
1396 panner_legal_c.disconnect ();
1401 IO::defer_pan_reset ()
1403 no_panner_reset = true;
1407 IO::allow_pan_reset ()
1409 no_panner_reset = false;
1415 IO::get_state (void)
1417 return state (true);
1421 IO::state (bool full_state)
1423 XMLNode* node = new XMLNode (state_node_name);
1426 bool need_ins = true;
1427 bool need_outs = true;
1428 LocaleGuard lg (X_("POSIX"));
1429 Glib::Mutex::Lock lm (io_lock);
1431 node->add_property("name", _name);
1432 id().print (buf, sizeof (buf));
1433 node->add_property("id", buf);
1434 node->add_property("active", _active? "yes" : "no");
1438 if (_input_connection) {
1439 node->add_property ("input-connection", _input_connection->name());
1443 if (_output_connection) {
1444 node->add_property ("output-connection", _output_connection->name());
1449 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1451 const char **connections = (*i)->get_connections();
1453 if (connections && connections[0]) {
1456 for (int n = 0; connections && connections[n]; ++n) {
1461 /* if its a connection to our own port,
1462 return only the port name, not the
1463 whole thing. this allows connections
1464 to be re-established even when our
1465 client name is different.
1468 str += _session.engine().make_port_name_relative (connections[n]);
1480 node->add_property ("inputs", str);
1486 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1488 const char **connections = (*i)->get_connections();
1490 if (connections && connections[0]) {
1494 for (int n = 0; connections[n]; ++n) {
1499 str += _session.engine().make_port_name_relative (connections[n]);
1511 node->add_property ("outputs", str);
1514 node->add_child_nocopy (_panner->state (full_state));
1515 node->add_child_nocopy (_gain_control.get_state ());
1517 snprintf (buf, sizeof(buf), "%2.12f", gain());
1518 node->add_property ("gain", buf);
1520 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1526 node->add_property ("iolimits", buf);
1532 XMLNode* autonode = new XMLNode (X_("Automation"));
1533 autonode->add_child_nocopy (get_automation_state());
1534 node->add_child_nocopy (*autonode);
1536 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1538 /* never store anything except Off for automation state in a template */
1539 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1546 IO::set_state (const XMLNode& node)
1548 const XMLProperty* prop;
1549 XMLNodeConstIterator iter;
1550 LocaleGuard lg (X_("POSIX"));
1552 /* force use of non-localized representation of decimal point,
1553 since we use it a lot in XML files and so forth.
1556 if (node.name() != state_node_name) {
1557 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1561 if ((prop = node.property ("name")) != 0) {
1562 _name = prop->value();
1563 /* used to set panner name with this, but no more */
1566 if ((prop = node.property ("id")) != 0) {
1567 _id = prop->value ();
1570 if ((prop = node.property ("iolimits")) != 0) {
1571 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1578 if ((prop = node.property ("gain")) != 0) {
1579 set_gain (atof (prop->value().c_str()), this);
1580 _gain = _desired_gain;
1583 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1584 /* old school automation handling */
1587 if ((prop = node.property (X_("active"))) != 0) {
1588 set_active (prop->value() == "yes");
1591 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1593 if ((*iter)->name() == "Panner") {
1595 _panner = new Panner (_name, _session);
1597 _panner->set_state (**iter);
1600 if ((*iter)->name() == X_("Automation")) {
1602 set_automation_state (*(*iter)->children().front());
1605 if ((*iter)->name() == X_("controllable")) {
1606 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1607 _gain_control.set_state (**iter);
1614 if (create_ports (node)) {
1620 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1623 if (panners_legal) {
1626 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1629 if (connecting_legal) {
1631 if (make_connections (node)) {
1637 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1640 if (!ports_legal || !connecting_legal) {
1641 pending_state_node = new XMLNode (node);
1644 last_automation_snapshot = 0;
1650 IO::set_automation_state (const XMLNode& node)
1652 return _gain_automation_curve.set_state (node);
1656 IO::get_automation_state ()
1658 return (_gain_automation_curve.get_state ());
1662 IO::load_automation (string path)
1667 uint32_t linecnt = 0;
1669 LocaleGuard lg (X_("POSIX"));
1671 fullpath = _session.automation_dir();
1674 in.open (fullpath.c_str());
1677 fullpath = _session.automation_dir();
1678 fullpath += _session.snap_name();
1682 in.open (fullpath.c_str());
1685 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1690 clear_automation ();
1692 while (in.getline (line, sizeof(line), '\n')) {
1694 jack_nframes_t when;
1697 if (++linecnt == 1) {
1698 if (memcmp (line, "version", 7) == 0) {
1699 if (sscanf (line, "version %f", &version) != 1) {
1700 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1704 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1711 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1712 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1718 _gain_automation_curve.fast_simple_add (when, value);
1728 /* older (pre-1.0) versions of ardour used this */
1732 warning << _("dubious automation event found (and ignored)") << endmsg;
1740 IO::connecting_became_legal ()
1744 if (pending_state_node == 0) {
1745 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1750 connection_legal_c.disconnect ();
1752 ret = make_connections (*pending_state_node);
1755 delete pending_state_node;
1756 pending_state_node = 0;
1762 IO::ports_became_legal ()
1766 if (pending_state_node == 0) {
1767 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1772 port_legal_c.disconnect ();
1774 ret = create_ports (*pending_state_node);
1776 if (connecting_legal) {
1777 delete pending_state_node;
1778 pending_state_node = 0;
1785 IO::create_ports (const XMLNode& node)
1787 const XMLProperty* prop;
1789 int num_outputs = 0;
1791 if ((prop = node.property ("input-connection")) != 0) {
1793 Connection* c = _session.connection_by_name (prop->value());
1796 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1798 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1799 error << _("No input connections available as a replacement")
1803 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1808 num_inputs = c->nports();
1810 } else if ((prop = node.property ("inputs")) != 0) {
1812 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1815 if ((prop = node.property ("output-connection")) != 0) {
1816 Connection* c = _session.connection_by_name (prop->value());
1819 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1821 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1822 error << _("No output connections available as a replacement")
1826 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1831 num_outputs = c->nports ();
1833 } else if ((prop = node.property ("outputs")) != 0) {
1834 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1837 no_panner_reset = true;
1839 if (ensure_io (num_inputs, num_outputs, true, this)) {
1840 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1844 no_panner_reset = false;
1846 set_deferred_state ();
1854 IO::make_connections (const XMLNode& node)
1856 const XMLProperty* prop;
1858 if ((prop = node.property ("input-connection")) != 0) {
1859 Connection* c = _session.connection_by_name (prop->value());
1862 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1864 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1865 error << _("No input connections available as a replacement")
1869 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1874 use_input_connection (*c, this);
1876 } else if ((prop = node.property ("inputs")) != 0) {
1877 if (set_inputs (prop->value())) {
1878 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1883 if ((prop = node.property ("output-connection")) != 0) {
1884 Connection* c = _session.connection_by_name (prop->value());
1887 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1889 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1890 error << _("No output connections available as a replacement")
1894 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1899 use_output_connection (*c, this);
1901 } else if ((prop = node.property ("outputs")) != 0) {
1902 if (set_outputs (prop->value())) {
1903 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1912 IO::set_inputs (const string& str)
1914 vector<string> ports;
1919 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1923 if (ensure_inputs (nports, true, true, this)) {
1927 string::size_type start, end, ostart;
1934 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1937 if ((end = str.find_first_of ('}', start)) == string::npos) {
1938 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1942 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1943 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1949 for (int x = 0; x < n; ++x) {
1950 connect_input (input (i), ports[x], this);
1962 IO::set_outputs (const string& str)
1964 vector<string> ports;
1969 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1973 if (ensure_outputs (nports, true, true, this)) {
1977 string::size_type start, end, ostart;
1984 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1987 if ((end = str.find_first_of ('}', start)) == string::npos) {
1988 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1992 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1993 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1999 for (int x = 0; x < n; ++x) {
2000 connect_output (output (i), ports[x], this);
2012 IO::parse_io_string (const string& str, vector<string>& ports)
2014 string::size_type pos, opos;
2016 if (str.length() == 0) {
2025 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2026 ports.push_back (str.substr (opos, pos - opos));
2030 if (opos < str.length()) {
2031 ports.push_back (str.substr(opos));
2034 return ports.size();
2038 IO::parse_gain_string (const string& str, vector<string>& ports)
2040 string::size_type pos, opos;
2046 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2047 ports.push_back (str.substr (opos, pos - opos));
2051 if (opos < str.length()) {
2052 ports.push_back (str.substr(opos));
2055 return ports.size();
2059 IO::set_name (string name, void* src)
2061 if (name == _name) {
2065 /* replace all colons in the name. i wish we didn't have to do this */
2067 if (replace_all (name, ":", "-")) {
2068 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
2071 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2072 string current_name = (*i)->short_name();
2073 current_name.replace (current_name.find (_name), _name.length(), name);
2074 (*i)->set_name (current_name);
2077 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2078 string current_name = (*i)->short_name();
2079 current_name.replace (current_name.find (_name), _name.length(), name);
2080 (*i)->set_name (current_name);
2084 name_changed (src); /* EMIT SIGNAL */
2090 IO::set_input_minimum (int n)
2096 IO::set_input_maximum (int n)
2102 IO::set_output_minimum (int n)
2104 _output_minimum = n;
2108 IO::set_output_maximum (int n)
2110 _output_maximum = n;
2114 IO::set_port_latency (nframes_t nframes)
2116 Glib::Mutex::Lock lm (io_lock);
2118 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2119 (*i)->set_latency (nframes);
2124 IO::output_latency () const
2126 nframes_t max_latency;
2131 /* io lock not taken - must be protected by other means */
2133 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2134 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2135 max_latency = latency;
2143 IO::input_latency () const
2145 nframes_t max_latency;
2150 /* io lock not taken - must be protected by other means */
2152 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2153 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2154 max_latency = latency;
2162 IO::use_input_connection (Connection& c, void* src)
2167 BLOCK_PROCESS_CALLBACK ();
2168 Glib::Mutex::Lock lm2 (io_lock);
2172 drop_input_connection ();
2174 if (ensure_inputs (limit, false, false, src)) {
2178 /* first pass: check the current state to see what's correctly
2179 connected, and drop anything that we don't want.
2182 for (uint32_t n = 0; n < limit; ++n) {
2183 const Connection::PortList& pl = c.port_connections (n);
2185 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2187 if (!_inputs[n]->connected_to ((*i))) {
2189 /* clear any existing connections */
2191 _session.engine().disconnect (_inputs[n]);
2193 } else if (_inputs[n]->connected() > 1) {
2195 /* OK, it is connected to the port we want,
2196 but its also connected to other ports.
2197 Change that situation.
2200 /* XXX could be optimized to not drop
2204 _session.engine().disconnect (_inputs[n]);
2210 /* second pass: connect all requested ports where necessary */
2212 for (uint32_t n = 0; n < limit; ++n) {
2213 const Connection::PortList& pl = c.port_connections (n);
2215 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2217 if (!_inputs[n]->connected_to ((*i))) {
2219 if (_session.engine().connect (*i, _inputs[n]->name())) {
2227 _input_connection = &c;
2229 input_connection_configuration_connection = c.ConfigurationChanged.connect
2230 (mem_fun (*this, &IO::input_connection_configuration_changed));
2231 input_connection_connection_connection = c.ConnectionsChanged.connect
2232 (mem_fun (*this, &IO::input_connection_connection_changed));
2235 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2240 IO::use_output_connection (Connection& c, void* src)
2245 BLOCK_PROCESS_CALLBACK ();
2246 Glib::Mutex::Lock lm2 (io_lock);
2250 drop_output_connection ();
2252 if (ensure_outputs (limit, false, false, src)) {
2256 /* first pass: check the current state to see what's correctly
2257 connected, and drop anything that we don't want.
2260 for (uint32_t n = 0; n < limit; ++n) {
2262 const Connection::PortList& pl = c.port_connections (n);
2264 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2266 if (!_outputs[n]->connected_to ((*i))) {
2268 /* clear any existing connections */
2270 _session.engine().disconnect (_outputs[n]);
2272 } else if (_outputs[n]->connected() > 1) {
2274 /* OK, it is connected to the port we want,
2275 but its also connected to other ports.
2276 Change that situation.
2279 /* XXX could be optimized to not drop
2283 _session.engine().disconnect (_outputs[n]);
2288 /* second pass: connect all requested ports where necessary */
2290 for (uint32_t n = 0; n < limit; ++n) {
2292 const Connection::PortList& pl = c.port_connections (n);
2294 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2296 if (!_outputs[n]->connected_to ((*i))) {
2298 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2305 _output_connection = &c;
2307 output_connection_configuration_connection = c.ConfigurationChanged.connect
2308 (mem_fun (*this, &IO::output_connection_configuration_changed));
2309 output_connection_connection_connection = c.ConnectionsChanged.connect
2310 (mem_fun (*this, &IO::output_connection_connection_changed));
2313 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2319 IO::disable_connecting ()
2321 connecting_legal = false;
2326 IO::enable_connecting ()
2328 connecting_legal = true;
2329 return ConnectingLegal ();
2333 IO::disable_ports ()
2335 ports_legal = false;
2343 return PortsLegal ();
2347 IO::disable_panners (void)
2349 panners_legal = false;
2354 IO::reset_panners ()
2356 panners_legal = true;
2357 return PannersLegal ();
2361 IO::input_connection_connection_changed (int ignored)
2363 use_input_connection (*_input_connection, this);
2367 IO::input_connection_configuration_changed ()
2369 use_input_connection (*_input_connection, this);
2373 IO::output_connection_connection_changed (int ignored)
2375 use_output_connection (*_output_connection, this);
2379 IO::output_connection_configuration_changed ()
2381 use_output_connection (*_output_connection, this);
2385 IO::GainControllable::set_value (float val)
2387 io.set_gain (direct_control_to_gain (val), this);
2391 IO::GainControllable::get_value (void) const
2393 return direct_gain_to_control (io.effective_gain());
2397 IO::reset_peak_meters ()
2399 uint32_t limit = max (_ninputs, _noutputs);
2401 for (uint32_t i = 0; i < limit; ++i) {
2407 IO::reset_max_peak_meters ()
2409 uint32_t limit = max (_ninputs, _noutputs);
2411 for (uint32_t i = 0; i < limit; ++i) {
2412 _max_peak_power[i] = -INFINITY;
2417 IO::setup_peak_meters ()
2419 uint32_t limit = max (_ninputs, _noutputs);
2421 while (_peak_power.size() < limit) {
2422 _peak_power.push_back (0);
2423 _visible_peak_power.push_back (-INFINITY);
2424 _max_peak_power.push_back (-INFINITY);
2429 Update the peak meters.
2431 The meter signal lock is taken to prevent modification of the
2432 Meter signal while updating the meters, taking the meter signal
2433 lock prior to taking the io_lock ensures that all IO will remain
2434 valid while metering.
2439 Glib::Mutex::Lock guard (m_meter_signal_lock);
2447 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2448 uint32_t limit = max (_ninputs, _noutputs);
2450 for (uint32_t n = 0; n < limit; ++n) {
2452 /* XXX we should use atomic exchange here */
2454 /* grab peak since last read */
2456 float new_peak = _peak_power[n];
2459 /* compute new visible value using falloff */
2461 if (new_peak > 0.0f) {
2462 new_peak = coefficient_to_dB (new_peak);
2464 new_peak = -INFINITY;
2467 /* update max peak */
2469 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2471 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2472 _visible_peak_power[n] = new_peak;
2474 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2475 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2476 _visible_peak_power[n] = max (new_peak, -INFINITY);
2482 IO::clear_automation ()
2484 Glib::Mutex::Lock lm (automation_lock);
2485 _gain_automation_curve.clear ();
2486 _panner->clear_automation ();
2490 IO::set_gain_automation_state (AutoState state)
2492 bool changed = false;
2495 Glib::Mutex::Lock lm (automation_lock);
2497 if (state != _gain_automation_curve.automation_state()) {
2499 last_automation_snapshot = 0;
2500 _gain_automation_curve.set_automation_state (state);
2503 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2509 _session.set_dirty ();
2510 gain_automation_state_changed (); /* EMIT SIGNAL */
2515 IO::set_gain_automation_style (AutoStyle style)
2517 bool changed = false;
2520 Glib::Mutex::Lock lm (automation_lock);
2522 if (style != _gain_automation_curve.automation_style()) {
2524 _gain_automation_curve.set_automation_style (style);
2529 gain_automation_style_changed (); /* EMIT SIGNAL */
2533 IO::inc_gain (gain_t factor, void *src)
2535 if (_desired_gain == 0.0f)
2536 set_gain (0.000001f + (0.000001f * factor), src);
2538 set_gain (_desired_gain + (_desired_gain * factor), src);
2542 IO::set_gain (gain_t val, void *src)
2544 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2545 if (val>1.99526231f) val=1.99526231f;
2548 Glib::Mutex::Lock dm (declick_lock);
2549 _desired_gain = val;
2552 if (_session.transport_stopped()) {
2553 _effective_gain = val;
2558 _gain_control.Changed (); /* EMIT SIGNAL */
2560 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2561 _gain_automation_curve.add (_session.transport_frame(), val);
2564 _session.set_dirty();
2568 IO::start_gain_touch ()
2570 _gain_automation_curve.start_touch ();
2574 IO::end_gain_touch ()
2576 _gain_automation_curve.stop_touch ();
2580 IO::start_pan_touch (uint32_t which)
2582 if (which < _panner->size()) {
2583 (*_panner)[which]->automation().start_touch();
2588 IO::end_pan_touch (uint32_t which)
2590 if (which < _panner->size()) {
2591 (*_panner)[which]->automation().stop_touch();
2597 IO::automation_snapshot (nframes_t now)
2599 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2601 if (gain_automation_recording()) {
2602 _gain_automation_curve.rt_add (now, gain());
2605 _panner->snapshot (now);
2607 last_automation_snapshot = now;
2612 IO::transport_stopped (nframes_t frame)
2614 _gain_automation_curve.reposition_for_rt_add (frame);
2616 if (_gain_automation_curve.automation_state() != Off) {
2618 /* the src=0 condition is a special signal to not propagate
2619 automation gain changes into the mix group when locating.
2622 set_gain (_gain_automation_curve.eval (frame), 0);
2625 _panner->transport_stopped (frame);
2629 IO::build_legal_port_name (bool in)
2631 const int name_size = jack_port_name_size();
2638 maxports = _input_maximum;
2641 maxports = _output_maximum;
2644 if (maxports == 1) {
2645 // allow space for the slash + the suffix
2646 limit = name_size - _session.engine().client_name().length() - (strlen (suffix) + 1);
2647 char buf[name_size+1];
2648 snprintf (buf, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix);
2649 return string (buf);
2652 // allow up to 4 digits for the output port number, plus the slash, suffix and extra space
2654 limit = name_size - _session.engine().client_name().length() - (strlen (suffix) + 5);
2656 char buf1[name_size+1];
2657 char buf2[name_size+1];
2659 snprintf (buf1, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix);
2664 port_number = find_input_port_hole (buf1);
2666 port_number = find_output_port_hole (buf1);
2669 snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
2671 return string (buf2);
2675 IO::find_input_port_hole (const char* base)
2677 /* CALLER MUST HOLD IO LOCK */
2681 if (_inputs.empty()) {
2685 /* we only allow up to 4 characters for the port number
2688 for (n = 1; n < 9999; ++n) {
2689 char buf[jack_port_name_size()];
2690 vector<Port*>::iterator i;
2692 snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
2694 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2695 if ((*i)->short_name() == buf) {
2700 if (i == _inputs.end()) {
2708 IO::find_output_port_hole (const char* base)
2710 /* CALLER MUST HOLD IO LOCK */
2714 if (_outputs.empty()) {
2718 /* we only allow up to 4 characters for the port number
2721 for (n = 1; n < 9999; ++n) {
2722 char buf[jack_port_name_size()];
2723 vector<Port*>::iterator i;
2725 snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
2727 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2728 if ((*i)->short_name() == buf) {
2733 if (i == _outputs.end()) {
2742 IO::set_active (bool yn)
2745 active_changed(); /* EMIT SIGNAL */