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)
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 // FIXME: naming scheme for differently typed ports?
858 if (_output_maximum == 1) {
859 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
861 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
864 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
865 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
869 _outputs.push_back (our_port);
870 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
872 drop_output_connection ();
873 setup_peak_meters ();
877 MoreOutputs (_noutputs); /* EMIT SIGNAL */
880 if (destination.length()) {
881 if (_session.engine().connect (our_port->name(), destination)) {
886 // pan_changed (src); /* EMIT SIGNAL */
887 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
888 _session.set_dirty ();
893 IO::remove_input_port (Port* port, void* src)
895 IOChange change (NoChange);
898 BLOCK_PROCESS_CALLBACK ();
902 Glib::Mutex::Lock lm (io_lock);
904 if (((int)_ninputs - 1) < _input_minimum) {
905 /* sorry, you can't do this */
908 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
911 change = IOChange (change|ConfigurationChanged);
913 if (port->connected()) {
914 change = IOChange (change|ConnectionsChanged);
917 _session.engine().unregister_port (*i);
920 drop_input_connection ();
926 if (change != NoChange) {
927 setup_peak_meters ();
933 if (change != NoChange) {
934 input_changed (change, src);
935 _session.set_dirty ();
943 /** Add an input port.
945 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
946 * @param destination Name of input port to connect new port to.
947 * @param src Source for emitted ConfigurationChanged signal.
950 IO::add_input_port (string source, void* src, DataType type)
955 if (type == DataType::NIL)
956 type = _default_type;
959 BLOCK_PROCESS_CALLBACK ();
962 Glib::Mutex::Lock lm (io_lock);
964 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
968 /* Create a new input port */
970 // FIXME: naming scheme for differently typed ports?
971 if (_input_maximum == 1) {
972 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
974 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
977 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
978 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
982 _inputs.push_back (our_port);
983 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
985 drop_input_connection ();
986 setup_peak_meters ();
990 MoreOutputs (_ninputs); /* EMIT SIGNAL */
993 if (source.length()) {
995 if (_session.engine().connect (source, our_port->name())) {
1000 // pan_changed (src); /* EMIT SIGNAL */
1001 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1002 _session.set_dirty ();
1008 IO::disconnect_inputs (void* src)
1011 BLOCK_PROCESS_CALLBACK ();
1014 Glib::Mutex::Lock lm (io_lock);
1016 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1017 _session.engine().disconnect (*i);
1020 drop_input_connection ();
1023 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1028 IO::disconnect_outputs (void* src)
1031 BLOCK_PROCESS_CALLBACK ();
1034 Glib::Mutex::Lock lm (io_lock);
1036 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1037 _session.engine().disconnect (*i);
1040 drop_output_connection ();
1044 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1045 _session.set_dirty ();
1050 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1053 bool changed = false;
1054 bool reduced = false;
1056 /* remove unused ports */
1058 while (_ninputs > n) {
1059 _session.engine().unregister_port (_inputs.back());
1066 /* create any necessary new ports */
1068 while (_ninputs < n) {
1072 /* Create a new input port (of the default type) */
1074 if (_input_maximum == 1) {
1075 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1078 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1083 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1084 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1089 catch (AudioEngine::PortRegistrationFailure& err) {
1090 setup_peak_meters ();
1096 _inputs.push_back (input_port);
1097 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1103 drop_input_connection ();
1104 setup_peak_meters ();
1106 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1107 _session.set_dirty ();
1111 /* disconnect all existing ports so that we get a fresh start */
1113 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1114 _session.engine().disconnect (*i);
1122 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1124 bool in_changed = false;
1125 bool out_changed = false;
1126 bool in_reduced = false;
1127 bool out_reduced = false;
1128 bool need_pan_reset;
1130 if (_input_maximum >= 0) {
1131 nin = min (_input_maximum, (int) nin);
1134 if (_output_maximum >= 0) {
1135 nout = min (_output_maximum, (int) nout);
1138 if (nin == _ninputs && nout == _noutputs && !clear) {
1143 BLOCK_PROCESS_CALLBACK ();
1144 Glib::Mutex::Lock lm (io_lock);
1148 if (_noutputs == nout) {
1149 need_pan_reset = false;
1151 need_pan_reset = true;
1154 /* remove unused ports */
1156 while (_ninputs > nin) {
1157 _session.engine().unregister_port (_inputs.back());
1164 while (_noutputs > nout) {
1165 _session.engine().unregister_port (_outputs.back());
1166 _outputs.pop_back();
1172 /* create any necessary new ports (of the default type) */
1174 while (_ninputs < nin) {
1178 /* Create a new input port */
1180 if (_input_maximum == 1) {
1181 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1184 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1188 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1189 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1194 catch (AudioEngine::PortRegistrationFailure& err) {
1195 setup_peak_meters ();
1201 _inputs.push_back (port);
1206 /* create any necessary new ports */
1208 while (_noutputs < nout) {
1212 /* Create a new output port */
1214 if (_output_maximum == 1) {
1215 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1217 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1221 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1222 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1227 catch (AudioEngine::PortRegistrationFailure& err) {
1228 setup_peak_meters ();
1234 _outputs.push_back (port);
1241 /* disconnect all existing ports so that we get a fresh start */
1243 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1244 _session.engine().disconnect (*i);
1247 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1248 _session.engine().disconnect (*i);
1252 if (in_changed || out_changed) {
1253 setup_peak_meters ();
1259 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1260 drop_output_connection ();
1261 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1265 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1266 drop_input_connection ();
1267 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1270 if (in_changed || out_changed) {
1271 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1272 _session.set_dirty ();
1279 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1281 bool changed = false;
1283 if (_input_maximum >= 0) {
1284 n = min (_input_maximum, (int) n);
1286 if (n == _ninputs && !clear) {
1292 BLOCK_PROCESS_CALLBACK ();
1293 Glib::Mutex::Lock im (io_lock);
1294 changed = ensure_inputs_locked (n, clear, src);
1296 changed = ensure_inputs_locked (n, clear, src);
1300 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1301 _session.set_dirty ();
1308 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1311 bool changed = false;
1312 bool reduced = false;
1313 bool need_pan_reset;
1315 if (_noutputs == n) {
1316 need_pan_reset = false;
1318 need_pan_reset = true;
1321 /* remove unused ports */
1323 while (_noutputs > n) {
1325 _session.engine().unregister_port (_outputs.back());
1326 _outputs.pop_back();
1332 /* create any necessary new ports */
1334 while (_noutputs < n) {
1338 /* Create a new output port */
1340 if (_output_maximum == 1) {
1341 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1343 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1346 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1347 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1351 _outputs.push_back (output_port);
1352 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1355 setup_peak_meters ();
1357 if (need_pan_reset) {
1363 drop_output_connection ();
1364 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1365 _session.set_dirty ();
1369 /* disconnect all existing ports so that we get a fresh start */
1371 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1372 _session.engine().disconnect (*i);
1380 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1382 bool changed = false;
1384 if (_output_maximum >= 0) {
1385 n = min (_output_maximum, (int) n);
1386 if (n == _noutputs && !clear) {
1391 /* XXX caller should hold io_lock, but generally doesn't */
1394 BLOCK_PROCESS_CALLBACK ();
1395 Glib::Mutex::Lock im (io_lock);
1396 changed = ensure_outputs_locked (n, clear, src);
1398 changed = ensure_outputs_locked (n, clear, src);
1402 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1409 IO::effective_gain () const
1411 if (gain_automation_playback()) {
1412 return _effective_gain;
1414 return _desired_gain;
1421 if (panners_legal) {
1422 if (!no_panner_reset) {
1423 _panner->reset (_noutputs, pans_required());
1426 panner_legal_c.disconnect ();
1427 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1432 IO::panners_became_legal ()
1434 _panner->reset (_noutputs, pans_required());
1435 _panner->load (); // automation
1436 panner_legal_c.disconnect ();
1441 IO::defer_pan_reset ()
1443 no_panner_reset = true;
1447 IO::allow_pan_reset ()
1449 no_panner_reset = false;
1455 IO::get_state (void)
1457 return state (true);
1461 IO::state (bool full_state)
1463 XMLNode* node = new XMLNode (state_node_name);
1466 bool need_ins = true;
1467 bool need_outs = true;
1468 LocaleGuard lg (X_("POSIX"));
1469 Glib::Mutex::Lock lm (io_lock);
1471 node->add_property("name", _name);
1472 id().print (buf, sizeof (buf));
1473 node->add_property("id", buf);
1474 node->add_property("active", _active? "yes" : "no");
1478 if (_input_connection) {
1479 node->add_property ("input-connection", _input_connection->name());
1483 if (_output_connection) {
1484 node->add_property ("output-connection", _output_connection->name());
1489 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1491 const char **connections = (*i)->get_connections();
1493 if (connections && connections[0]) {
1496 for (int n = 0; connections && connections[n]; ++n) {
1501 /* if its a connection to our own port,
1502 return only the port name, not the
1503 whole thing. this allows connections
1504 to be re-established even when our
1505 client name is different.
1508 str += _session.engine().make_port_name_relative (connections[n]);
1520 node->add_property ("inputs", str);
1526 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1528 const char **connections = (*i)->get_connections();
1530 if (connections && connections[0]) {
1534 for (int n = 0; connections[n]; ++n) {
1539 str += _session.engine().make_port_name_relative (connections[n]);
1551 node->add_property ("outputs", str);
1554 node->add_child_nocopy (_panner->state (full_state));
1555 node->add_child_nocopy (_gain_control.get_state ());
1557 snprintf (buf, sizeof(buf), "%2.12f", gain());
1558 node->add_property ("gain", buf);
1560 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1566 node->add_property ("iolimits", buf);
1572 XMLNode* autonode = new XMLNode (X_("Automation"));
1573 autonode->add_child_nocopy (get_automation_state());
1574 node->add_child_nocopy (*autonode);
1576 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1578 /* never store anything except Off for automation state in a template */
1579 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1586 IO::set_state (const XMLNode& node)
1588 const XMLProperty* prop;
1589 XMLNodeConstIterator iter;
1590 LocaleGuard lg (X_("POSIX"));
1592 /* force use of non-localized representation of decimal point,
1593 since we use it a lot in XML files and so forth.
1596 if (node.name() != state_node_name) {
1597 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1601 if ((prop = node.property ("name")) != 0) {
1602 _name = prop->value();
1603 /* used to set panner name with this, but no more */
1606 if ((prop = node.property ("id")) != 0) {
1607 _id = prop->value ();
1610 if ((prop = node.property ("iolimits")) != 0) {
1611 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1618 if ((prop = node.property ("gain")) != 0) {
1619 set_gain (atof (prop->value().c_str()), this);
1620 _gain = _desired_gain;
1623 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1624 /* old school automation handling */
1627 if ((prop = node.property (X_("active"))) != 0) {
1628 set_active (prop->value() == "yes");
1631 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1633 if ((*iter)->name() == "Panner") {
1635 _panner = new Panner (_name, _session);
1637 _panner->set_state (**iter);
1640 if ((*iter)->name() == X_("Automation")) {
1642 set_automation_state (*(*iter)->children().front());
1645 if ((*iter)->name() == X_("controllable")) {
1646 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1647 _gain_control.set_state (**iter);
1654 if (create_ports (node)) {
1660 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1663 if (panners_legal) {
1666 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1669 if (connecting_legal) {
1671 if (make_connections (node)) {
1677 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1680 if (!ports_legal || !connecting_legal) {
1681 pending_state_node = new XMLNode (node);
1684 last_automation_snapshot = 0;
1690 IO::set_automation_state (const XMLNode& node)
1692 return _gain_automation_curve.set_state (node);
1696 IO::get_automation_state ()
1698 return (_gain_automation_curve.get_state ());
1702 IO::load_automation (string path)
1707 uint32_t linecnt = 0;
1709 LocaleGuard lg (X_("POSIX"));
1711 fullpath = _session.automation_dir();
1714 in.open (fullpath.c_str());
1717 fullpath = _session.automation_dir();
1718 fullpath += _session.snap_name();
1722 in.open (fullpath.c_str());
1725 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1730 clear_automation ();
1732 while (in.getline (line, sizeof(line), '\n')) {
1734 jack_nframes_t when;
1737 if (++linecnt == 1) {
1738 if (memcmp (line, "version", 7) == 0) {
1739 if (sscanf (line, "version %f", &version) != 1) {
1740 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1744 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1751 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1752 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1758 _gain_automation_curve.fast_simple_add (when, value);
1768 /* older (pre-1.0) versions of ardour used this */
1772 warning << _("dubious automation event found (and ignored)") << endmsg;
1780 IO::connecting_became_legal ()
1784 if (pending_state_node == 0) {
1785 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1790 connection_legal_c.disconnect ();
1792 ret = make_connections (*pending_state_node);
1795 delete pending_state_node;
1796 pending_state_node = 0;
1802 IO::ports_became_legal ()
1806 if (pending_state_node == 0) {
1807 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1812 port_legal_c.disconnect ();
1814 ret = create_ports (*pending_state_node);
1816 if (connecting_legal) {
1817 delete pending_state_node;
1818 pending_state_node = 0;
1825 IO::create_ports (const XMLNode& node)
1827 const XMLProperty* prop;
1829 int num_outputs = 0;
1831 if ((prop = node.property ("input-connection")) != 0) {
1833 Connection* c = _session.connection_by_name (prop->value());
1836 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1838 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1839 error << _("No input connections available as a replacement")
1843 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1848 num_inputs = c->nports();
1850 } else if ((prop = node.property ("inputs")) != 0) {
1852 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1855 if ((prop = node.property ("output-connection")) != 0) {
1856 Connection* c = _session.connection_by_name (prop->value());
1859 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1861 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1862 error << _("No output connections available as a replacement")
1866 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1871 num_outputs = c->nports ();
1873 } else if ((prop = node.property ("outputs")) != 0) {
1874 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1877 no_panner_reset = true;
1879 if (ensure_io (num_inputs, num_outputs, true, this)) {
1880 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1884 no_panner_reset = false;
1886 set_deferred_state ();
1894 IO::make_connections (const XMLNode& node)
1896 const XMLProperty* prop;
1898 if ((prop = node.property ("input-connection")) != 0) {
1899 Connection* c = _session.connection_by_name (prop->value());
1902 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1904 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1905 error << _("No input connections available as a replacement")
1909 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1914 use_input_connection (*c, this);
1916 } else if ((prop = node.property ("inputs")) != 0) {
1917 if (set_inputs (prop->value())) {
1918 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1923 if ((prop = node.property ("output-connection")) != 0) {
1924 Connection* c = _session.connection_by_name (prop->value());
1927 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1929 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1930 error << _("No output connections available as a replacement")
1934 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1939 use_output_connection (*c, this);
1941 } else if ((prop = node.property ("outputs")) != 0) {
1942 if (set_outputs (prop->value())) {
1943 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1952 IO::set_inputs (const string& str)
1954 vector<string> ports;
1959 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1963 if (ensure_inputs (nports, true, true, this)) {
1967 string::size_type start, end, ostart;
1974 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1977 if ((end = str.find_first_of ('}', start)) == string::npos) {
1978 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1982 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1983 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1989 for (int x = 0; x < n; ++x) {
1990 connect_input (input (i), ports[x], this);
2002 IO::set_outputs (const string& str)
2004 vector<string> ports;
2009 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
2013 if (ensure_outputs (nports, true, true, this)) {
2017 string::size_type start, end, ostart;
2024 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
2027 if ((end = str.find_first_of ('}', start)) == string::npos) {
2028 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
2032 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
2033 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
2039 for (int x = 0; x < n; ++x) {
2040 connect_output (output (i), ports[x], this);
2052 IO::parse_io_string (const string& str, vector<string>& ports)
2054 string::size_type pos, opos;
2056 if (str.length() == 0) {
2065 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2066 ports.push_back (str.substr (opos, pos - opos));
2070 if (opos < str.length()) {
2071 ports.push_back (str.substr(opos));
2074 return ports.size();
2078 IO::parse_gain_string (const string& str, vector<string>& ports)
2080 string::size_type pos, opos;
2086 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2087 ports.push_back (str.substr (opos, pos - opos));
2091 if (opos < str.length()) {
2092 ports.push_back (str.substr(opos));
2095 return ports.size();
2099 IO::set_name (string name, void* src)
2101 if (name == _name) {
2105 /* replace all colons in the name. i wish we didn't have to do this */
2107 if (replace_all (name, ":", "-")) {
2108 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
2111 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2112 string current_name = (*i)->short_name();
2113 current_name.replace (current_name.find (_name), _name.length(), name);
2114 (*i)->set_name (current_name);
2117 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2118 string current_name = (*i)->short_name();
2119 current_name.replace (current_name.find (_name), _name.length(), name);
2120 (*i)->set_name (current_name);
2124 name_changed (src); /* EMIT SIGNAL */
2130 IO::set_input_minimum (int n)
2136 IO::set_input_maximum (int n)
2142 IO::set_output_minimum (int n)
2144 _output_minimum = n;
2148 IO::set_output_maximum (int n)
2150 _output_maximum = n;
2154 IO::set_port_latency (nframes_t nframes)
2156 Glib::Mutex::Lock lm (io_lock);
2158 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2159 (*i)->set_latency (nframes);
2164 IO::output_latency () const
2166 nframes_t max_latency;
2171 /* io lock not taken - must be protected by other means */
2173 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2174 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2175 max_latency = latency;
2183 IO::input_latency () const
2185 nframes_t max_latency;
2190 /* io lock not taken - must be protected by other means */
2192 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2193 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2194 max_latency = latency;
2202 IO::use_input_connection (Connection& c, void* src)
2207 BLOCK_PROCESS_CALLBACK ();
2208 Glib::Mutex::Lock lm2 (io_lock);
2212 drop_input_connection ();
2214 if (ensure_inputs (limit, false, false, src)) {
2218 /* first pass: check the current state to see what's correctly
2219 connected, and drop anything that we don't want.
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 /* clear any existing connections */
2231 _session.engine().disconnect (_inputs[n]);
2233 } else if (_inputs[n]->connected() > 1) {
2235 /* OK, it is connected to the port we want,
2236 but its also connected to other ports.
2237 Change that situation.
2240 /* XXX could be optimized to not drop
2244 _session.engine().disconnect (_inputs[n]);
2250 /* second pass: connect all requested ports where necessary */
2252 for (uint32_t n = 0; n < limit; ++n) {
2253 const Connection::PortList& pl = c.port_connections (n);
2255 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2257 if (!_inputs[n]->connected_to ((*i))) {
2259 if (_session.engine().connect (*i, _inputs[n]->name())) {
2267 _input_connection = &c;
2269 input_connection_configuration_connection = c.ConfigurationChanged.connect
2270 (mem_fun (*this, &IO::input_connection_configuration_changed));
2271 input_connection_connection_connection = c.ConnectionsChanged.connect
2272 (mem_fun (*this, &IO::input_connection_connection_changed));
2275 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2280 IO::use_output_connection (Connection& c, void* src)
2285 BLOCK_PROCESS_CALLBACK ();
2286 Glib::Mutex::Lock lm2 (io_lock);
2290 drop_output_connection ();
2292 if (ensure_outputs (limit, false, false, src)) {
2296 /* first pass: check the current state to see what's correctly
2297 connected, and drop anything that we don't want.
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 /* clear any existing connections */
2310 _session.engine().disconnect (_outputs[n]);
2312 } else if (_outputs[n]->connected() > 1) {
2314 /* OK, it is connected to the port we want,
2315 but its also connected to other ports.
2316 Change that situation.
2319 /* XXX could be optimized to not drop
2323 _session.engine().disconnect (_outputs[n]);
2328 /* second pass: connect all requested ports where necessary */
2330 for (uint32_t n = 0; n < limit; ++n) {
2332 const Connection::PortList& pl = c.port_connections (n);
2334 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2336 if (!_outputs[n]->connected_to ((*i))) {
2338 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2345 _output_connection = &c;
2347 output_connection_configuration_connection = c.ConfigurationChanged.connect
2348 (mem_fun (*this, &IO::output_connection_configuration_changed));
2349 output_connection_connection_connection = c.ConnectionsChanged.connect
2350 (mem_fun (*this, &IO::output_connection_connection_changed));
2353 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2359 IO::disable_connecting ()
2361 connecting_legal = false;
2366 IO::enable_connecting ()
2368 connecting_legal = true;
2369 return ConnectingLegal ();
2373 IO::disable_ports ()
2375 ports_legal = false;
2383 return PortsLegal ();
2387 IO::disable_panners (void)
2389 panners_legal = false;
2394 IO::reset_panners ()
2396 panners_legal = true;
2397 return PannersLegal ();
2401 IO::input_connection_connection_changed (int ignored)
2403 use_input_connection (*_input_connection, this);
2407 IO::input_connection_configuration_changed ()
2409 use_input_connection (*_input_connection, this);
2413 IO::output_connection_connection_changed (int ignored)
2415 use_output_connection (*_output_connection, this);
2419 IO::output_connection_configuration_changed ()
2421 use_output_connection (*_output_connection, this);
2425 IO::GainControllable::set_value (float val)
2427 io.set_gain (direct_control_to_gain (val), this);
2431 IO::GainControllable::get_value (void) const
2433 return direct_gain_to_control (io.effective_gain());
2437 IO::reset_peak_meters ()
2439 uint32_t limit = max (_ninputs, _noutputs);
2441 for (uint32_t i = 0; i < limit; ++i) {
2447 IO::reset_max_peak_meters ()
2449 uint32_t limit = max (_ninputs, _noutputs);
2451 for (uint32_t i = 0; i < limit; ++i) {
2452 _max_peak_power[i] = -INFINITY;
2457 IO::setup_peak_meters ()
2459 uint32_t limit = max (_ninputs, _noutputs);
2461 while (_peak_power.size() < limit) {
2462 _peak_power.push_back (0);
2463 _visible_peak_power.push_back (-INFINITY);
2464 _max_peak_power.push_back (-INFINITY);
2469 Update the peak meters.
2471 The meter signal lock is taken to prevent modification of the
2472 Meter signal while updating the meters, taking the meter signal
2473 lock prior to taking the io_lock ensures that all IO will remain
2474 valid while metering.
2479 Glib::Mutex::Lock guard (m_meter_signal_lock);
2487 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2488 uint32_t limit = max (_ninputs, _noutputs);
2490 for (uint32_t n = 0; n < limit; ++n) {
2492 /* XXX we should use atomic exchange here */
2494 /* grab peak since last read */
2496 float new_peak = _peak_power[n];
2499 /* compute new visible value using falloff */
2501 if (new_peak > 0.0f) {
2502 new_peak = coefficient_to_dB (new_peak);
2504 new_peak = -INFINITY;
2507 /* update max peak */
2509 _max_peak_power[n] = max (new_peak, _max_peak_power[n]);
2511 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2512 _visible_peak_power[n] = new_peak;
2514 // do falloff, the config value is in dB/sec, we get updated at 100/sec currently (should be a var somewhere)
2515 new_peak = _visible_peak_power[n] - (Config->get_meter_falloff() * 0.01f);
2516 _visible_peak_power[n] = max (new_peak, -INFINITY);
2522 IO::clear_automation ()
2524 Glib::Mutex::Lock lm (automation_lock);
2525 _gain_automation_curve.clear ();
2526 _panner->clear_automation ();
2530 IO::set_gain_automation_state (AutoState state)
2532 bool changed = false;
2535 Glib::Mutex::Lock lm (automation_lock);
2537 if (state != _gain_automation_curve.automation_state()) {
2539 last_automation_snapshot = 0;
2540 _gain_automation_curve.set_automation_state (state);
2543 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2549 _session.set_dirty ();
2550 gain_automation_state_changed (); /* EMIT SIGNAL */
2555 IO::set_gain_automation_style (AutoStyle style)
2557 bool changed = false;
2560 Glib::Mutex::Lock lm (automation_lock);
2562 if (style != _gain_automation_curve.automation_style()) {
2564 _gain_automation_curve.set_automation_style (style);
2569 gain_automation_style_changed (); /* EMIT SIGNAL */
2573 IO::inc_gain (gain_t factor, void *src)
2575 if (_desired_gain == 0.0f)
2576 set_gain (0.000001f + (0.000001f * factor), src);
2578 set_gain (_desired_gain + (_desired_gain * factor), src);
2582 IO::set_gain (gain_t val, void *src)
2584 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2585 if (val>1.99526231f) val=1.99526231f;
2588 Glib::Mutex::Lock dm (declick_lock);
2589 _desired_gain = val;
2592 if (_session.transport_stopped()) {
2593 _effective_gain = val;
2598 _gain_control.Changed (); /* EMIT SIGNAL */
2600 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2601 _gain_automation_curve.add (_session.transport_frame(), val);
2604 _session.set_dirty();
2608 IO::start_gain_touch ()
2610 _gain_automation_curve.start_touch ();
2614 IO::end_gain_touch ()
2616 _gain_automation_curve.stop_touch ();
2620 IO::start_pan_touch (uint32_t which)
2622 if (which < _panner->size()) {
2623 (*_panner)[which]->automation().start_touch();
2628 IO::end_pan_touch (uint32_t which)
2630 if (which < _panner->size()) {
2631 (*_panner)[which]->automation().stop_touch();
2637 IO::automation_snapshot (nframes_t now)
2639 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2641 if (gain_automation_recording()) {
2642 _gain_automation_curve.rt_add (now, gain());
2645 _panner->snapshot (now);
2647 last_automation_snapshot = now;
2652 IO::transport_stopped (nframes_t frame)
2654 _gain_automation_curve.reposition_for_rt_add (frame);
2656 if (_gain_automation_curve.automation_state() != Off) {
2658 /* the src=0 condition is a special signal to not propagate
2659 automation gain changes into the mix group when locating.
2662 set_gain (_gain_automation_curve.eval (frame), 0);
2665 _panner->transport_stopped (frame);
2669 IO::find_input_port_hole ()
2671 /* CALLER MUST HOLD IO LOCK */
2675 if (_inputs.empty()) {
2679 for (n = 1; n < UINT_MAX; ++n) {
2680 char buf[jack_port_name_size()];
2681 vector<Port*>::iterator i;
2683 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2685 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2686 if ((*i)->short_name() == buf) {
2691 if (i == _inputs.end()) {
2699 IO::find_output_port_hole ()
2701 /* CALLER MUST HOLD IO LOCK */
2705 if (_outputs.empty()) {
2709 for (n = 1; n < UINT_MAX; ++n) {
2710 char buf[jack_port_name_size()];
2711 vector<Port*>::iterator i;
2713 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2715 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2716 if ((*i)->short_name() == buf) {
2721 if (i == _outputs.end()) {
2730 IO::set_active (bool yn)
2733 active_changed(); /* EMIT SIGNAL */