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 <pbd/lockmonitor.h>
29 #include <pbd/xml++.h>
31 #include <ardour/audioengine.h>
32 #include <ardour/io.h>
33 #include <ardour/port.h>
34 #include <ardour/connection.h>
35 #include <ardour/session.h>
36 #include <ardour/cycle_timer.h>
37 #include <ardour/panner.h>
38 #include <ardour/dB.h>
45 A bug in OS X's cmath that causes isnan() and isinf() to be
46 "undeclared". the following works around that
49 #if defined(__APPLE__) && defined(__MACH__)
50 extern "C" int isnan (double);
51 extern "C" int isinf (double);
56 using namespace ARDOUR;
57 //using namespace sigc;
59 static float current_automation_version_number = 1.0;
61 jack_nframes_t IO::_automation_interval = 0;
62 const string IO::state_node_name = "IO";
63 bool IO::connecting_legal = false;
64 bool IO::ports_legal = false;
65 bool IO::panners_legal = false;
66 sigc::signal<void> IO::GrabPeakPower;
67 sigc::signal<int> IO::ConnectingLegal;
68 sigc::signal<int> IO::PortsLegal;
69 sigc::signal<int> IO::PannersLegal;
70 sigc::signal<void,uint32_t> IO::MoreOutputs;
71 sigc::signal<int> IO::PortsCreated;
73 /* this is a default mapper of MIDI control values to a gain coefficient.
74 others can be imagined. see IO::set_midi_to_gain_function().
77 static gain_t direct_midi_to_gain (double fract) {
78 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
79 /* this maxes at +6dB */
80 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
83 static double direct_gain_to_midi (gain_t gain) {
84 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
85 if (gain == 0) return 0.0;
87 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
90 static bool sort_ports_by_name (Port* a, Port* b)
92 return a->name() < b->name();
96 IO::IO (Session& s, string name,
98 int input_min, int input_max, int output_min, int output_max)
101 _midi_gain_control (*this, _session.midi_port()),
102 _gain_automation_curve (0.0, 2.0, 1.0),
103 _input_minimum (input_min),
104 _input_maximum (input_max),
105 _output_minimum (output_min),
106 _output_maximum (output_max)
109 _panner = new Panner (name, _session);
112 _input_connection = 0;
113 _output_connection = 0;
114 pending_state_node = 0;
117 no_panner_reset = false;
120 _midi_gain_control.midi_to_gain = direct_midi_to_gain;
121 _midi_gain_control.gain_to_midi = direct_gain_to_midi;
123 apply_gain_automation = false;
125 last_automation_snapshot = 0;
127 _gain_automation_state = Off;
128 _gain_automation_style = Absolute;
130 GrabPeakPower.connect (mem_fun (*this, &IO::grab_peak_power));
135 LockMonitor lm (io_lock, __LINE__, __FILE__);
136 vector<Port *>::iterator i;
138 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
139 _session.engine().unregister_port (*i);
142 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
143 _session.engine().unregister_port (*i);
148 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
150 /* io_lock, not taken: function must be called from Session::process() calltree */
152 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
153 (*i)->silence (nframes, offset);
158 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
160 jack_nframes_t declick = min ((jack_nframes_t)4096, nframes);
163 double fractional_shift;
164 double fractional_pos;
165 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
167 if (nframes == 0) return;
169 fractional_shift = -1.0/declick;
171 if (target < initial) {
172 /* fade out: remove more and more of delta from initial */
173 delta = -(initial - target);
175 /* fade in: add more and more of delta from initial */
176 delta = target - initial;
179 for (uint32_t n = 0; n < nbufs; ++n) {
182 fractional_pos = 1.0;
184 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
185 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
186 fractional_pos += fractional_shift;
189 /* now ensure the rest of the buffer has the target value
190 applied, if necessary.
193 if (declick != nframes) {
195 if (invert_polarity) {
200 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
201 } else if (target != 1.0) {
202 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
203 buffer[nx] *= target;
211 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)
215 /* io_lock, not taken: function must be called from Session::process() calltree */
217 if (_noutputs == 0) {
221 if (_noutputs == 1) {
223 dst = output(0)->get_buffer (nframes) + offset;
225 for (uint32_t n = 0; n < nbufs; ++n) {
226 if (bufs[n] != dst) {
227 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
231 output(0)->mark_silence (false);
237 vector<Port *>::iterator out;
238 vector<Sample *>::iterator in;
239 Panner::iterator pan;
240 Sample* obufs[_noutputs];
242 /* the terrible silence ... */
244 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
245 obufs[o] = (*out)->get_buffer (nframes) + offset;
246 memset (obufs[o], 0, sizeof (Sample) * nframes);
247 (*out)->mark_silence (false);
252 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
253 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
258 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
263 /* io_lock, not taken: function must be called from Session::process() calltree */
265 if (_noutputs == 0) {
269 /* the panner can be empty if there are no inputs to the
270 route, but still outputs
273 if (_panner->bypassed() || _panner->empty()) {
274 deliver_output_no_pan (bufs, nbufs, nframes, offset);
278 if (_noutputs == 1) {
280 dst = output(0)->get_buffer (nframes) + offset;
282 if (gain_coeff == 0.0f) {
284 /* only one output, and gain was zero, so make it silent */
286 memset (dst, 0, sizeof (Sample) * nframes);
288 } else if (gain_coeff == 1.0f){
290 /* mix all buffers into the output */
294 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
296 for (n = 1; n < nbufs; ++n) {
299 for (jack_nframes_t n = 0; n < nframes; ++n) {
304 output(0)->mark_silence (false);
308 /* mix all buffers into the output, scaling them all by the gain */
314 for (jack_nframes_t n = 0; n < nframes; ++n) {
315 dst[n] = src[n] * gain_coeff;
318 for (n = 1; n < nbufs; ++n) {
321 for (jack_nframes_t n = 0; n < nframes; ++n) {
322 dst[n] += src[n] * gain_coeff;
326 output(0)->mark_silence (false);
333 vector<Port *>::iterator out;
334 vector<Sample *>::iterator in;
335 Panner::iterator pan;
336 Sample* obufs[_noutputs];
338 /* the terrible silence ... */
340 /* XXX this is wasteful but i see no way to avoid it */
342 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
343 obufs[o] = (*out)->get_buffer (nframes) + offset;
344 memset (obufs[o], 0, sizeof (Sample) * nframes);
345 (*out)->mark_silence (false);
350 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
351 Panner::iterator tmp;
356 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
358 if (tmp != _panner->end()) {
365 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
367 /* io_lock, not taken: function must be called from Session::process() calltree */
369 if (_noutputs == 0) {
373 if (_panner->bypassed() || _panner->empty()) {
374 deliver_output_no_pan (bufs, nbufs, nframes, offset);
380 gain_t pangain = _gain;
383 TentativeLockMonitor dm (declick_lock, __LINE__, __FILE__);
393 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
398 /* simple, non-automation panning to outputs */
400 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
401 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
403 pan (bufs, nbufs, nframes, offset, pangain);
408 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
410 /* io_lock, not taken: function must be called from Session::process() calltree */
412 if (_noutputs == 0) {
417 gain_t old_gain = _gain;
419 if (apply_gain_automation) {
421 /* gain has already been applied by automation code. do nothing here except
430 TentativeLockMonitor dm (declick_lock, __LINE__, __FILE__);
442 vector<Port*>::iterator o;
443 vector<Sample*> outs;
447 /* unlikely condition */
448 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
449 outs.push_back ((*o)->get_buffer (nframes) + offset);
453 /* reduce nbufs to the index of the last input buffer */
457 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
458 actual_gain = _gain * speed_quietning;
463 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
465 dst = (*o)->get_buffer (nframes) + offset;
466 src = bufs[min(nbufs,i)];
468 if (dg != _gain || actual_gain == 1.0f) {
469 memcpy (dst, src, sizeof (Sample) * nframes);
470 } else if (actual_gain == 0.0f) {
471 memset (dst, 0, sizeof (Sample) * nframes);
473 for (jack_nframes_t x = 0; x < nframes; ++x) {
474 dst[x] = src[x] * actual_gain;
478 (*o)->mark_silence (false);
482 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
486 if (apply_gain_automation) {
492 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
494 /* io_lock, not taken: function must be called from Session::process() calltree */
496 vector<Port *>::iterator i;
500 /* we require that bufs.size() >= 1 */
502 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
503 if (i == _inputs.end()) {
507 /* XXX always read the full extent of the port buffer that
508 we need. One day, we may use jack_port_get_buffer_at_offset()
509 or something similar. For now, this simple hack will
512 Hack? Why yes .. we only need to read nframes-worth of
513 data, but the data we want is at `offset' within the
517 last = (*i)->get_buffer (nframes+offset) + offset;
518 // the dest buffer's offset has already been applied
519 memcpy (bufs[n], last, sizeof (Sample) * nframes);
522 /* fill any excess outputs with the last input */
524 while (n < nbufs && last) {
525 // the dest buffer's offset has already been applied
526 memcpy (bufs[n], last, sizeof (Sample) * nframes);
532 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
533 jack_nframes_t nframes, jack_nframes_t offset)
535 vector<Sample*>& bufs = _session.get_passthru_buffers ();
536 uint32_t nbufs = n_process_buffers ();
538 collect_input (bufs, nbufs, nframes, offset);
540 for (uint32_t n = 0; n < nbufs; ++n) {
541 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
546 IO::drop_input_connection ()
548 _input_connection = 0;
549 input_connection_configuration_connection.disconnect();
550 input_connection_connection_connection.disconnect();
551 _session.set_dirty ();
555 IO::drop_output_connection ()
557 _output_connection = 0;
558 output_connection_configuration_connection.disconnect();
559 output_connection_connection_connection.disconnect();
560 _session.set_dirty ();
564 IO::disconnect_input (Port* our_port, string other_port, void* src)
566 if (other_port.length() == 0 || our_port == 0) {
571 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
574 LockMonitor lm (io_lock, __LINE__, __FILE__);
576 /* check that our_port is really one of ours */
578 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
582 /* disconnect it from the source */
584 if (_session.engine().disconnect (other_port, our_port->name())) {
585 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
589 drop_input_connection();
593 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
594 _session.set_dirty ();
600 IO::connect_input (Port* our_port, string other_port, void* src)
602 if (other_port.length() == 0 || our_port == 0) {
607 LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
610 LockMonitor lm (io_lock, __LINE__, __FILE__);
612 /* check that our_port is really one of ours */
614 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
618 /* connect it to the source */
620 if (_session.engine().connect (other_port, our_port->name())) {
624 drop_input_connection ();
628 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
629 _session.set_dirty ();
634 IO::disconnect_output (Port* our_port, string other_port, void* src)
636 if (other_port.length() == 0 || our_port == 0) {
641 LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
644 LockMonitor lm (io_lock, __LINE__, __FILE__);
646 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
650 /* disconnect it from the destination */
652 if (_session.engine().disconnect (our_port->name(), other_port)) {
653 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
657 drop_output_connection ();
661 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
662 _session.set_dirty ();
667 IO::connect_output (Port* our_port, string other_port, void* src)
669 if (other_port.length() == 0 || our_port == 0) {
674 LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
677 LockMonitor lm (io_lock, __LINE__, __FILE__);
679 /* check that our_port is really one of ours */
681 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
685 /* connect it to the destination */
687 if (_session.engine().connect (our_port->name(), other_port)) {
691 drop_output_connection ();
695 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
696 _session.set_dirty ();
701 IO::set_input (Port* other_port, void* src)
703 /* this removes all but one ports, and connects that one port
704 to the specified source.
707 if (_input_minimum > 1 || _input_minimum == 0) {
708 /* sorry, you can't do this */
712 if (other_port == 0) {
713 if (_input_minimum < 0) {
714 return ensure_inputs (0, false, true, src);
720 if (ensure_inputs (1, true, true, src)) {
724 return connect_input (_inputs.front(), other_port->name(), src);
728 IO::remove_output_port (Port* port, void* src)
730 IOChange change (NoChange);
733 LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
736 LockMonitor lm (io_lock, __LINE__, __FILE__);
738 if (_noutputs - 1 == (uint32_t) _output_minimum) {
739 /* sorry, you can't do this */
743 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
745 change = IOChange (change|ConfigurationChanged);
746 if (port->connected()) {
747 change = IOChange (change|ConnectionsChanged);
750 _session.engine().unregister_port (*i);
753 drop_output_connection ();
759 if (change != NoChange) {
760 setup_peak_meters ();
766 if (change != NoChange) {
767 output_changed (change, src); /* EMIT SIGNAL */
768 _session.set_dirty ();
776 IO::add_output_port (string destination, void* src)
782 LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
785 LockMonitor lm (io_lock, __LINE__, __FILE__);
787 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
791 /* Create a new output port */
793 if (_output_maximum == 1) {
794 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
796 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
799 if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) {
800 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
804 _outputs.push_back (our_port);
805 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
807 drop_output_connection ();
808 setup_peak_meters ();
812 MoreOutputs (_noutputs); /* EMIT SIGNAL */
815 if (destination.length()) {
816 if (_session.engine().connect (our_port->name(), destination)) {
821 // pan_changed (src); /* EMIT SIGNAL */
822 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
823 _session.set_dirty ();
828 IO::remove_input_port (Port* port, void* src)
830 IOChange change (NoChange);
833 LockMonitor em(_session.engine().process_lock(), __LINE__, __FILE__);
836 LockMonitor lm (io_lock, __LINE__, __FILE__);
838 if (((int)_ninputs - 1) < _input_minimum) {
839 /* sorry, you can't do this */
842 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
845 change = IOChange (change|ConfigurationChanged);
847 if (port->connected()) {
848 change = IOChange (change|ConnectionsChanged);
851 _session.engine().unregister_port (*i);
854 drop_input_connection ();
860 if (change != NoChange) {
861 setup_peak_meters ();
867 if (change != NoChange) {
868 input_changed (change, src);
869 _session.set_dirty ();
877 IO::add_input_port (string source, void* src)
883 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
886 LockMonitor lm (io_lock, __LINE__, __FILE__);
888 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
892 /* Create a new input port */
894 if (_input_maximum == 1) {
895 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
897 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
900 if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) {
901 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
905 _inputs.push_back (our_port);
906 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
908 drop_input_connection ();
909 setup_peak_meters ();
913 MoreOutputs (_ninputs); /* EMIT SIGNAL */
916 if (source.length()) {
918 if (_session.engine().connect (source, our_port->name())) {
923 // pan_changed (src); /* EMIT SIGNAL */
924 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
925 _session.set_dirty ();
931 IO::disconnect_inputs (void* src)
934 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
937 LockMonitor lm (io_lock, __LINE__, __FILE__);
939 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
940 _session.engine().disconnect (*i);
943 drop_input_connection ();
946 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
951 IO::disconnect_outputs (void* src)
954 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
957 LockMonitor lm (io_lock, __LINE__, __FILE__);
959 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
960 _session.engine().disconnect (*i);
963 drop_output_connection ();
967 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
968 _session.set_dirty ();
973 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
976 bool changed = false;
977 bool reduced = false;
979 /* remove unused ports */
981 while (_ninputs > n) {
982 _session.engine().unregister_port (_inputs.back());
989 /* create any necessary new ports */
991 while (_ninputs < n) {
995 /* Create a new input port */
997 if (_input_maximum == 1) {
998 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1001 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1006 if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) {
1007 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1012 catch (AudioEngine::PortRegistrationFailure& err) {
1013 setup_peak_meters ();
1019 _inputs.push_back (input_port);
1020 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1026 drop_input_connection ();
1027 setup_peak_meters ();
1029 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1030 _session.set_dirty ();
1034 /* disconnect all existing ports so that we get a fresh start */
1036 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1037 _session.engine().disconnect (*i);
1045 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1047 bool in_changed = false;
1048 bool out_changed = false;
1049 bool in_reduced = false;
1050 bool out_reduced = false;
1051 bool need_pan_reset;
1053 if (_input_maximum >= 0) {
1054 nin = min (_input_maximum, (int) nin);
1057 if (_output_maximum >= 0) {
1058 nout = min (_output_maximum, (int) nout);
1061 if (nin == _ninputs && nout == _noutputs && !clear) {
1066 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
1067 LockMonitor lm (io_lock, __LINE__, __FILE__);
1071 if (_noutputs == nout) {
1072 need_pan_reset = false;
1074 need_pan_reset = true;
1077 /* remove unused ports */
1079 while (_ninputs > nin) {
1080 _session.engine().unregister_port (_inputs.back());
1087 while (_noutputs > nout) {
1088 _session.engine().unregister_port (_outputs.back());
1089 _outputs.pop_back();
1095 /* create any necessary new ports */
1097 while (_ninputs < nin) {
1101 /* Create a new input port */
1103 if (_input_maximum == 1) {
1104 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1107 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1111 if ((port = _session.engine().register_audio_input_port (buf)) == 0) {
1112 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1117 catch (AudioEngine::PortRegistrationFailure& err) {
1118 setup_peak_meters ();
1124 _inputs.push_back (port);
1129 /* create any necessary new ports */
1131 while (_noutputs < nout) {
1135 /* Create a new output port */
1137 if (_output_maximum == 1) {
1138 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1140 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1144 if ((port = _session.engine().register_audio_output_port (buf)) == 0) {
1145 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1150 catch (AudioEngine::PortRegistrationFailure& err) {
1151 setup_peak_meters ();
1157 _outputs.push_back (port);
1164 /* disconnect all existing ports so that we get a fresh start */
1166 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1167 _session.engine().disconnect (*i);
1170 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1171 _session.engine().disconnect (*i);
1176 if (in_changed || out_changed) {
1177 setup_peak_meters ();
1182 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1183 drop_output_connection ();
1184 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1188 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1189 drop_input_connection ();
1190 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1193 if (in_changed || out_changed) {
1194 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1195 _session.set_dirty ();
1202 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1204 bool changed = false;
1206 if (_input_maximum >= 0) {
1207 n = min (_input_maximum, (int) n);
1209 if (n == _ninputs && !clear) {
1215 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
1216 changed = ensure_inputs_locked (n, clear, src);
1218 changed = ensure_inputs_locked (n, clear, src);
1222 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1223 _session.set_dirty ();
1230 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1233 bool changed = false;
1234 bool reduced = false;
1235 bool need_pan_reset;
1237 if (_noutputs == n) {
1238 need_pan_reset = false;
1240 need_pan_reset = true;
1243 /* remove unused ports */
1245 while (_noutputs > n) {
1247 _session.engine().unregister_port (_outputs.back());
1248 _outputs.pop_back();
1254 /* create any necessary new ports */
1256 while (_noutputs < n) {
1260 /* Create a new output port */
1262 if (_output_maximum == 1) {
1263 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1265 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1268 if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) {
1269 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1273 _outputs.push_back (output_port);
1274 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1277 setup_peak_meters ();
1279 if (need_pan_reset) {
1285 drop_output_connection ();
1286 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1287 _session.set_dirty ();
1291 /* disconnect all existing ports so that we get a fresh start */
1293 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1294 _session.engine().disconnect (*i);
1302 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1304 bool changed = false;
1306 if (_output_maximum >= 0) {
1307 n = min (_output_maximum, (int) n);
1308 if (n == _noutputs && !clear) {
1313 /* XXX caller should hold io_lock, but generally doesn't */
1316 LockMonitor em (_session.engine().process_lock(), __LINE__, __FILE__);
1317 changed = ensure_outputs_locked (n, clear, src);
1319 changed = ensure_outputs_locked (n, clear, src);
1323 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1330 IO::effective_gain () const
1332 if (gain_automation_playback()) {
1333 return _effective_gain;
1335 return _desired_gain;
1342 if (panners_legal) {
1343 if (!no_panner_reset) {
1344 _panner->reset (_noutputs, pans_required());
1347 panner_legal_c.disconnect ();
1348 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1353 IO::panners_became_legal ()
1355 _panner->reset (_noutputs, pans_required());
1356 _panner->load (); // automation
1357 panner_legal_c.disconnect ();
1362 IO::defer_pan_reset ()
1364 no_panner_reset = true;
1368 IO::allow_pan_reset ()
1370 no_panner_reset = false;
1376 IO::get_state (void)
1378 return state (true);
1382 IO::state (bool full_state)
1384 XMLNode* node = new XMLNode (state_node_name);
1387 bool need_ins = true;
1388 bool need_outs = true;
1389 LocaleGuard lg (X_("POSIX"));
1390 LockMonitor lm (io_lock, __LINE__, __FILE__);
1392 node->add_property("name", _name);
1393 snprintf (buf, sizeof(buf), "%" PRIu64, id());
1394 node->add_property("id", buf);
1398 if (_input_connection) {
1399 node->add_property ("input-connection", _input_connection->name());
1403 if (_output_connection) {
1404 node->add_property ("output-connection", _output_connection->name());
1409 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1411 const char **connections = (*i)->get_connections();
1413 if (connections && connections[0]) {
1416 for (int n = 0; connections && connections[n]; ++n) {
1421 /* if its a connection to our own port,
1422 return only the port name, not the
1423 whole thing. this allows connections
1424 to be re-established even when our
1425 client name is different.
1428 str += _session.engine().make_port_name_relative (connections[n]);
1440 node->add_property ("inputs", str);
1446 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1448 const char **connections = (*i)->get_connections();
1450 if (connections && connections[0]) {
1454 for (int n = 0; connections[n]; ++n) {
1459 str += _session.engine().make_port_name_relative (connections[n]);
1471 node->add_property ("outputs", str);
1474 node->add_child_nocopy (_panner->state (full_state));
1476 snprintf (buf, sizeof(buf), "%2.12f", gain());
1477 node->add_property ("gain", buf);
1479 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1485 node->add_property ("iolimits", buf);
1489 MIDI::channel_t chn;
1491 MIDI::byte additional;
1492 XMLNode* midi_node = 0;
1495 if (_midi_gain_control.get_control_info (chn, ev, additional)) {
1497 midi_node = node->add_child ("MIDI");
1499 child = midi_node->add_child ("gain");
1500 set_midi_node_info (child, ev, chn, additional);
1506 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1508 /* never store anything except Off for automation state in a template */
1509 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1511 node->add_property ("automation-state", buf);
1512 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1513 node->add_property ("automation-style", buf);
1515 /* XXX same for pan etc. */
1521 IO::connecting_became_legal ()
1525 if (pending_state_node == 0) {
1526 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1531 connection_legal_c.disconnect ();
1533 ret = make_connections (*pending_state_node);
1536 delete pending_state_node;
1537 pending_state_node = 0;
1544 IO::ports_became_legal ()
1548 if (pending_state_node == 0) {
1549 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1554 port_legal_c.disconnect ();
1556 ret = create_ports (*pending_state_node);
1558 if (connecting_legal) {
1559 delete pending_state_node;
1560 pending_state_node = 0;
1567 IO::set_state (const XMLNode& node)
1569 const XMLProperty* prop;
1570 XMLNodeConstIterator iter;
1571 XMLNodeList midi_kids;
1572 LocaleGuard lg (X_("POSIX"));
1574 /* force use of non-localized representation of decimal point,
1575 since we use it a lot in XML files and so forth.
1578 if (node.name() != state_node_name) {
1579 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1583 if ((prop = node.property ("name")) != 0) {
1584 _name = prop->value();
1585 _panner->set_name (_name);
1588 if ((prop = node.property ("id")) != 0) {
1589 sscanf (prop->value().c_str(), "%" PRIu64, &_id);
1592 if ((prop = node.property ("iolimits")) != 0) {
1593 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1600 if ((prop = node.property ("gain")) != 0) {
1601 set_gain (atof (prop->value().c_str()), this);
1602 _gain = _desired_gain;
1605 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1606 if ((*iter)->name() == "Panner") {
1607 _panner->set_state (**iter);
1611 midi_kids = node.children ("MIDI");
1613 for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) {
1616 XMLNodeConstIterator miter;
1619 kids = (*iter)->children ();
1621 for (miter = kids.begin(); miter != kids.end(); ++miter) {
1625 if (child->name() == "gain") {
1627 MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */
1628 MIDI::byte additional = 0; /* ditto */
1629 MIDI::channel_t chn = 0; /* ditto */
1631 if (get_midi_node_info (child, ev, chn, additional)) {
1632 _midi_gain_control.set_control_type (chn, ev, additional);
1634 error << string_compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
1640 if ((prop = node.property ("automation-state")) != 0) {
1643 x = strtol (prop->value().c_str(), 0, 16);
1644 set_gain_automation_state (AutoState (x));
1647 if ((prop = node.property ("automation-style")) != 0) {
1650 x = strtol (prop->value().c_str(), 0, 16);
1651 set_gain_automation_style (AutoStyle (x));
1656 if (create_ports (node)) {
1662 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1665 if (panners_legal) {
1668 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1671 if (connecting_legal) {
1673 if (make_connections (node)) {
1679 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1682 if (!ports_legal || !connecting_legal) {
1683 pending_state_node = new XMLNode (node);
1690 IO::create_ports (const XMLNode& node)
1692 const XMLProperty* prop;
1694 int num_outputs = 0;
1696 if ((prop = node.property ("input-connection")) != 0) {
1698 Connection* c = _session.connection_by_name (prop->value());
1701 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1703 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1704 error << _("No input connections available as a replacement")
1708 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1713 num_inputs = c->nports();
1715 } else if ((prop = node.property ("inputs")) != 0) {
1717 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1720 if ((prop = node.property ("output-connection")) != 0) {
1721 Connection* c = _session.connection_by_name (prop->value());
1724 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1726 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1727 error << _("No output connections available as a replacement")
1731 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1736 num_outputs = c->nports ();
1738 } else if ((prop = node.property ("outputs")) != 0) {
1739 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1742 no_panner_reset = true;
1744 if (ensure_io (num_inputs, num_outputs, true, this)) {
1745 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1749 no_panner_reset = false;
1751 set_deferred_state ();
1758 IO::get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional)
1761 const XMLProperty* prop;
1764 if ((prop = node->property ("event")) != 0) {
1765 sscanf (prop->value().c_str(), "0x%x", &xx);
1766 ev = (MIDI::eventType) xx;
1771 if (ok && ((prop = node->property ("channel")) != 0)) {
1772 sscanf (prop->value().c_str(), "%d", &xx);
1773 chan = (MIDI::channel_t) xx;
1778 if (ok && ((prop = node->property ("additional")) != 0)) {
1779 sscanf (prop->value().c_str(), "0x%x", &xx);
1780 additional = (MIDI::byte) xx;
1787 IO::set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional)
1791 snprintf (buf, sizeof(buf), "0x%x", ev);
1792 node->add_property ("event", buf);
1793 snprintf (buf, sizeof(buf), "%d", chan);
1794 node->add_property ("channel", buf);
1795 snprintf (buf, sizeof(buf), "0x%x", additional);
1796 node->add_property ("additional", buf);
1803 IO::make_connections (const XMLNode& node)
1805 const XMLProperty* prop;
1807 if ((prop = node.property ("input-connection")) != 0) {
1808 Connection* c = _session.connection_by_name (prop->value());
1811 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1813 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1814 error << _("No input connections available as a replacement")
1818 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1823 use_input_connection (*c, this);
1825 } else if ((prop = node.property ("inputs")) != 0) {
1826 if (set_inputs (prop->value())) {
1827 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1832 if ((prop = node.property ("output-connection")) != 0) {
1833 Connection* c = _session.connection_by_name (prop->value());
1836 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1838 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1839 error << _("No output connections available as a replacement")
1843 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1848 use_output_connection (*c, this);
1850 } else if ((prop = node.property ("outputs")) != 0) {
1851 if (set_outputs (prop->value())) {
1852 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1861 IO::set_inputs (const string& str)
1863 vector<string> ports;
1868 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1872 if (ensure_inputs (nports, true, true, this)) {
1876 string::size_type start, end, ostart;
1883 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1886 if ((end = str.find_first_of ('}', start)) == string::npos) {
1887 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1891 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1892 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1898 for (int x = 0; x < n; ++x) {
1899 connect_input (input (i), ports[x], this);
1911 IO::set_outputs (const string& str)
1913 vector<string> ports;
1918 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1922 if (ensure_outputs (nports, true, true, this)) {
1926 string::size_type start, end, ostart;
1933 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1936 if ((end = str.find_first_of ('}', start)) == string::npos) {
1937 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1941 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1942 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1948 for (int x = 0; x < n; ++x) {
1949 connect_output (output (i), ports[x], this);
1961 IO::parse_io_string (const string& str, vector<string>& ports)
1963 string::size_type pos, opos;
1965 if (str.length() == 0) {
1974 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1975 ports.push_back (str.substr (opos, pos - opos));
1979 if (opos < str.length()) {
1980 ports.push_back (str.substr(opos));
1983 return ports.size();
1987 IO::parse_gain_string (const string& str, vector<string>& ports)
1989 string::size_type pos, opos;
1995 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1996 ports.push_back (str.substr (opos, pos - opos));
2000 if (opos < str.length()) {
2001 ports.push_back (str.substr(opos));
2004 return ports.size();
2008 IO::set_name (string name, void* src)
2010 if (name == _name) {
2014 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2015 string current_name = (*i)->short_name();
2016 current_name.replace (current_name.find (_name), _name.length(), name);
2017 (*i)->set_name (current_name);
2020 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2021 string current_name = (*i)->short_name();
2022 current_name.replace (current_name.find (_name), _name.length(), name);
2023 (*i)->set_name (current_name);
2027 name_changed (src); /* EMIT SIGNAL */
2033 IO::set_input_minimum (int n)
2039 IO::set_input_maximum (int n)
2045 IO::set_output_minimum (int n)
2047 _output_minimum = n;
2051 IO::set_output_maximum (int n)
2053 _output_maximum = n;
2057 IO::set_port_latency (jack_nframes_t nframes)
2059 LockMonitor lm (io_lock, __LINE__, __FILE__);
2061 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2062 (*i)->set_latency (nframes);
2067 IO::output_latency () const
2069 jack_nframes_t max_latency;
2070 jack_nframes_t latency;
2074 /* io lock not taken - must be protected by other means */
2076 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2077 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2078 max_latency = latency;
2086 IO::input_latency () const
2088 jack_nframes_t max_latency;
2089 jack_nframes_t latency;
2093 /* io lock not taken - must be protected by other means */
2095 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2096 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2097 max_latency = latency;
2105 IO::use_input_connection (Connection& c, void* src)
2110 LockMonitor lm (_session.engine().process_lock(), __LINE__, __FILE__);
2111 LockMonitor lm2 (io_lock, __LINE__, __FILE__);
2115 drop_input_connection ();
2117 if (ensure_inputs (limit, false, false, src)) {
2121 /* first pass: check the current state to see what's correctly
2122 connected, and drop anything that we don't want.
2125 for (uint32_t n = 0; n < limit; ++n) {
2126 const Connection::PortList& pl = c.port_connections (n);
2128 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2130 if (!_inputs[n]->connected_to ((*i))) {
2132 /* clear any existing connections */
2134 _session.engine().disconnect (_inputs[n]);
2136 } else if (_inputs[n]->connected() > 1) {
2138 /* OK, it is connected to the port we want,
2139 but its also connected to other ports.
2140 Change that situation.
2143 /* XXX could be optimized to not drop
2147 _session.engine().disconnect (_inputs[n]);
2153 /* second pass: connect all requested ports where necessary */
2155 for (uint32_t n = 0; n < limit; ++n) {
2156 const Connection::PortList& pl = c.port_connections (n);
2158 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2160 if (!_inputs[n]->connected_to ((*i))) {
2162 if (_session.engine().connect (*i, _inputs[n]->name())) {
2170 _input_connection = &c;
2172 input_connection_configuration_connection = c.ConfigurationChanged.connect
2173 (mem_fun (*this, &IO::input_connection_configuration_changed));
2174 input_connection_connection_connection = c.ConnectionsChanged.connect
2175 (mem_fun (*this, &IO::input_connection_connection_changed));
2178 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2183 IO::use_output_connection (Connection& c, void* src)
2188 LockMonitor lm (_session.engine().process_lock(), __LINE__, __FILE__);
2189 LockMonitor lm2 (io_lock, __LINE__, __FILE__);
2193 drop_output_connection ();
2195 if (ensure_outputs (limit, false, false, src)) {
2199 /* first pass: check the current state to see what's correctly
2200 connected, and drop anything that we don't want.
2203 for (uint32_t n = 0; n < limit; ++n) {
2205 const Connection::PortList& pl = c.port_connections (n);
2207 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2209 if (!_outputs[n]->connected_to ((*i))) {
2211 /* clear any existing connections */
2213 _session.engine().disconnect (_outputs[n]);
2215 } else if (_outputs[n]->connected() > 1) {
2217 /* OK, it is connected to the port we want,
2218 but its also connected to other ports.
2219 Change that situation.
2222 /* XXX could be optimized to not drop
2226 _session.engine().disconnect (_outputs[n]);
2231 /* second pass: connect all requested ports where necessary */
2233 for (uint32_t n = 0; n < limit; ++n) {
2235 const Connection::PortList& pl = c.port_connections (n);
2237 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2239 if (!_outputs[n]->connected_to ((*i))) {
2241 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2248 _output_connection = &c;
2250 output_connection_configuration_connection = c.ConfigurationChanged.connect
2251 (mem_fun (*this, &IO::output_connection_configuration_changed));
2252 output_connection_connection_connection = c.ConnectionsChanged.connect
2253 (mem_fun (*this, &IO::output_connection_connection_changed));
2256 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2262 IO::disable_connecting ()
2264 connecting_legal = false;
2269 IO::enable_connecting ()
2271 connecting_legal = true;
2272 return ConnectingLegal ();
2276 IO::disable_ports ()
2278 ports_legal = false;
2286 return PortsLegal ();
2290 IO::disable_panners (void)
2292 panners_legal = false;
2297 IO::reset_panners ()
2299 panners_legal = true;
2300 return PannersLegal ();
2304 IO::input_connection_connection_changed (int ignored)
2306 use_input_connection (*_input_connection, this);
2310 IO::input_connection_configuration_changed ()
2312 use_input_connection (*_input_connection, this);
2316 IO::output_connection_connection_changed (int ignored)
2318 use_output_connection (*_output_connection, this);
2322 IO::output_connection_configuration_changed ()
2324 use_output_connection (*_output_connection, this);
2327 IO::MIDIGainControl::MIDIGainControl (IO& i, MIDI::Port* port)
2328 : MIDI::Controllable (port, 0), io (i), setting(false)
2333 last_written = 0; /* XXX need a good out-of-bound-value */
2337 IO::MIDIGainControl::set_value (float val)
2339 if (midi_to_gain == 0) return;
2342 io.set_gain (midi_to_gain (val), this);
2347 IO::MIDIGainControl::send_feedback (gain_t gain)
2349 if (!setting && get_midi_feedback() && gain_to_midi) {
2350 MIDI::byte val = (MIDI::byte) (gain_to_midi (gain) * 127.0);
2351 MIDI::channel_t ch = 0;
2352 MIDI::eventType ev = MIDI::none;
2353 MIDI::byte additional = 0;
2354 MIDI::EventTwoBytes data;
2356 if (get_control_info (ch, ev, additional)) {
2357 data.controller_number = additional;
2361 io._session.send_midi_message (get_port(), ev, ch, data);
2363 //send_midi_feedback (gain_to_midi (gain));
2368 IO::MIDIGainControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force)
2370 if (get_midi_feedback() && gain_to_midi && bufsize > 2) {
2371 MIDI::channel_t ch = 0;
2372 MIDI::eventType ev = MIDI::none;
2373 MIDI::byte additional = 0;
2376 if (get_control_info (ch, ev, additional)) {
2377 gm = (MIDI::byte) (gain_to_midi (val) * 127.0);
2379 if (gm != last_written) {
2380 *buf++ = (0xF0 & ev) | (0xF & ch);
2381 *buf++ = additional; /* controller number */
2393 IO::reset_peak_meters ()
2395 uint32_t limit = max (_ninputs, _noutputs);
2397 for (uint32_t i = 0; i < limit; ++i) {
2403 IO::setup_peak_meters ()
2405 uint32_t limit = max (_ninputs, _noutputs);
2407 while (_peak_power.size() < limit) {
2408 _peak_power.push_back (0);
2409 _stored_peak_power.push_back (0);
2414 IO::get_memento() const
2416 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2420 IO::restore_state (StateManager::State& state)
2425 StateManager::State*
2426 IO::state_factory (std::string why) const
2428 StateManager::State* state = new StateManager::State (why);
2433 IO::send_state_changed ()
2439 IO::grab_peak_power ()
2441 LockMonitor lm (io_lock, __LINE__, __FILE__);
2443 uint32_t limit = max (_ninputs, _noutputs);
2445 for (uint32_t n = 0; n < limit; ++n) {
2446 /* XXX should we use atomic exchange here ? */
2447 _stored_peak_power[n] = _peak_power[n];
2453 IO::reset_midi_control (MIDI::Port* port, bool on)
2455 MIDI::channel_t chn;
2459 _midi_gain_control.get_control_info (chn, ev, extra);
2463 _midi_gain_control.midi_rebind (port, chn);
2465 _panner->reset_midi_control (port, on);
2470 IO::save_automation (const string& path)
2475 fullpath = _session.automation_dir();
2478 out.open (fullpath.c_str());
2481 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2485 out << X_("version ") << current_automation_version_number << endl;
2487 /* XXX use apply_to_points to get thread safety */
2489 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2490 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2499 IO::load_automation (const string& path)
2504 uint32_t linecnt = 0;
2506 LocaleGuard lg (X_("POSIX"));
2508 fullpath = _session.automation_dir();
2511 in.open (fullpath.c_str());
2514 fullpath = _session.automation_dir();
2515 fullpath += _session.snap_name();
2518 in.open (fullpath.c_str());
2520 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2525 clear_automation ();
2527 while (in.getline (line, sizeof(line), '\n')) {
2529 jack_nframes_t when;
2532 if (++linecnt == 1) {
2533 if (memcmp (line, "version", 7) == 0) {
2534 if (sscanf (line, "version %f", &version) != 1) {
2535 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2539 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2543 if (version != current_automation_version_number) {
2544 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2551 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2552 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2558 _gain_automation_curve.add (when, value, true);
2568 /* older (pre-1.0) versions of ardour used this */
2572 warning << _("dubious automation event found (and ignored)") << endmsg;
2576 _gain_automation_curve.save_state (_("loaded from disk"));
2582 IO::clear_automation ()
2584 LockMonitor lm (automation_lock, __LINE__, __FILE__);
2585 _gain_automation_curve.clear ();
2586 _panner->clear_automation ();
2590 IO::set_gain_automation_state (AutoState state)
2592 bool changed = false;
2595 LockMonitor lm (automation_lock, __LINE__, __FILE__);
2597 if (state != _gain_automation_curve.automation_state()) {
2599 last_automation_snapshot = 0;
2600 _gain_automation_curve.set_automation_state (state);
2603 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2609 _session.set_dirty ();
2610 gain_automation_state_changed (); /* EMIT SIGNAL */
2615 IO::set_gain_automation_style (AutoStyle style)
2617 bool changed = false;
2620 LockMonitor lm (automation_lock, __LINE__, __FILE__);
2622 if (style != _gain_automation_curve.automation_style()) {
2624 _gain_automation_curve.set_automation_style (style);
2629 gain_automation_style_changed (); /* EMIT SIGNAL */
2633 IO::inc_gain (gain_t factor, void *src)
2635 if (_desired_gain == 0.0f)
2636 set_gain (0.000001f + (0.000001f * factor), src);
2638 set_gain (_desired_gain + (_desired_gain * factor), src);
2642 IO::set_gain (gain_t val, void *src)
2644 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2645 if (val>1.99526231f) val=1.99526231f;
2648 LockMonitor dm (declick_lock, __LINE__, __FILE__);
2649 _desired_gain = val;
2652 if (_session.transport_stopped()) {
2653 _effective_gain = val;
2659 if (_session.get_midi_feedback()) {
2660 _midi_gain_control.send_feedback (_desired_gain);
2663 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2664 _gain_automation_curve.add (_session.transport_frame(), val);
2668 _session.set_dirty();
2672 IO::send_all_midi_feedback ()
2674 if (_session.get_midi_feedback()) {
2675 _midi_gain_control.send_feedback (_effective_gain);
2678 _panner->send_all_midi_feedback();
2683 IO::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize)
2685 if (_session.get_midi_feedback()) {
2686 if (gain_automation_playback ()) {
2687 buf = _midi_gain_control.write_feedback (buf, bufsize, _effective_gain);
2689 buf = _panner->write_midi_feedback (buf, bufsize);
2696 IO::start_gain_touch ()
2698 _gain_automation_curve.start_touch ();
2702 IO::end_gain_touch ()
2704 _gain_automation_curve.stop_touch ();
2708 IO::start_pan_touch (uint32_t which)
2710 if (which < _panner->size()) {
2711 (*_panner)[which]->automation().start_touch();
2716 IO::end_pan_touch (uint32_t which)
2718 if (which < _panner->size()) {
2719 (*_panner)[which]->automation().stop_touch();
2725 IO::automation_snapshot (jack_nframes_t now)
2727 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2729 if (gain_automation_recording()) {
2730 _gain_automation_curve.rt_add (now, gain());
2733 _panner->snapshot (now);
2735 last_automation_snapshot = now;
2740 IO::transport_stopped (jack_nframes_t frame)
2742 _gain_automation_curve.reposition_for_rt_add (frame);
2744 if (_gain_automation_curve.automation_state() != Off) {
2746 if (gain_automation_recording()) {
2747 _gain_automation_curve.save_state (_("automation write/touch"));
2750 /* the src=0 condition is a special signal to not propagate
2751 automation gain changes into the mix group when locating.
2754 set_gain (_gain_automation_curve.eval (frame), 0);
2757 _panner->transport_stopped (frame);
2761 IO::find_input_port_hole ()
2763 /* CALLER MUST HOLD IO LOCK */
2767 if (_inputs.empty()) {
2771 for (n = 1; n < UINT_MAX; ++n) {
2772 char buf[jack_port_name_size()];
2773 vector<Port*>::iterator i;
2775 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2777 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2778 if ((*i)->short_name() == buf) {
2783 if (i == _inputs.end()) {
2791 IO::find_output_port_hole ()
2793 /* CALLER MUST HOLD IO LOCK */
2797 if (_outputs.empty()) {
2801 for (n = 1; n < UINT_MAX; ++n) {
2802 char buf[jack_port_name_size()];
2803 vector<Port*>::iterator i;
2805 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2807 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2808 if ((*i)->short_name() == buf) {
2813 if (i == _outputs.end()) {