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>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/connection.h>
36 #include <ardour/session.h>
37 #include <ardour/cycle_timer.h>
38 #include <ardour/panner.h>
39 #include <ardour/dB.h>
46 A bug in OS X's cmath that causes isnan() and isinf() to be
47 "undeclared". the following works around that
50 #if defined(__APPLE__) && defined(__MACH__)
51 extern "C" int isnan (double);
52 extern "C" int isinf (double);
57 using namespace ARDOUR;
61 static float current_automation_version_number = 1.0;
63 jack_nframes_t IO::_automation_interval = 0;
64 const string IO::state_node_name = "IO";
65 bool IO::connecting_legal = false;
66 bool IO::ports_legal = false;
67 bool IO::panners_legal = false;
68 sigc::signal<void> IO::Meter;
69 sigc::signal<int> IO::ConnectingLegal;
70 sigc::signal<int> IO::PortsLegal;
71 sigc::signal<int> IO::PannersLegal;
72 sigc::signal<void,uint32_t> IO::MoreOutputs;
73 sigc::signal<int> IO::PortsCreated;
75 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
77 /* this is a default mapper of MIDI control values to a gain coefficient.
78 others can be imagined. see IO::set_midi_to_gain_function().
81 static gain_t direct_midi_to_gain (double fract) {
82 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
83 /* this maxes at +6dB */
84 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
87 static double direct_gain_to_midi (gain_t gain) {
88 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
89 if (gain == 0) return 0.0;
91 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
94 static bool sort_ports_by_name (Port* a, Port* b)
96 return a->name() < b->name();
100 /** The 'default_type' argument here isn't very good, but port creation is too
101 * brufty and all over the place to make anything else feasible without massive
102 * changes. The default typed passed is the type of port that will be created
103 * by ensure_io and friends. This is a temporary compatibility hack to get
104 * multiple data types off the gound and should be removed.
106 IO::IO (Session& s, string name,
107 int input_min, int input_max, int output_min, int output_max,
108 Buffer::Type default_type)
111 _default_type(default_type),
112 _midi_gain_control (*this, _session.midi_port()),
113 _gain_automation_curve (0.0, 2.0, 1.0),
114 _input_minimum (input_min),
115 _input_maximum (input_max),
116 _output_minimum (output_min),
117 _output_maximum (output_max)
120 _panner = new Panner (name, _session);
123 _input_connection = 0;
124 _output_connection = 0;
125 pending_state_node = 0;
128 no_panner_reset = false;
131 _midi_gain_control.midi_to_gain = direct_midi_to_gain;
132 _midi_gain_control.gain_to_midi = direct_gain_to_midi;
134 apply_gain_automation = false;
136 last_automation_snapshot = 0;
138 _gain_automation_state = Off;
139 _gain_automation_style = Absolute;
142 // IO::Meter is emitted from another thread so the
143 // Meter signal must be protected.
144 Glib::Mutex::Lock guard (m_meter_signal_lock);
145 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
152 Glib::Mutex::Lock guard (m_meter_signal_lock);
153 Glib::Mutex::Lock lm (io_lock);
154 vector<Port *>::iterator i;
156 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
157 _session.engine().unregister_port (*i);
160 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
161 _session.engine().unregister_port (*i);
164 m_meter_connection.disconnect();
168 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
170 /* io_lock, not taken: function must be called from Session::process() calltree */
172 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
173 (*i)->silence (nframes, offset);
178 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
180 jack_nframes_t declick = min ((jack_nframes_t)4096, nframes);
183 double fractional_shift;
184 double fractional_pos;
185 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
187 if (nframes == 0) return;
189 fractional_shift = -1.0/declick;
191 if (target < initial) {
192 /* fade out: remove more and more of delta from initial */
193 delta = -(initial - target);
195 /* fade in: add more and more of delta from initial */
196 delta = target - initial;
199 for (uint32_t n = 0; n < nbufs; ++n) {
202 fractional_pos = 1.0;
204 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
205 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
206 fractional_pos += fractional_shift;
209 /* now ensure the rest of the buffer has the target value
210 applied, if necessary.
213 if (declick != nframes) {
215 if (invert_polarity) {
220 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
221 } else if (target != 1.0) {
222 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
223 buffer[nx] *= target;
231 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, jack_nframes_t offset)
235 /* io_lock, not taken: function must be called from Session::process() calltree */
237 if (_noutputs == 0) {
241 if (_noutputs == 1) {
243 dst = output(0)->get_buffer (nframes) + offset;
245 for (uint32_t n = 0; n < nbufs; ++n) {
246 if (bufs[n] != dst) {
247 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
251 output(0)->mark_silence (false);
257 vector<Port *>::iterator out;
258 vector<Sample *>::iterator in;
259 Panner::iterator pan;
260 Sample* obufs[_noutputs];
262 /* the terrible silence ... */
264 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
265 obufs[o] = (*out)->get_buffer (nframes) + offset;
266 memset (obufs[o], 0, sizeof (Sample) * nframes);
267 (*out)->mark_silence (false);
272 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
273 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
278 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
283 /* io_lock, not taken: function must be called from Session::process() calltree */
285 if (_noutputs == 0) {
289 /* the panner can be empty if there are no inputs to the
290 route, but still outputs
293 if (_panner->bypassed() || _panner->empty()) {
294 deliver_output_no_pan (bufs, nbufs, nframes, offset);
298 if (_noutputs == 1) {
300 dst = output(0)->get_buffer (nframes) + offset;
302 if (gain_coeff == 0.0f) {
304 /* only one output, and gain was zero, so make it silent */
306 memset (dst, 0, sizeof (Sample) * nframes);
308 } else if (gain_coeff == 1.0f){
310 /* mix all buffers into the output */
314 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
316 for (n = 1; n < nbufs; ++n) {
319 for (jack_nframes_t n = 0; n < nframes; ++n) {
324 output(0)->mark_silence (false);
328 /* mix all buffers into the output, scaling them all by the gain */
334 for (jack_nframes_t n = 0; n < nframes; ++n) {
335 dst[n] = src[n] * gain_coeff;
338 for (n = 1; n < nbufs; ++n) {
341 for (jack_nframes_t n = 0; n < nframes; ++n) {
342 dst[n] += src[n] * gain_coeff;
346 output(0)->mark_silence (false);
353 vector<Port *>::iterator out;
354 vector<Sample *>::iterator in;
355 Panner::iterator pan;
356 Sample* obufs[_noutputs];
358 /* the terrible silence ... */
360 /* XXX this is wasteful but i see no way to avoid it */
362 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
363 obufs[o] = (*out)->get_buffer (nframes) + offset;
364 memset (obufs[o], 0, sizeof (Sample) * nframes);
365 (*out)->mark_silence (false);
370 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
371 Panner::iterator tmp;
376 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
378 if (tmp != _panner->end()) {
385 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
387 /* io_lock, not taken: function must be called from Session::process() calltree */
389 if (_noutputs == 0) {
393 if (_panner->bypassed() || _panner->empty()) {
394 deliver_output_no_pan (bufs, nbufs, nframes, offset);
400 gain_t pangain = _gain;
403 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
413 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
418 /* simple, non-automation panning to outputs */
420 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
421 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
423 pan (bufs, nbufs, nframes, offset, pangain);
428 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
430 /* io_lock, not taken: function must be called from Session::process() calltree */
432 if (_noutputs == 0) {
437 gain_t old_gain = _gain;
439 if (apply_gain_automation) {
441 /* gain has already been applied by automation code. do nothing here except
450 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
462 vector<Port*>::iterator o;
463 vector<Sample*> outs;
467 /* unlikely condition */
468 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
469 outs.push_back ((*o)->get_buffer (nframes) + offset);
473 /* reduce nbufs to the index of the last input buffer */
477 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
478 actual_gain = _gain * speed_quietning;
483 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
485 dst = (*o)->get_buffer (nframes) + offset;
486 src = bufs[min(nbufs,i)];
488 if (dg != _gain || actual_gain == 1.0f) {
489 memcpy (dst, src, sizeof (Sample) * nframes);
490 } else if (actual_gain == 0.0f) {
491 memset (dst, 0, sizeof (Sample) * nframes);
493 for (jack_nframes_t x = 0; x < nframes; ++x) {
494 dst[x] = src[x] * actual_gain;
498 (*o)->mark_silence (false);
502 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
506 if (apply_gain_automation) {
512 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
514 /* io_lock, not taken: function must be called from Session::process() calltree */
516 vector<Port *>::iterator i;
520 /* we require that bufs.size() >= 1 */
522 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
523 if (i == _inputs.end()) {
527 /* XXX always read the full extent of the port buffer that
528 we need. One day, we may use jack_port_get_buffer_at_offset()
529 or something similar. For now, this simple hack will
532 Hack? Why yes .. we only need to read nframes-worth of
533 data, but the data we want is at `offset' within the
537 last = (*i)->get_buffer (nframes+offset) + offset;
538 // the dest buffer's offset has already been applied
539 memcpy (bufs[n], last, sizeof (Sample) * nframes);
542 /* fill any excess outputs with the last input */
544 while (n < nbufs && last) {
545 // the dest buffer's offset has already been applied
546 memcpy (bufs[n], last, sizeof (Sample) * nframes);
552 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
553 jack_nframes_t nframes, jack_nframes_t offset)
555 vector<Sample*>& bufs = _session.get_passthru_buffers ();
556 uint32_t nbufs = n_process_buffers ();
558 collect_input (bufs, nbufs, nframes, offset);
560 for (uint32_t n = 0; n < nbufs; ++n) {
561 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
566 IO::drop_input_connection ()
568 _input_connection = 0;
569 input_connection_configuration_connection.disconnect();
570 input_connection_connection_connection.disconnect();
571 _session.set_dirty ();
575 IO::drop_output_connection ()
577 _output_connection = 0;
578 output_connection_configuration_connection.disconnect();
579 output_connection_connection_connection.disconnect();
580 _session.set_dirty ();
584 IO::disconnect_input (Port* our_port, string other_port, void* src)
586 if (other_port.length() == 0 || our_port == 0) {
591 Glib::Mutex::Lock em (_session.engine().process_lock());
594 Glib::Mutex::Lock lm (io_lock);
596 /* check that our_port is really one of ours */
598 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
602 /* disconnect it from the source */
604 if (_session.engine().disconnect (other_port, our_port->name())) {
605 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
609 drop_input_connection();
613 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
614 _session.set_dirty ();
620 IO::connect_input (Port* our_port, string other_port, void* src)
622 if (other_port.length() == 0 || our_port == 0) {
627 Glib::Mutex::Lock em(_session.engine().process_lock());
630 Glib::Mutex::Lock lm (io_lock);
632 /* check that our_port is really one of ours */
634 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
638 /* connect it to the source */
640 if (_session.engine().connect (other_port, our_port->name())) {
644 drop_input_connection ();
648 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
649 _session.set_dirty ();
654 IO::disconnect_output (Port* our_port, string other_port, void* src)
656 if (other_port.length() == 0 || our_port == 0) {
661 Glib::Mutex::Lock em(_session.engine().process_lock());
664 Glib::Mutex::Lock lm (io_lock);
666 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
670 /* disconnect it from the destination */
672 if (_session.engine().disconnect (our_port->name(), other_port)) {
673 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
677 drop_output_connection ();
681 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
682 _session.set_dirty ();
687 IO::connect_output (Port* our_port, string other_port, void* src)
689 if (other_port.length() == 0 || our_port == 0) {
694 Glib::Mutex::Lock em(_session.engine().process_lock());
697 Glib::Mutex::Lock lm (io_lock);
699 /* check that our_port is really one of ours */
701 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
705 /* connect it to the destination */
707 if (_session.engine().connect (our_port->name(), other_port)) {
711 drop_output_connection ();
715 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
716 _session.set_dirty ();
721 IO::set_input (Port* other_port, void* src)
723 /* this removes all but one ports, and connects that one port
724 to the specified source.
727 if (_input_minimum > 1 || _input_minimum == 0) {
728 /* sorry, you can't do this */
732 if (other_port == 0) {
733 if (_input_minimum < 0) {
734 return ensure_inputs (0, false, true, src);
740 if (ensure_inputs (1, true, true, src)) {
744 return connect_input (_inputs.front(), other_port->name(), src);
748 IO::remove_output_port (Port* port, void* src)
750 IOChange change (NoChange);
753 Glib::Mutex::Lock em(_session.engine().process_lock());
756 Glib::Mutex::Lock lm (io_lock);
758 if (_noutputs - 1 == (uint32_t) _output_minimum) {
759 /* sorry, you can't do this */
763 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
765 change = IOChange (change|ConfigurationChanged);
766 if (port->connected()) {
767 change = IOChange (change|ConnectionsChanged);
770 _session.engine().unregister_port (*i);
773 drop_output_connection ();
779 if (change != NoChange) {
780 setup_peak_meters ();
786 if (change != NoChange) {
787 output_changed (change, src); /* EMIT SIGNAL */
788 _session.set_dirty ();
795 /** Add an output port.
797 * @param destination Name of input port to connect new port to.
798 * @param src Source for emitted ConfigurationChanged signal.
799 * @param type Data type of port. Default value (Buffer::NIL) will use this IO's default type.
802 IO::add_output_port (string destination, void* src, Buffer::Type type)
807 if (type == Buffer::NIL)
808 type = _default_type;
811 Glib::Mutex::Lock em(_session.engine().process_lock());
814 Glib::Mutex::Lock lm (io_lock);
816 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
820 /* Create a new output port */
822 // FIXME: naming scheme for differently typed ports?
823 if (_output_maximum == 1) {
824 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
826 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
829 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
830 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
834 _outputs.push_back (our_port);
835 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
837 drop_output_connection ();
838 setup_peak_meters ();
842 MoreOutputs (_noutputs); /* EMIT SIGNAL */
845 if (destination.length()) {
846 if (_session.engine().connect (our_port->name(), destination)) {
851 // pan_changed (src); /* EMIT SIGNAL */
852 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
853 _session.set_dirty ();
858 IO::remove_input_port (Port* port, void* src)
860 IOChange change (NoChange);
863 Glib::Mutex::Lock em(_session.engine().process_lock());
866 Glib::Mutex::Lock lm (io_lock);
868 if (((int)_ninputs - 1) < _input_minimum) {
869 /* sorry, you can't do this */
872 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
875 change = IOChange (change|ConfigurationChanged);
877 if (port->connected()) {
878 change = IOChange (change|ConnectionsChanged);
881 _session.engine().unregister_port (*i);
884 drop_input_connection ();
890 if (change != NoChange) {
891 setup_peak_meters ();
897 if (change != NoChange) {
898 input_changed (change, src);
899 _session.set_dirty ();
907 /** Add an input port.
909 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
910 * @param destination Name of input port to connect new port to.
911 * @param src Source for emitted ConfigurationChanged signal.
914 IO::add_input_port (string source, void* src, Buffer::Type type)
919 if (type == Buffer::NIL)
920 type = _default_type;
923 Glib::Mutex::Lock em (_session.engine().process_lock());
926 Glib::Mutex::Lock lm (io_lock);
928 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
932 /* Create a new input port */
934 // FIXME: naming scheme for differently typed ports?
935 if (_input_maximum == 1) {
936 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
938 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
941 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
942 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
946 _inputs.push_back (our_port);
947 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
949 drop_input_connection ();
950 setup_peak_meters ();
954 MoreOutputs (_ninputs); /* EMIT SIGNAL */
957 if (source.length()) {
959 if (_session.engine().connect (source, our_port->name())) {
964 // pan_changed (src); /* EMIT SIGNAL */
965 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
966 _session.set_dirty ();
972 IO::disconnect_inputs (void* src)
975 Glib::Mutex::Lock em (_session.engine().process_lock());
978 Glib::Mutex::Lock lm (io_lock);
980 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
981 _session.engine().disconnect (*i);
984 drop_input_connection ();
987 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
992 IO::disconnect_outputs (void* src)
995 Glib::Mutex::Lock em (_session.engine().process_lock());
998 Glib::Mutex::Lock lm (io_lock);
1000 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1001 _session.engine().disconnect (*i);
1004 drop_output_connection ();
1008 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1009 _session.set_dirty ();
1014 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1017 bool changed = false;
1018 bool reduced = false;
1020 /* remove unused ports */
1022 while (_ninputs > n) {
1023 _session.engine().unregister_port (_inputs.back());
1030 /* create any necessary new ports */
1032 while (_ninputs < n) {
1036 /* Create a new input port */
1038 // FIXME: of what type?
1040 if (_input_maximum == 1) {
1041 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1044 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1049 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1050 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1055 catch (AudioEngine::PortRegistrationFailure& err) {
1056 setup_peak_meters ();
1062 _inputs.push_back (input_port);
1063 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1069 drop_input_connection ();
1070 setup_peak_meters ();
1072 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1073 _session.set_dirty ();
1077 /* disconnect all existing ports so that we get a fresh start */
1079 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1080 _session.engine().disconnect (*i);
1088 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1090 bool in_changed = false;
1091 bool out_changed = false;
1092 bool in_reduced = false;
1093 bool out_reduced = false;
1094 bool need_pan_reset;
1096 if (_input_maximum >= 0) {
1097 nin = min (_input_maximum, (int) nin);
1100 if (_output_maximum >= 0) {
1101 nout = min (_output_maximum, (int) nout);
1104 if (nin == _ninputs && nout == _noutputs && !clear) {
1109 Glib::Mutex::Lock em (_session.engine().process_lock());
1110 Glib::Mutex::Lock lm (io_lock);
1114 if (_noutputs == nout) {
1115 need_pan_reset = false;
1117 need_pan_reset = true;
1120 /* remove unused ports */
1122 while (_ninputs > nin) {
1123 _session.engine().unregister_port (_inputs.back());
1130 while (_noutputs > nout) {
1131 _session.engine().unregister_port (_outputs.back());
1132 _outputs.pop_back();
1138 /* create any necessary new ports */
1140 // FIXME: of what type?
1142 while (_ninputs < nin) {
1146 /* Create a new input port */
1148 if (_input_maximum == 1) {
1149 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1152 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1156 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1157 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1162 catch (AudioEngine::PortRegistrationFailure& err) {
1163 setup_peak_meters ();
1169 _inputs.push_back (port);
1174 /* create any necessary new ports */
1176 while (_noutputs < nout) {
1180 /* Create a new output port */
1182 if (_output_maximum == 1) {
1183 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1185 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1189 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1190 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1195 catch (AudioEngine::PortRegistrationFailure& err) {
1196 setup_peak_meters ();
1202 _outputs.push_back (port);
1209 /* disconnect all existing ports so that we get a fresh start */
1211 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1212 _session.engine().disconnect (*i);
1215 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1216 _session.engine().disconnect (*i);
1220 if (in_changed || out_changed) {
1221 setup_peak_meters ();
1227 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1228 drop_output_connection ();
1229 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1233 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1234 drop_input_connection ();
1235 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1238 if (in_changed || out_changed) {
1239 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1240 _session.set_dirty ();
1247 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1249 bool changed = false;
1251 if (_input_maximum >= 0) {
1252 n = min (_input_maximum, (int) n);
1254 if (n == _ninputs && !clear) {
1260 Glib::Mutex::Lock em (_session.engine().process_lock());
1261 Glib::Mutex::Lock im (io_lock);
1262 changed = ensure_inputs_locked (n, clear, src);
1264 changed = ensure_inputs_locked (n, clear, src);
1268 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1269 _session.set_dirty ();
1276 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1279 bool changed = false;
1280 bool reduced = false;
1281 bool need_pan_reset;
1283 if (_noutputs == n) {
1284 need_pan_reset = false;
1286 need_pan_reset = true;
1289 /* remove unused ports */
1291 while (_noutputs > n) {
1293 _session.engine().unregister_port (_outputs.back());
1294 _outputs.pop_back();
1300 /* create any necessary new ports */
1302 while (_noutputs < n) {
1306 /* Create a new output port */
1308 if (_output_maximum == 1) {
1309 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1311 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1314 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1315 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1319 _outputs.push_back (output_port);
1320 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1323 setup_peak_meters ();
1325 if (need_pan_reset) {
1331 drop_output_connection ();
1332 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1333 _session.set_dirty ();
1337 /* disconnect all existing ports so that we get a fresh start */
1339 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1340 _session.engine().disconnect (*i);
1348 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1350 bool changed = false;
1352 if (_output_maximum >= 0) {
1353 n = min (_output_maximum, (int) n);
1354 if (n == _noutputs && !clear) {
1359 /* XXX caller should hold io_lock, but generally doesn't */
1362 Glib::Mutex::Lock em (_session.engine().process_lock());
1363 Glib::Mutex::Lock im (io_lock);
1364 changed = ensure_outputs_locked (n, clear, src);
1366 changed = ensure_outputs_locked (n, clear, src);
1370 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1377 IO::effective_gain () const
1379 if (gain_automation_playback()) {
1380 return _effective_gain;
1382 return _desired_gain;
1389 if (panners_legal) {
1390 if (!no_panner_reset) {
1391 _panner->reset (_noutputs, pans_required());
1394 panner_legal_c.disconnect ();
1395 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1400 IO::panners_became_legal ()
1402 _panner->reset (_noutputs, pans_required());
1403 _panner->load (); // automation
1404 panner_legal_c.disconnect ();
1409 IO::defer_pan_reset ()
1411 no_panner_reset = true;
1415 IO::allow_pan_reset ()
1417 no_panner_reset = false;
1423 IO::get_state (void)
1425 return state (true);
1429 IO::state (bool full_state)
1431 XMLNode* node = new XMLNode (state_node_name);
1434 bool need_ins = true;
1435 bool need_outs = true;
1436 LocaleGuard lg (X_("POSIX"));
1437 Glib::Mutex::Lock lm (io_lock);
1439 node->add_property("name", _name);
1440 snprintf (buf, sizeof(buf), "%" PRIu64, id());
1441 node->add_property("id", buf);
1445 if (_input_connection) {
1446 node->add_property ("input-connection", _input_connection->name());
1450 if (_output_connection) {
1451 node->add_property ("output-connection", _output_connection->name());
1456 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1458 const char **connections = (*i)->get_connections();
1460 if (connections && connections[0]) {
1463 for (int n = 0; connections && connections[n]; ++n) {
1468 /* if its a connection to our own port,
1469 return only the port name, not the
1470 whole thing. this allows connections
1471 to be re-established even when our
1472 client name is different.
1475 str += _session.engine().make_port_name_relative (connections[n]);
1487 node->add_property ("inputs", str);
1493 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1495 const char **connections = (*i)->get_connections();
1497 if (connections && connections[0]) {
1501 for (int n = 0; connections[n]; ++n) {
1506 str += _session.engine().make_port_name_relative (connections[n]);
1518 node->add_property ("outputs", str);
1521 node->add_child_nocopy (_panner->state (full_state));
1523 snprintf (buf, sizeof(buf), "%2.12f", gain());
1524 node->add_property ("gain", buf);
1526 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1532 node->add_property ("iolimits", buf);
1536 MIDI::channel_t chn;
1538 MIDI::byte additional;
1539 XMLNode* midi_node = 0;
1542 if (_midi_gain_control.get_control_info (chn, ev, additional)) {
1544 midi_node = node->add_child ("MIDI");
1546 child = midi_node->add_child ("gain");
1547 set_midi_node_info (child, ev, chn, additional);
1553 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1555 /* never store anything except Off for automation state in a template */
1556 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1558 node->add_property ("automation-state", buf);
1559 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1560 node->add_property ("automation-style", buf);
1562 /* XXX same for pan etc. */
1568 IO::connecting_became_legal ()
1572 if (pending_state_node == 0) {
1573 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1578 connection_legal_c.disconnect ();
1580 ret = make_connections (*pending_state_node);
1583 delete pending_state_node;
1584 pending_state_node = 0;
1591 IO::ports_became_legal ()
1595 if (pending_state_node == 0) {
1596 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1601 port_legal_c.disconnect ();
1603 ret = create_ports (*pending_state_node);
1605 if (connecting_legal) {
1606 delete pending_state_node;
1607 pending_state_node = 0;
1614 IO::set_state (const XMLNode& node)
1616 const XMLProperty* prop;
1617 XMLNodeConstIterator iter;
1618 XMLNodeList midi_kids;
1619 LocaleGuard lg (X_("POSIX"));
1621 /* force use of non-localized representation of decimal point,
1622 since we use it a lot in XML files and so forth.
1625 if (node.name() != state_node_name) {
1626 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1630 if ((prop = node.property ("name")) != 0) {
1631 _name = prop->value();
1632 _panner->set_name (_name);
1635 if ((prop = node.property ("id")) != 0) {
1636 sscanf (prop->value().c_str(), "%" PRIu64, &_id);
1639 if ((prop = node.property ("iolimits")) != 0) {
1640 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1647 if ((prop = node.property ("gain")) != 0) {
1648 set_gain (atof (prop->value().c_str()), this);
1649 _gain = _desired_gain;
1652 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1653 if ((*iter)->name() == "Panner") {
1654 _panner->set_state (**iter);
1658 midi_kids = node.children ("MIDI");
1660 for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) {
1663 XMLNodeConstIterator miter;
1666 kids = (*iter)->children ();
1668 for (miter = kids.begin(); miter != kids.end(); ++miter) {
1672 if (child->name() == "gain") {
1674 MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */
1675 MIDI::byte additional = 0; /* ditto */
1676 MIDI::channel_t chn = 0; /* ditto */
1678 if (get_midi_node_info (child, ev, chn, additional)) {
1679 _midi_gain_control.set_control_type (chn, ev, additional);
1681 error << string_compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
1687 if ((prop = node.property ("automation-state")) != 0) {
1690 x = strtol (prop->value().c_str(), 0, 16);
1691 set_gain_automation_state (AutoState (x));
1694 if ((prop = node.property ("automation-style")) != 0) {
1697 x = strtol (prop->value().c_str(), 0, 16);
1698 set_gain_automation_style (AutoStyle (x));
1703 if (create_ports (node)) {
1709 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1712 if (panners_legal) {
1715 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1718 if (connecting_legal) {
1720 if (make_connections (node)) {
1726 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1729 if (!ports_legal || !connecting_legal) {
1730 pending_state_node = new XMLNode (node);
1737 IO::create_ports (const XMLNode& node)
1739 const XMLProperty* prop;
1741 int num_outputs = 0;
1743 if ((prop = node.property ("input-connection")) != 0) {
1745 Connection* c = _session.connection_by_name (prop->value());
1748 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1750 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1751 error << _("No input connections available as a replacement")
1755 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1760 num_inputs = c->nports();
1762 } else if ((prop = node.property ("inputs")) != 0) {
1764 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1767 if ((prop = node.property ("output-connection")) != 0) {
1768 Connection* c = _session.connection_by_name (prop->value());
1771 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1773 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1774 error << _("No output connections available as a replacement")
1778 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1783 num_outputs = c->nports ();
1785 } else if ((prop = node.property ("outputs")) != 0) {
1786 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1789 no_panner_reset = true;
1791 if (ensure_io (num_inputs, num_outputs, true, this)) {
1792 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1796 no_panner_reset = false;
1798 set_deferred_state ();
1805 IO::get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional)
1808 const XMLProperty* prop;
1811 if ((prop = node->property ("event")) != 0) {
1812 sscanf (prop->value().c_str(), "0x%x", &xx);
1813 ev = (MIDI::eventType) xx;
1818 if (ok && ((prop = node->property ("channel")) != 0)) {
1819 sscanf (prop->value().c_str(), "%d", &xx);
1820 chan = (MIDI::channel_t) xx;
1825 if (ok && ((prop = node->property ("additional")) != 0)) {
1826 sscanf (prop->value().c_str(), "0x%x", &xx);
1827 additional = (MIDI::byte) xx;
1834 IO::set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional)
1838 snprintf (buf, sizeof(buf), "0x%x", ev);
1839 node->add_property ("event", buf);
1840 snprintf (buf, sizeof(buf), "%d", chan);
1841 node->add_property ("channel", buf);
1842 snprintf (buf, sizeof(buf), "0x%x", additional);
1843 node->add_property ("additional", buf);
1850 IO::make_connections (const XMLNode& node)
1852 const XMLProperty* prop;
1854 if ((prop = node.property ("input-connection")) != 0) {
1855 Connection* c = _session.connection_by_name (prop->value());
1858 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1860 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1861 error << _("No input connections available as a replacement")
1865 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1870 use_input_connection (*c, this);
1872 } else if ((prop = node.property ("inputs")) != 0) {
1873 if (set_inputs (prop->value())) {
1874 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1879 if ((prop = node.property ("output-connection")) != 0) {
1880 Connection* c = _session.connection_by_name (prop->value());
1883 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1885 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1886 error << _("No output connections available as a replacement")
1890 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1895 use_output_connection (*c, this);
1897 } else if ((prop = node.property ("outputs")) != 0) {
1898 if (set_outputs (prop->value())) {
1899 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1908 IO::set_inputs (const string& str)
1910 vector<string> ports;
1915 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1919 if (ensure_inputs (nports, true, true, this)) {
1923 string::size_type start, end, ostart;
1930 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1933 if ((end = str.find_first_of ('}', start)) == string::npos) {
1934 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1938 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1939 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1945 for (int x = 0; x < n; ++x) {
1946 connect_input (input (i), ports[x], this);
1958 IO::set_outputs (const string& str)
1960 vector<string> ports;
1965 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1969 if (ensure_outputs (nports, true, true, this)) {
1973 string::size_type start, end, ostart;
1980 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1983 if ((end = str.find_first_of ('}', start)) == string::npos) {
1984 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1988 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1989 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1995 for (int x = 0; x < n; ++x) {
1996 connect_output (output (i), ports[x], this);
2008 IO::parse_io_string (const string& str, vector<string>& ports)
2010 string::size_type pos, opos;
2012 if (str.length() == 0) {
2021 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2022 ports.push_back (str.substr (opos, pos - opos));
2026 if (opos < str.length()) {
2027 ports.push_back (str.substr(opos));
2030 return ports.size();
2034 IO::parse_gain_string (const string& str, vector<string>& ports)
2036 string::size_type pos, opos;
2042 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2043 ports.push_back (str.substr (opos, pos - opos));
2047 if (opos < str.length()) {
2048 ports.push_back (str.substr(opos));
2051 return ports.size();
2055 IO::set_name (string name, void* src)
2057 if (name == _name) {
2061 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2062 string current_name = (*i)->short_name();
2063 current_name.replace (current_name.find (_name), _name.length(), name);
2064 (*i)->set_name (current_name);
2067 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2068 string current_name = (*i)->short_name();
2069 current_name.replace (current_name.find (_name), _name.length(), name);
2070 (*i)->set_name (current_name);
2074 name_changed (src); /* EMIT SIGNAL */
2080 IO::set_input_minimum (int n)
2086 IO::set_input_maximum (int n)
2092 IO::set_output_minimum (int n)
2094 _output_minimum = n;
2098 IO::set_output_maximum (int n)
2100 _output_maximum = n;
2104 IO::set_port_latency (jack_nframes_t nframes)
2106 Glib::Mutex::Lock lm (io_lock);
2108 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2109 (*i)->set_latency (nframes);
2114 IO::output_latency () const
2116 jack_nframes_t max_latency;
2117 jack_nframes_t latency;
2121 /* io lock not taken - must be protected by other means */
2123 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2124 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2125 max_latency = latency;
2133 IO::input_latency () const
2135 jack_nframes_t max_latency;
2136 jack_nframes_t latency;
2140 /* io lock not taken - must be protected by other means */
2142 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2143 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2144 max_latency = latency;
2152 IO::use_input_connection (Connection& c, void* src)
2157 Glib::Mutex::Lock lm (_session.engine().process_lock());
2158 Glib::Mutex::Lock lm2 (io_lock);
2162 drop_input_connection ();
2164 if (ensure_inputs (limit, false, false, src)) {
2168 /* first pass: check the current state to see what's correctly
2169 connected, and drop anything that we don't want.
2172 for (uint32_t n = 0; n < limit; ++n) {
2173 const Connection::PortList& pl = c.port_connections (n);
2175 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2177 if (!_inputs[n]->connected_to ((*i))) {
2179 /* clear any existing connections */
2181 _session.engine().disconnect (_inputs[n]);
2183 } else if (_inputs[n]->connected() > 1) {
2185 /* OK, it is connected to the port we want,
2186 but its also connected to other ports.
2187 Change that situation.
2190 /* XXX could be optimized to not drop
2194 _session.engine().disconnect (_inputs[n]);
2200 /* second pass: connect all requested ports where necessary */
2202 for (uint32_t n = 0; n < limit; ++n) {
2203 const Connection::PortList& pl = c.port_connections (n);
2205 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2207 if (!_inputs[n]->connected_to ((*i))) {
2209 if (_session.engine().connect (*i, _inputs[n]->name())) {
2217 _input_connection = &c;
2219 input_connection_configuration_connection = c.ConfigurationChanged.connect
2220 (mem_fun (*this, &IO::input_connection_configuration_changed));
2221 input_connection_connection_connection = c.ConnectionsChanged.connect
2222 (mem_fun (*this, &IO::input_connection_connection_changed));
2225 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2230 IO::use_output_connection (Connection& c, void* src)
2235 Glib::Mutex::Lock lm (_session.engine().process_lock());
2236 Glib::Mutex::Lock lm2 (io_lock);
2240 drop_output_connection ();
2242 if (ensure_outputs (limit, false, false, src)) {
2246 /* first pass: check the current state to see what's correctly
2247 connected, and drop anything that we don't want.
2250 for (uint32_t n = 0; n < limit; ++n) {
2252 const Connection::PortList& pl = c.port_connections (n);
2254 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2256 if (!_outputs[n]->connected_to ((*i))) {
2258 /* clear any existing connections */
2260 _session.engine().disconnect (_outputs[n]);
2262 } else if (_outputs[n]->connected() > 1) {
2264 /* OK, it is connected to the port we want,
2265 but its also connected to other ports.
2266 Change that situation.
2269 /* XXX could be optimized to not drop
2273 _session.engine().disconnect (_outputs[n]);
2278 /* second pass: connect all requested ports where necessary */
2280 for (uint32_t n = 0; n < limit; ++n) {
2282 const Connection::PortList& pl = c.port_connections (n);
2284 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2286 if (!_outputs[n]->connected_to ((*i))) {
2288 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2295 _output_connection = &c;
2297 output_connection_configuration_connection = c.ConfigurationChanged.connect
2298 (mem_fun (*this, &IO::output_connection_configuration_changed));
2299 output_connection_connection_connection = c.ConnectionsChanged.connect
2300 (mem_fun (*this, &IO::output_connection_connection_changed));
2303 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2309 IO::disable_connecting ()
2311 connecting_legal = false;
2316 IO::enable_connecting ()
2318 connecting_legal = true;
2319 return ConnectingLegal ();
2323 IO::disable_ports ()
2325 ports_legal = false;
2333 return PortsLegal ();
2337 IO::disable_panners (void)
2339 panners_legal = false;
2344 IO::reset_panners ()
2346 panners_legal = true;
2347 return PannersLegal ();
2351 IO::input_connection_connection_changed (int ignored)
2353 use_input_connection (*_input_connection, this);
2357 IO::input_connection_configuration_changed ()
2359 use_input_connection (*_input_connection, this);
2363 IO::output_connection_connection_changed (int ignored)
2365 use_output_connection (*_output_connection, this);
2369 IO::output_connection_configuration_changed ()
2371 use_output_connection (*_output_connection, this);
2374 IO::MIDIGainControl::MIDIGainControl (IO& i, MIDI::Port* port)
2375 : MIDI::Controllable (port, 0), io (i), setting(false)
2380 last_written = 0; /* XXX need a good out-of-bound-value */
2384 IO::MIDIGainControl::set_value (float val)
2386 if (midi_to_gain == 0) return;
2389 io.set_gain (midi_to_gain (val), this);
2394 IO::MIDIGainControl::send_feedback (gain_t gain)
2396 if (!setting && get_midi_feedback() && gain_to_midi) {
2397 MIDI::byte val = (MIDI::byte) (gain_to_midi (gain) * 127.0);
2398 MIDI::channel_t ch = 0;
2399 MIDI::eventType ev = MIDI::none;
2400 MIDI::byte additional = 0;
2401 MIDI::EventTwoBytes data;
2403 if (get_control_info (ch, ev, additional)) {
2404 data.controller_number = additional;
2408 io._session.send_midi_message (get_port(), ev, ch, data);
2410 //send_midi_feedback (gain_to_midi (gain));
2415 IO::MIDIGainControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force)
2417 if (get_midi_feedback() && gain_to_midi && bufsize > 2) {
2418 MIDI::channel_t ch = 0;
2419 MIDI::eventType ev = MIDI::none;
2420 MIDI::byte additional = 0;
2423 if (get_control_info (ch, ev, additional)) {
2424 gm = (MIDI::byte) (gain_to_midi (val) * 127.0);
2426 if (gm != last_written) {
2427 *buf++ = (0xF0 & ev) | (0xF & ch);
2428 *buf++ = additional; /* controller number */
2440 IO::reset_peak_meters ()
2442 uint32_t limit = max (_ninputs, _noutputs);
2444 for (uint32_t i = 0; i < limit; ++i) {
2450 IO::setup_peak_meters ()
2452 uint32_t limit = max (_ninputs, _noutputs);
2454 while (_peak_power.size() < limit) {
2455 _peak_power.push_back (0);
2456 _visible_peak_power.push_back (0);
2461 IO::get_memento() const
2463 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2467 IO::restore_state (StateManager::State& state)
2472 StateManager::State*
2473 IO::state_factory (std::string why) const
2475 StateManager::State* state = new StateManager::State (why);
2480 Update the peak meters.
2482 The meter signal lock is taken to prevent modification of the
2483 Meter signal while updating the meters, taking the meter signal
2484 lock prior to taking the io_lock ensures that all IO will remain
2485 valid while metering.
2490 Glib::Mutex::Lock guard (m_meter_signal_lock);
2498 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2499 uint32_t limit = max (_ninputs, _noutputs);
2501 for (uint32_t n = 0; n < limit; ++n) {
2503 /* XXX we should use atomic exchange here */
2505 /* grab peak since last read */
2507 float new_peak = _peak_power[n];
2510 /* compute new visible value using falloff */
2512 if (new_peak > 0.0) {
2513 new_peak = coefficient_to_dB (new_peak);
2515 new_peak = minus_infinity();
2518 if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2519 _visible_peak_power[n] = new_peak;
2522 new_peak = _visible_peak_power[n] - _session.meter_falloff();
2523 _visible_peak_power[n] = max (new_peak, -INFINITY);
2529 IO::reset_midi_control (MIDI::Port* port, bool on)
2531 MIDI::channel_t chn;
2535 _midi_gain_control.get_control_info (chn, ev, extra);
2539 _midi_gain_control.midi_rebind (port, chn);
2541 _panner->reset_midi_control (port, on);
2546 IO::save_automation (const string& path)
2551 fullpath = _session.automation_dir();
2554 out.open (fullpath.c_str());
2557 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2561 out << X_("version ") << current_automation_version_number << endl;
2563 /* XXX use apply_to_points to get thread safety */
2565 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2566 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2575 IO::load_automation (const string& path)
2580 uint32_t linecnt = 0;
2582 LocaleGuard lg (X_("POSIX"));
2584 fullpath = _session.automation_dir();
2587 in.open (fullpath.c_str());
2590 fullpath = _session.automation_dir();
2591 fullpath += _session.snap_name();
2594 in.open (fullpath.c_str());
2596 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2601 clear_automation ();
2603 while (in.getline (line, sizeof(line), '\n')) {
2605 jack_nframes_t when;
2608 if (++linecnt == 1) {
2609 if (memcmp (line, "version", 7) == 0) {
2610 if (sscanf (line, "version %f", &version) != 1) {
2611 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2615 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2619 if (version != current_automation_version_number) {
2620 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2627 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2628 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2634 _gain_automation_curve.add (when, value, true);
2644 /* older (pre-1.0) versions of ardour used this */
2648 warning << _("dubious automation event found (and ignored)") << endmsg;
2652 _gain_automation_curve.save_state (_("loaded from disk"));
2658 IO::clear_automation ()
2660 Glib::Mutex::Lock lm (automation_lock);
2661 _gain_automation_curve.clear ();
2662 _panner->clear_automation ();
2666 IO::set_gain_automation_state (AutoState state)
2668 bool changed = false;
2671 Glib::Mutex::Lock lm (automation_lock);
2673 if (state != _gain_automation_curve.automation_state()) {
2675 last_automation_snapshot = 0;
2676 _gain_automation_curve.set_automation_state (state);
2679 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2685 _session.set_dirty ();
2686 gain_automation_state_changed (); /* EMIT SIGNAL */
2691 IO::set_gain_automation_style (AutoStyle style)
2693 bool changed = false;
2696 Glib::Mutex::Lock lm (automation_lock);
2698 if (style != _gain_automation_curve.automation_style()) {
2700 _gain_automation_curve.set_automation_style (style);
2705 gain_automation_style_changed (); /* EMIT SIGNAL */
2709 IO::inc_gain (gain_t factor, void *src)
2711 if (_desired_gain == 0.0f)
2712 set_gain (0.000001f + (0.000001f * factor), src);
2714 set_gain (_desired_gain + (_desired_gain * factor), src);
2718 IO::set_gain (gain_t val, void *src)
2720 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2721 if (val>1.99526231f) val=1.99526231f;
2724 Glib::Mutex::Lock dm (declick_lock);
2725 _desired_gain = val;
2728 if (_session.transport_stopped()) {
2729 _effective_gain = val;
2735 if (_session.get_midi_feedback()) {
2736 _midi_gain_control.send_feedback (_desired_gain);
2739 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2740 _gain_automation_curve.add (_session.transport_frame(), val);
2744 _session.set_dirty();
2748 IO::send_all_midi_feedback ()
2750 if (_session.get_midi_feedback()) {
2751 _midi_gain_control.send_feedback (_effective_gain);
2754 _panner->send_all_midi_feedback();
2759 IO::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize)
2761 if (_session.get_midi_feedback()) {
2762 if (gain_automation_playback ()) {
2763 buf = _midi_gain_control.write_feedback (buf, bufsize, _effective_gain);
2765 buf = _panner->write_midi_feedback (buf, bufsize);
2772 IO::start_gain_touch ()
2774 _gain_automation_curve.start_touch ();
2778 IO::end_gain_touch ()
2780 _gain_automation_curve.stop_touch ();
2784 IO::start_pan_touch (uint32_t which)
2786 if (which < _panner->size()) {
2787 (*_panner)[which]->automation().start_touch();
2792 IO::end_pan_touch (uint32_t which)
2794 if (which < _panner->size()) {
2795 (*_panner)[which]->automation().stop_touch();
2801 IO::automation_snapshot (jack_nframes_t now)
2803 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2805 if (gain_automation_recording()) {
2806 _gain_automation_curve.rt_add (now, gain());
2809 _panner->snapshot (now);
2811 last_automation_snapshot = now;
2816 IO::transport_stopped (jack_nframes_t frame)
2818 _gain_automation_curve.reposition_for_rt_add (frame);
2820 if (_gain_automation_curve.automation_state() != Off) {
2822 if (gain_automation_recording()) {
2823 _gain_automation_curve.save_state (_("automation write/touch"));
2826 /* the src=0 condition is a special signal to not propagate
2827 automation gain changes into the mix group when locating.
2830 set_gain (_gain_automation_curve.eval (frame), 0);
2833 _panner->transport_stopped (frame);
2837 IO::find_input_port_hole ()
2839 /* CALLER MUST HOLD IO LOCK */
2843 if (_inputs.empty()) {
2847 for (n = 1; n < UINT_MAX; ++n) {
2848 char buf[jack_port_name_size()];
2849 vector<Port*>::iterator i;
2851 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2853 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2854 if ((*i)->short_name() == buf) {
2859 if (i == _inputs.end()) {
2867 IO::find_output_port_hole ()
2869 /* CALLER MUST HOLD IO LOCK */
2873 if (_outputs.empty()) {
2877 for (n = 1; n < UINT_MAX; ++n) {
2878 char buf[jack_port_name_size()];
2879 vector<Port*>::iterator i;
2881 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2883 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2884 if ((*i)->short_name() == buf) {
2889 if (i == _outputs.end()) {