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;
58 //using namespace sigc;
60 static float current_automation_version_number = 1.0;
62 jack_nframes_t IO::_automation_interval = 0;
63 const string IO::state_node_name = "IO";
64 bool IO::connecting_legal = false;
65 bool IO::ports_legal = false;
66 bool IO::panners_legal = false;
67 sigc::signal<void> IO::Meter;
68 sigc::signal<int> IO::ConnectingLegal;
69 sigc::signal<int> IO::PortsLegal;
70 sigc::signal<int> IO::PannersLegal;
71 sigc::signal<void,uint32_t> IO::MoreOutputs;
72 sigc::signal<int> IO::PortsCreated;
74 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
76 /* this is a default mapper of MIDI control values to a gain coefficient.
77 others can be imagined. see IO::set_midi_to_gain_function().
80 static gain_t direct_midi_to_gain (double fract) {
81 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
82 /* this maxes at +6dB */
83 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
86 static double direct_gain_to_midi (gain_t gain) {
87 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
88 if (gain == 0) return 0.0;
90 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
93 static bool sort_ports_by_name (Port* a, Port* b)
95 return a->name() < b->name();
99 IO::IO (Session& s, string name,
101 int input_min, int input_max, int output_min, int output_max)
104 _midi_gain_control (*this, _session.midi_port()),
105 _gain_automation_curve (0.0, 2.0, 1.0),
106 _input_minimum (input_min),
107 _input_maximum (input_max),
108 _output_minimum (output_min),
109 _output_maximum (output_max)
112 _panner = new Panner (name, _session);
115 _input_connection = 0;
116 _output_connection = 0;
117 pending_state_node = 0;
120 no_panner_reset = false;
123 _midi_gain_control.midi_to_gain = direct_midi_to_gain;
124 _midi_gain_control.gain_to_midi = direct_gain_to_midi;
126 apply_gain_automation = false;
128 last_automation_snapshot = 0;
130 _gain_automation_state = Off;
131 _gain_automation_style = Absolute;
134 // IO::Meter is emitted from another thread so the
135 // Meter signal must be protected.
136 Glib::Mutex::Lock guard (m_meter_signal_lock);
137 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
144 Glib::Mutex::Lock guard (m_meter_signal_lock);
145 Glib::Mutex::Lock lm (io_lock);
146 vector<Port *>::iterator i;
148 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
149 _session.engine().unregister_port (*i);
152 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
153 _session.engine().unregister_port (*i);
156 m_meter_connection.disconnect();
160 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
162 /* io_lock, not taken: function must be called from Session::process() calltree */
164 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
165 (*i)->silence (nframes, offset);
170 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
172 jack_nframes_t declick = min ((jack_nframes_t)4096, nframes);
175 double fractional_shift;
176 double fractional_pos;
177 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
179 if (nframes == 0) return;
181 fractional_shift = -1.0/declick;
183 if (target < initial) {
184 /* fade out: remove more and more of delta from initial */
185 delta = -(initial - target);
187 /* fade in: add more and more of delta from initial */
188 delta = target - initial;
191 for (uint32_t n = 0; n < nbufs; ++n) {
194 fractional_pos = 1.0;
196 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
197 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
198 fractional_pos += fractional_shift;
201 /* now ensure the rest of the buffer has the target value
202 applied, if necessary.
205 if (declick != nframes) {
207 if (invert_polarity) {
212 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
213 } else if (target != 1.0) {
214 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
215 buffer[nx] *= target;
223 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)
227 /* io_lock, not taken: function must be called from Session::process() calltree */
229 if (_noutputs == 0) {
233 if (_noutputs == 1) {
235 dst = output(0)->get_buffer (nframes) + offset;
237 for (uint32_t n = 0; n < nbufs; ++n) {
238 if (bufs[n] != dst) {
239 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
243 output(0)->mark_silence (false);
249 vector<Port *>::iterator out;
250 vector<Sample *>::iterator in;
251 Panner::iterator pan;
252 Sample* obufs[_noutputs];
254 /* the terrible silence ... */
256 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
257 obufs[o] = (*out)->get_buffer (nframes) + offset;
258 memset (obufs[o], 0, sizeof (Sample) * nframes);
259 (*out)->mark_silence (false);
264 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
265 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
270 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
275 /* io_lock, not taken: function must be called from Session::process() calltree */
277 if (_noutputs == 0) {
281 /* the panner can be empty if there are no inputs to the
282 route, but still outputs
285 if (_panner->bypassed() || _panner->empty()) {
286 deliver_output_no_pan (bufs, nbufs, nframes, offset);
290 if (_noutputs == 1) {
292 dst = output(0)->get_buffer (nframes) + offset;
294 if (gain_coeff == 0.0f) {
296 /* only one output, and gain was zero, so make it silent */
298 memset (dst, 0, sizeof (Sample) * nframes);
300 } else if (gain_coeff == 1.0f){
302 /* mix all buffers into the output */
306 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
308 for (n = 1; n < nbufs; ++n) {
311 for (jack_nframes_t n = 0; n < nframes; ++n) {
316 output(0)->mark_silence (false);
320 /* mix all buffers into the output, scaling them all by the gain */
326 for (jack_nframes_t n = 0; n < nframes; ++n) {
327 dst[n] = src[n] * gain_coeff;
330 for (n = 1; n < nbufs; ++n) {
333 for (jack_nframes_t n = 0; n < nframes; ++n) {
334 dst[n] += src[n] * gain_coeff;
338 output(0)->mark_silence (false);
345 vector<Port *>::iterator out;
346 vector<Sample *>::iterator in;
347 Panner::iterator pan;
348 Sample* obufs[_noutputs];
350 /* the terrible silence ... */
352 /* XXX this is wasteful but i see no way to avoid it */
354 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
355 obufs[o] = (*out)->get_buffer (nframes) + offset;
356 memset (obufs[o], 0, sizeof (Sample) * nframes);
357 (*out)->mark_silence (false);
362 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
363 Panner::iterator tmp;
368 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
370 if (tmp != _panner->end()) {
377 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
379 /* io_lock, not taken: function must be called from Session::process() calltree */
381 if (_noutputs == 0) {
385 if (_panner->bypassed() || _panner->empty()) {
386 deliver_output_no_pan (bufs, nbufs, nframes, offset);
392 gain_t pangain = _gain;
395 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
405 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
410 /* simple, non-automation panning to outputs */
412 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
413 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
415 pan (bufs, nbufs, nframes, offset, pangain);
420 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
422 /* io_lock, not taken: function must be called from Session::process() calltree */
424 if (_noutputs == 0) {
429 gain_t old_gain = _gain;
431 if (apply_gain_automation) {
433 /* gain has already been applied by automation code. do nothing here except
442 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
454 vector<Port*>::iterator o;
455 vector<Sample*> outs;
459 /* unlikely condition */
460 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
461 outs.push_back ((*o)->get_buffer (nframes) + offset);
465 /* reduce nbufs to the index of the last input buffer */
469 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
470 actual_gain = _gain * speed_quietning;
475 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
477 dst = (*o)->get_buffer (nframes) + offset;
478 src = bufs[min(nbufs,i)];
480 if (dg != _gain || actual_gain == 1.0f) {
481 memcpy (dst, src, sizeof (Sample) * nframes);
482 } else if (actual_gain == 0.0f) {
483 memset (dst, 0, sizeof (Sample) * nframes);
485 for (jack_nframes_t x = 0; x < nframes; ++x) {
486 dst[x] = src[x] * actual_gain;
490 (*o)->mark_silence (false);
494 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
498 if (apply_gain_automation) {
504 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
506 /* io_lock, not taken: function must be called from Session::process() calltree */
508 vector<Port *>::iterator i;
512 /* we require that bufs.size() >= 1 */
514 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
515 if (i == _inputs.end()) {
519 /* XXX always read the full extent of the port buffer that
520 we need. One day, we may use jack_port_get_buffer_at_offset()
521 or something similar. For now, this simple hack will
524 Hack? Why yes .. we only need to read nframes-worth of
525 data, but the data we want is at `offset' within the
529 last = (*i)->get_buffer (nframes+offset) + offset;
530 // the dest buffer's offset has already been applied
531 memcpy (bufs[n], last, sizeof (Sample) * nframes);
534 /* fill any excess outputs with the last input */
536 while (n < nbufs && last) {
537 // the dest buffer's offset has already been applied
538 memcpy (bufs[n], last, sizeof (Sample) * nframes);
544 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
545 jack_nframes_t nframes, jack_nframes_t offset)
547 vector<Sample*>& bufs = _session.get_passthru_buffers ();
548 uint32_t nbufs = n_process_buffers ();
550 collect_input (bufs, nbufs, nframes, offset);
552 for (uint32_t n = 0; n < nbufs; ++n) {
553 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
558 IO::drop_input_connection ()
560 _input_connection = 0;
561 input_connection_configuration_connection.disconnect();
562 input_connection_connection_connection.disconnect();
563 _session.set_dirty ();
567 IO::drop_output_connection ()
569 _output_connection = 0;
570 output_connection_configuration_connection.disconnect();
571 output_connection_connection_connection.disconnect();
572 _session.set_dirty ();
576 IO::disconnect_input (Port* our_port, string other_port, void* src)
578 if (other_port.length() == 0 || our_port == 0) {
583 Glib::Mutex::Lock em (_session.engine().process_lock());
586 Glib::Mutex::Lock lm (io_lock);
588 /* check that our_port is really one of ours */
590 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
594 /* disconnect it from the source */
596 if (_session.engine().disconnect (other_port, our_port->name())) {
597 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
601 drop_input_connection();
605 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
606 _session.set_dirty ();
612 IO::connect_input (Port* our_port, string other_port, void* src)
614 if (other_port.length() == 0 || our_port == 0) {
619 Glib::Mutex::Lock em(_session.engine().process_lock());
622 Glib::Mutex::Lock lm (io_lock);
624 /* check that our_port is really one of ours */
626 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
630 /* connect it to the source */
632 if (_session.engine().connect (other_port, our_port->name())) {
636 drop_input_connection ();
640 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
641 _session.set_dirty ();
646 IO::disconnect_output (Port* our_port, string other_port, void* src)
648 if (other_port.length() == 0 || our_port == 0) {
653 Glib::Mutex::Lock em(_session.engine().process_lock());
656 Glib::Mutex::Lock lm (io_lock);
658 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
662 /* disconnect it from the destination */
664 if (_session.engine().disconnect (our_port->name(), other_port)) {
665 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
669 drop_output_connection ();
673 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
674 _session.set_dirty ();
679 IO::connect_output (Port* our_port, string other_port, void* src)
681 if (other_port.length() == 0 || our_port == 0) {
686 Glib::Mutex::Lock em(_session.engine().process_lock());
689 Glib::Mutex::Lock lm (io_lock);
691 /* check that our_port is really one of ours */
693 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
697 /* connect it to the destination */
699 if (_session.engine().connect (our_port->name(), other_port)) {
703 drop_output_connection ();
707 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
708 _session.set_dirty ();
713 IO::set_input (Port* other_port, void* src)
715 /* this removes all but one ports, and connects that one port
716 to the specified source.
719 if (_input_minimum > 1 || _input_minimum == 0) {
720 /* sorry, you can't do this */
724 if (other_port == 0) {
725 if (_input_minimum < 0) {
726 return ensure_inputs (0, false, true, src);
732 if (ensure_inputs (1, true, true, src)) {
736 return connect_input (_inputs.front(), other_port->name(), src);
740 IO::remove_output_port (Port* port, void* src)
742 IOChange change (NoChange);
745 Glib::Mutex::Lock em(_session.engine().process_lock());
748 Glib::Mutex::Lock lm (io_lock);
750 if (_noutputs - 1 == (uint32_t) _output_minimum) {
751 /* sorry, you can't do this */
755 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
757 change = IOChange (change|ConfigurationChanged);
758 if (port->connected()) {
759 change = IOChange (change|ConnectionsChanged);
762 _session.engine().unregister_port (*i);
765 drop_output_connection ();
771 if (change != NoChange) {
772 setup_peak_meters ();
778 if (change != NoChange) {
779 output_changed (change, src); /* EMIT SIGNAL */
780 _session.set_dirty ();
788 IO::add_output_port (string destination, void* src)
794 Glib::Mutex::Lock em(_session.engine().process_lock());
797 Glib::Mutex::Lock lm (io_lock);
799 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
803 /* Create a new output port */
805 if (_output_maximum == 1) {
806 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
808 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
811 if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) {
812 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
816 _outputs.push_back (our_port);
817 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
819 drop_output_connection ();
820 setup_peak_meters ();
824 MoreOutputs (_noutputs); /* EMIT SIGNAL */
827 if (destination.length()) {
828 if (_session.engine().connect (our_port->name(), destination)) {
833 // pan_changed (src); /* EMIT SIGNAL */
834 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
835 _session.set_dirty ();
840 IO::remove_input_port (Port* port, void* src)
842 IOChange change (NoChange);
845 Glib::Mutex::Lock em(_session.engine().process_lock());
848 Glib::Mutex::Lock lm (io_lock);
850 if (((int)_ninputs - 1) < _input_minimum) {
851 /* sorry, you can't do this */
854 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
857 change = IOChange (change|ConfigurationChanged);
859 if (port->connected()) {
860 change = IOChange (change|ConnectionsChanged);
863 _session.engine().unregister_port (*i);
866 drop_input_connection ();
872 if (change != NoChange) {
873 setup_peak_meters ();
879 if (change != NoChange) {
880 input_changed (change, src);
881 _session.set_dirty ();
889 IO::add_input_port (string source, void* src)
895 Glib::Mutex::Lock em (_session.engine().process_lock());
898 Glib::Mutex::Lock lm (io_lock);
900 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
904 /* Create a new input port */
906 if (_input_maximum == 1) {
907 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
909 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
912 if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) {
913 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
917 _inputs.push_back (our_port);
918 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
920 drop_input_connection ();
921 setup_peak_meters ();
925 MoreOutputs (_ninputs); /* EMIT SIGNAL */
928 if (source.length()) {
930 if (_session.engine().connect (source, our_port->name())) {
935 // pan_changed (src); /* EMIT SIGNAL */
936 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
937 _session.set_dirty ();
943 IO::disconnect_inputs (void* src)
946 Glib::Mutex::Lock em (_session.engine().process_lock());
949 Glib::Mutex::Lock lm (io_lock);
951 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
952 _session.engine().disconnect (*i);
955 drop_input_connection ();
958 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
963 IO::disconnect_outputs (void* src)
966 Glib::Mutex::Lock em (_session.engine().process_lock());
969 Glib::Mutex::Lock lm (io_lock);
971 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
972 _session.engine().disconnect (*i);
975 drop_output_connection ();
979 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
980 _session.set_dirty ();
985 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
988 bool changed = false;
989 bool reduced = false;
991 /* remove unused ports */
993 while (_ninputs > n) {
994 _session.engine().unregister_port (_inputs.back());
1001 /* create any necessary new ports */
1003 while (_ninputs < n) {
1007 /* Create a new input port */
1009 if (_input_maximum == 1) {
1010 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1013 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1018 if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) {
1019 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1024 catch (AudioEngine::PortRegistrationFailure& err) {
1025 setup_peak_meters ();
1031 _inputs.push_back (input_port);
1032 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1038 drop_input_connection ();
1039 setup_peak_meters ();
1041 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1042 _session.set_dirty ();
1046 /* disconnect all existing ports so that we get a fresh start */
1048 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1049 _session.engine().disconnect (*i);
1057 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1059 bool in_changed = false;
1060 bool out_changed = false;
1061 bool in_reduced = false;
1062 bool out_reduced = false;
1063 bool need_pan_reset;
1065 if (_input_maximum >= 0) {
1066 nin = min (_input_maximum, (int) nin);
1069 if (_output_maximum >= 0) {
1070 nout = min (_output_maximum, (int) nout);
1073 if (nin == _ninputs && nout == _noutputs && !clear) {
1078 Glib::Mutex::Lock em (_session.engine().process_lock());
1079 Glib::Mutex::Lock lm (io_lock);
1083 if (_noutputs == nout) {
1084 need_pan_reset = false;
1086 need_pan_reset = true;
1089 /* remove unused ports */
1091 while (_ninputs > nin) {
1092 _session.engine().unregister_port (_inputs.back());
1099 while (_noutputs > nout) {
1100 _session.engine().unregister_port (_outputs.back());
1101 _outputs.pop_back();
1107 /* create any necessary new ports */
1109 while (_ninputs < nin) {
1113 /* Create a new input port */
1115 if (_input_maximum == 1) {
1116 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1119 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1123 if ((port = _session.engine().register_audio_input_port (buf)) == 0) {
1124 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1129 catch (AudioEngine::PortRegistrationFailure& err) {
1130 setup_peak_meters ();
1136 _inputs.push_back (port);
1141 /* create any necessary new ports */
1143 while (_noutputs < nout) {
1147 /* Create a new output port */
1149 if (_output_maximum == 1) {
1150 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1152 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1156 if ((port = _session.engine().register_audio_output_port (buf)) == 0) {
1157 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1162 catch (AudioEngine::PortRegistrationFailure& err) {
1163 setup_peak_meters ();
1169 _outputs.push_back (port);
1176 /* disconnect all existing ports so that we get a fresh start */
1178 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1179 _session.engine().disconnect (*i);
1182 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1183 _session.engine().disconnect (*i);
1187 if (in_changed || out_changed) {
1188 setup_peak_meters ();
1194 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1195 drop_output_connection ();
1196 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1200 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1201 drop_input_connection ();
1202 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1205 if (in_changed || out_changed) {
1206 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1207 _session.set_dirty ();
1214 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1216 bool changed = false;
1218 if (_input_maximum >= 0) {
1219 n = min (_input_maximum, (int) n);
1221 if (n == _ninputs && !clear) {
1227 Glib::Mutex::Lock em (_session.engine().process_lock());
1228 Glib::Mutex::Lock im (io_lock);
1229 changed = ensure_inputs_locked (n, clear, src);
1231 changed = ensure_inputs_locked (n, clear, src);
1235 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1236 _session.set_dirty ();
1243 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1246 bool changed = false;
1247 bool reduced = false;
1248 bool need_pan_reset;
1250 if (_noutputs == n) {
1251 need_pan_reset = false;
1253 need_pan_reset = true;
1256 /* remove unused ports */
1258 while (_noutputs > n) {
1260 _session.engine().unregister_port (_outputs.back());
1261 _outputs.pop_back();
1267 /* create any necessary new ports */
1269 while (_noutputs < n) {
1273 /* Create a new output port */
1275 if (_output_maximum == 1) {
1276 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1278 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1281 if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) {
1282 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1286 _outputs.push_back (output_port);
1287 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1290 setup_peak_meters ();
1292 if (need_pan_reset) {
1298 drop_output_connection ();
1299 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1300 _session.set_dirty ();
1304 /* disconnect all existing ports so that we get a fresh start */
1306 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1307 _session.engine().disconnect (*i);
1315 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1317 bool changed = false;
1319 if (_output_maximum >= 0) {
1320 n = min (_output_maximum, (int) n);
1321 if (n == _noutputs && !clear) {
1326 /* XXX caller should hold io_lock, but generally doesn't */
1329 Glib::Mutex::Lock em (_session.engine().process_lock());
1330 Glib::Mutex::Lock im (io_lock);
1331 changed = ensure_outputs_locked (n, clear, src);
1333 changed = ensure_outputs_locked (n, clear, src);
1337 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1344 IO::effective_gain () const
1346 if (gain_automation_playback()) {
1347 return _effective_gain;
1349 return _desired_gain;
1356 if (panners_legal) {
1357 if (!no_panner_reset) {
1358 _panner->reset (_noutputs, pans_required());
1361 panner_legal_c.disconnect ();
1362 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1367 IO::panners_became_legal ()
1369 _panner->reset (_noutputs, pans_required());
1370 _panner->load (); // automation
1371 panner_legal_c.disconnect ();
1376 IO::defer_pan_reset ()
1378 no_panner_reset = true;
1382 IO::allow_pan_reset ()
1384 no_panner_reset = false;
1390 IO::get_state (void)
1392 return state (true);
1396 IO::state (bool full_state)
1398 XMLNode* node = new XMLNode (state_node_name);
1401 bool need_ins = true;
1402 bool need_outs = true;
1403 LocaleGuard lg (X_("POSIX"));
1404 Glib::Mutex::Lock lm (io_lock);
1406 node->add_property("name", _name);
1407 snprintf (buf, sizeof(buf), "%" PRIu64, id());
1408 node->add_property("id", buf);
1412 if (_input_connection) {
1413 node->add_property ("input-connection", _input_connection->name());
1417 if (_output_connection) {
1418 node->add_property ("output-connection", _output_connection->name());
1423 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1425 const char **connections = (*i)->get_connections();
1427 if (connections && connections[0]) {
1430 for (int n = 0; connections && connections[n]; ++n) {
1435 /* if its a connection to our own port,
1436 return only the port name, not the
1437 whole thing. this allows connections
1438 to be re-established even when our
1439 client name is different.
1442 str += _session.engine().make_port_name_relative (connections[n]);
1454 node->add_property ("inputs", str);
1460 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1462 const char **connections = (*i)->get_connections();
1464 if (connections && connections[0]) {
1468 for (int n = 0; connections[n]; ++n) {
1473 str += _session.engine().make_port_name_relative (connections[n]);
1485 node->add_property ("outputs", str);
1488 node->add_child_nocopy (_panner->state (full_state));
1490 snprintf (buf, sizeof(buf), "%2.12f", gain());
1491 node->add_property ("gain", buf);
1493 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1499 node->add_property ("iolimits", buf);
1503 MIDI::channel_t chn;
1505 MIDI::byte additional;
1506 XMLNode* midi_node = 0;
1509 if (_midi_gain_control.get_control_info (chn, ev, additional)) {
1511 midi_node = node->add_child ("MIDI");
1513 child = midi_node->add_child ("gain");
1514 set_midi_node_info (child, ev, chn, additional);
1520 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1522 /* never store anything except Off for automation state in a template */
1523 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1525 node->add_property ("automation-state", buf);
1526 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1527 node->add_property ("automation-style", buf);
1529 /* XXX same for pan etc. */
1535 IO::connecting_became_legal ()
1539 if (pending_state_node == 0) {
1540 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1545 connection_legal_c.disconnect ();
1547 ret = make_connections (*pending_state_node);
1550 delete pending_state_node;
1551 pending_state_node = 0;
1558 IO::ports_became_legal ()
1562 if (pending_state_node == 0) {
1563 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1568 port_legal_c.disconnect ();
1570 ret = create_ports (*pending_state_node);
1572 if (connecting_legal) {
1573 delete pending_state_node;
1574 pending_state_node = 0;
1581 IO::set_state (const XMLNode& node)
1583 const XMLProperty* prop;
1584 XMLNodeConstIterator iter;
1585 XMLNodeList midi_kids;
1586 LocaleGuard lg (X_("POSIX"));
1588 /* force use of non-localized representation of decimal point,
1589 since we use it a lot in XML files and so forth.
1592 if (node.name() != state_node_name) {
1593 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1597 if ((prop = node.property ("name")) != 0) {
1598 _name = prop->value();
1599 _panner->set_name (_name);
1602 if ((prop = node.property ("id")) != 0) {
1603 sscanf (prop->value().c_str(), "%" PRIu64, &_id);
1606 if ((prop = node.property ("iolimits")) != 0) {
1607 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1614 if ((prop = node.property ("gain")) != 0) {
1615 set_gain (atof (prop->value().c_str()), this);
1616 _gain = _desired_gain;
1619 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1620 if ((*iter)->name() == "Panner") {
1621 _panner->set_state (**iter);
1625 midi_kids = node.children ("MIDI");
1627 for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) {
1630 XMLNodeConstIterator miter;
1633 kids = (*iter)->children ();
1635 for (miter = kids.begin(); miter != kids.end(); ++miter) {
1639 if (child->name() == "gain") {
1641 MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */
1642 MIDI::byte additional = 0; /* ditto */
1643 MIDI::channel_t chn = 0; /* ditto */
1645 if (get_midi_node_info (child, ev, chn, additional)) {
1646 _midi_gain_control.set_control_type (chn, ev, additional);
1648 error << string_compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
1654 if ((prop = node.property ("automation-state")) != 0) {
1657 x = strtol (prop->value().c_str(), 0, 16);
1658 set_gain_automation_state (AutoState (x));
1661 if ((prop = node.property ("automation-style")) != 0) {
1664 x = strtol (prop->value().c_str(), 0, 16);
1665 set_gain_automation_style (AutoStyle (x));
1670 if (create_ports (node)) {
1676 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1679 if (panners_legal) {
1682 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1685 if (connecting_legal) {
1687 if (make_connections (node)) {
1693 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1696 if (!ports_legal || !connecting_legal) {
1697 pending_state_node = new XMLNode (node);
1704 IO::create_ports (const XMLNode& node)
1706 const XMLProperty* prop;
1708 int num_outputs = 0;
1710 if ((prop = node.property ("input-connection")) != 0) {
1712 Connection* c = _session.connection_by_name (prop->value());
1715 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1717 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1718 error << _("No input connections available as a replacement")
1722 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1727 num_inputs = c->nports();
1729 } else if ((prop = node.property ("inputs")) != 0) {
1731 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1734 if ((prop = node.property ("output-connection")) != 0) {
1735 Connection* c = _session.connection_by_name (prop->value());
1738 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1740 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1741 error << _("No output connections available as a replacement")
1745 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1750 num_outputs = c->nports ();
1752 } else if ((prop = node.property ("outputs")) != 0) {
1753 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1756 no_panner_reset = true;
1758 if (ensure_io (num_inputs, num_outputs, true, this)) {
1759 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1763 no_panner_reset = false;
1765 set_deferred_state ();
1772 IO::get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional)
1775 const XMLProperty* prop;
1778 if ((prop = node->property ("event")) != 0) {
1779 sscanf (prop->value().c_str(), "0x%x", &xx);
1780 ev = (MIDI::eventType) xx;
1785 if (ok && ((prop = node->property ("channel")) != 0)) {
1786 sscanf (prop->value().c_str(), "%d", &xx);
1787 chan = (MIDI::channel_t) xx;
1792 if (ok && ((prop = node->property ("additional")) != 0)) {
1793 sscanf (prop->value().c_str(), "0x%x", &xx);
1794 additional = (MIDI::byte) xx;
1801 IO::set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional)
1805 snprintf (buf, sizeof(buf), "0x%x", ev);
1806 node->add_property ("event", buf);
1807 snprintf (buf, sizeof(buf), "%d", chan);
1808 node->add_property ("channel", buf);
1809 snprintf (buf, sizeof(buf), "0x%x", additional);
1810 node->add_property ("additional", buf);
1817 IO::make_connections (const XMLNode& node)
1819 const XMLProperty* prop;
1821 if ((prop = node.property ("input-connection")) != 0) {
1822 Connection* c = _session.connection_by_name (prop->value());
1825 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1827 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1828 error << _("No input connections available as a replacement")
1832 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1837 use_input_connection (*c, this);
1839 } else if ((prop = node.property ("inputs")) != 0) {
1840 if (set_inputs (prop->value())) {
1841 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1846 if ((prop = node.property ("output-connection")) != 0) {
1847 Connection* c = _session.connection_by_name (prop->value());
1850 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1852 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1853 error << _("No output connections available as a replacement")
1857 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1862 use_output_connection (*c, this);
1864 } else if ((prop = node.property ("outputs")) != 0) {
1865 if (set_outputs (prop->value())) {
1866 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1875 IO::set_inputs (const string& str)
1877 vector<string> ports;
1882 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1886 if (ensure_inputs (nports, true, true, this)) {
1890 string::size_type start, end, ostart;
1897 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1900 if ((end = str.find_first_of ('}', start)) == string::npos) {
1901 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1905 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1906 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1912 for (int x = 0; x < n; ++x) {
1913 connect_input (input (i), ports[x], this);
1925 IO::set_outputs (const string& str)
1927 vector<string> ports;
1932 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1936 if (ensure_outputs (nports, true, true, this)) {
1940 string::size_type start, end, ostart;
1947 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1950 if ((end = str.find_first_of ('}', start)) == string::npos) {
1951 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1955 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1956 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1962 for (int x = 0; x < n; ++x) {
1963 connect_output (output (i), ports[x], this);
1975 IO::parse_io_string (const string& str, vector<string>& ports)
1977 string::size_type pos, opos;
1979 if (str.length() == 0) {
1988 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1989 ports.push_back (str.substr (opos, pos - opos));
1993 if (opos < str.length()) {
1994 ports.push_back (str.substr(opos));
1997 return ports.size();
2001 IO::parse_gain_string (const string& str, vector<string>& ports)
2003 string::size_type pos, opos;
2009 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2010 ports.push_back (str.substr (opos, pos - opos));
2014 if (opos < str.length()) {
2015 ports.push_back (str.substr(opos));
2018 return ports.size();
2022 IO::set_name (string name, void* src)
2024 if (name == _name) {
2028 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2029 string current_name = (*i)->short_name();
2030 current_name.replace (current_name.find (_name), _name.length(), name);
2031 (*i)->set_name (current_name);
2034 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2035 string current_name = (*i)->short_name();
2036 current_name.replace (current_name.find (_name), _name.length(), name);
2037 (*i)->set_name (current_name);
2041 name_changed (src); /* EMIT SIGNAL */
2047 IO::set_input_minimum (int n)
2053 IO::set_input_maximum (int n)
2059 IO::set_output_minimum (int n)
2061 _output_minimum = n;
2065 IO::set_output_maximum (int n)
2067 _output_maximum = n;
2071 IO::set_port_latency (jack_nframes_t nframes)
2073 Glib::Mutex::Lock lm (io_lock);
2075 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2076 (*i)->set_latency (nframes);
2081 IO::output_latency () const
2083 jack_nframes_t max_latency;
2084 jack_nframes_t latency;
2088 /* io lock not taken - must be protected by other means */
2090 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2091 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2092 max_latency = latency;
2100 IO::input_latency () const
2102 jack_nframes_t max_latency;
2103 jack_nframes_t latency;
2107 /* io lock not taken - must be protected by other means */
2109 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2110 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2111 max_latency = latency;
2119 IO::use_input_connection (Connection& c, void* src)
2124 Glib::Mutex::Lock lm (_session.engine().process_lock());
2125 Glib::Mutex::Lock lm2 (io_lock);
2129 drop_input_connection ();
2131 if (ensure_inputs (limit, false, false, src)) {
2135 /* first pass: check the current state to see what's correctly
2136 connected, and drop anything that we don't want.
2139 for (uint32_t n = 0; n < limit; ++n) {
2140 const Connection::PortList& pl = c.port_connections (n);
2142 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2144 if (!_inputs[n]->connected_to ((*i))) {
2146 /* clear any existing connections */
2148 _session.engine().disconnect (_inputs[n]);
2150 } else if (_inputs[n]->connected() > 1) {
2152 /* OK, it is connected to the port we want,
2153 but its also connected to other ports.
2154 Change that situation.
2157 /* XXX could be optimized to not drop
2161 _session.engine().disconnect (_inputs[n]);
2167 /* second pass: connect all requested ports where necessary */
2169 for (uint32_t n = 0; n < limit; ++n) {
2170 const Connection::PortList& pl = c.port_connections (n);
2172 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2174 if (!_inputs[n]->connected_to ((*i))) {
2176 if (_session.engine().connect (*i, _inputs[n]->name())) {
2184 _input_connection = &c;
2186 input_connection_configuration_connection = c.ConfigurationChanged.connect
2187 (mem_fun (*this, &IO::input_connection_configuration_changed));
2188 input_connection_connection_connection = c.ConnectionsChanged.connect
2189 (mem_fun (*this, &IO::input_connection_connection_changed));
2192 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2197 IO::use_output_connection (Connection& c, void* src)
2202 Glib::Mutex::Lock lm (_session.engine().process_lock());
2203 Glib::Mutex::Lock lm2 (io_lock);
2207 drop_output_connection ();
2209 if (ensure_outputs (limit, false, false, src)) {
2213 /* first pass: check the current state to see what's correctly
2214 connected, and drop anything that we don't want.
2217 for (uint32_t n = 0; n < limit; ++n) {
2219 const Connection::PortList& pl = c.port_connections (n);
2221 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2223 if (!_outputs[n]->connected_to ((*i))) {
2225 /* clear any existing connections */
2227 _session.engine().disconnect (_outputs[n]);
2229 } else if (_outputs[n]->connected() > 1) {
2231 /* OK, it is connected to the port we want,
2232 but its also connected to other ports.
2233 Change that situation.
2236 /* XXX could be optimized to not drop
2240 _session.engine().disconnect (_outputs[n]);
2245 /* second pass: connect all requested ports where necessary */
2247 for (uint32_t n = 0; n < limit; ++n) {
2249 const Connection::PortList& pl = c.port_connections (n);
2251 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2253 if (!_outputs[n]->connected_to ((*i))) {
2255 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2262 _output_connection = &c;
2264 output_connection_configuration_connection = c.ConfigurationChanged.connect
2265 (mem_fun (*this, &IO::output_connection_configuration_changed));
2266 output_connection_connection_connection = c.ConnectionsChanged.connect
2267 (mem_fun (*this, &IO::output_connection_connection_changed));
2270 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2276 IO::disable_connecting ()
2278 connecting_legal = false;
2283 IO::enable_connecting ()
2285 connecting_legal = true;
2286 return ConnectingLegal ();
2290 IO::disable_ports ()
2292 ports_legal = false;
2300 return PortsLegal ();
2304 IO::disable_panners (void)
2306 panners_legal = false;
2311 IO::reset_panners ()
2313 panners_legal = true;
2314 return PannersLegal ();
2318 IO::input_connection_connection_changed (int ignored)
2320 use_input_connection (*_input_connection, this);
2324 IO::input_connection_configuration_changed ()
2326 use_input_connection (*_input_connection, this);
2330 IO::output_connection_connection_changed (int ignored)
2332 use_output_connection (*_output_connection, this);
2336 IO::output_connection_configuration_changed ()
2338 use_output_connection (*_output_connection, this);
2341 IO::MIDIGainControl::MIDIGainControl (IO& i, MIDI::Port* port)
2342 : MIDI::Controllable (port, 0), io (i), setting(false)
2347 last_written = 0; /* XXX need a good out-of-bound-value */
2351 IO::MIDIGainControl::set_value (float val)
2353 if (midi_to_gain == 0) return;
2356 io.set_gain (midi_to_gain (val), this);
2361 IO::MIDIGainControl::send_feedback (gain_t gain)
2363 if (!setting && get_midi_feedback() && gain_to_midi) {
2364 MIDI::byte val = (MIDI::byte) (gain_to_midi (gain) * 127.0);
2365 MIDI::channel_t ch = 0;
2366 MIDI::eventType ev = MIDI::none;
2367 MIDI::byte additional = 0;
2368 MIDI::EventTwoBytes data;
2370 if (get_control_info (ch, ev, additional)) {
2371 data.controller_number = additional;
2375 io._session.send_midi_message (get_port(), ev, ch, data);
2377 //send_midi_feedback (gain_to_midi (gain));
2382 IO::MIDIGainControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force)
2384 if (get_midi_feedback() && gain_to_midi && bufsize > 2) {
2385 MIDI::channel_t ch = 0;
2386 MIDI::eventType ev = MIDI::none;
2387 MIDI::byte additional = 0;
2390 if (get_control_info (ch, ev, additional)) {
2391 gm = (MIDI::byte) (gain_to_midi (val) * 127.0);
2393 if (gm != last_written) {
2394 *buf++ = (0xF0 & ev) | (0xF & ch);
2395 *buf++ = additional; /* controller number */
2407 IO::reset_peak_meters ()
2409 uint32_t limit = max (_ninputs, _noutputs);
2411 for (uint32_t i = 0; i < limit; ++i) {
2417 IO::setup_peak_meters ()
2419 uint32_t limit = max (_ninputs, _noutputs);
2421 while (_peak_power.size() < limit) {
2422 _peak_power.push_back (0);
2423 _visible_peak_power.push_back (0);
2428 IO::get_memento() const
2430 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2434 IO::restore_state (StateManager::State& state)
2439 StateManager::State*
2440 IO::state_factory (std::string why) const
2442 StateManager::State* state = new StateManager::State (why);
2447 Update the peak meters.
2449 The meter signal lock is taken to prevent modification of the
2450 Meter signal while updating the meters, taking the meter signal
2451 lock prior to taking the io_lock ensures that all IO will remain
2452 valid while metering.
2457 Glib::Mutex::Lock guard (m_meter_signal_lock);
2465 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2466 uint32_t limit = max (_ninputs, _noutputs);
2468 for (uint32_t n = 0; n < limit; ++n) {
2470 /* XXX we should use atomic exchange here */
2472 /* grab peak since last read */
2474 float new_peak = _peak_power[n];
2477 /* compute new visible value using falloff */
2479 if (new_peak > 0.0) {
2480 new_peak = coefficient_to_dB (new_peak);
2482 new_peak = minus_infinity();
2485 if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2486 _visible_peak_power[n] = new_peak;
2489 new_peak = _visible_peak_power[n] - _session.meter_falloff();
2490 _visible_peak_power[n] = max (new_peak, -INFINITY);
2496 IO::reset_midi_control (MIDI::Port* port, bool on)
2498 MIDI::channel_t chn;
2502 _midi_gain_control.get_control_info (chn, ev, extra);
2506 _midi_gain_control.midi_rebind (port, chn);
2508 _panner->reset_midi_control (port, on);
2513 IO::save_automation (const string& path)
2518 fullpath = _session.automation_dir();
2521 out.open (fullpath.c_str());
2524 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2528 out << X_("version ") << current_automation_version_number << endl;
2530 /* XXX use apply_to_points to get thread safety */
2532 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2533 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2542 IO::load_automation (const string& path)
2547 uint32_t linecnt = 0;
2549 LocaleGuard lg (X_("POSIX"));
2551 fullpath = _session.automation_dir();
2554 in.open (fullpath.c_str());
2557 fullpath = _session.automation_dir();
2558 fullpath += _session.snap_name();
2561 in.open (fullpath.c_str());
2563 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2568 clear_automation ();
2570 while (in.getline (line, sizeof(line), '\n')) {
2572 jack_nframes_t when;
2575 if (++linecnt == 1) {
2576 if (memcmp (line, "version", 7) == 0) {
2577 if (sscanf (line, "version %f", &version) != 1) {
2578 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2582 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2586 if (version != current_automation_version_number) {
2587 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2594 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2595 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2601 _gain_automation_curve.add (when, value, true);
2611 /* older (pre-1.0) versions of ardour used this */
2615 warning << _("dubious automation event found (and ignored)") << endmsg;
2619 _gain_automation_curve.save_state (_("loaded from disk"));
2625 IO::clear_automation ()
2627 Glib::Mutex::Lock lm (automation_lock);
2628 _gain_automation_curve.clear ();
2629 _panner->clear_automation ();
2633 IO::set_gain_automation_state (AutoState state)
2635 bool changed = false;
2638 Glib::Mutex::Lock lm (automation_lock);
2640 if (state != _gain_automation_curve.automation_state()) {
2642 last_automation_snapshot = 0;
2643 _gain_automation_curve.set_automation_state (state);
2646 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2652 _session.set_dirty ();
2653 gain_automation_state_changed (); /* EMIT SIGNAL */
2658 IO::set_gain_automation_style (AutoStyle style)
2660 bool changed = false;
2663 Glib::Mutex::Lock lm (automation_lock);
2665 if (style != _gain_automation_curve.automation_style()) {
2667 _gain_automation_curve.set_automation_style (style);
2672 gain_automation_style_changed (); /* EMIT SIGNAL */
2676 IO::inc_gain (gain_t factor, void *src)
2678 if (_desired_gain == 0.0f)
2679 set_gain (0.000001f + (0.000001f * factor), src);
2681 set_gain (_desired_gain + (_desired_gain * factor), src);
2685 IO::set_gain (gain_t val, void *src)
2687 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2688 if (val>1.99526231f) val=1.99526231f;
2691 Glib::Mutex::Lock dm (declick_lock);
2692 _desired_gain = val;
2695 if (_session.transport_stopped()) {
2696 _effective_gain = val;
2702 if (_session.get_midi_feedback()) {
2703 _midi_gain_control.send_feedback (_desired_gain);
2706 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2707 _gain_automation_curve.add (_session.transport_frame(), val);
2711 _session.set_dirty();
2715 IO::send_all_midi_feedback ()
2717 if (_session.get_midi_feedback()) {
2718 _midi_gain_control.send_feedback (_effective_gain);
2721 _panner->send_all_midi_feedback();
2726 IO::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize)
2728 if (_session.get_midi_feedback()) {
2729 if (gain_automation_playback ()) {
2730 buf = _midi_gain_control.write_feedback (buf, bufsize, _effective_gain);
2732 buf = _panner->write_midi_feedback (buf, bufsize);
2739 IO::start_gain_touch ()
2741 _gain_automation_curve.start_touch ();
2745 IO::end_gain_touch ()
2747 _gain_automation_curve.stop_touch ();
2751 IO::start_pan_touch (uint32_t which)
2753 if (which < _panner->size()) {
2754 (*_panner)[which]->automation().start_touch();
2759 IO::end_pan_touch (uint32_t which)
2761 if (which < _panner->size()) {
2762 (*_panner)[which]->automation().stop_touch();
2768 IO::automation_snapshot (jack_nframes_t now)
2770 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2772 if (gain_automation_recording()) {
2773 _gain_automation_curve.rt_add (now, gain());
2776 _panner->snapshot (now);
2778 last_automation_snapshot = now;
2783 IO::transport_stopped (jack_nframes_t frame)
2785 _gain_automation_curve.reposition_for_rt_add (frame);
2787 if (_gain_automation_curve.automation_state() != Off) {
2789 if (gain_automation_recording()) {
2790 _gain_automation_curve.save_state (_("automation write/touch"));
2793 /* the src=0 condition is a special signal to not propagate
2794 automation gain changes into the mix group when locating.
2797 set_gain (_gain_automation_curve.eval (frame), 0);
2800 _panner->transport_stopped (frame);
2804 IO::find_input_port_hole ()
2806 /* CALLER MUST HOLD IO LOCK */
2810 if (_inputs.empty()) {
2814 for (n = 1; n < UINT_MAX; ++n) {
2815 char buf[jack_port_name_size()];
2816 vector<Port*>::iterator i;
2818 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2820 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2821 if ((*i)->short_name() == buf) {
2826 if (i == _inputs.end()) {
2834 IO::find_output_port_hole ()
2836 /* CALLER MUST HOLD IO LOCK */
2840 if (_outputs.empty()) {
2844 for (n = 1; n < UINT_MAX; ++n) {
2845 char buf[jack_port_name_size()];
2846 vector<Port*>::iterator i;
2848 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2850 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2851 if ((*i)->short_name() == buf) {
2856 if (i == _outputs.end()) {