2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/connection.h>
36 #include <ardour/session.h>
37 #include <ardour/cycle_timer.h>
38 #include <ardour/panner.h>
39 #include <ardour/dB.h>
46 A bug in OS X's cmath that causes isnan() and isinf() to be
47 "undeclared". the following works around that
50 #if defined(__APPLE__) && defined(__MACH__)
51 extern "C" int isnan (double);
52 extern "C" int isinf (double);
57 using namespace ARDOUR;
61 static float current_automation_version_number = 1.0;
63 jack_nframes_t IO::_automation_interval = 0;
64 const string IO::state_node_name = "IO";
65 bool IO::connecting_legal = false;
66 bool IO::ports_legal = false;
67 bool IO::panners_legal = false;
68 sigc::signal<void> IO::Meter;
69 sigc::signal<int> IO::ConnectingLegal;
70 sigc::signal<int> IO::PortsLegal;
71 sigc::signal<int> IO::PannersLegal;
72 sigc::signal<void,uint32_t> IO::MoreOutputs;
73 sigc::signal<int> IO::PortsCreated;
75 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
77 /* this is a default mapper of MIDI control values to a gain coefficient.
78 others can be imagined. see IO::set_midi_to_gain_function().
81 static gain_t direct_midi_to_gain (double fract) {
82 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
83 /* this maxes at +6dB */
84 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
87 static double direct_gain_to_midi (gain_t gain) {
88 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
89 if (gain == 0) return 0.0;
91 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
94 static bool sort_ports_by_name (Port* a, Port* b)
96 return a->name() < b->name();
100 IO::IO (Session& s, string name,
102 int input_min, int input_max, int output_min, int output_max)
105 _midi_gain_control (*this, _session.midi_port()),
106 _gain_automation_curve (0.0, 2.0, 1.0),
107 _input_minimum (input_min),
108 _input_maximum (input_max),
109 _output_minimum (output_min),
110 _output_maximum (output_max)
113 _panner = new Panner (name, _session);
116 _input_connection = 0;
117 _output_connection = 0;
118 pending_state_node = 0;
121 no_panner_reset = false;
124 _midi_gain_control.midi_to_gain = direct_midi_to_gain;
125 _midi_gain_control.gain_to_midi = direct_gain_to_midi;
127 apply_gain_automation = false;
129 last_automation_snapshot = 0;
131 _gain_automation_state = Off;
132 _gain_automation_style = Absolute;
135 // IO::Meter is emitted from another thread so the
136 // Meter signal must be protected.
137 Glib::Mutex::Lock guard (m_meter_signal_lock);
138 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
145 Glib::Mutex::Lock guard (m_meter_signal_lock);
146 Glib::Mutex::Lock lm (io_lock);
147 vector<Port *>::iterator i;
149 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
150 _session.engine().unregister_port (*i);
153 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
154 _session.engine().unregister_port (*i);
157 m_meter_connection.disconnect();
161 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
163 /* io_lock, not taken: function must be called from Session::process() calltree */
165 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
166 (*i)->silence (nframes, offset);
171 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
173 jack_nframes_t declick = min ((jack_nframes_t)4096, nframes);
176 double fractional_shift;
177 double fractional_pos;
178 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
180 if (nframes == 0) return;
182 fractional_shift = -1.0/declick;
184 if (target < initial) {
185 /* fade out: remove more and more of delta from initial */
186 delta = -(initial - target);
188 /* fade in: add more and more of delta from initial */
189 delta = target - initial;
192 for (uint32_t n = 0; n < nbufs; ++n) {
195 fractional_pos = 1.0;
197 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
198 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
199 fractional_pos += fractional_shift;
202 /* now ensure the rest of the buffer has the target value
203 applied, if necessary.
206 if (declick != nframes) {
208 if (invert_polarity) {
213 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
214 } else if (target != 1.0) {
215 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
216 buffer[nx] *= target;
224 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)
228 /* io_lock, not taken: function must be called from Session::process() calltree */
230 if (_noutputs == 0) {
234 if (_noutputs == 1) {
236 dst = output(0)->get_buffer (nframes) + offset;
238 for (uint32_t n = 0; n < nbufs; ++n) {
239 if (bufs[n] != dst) {
240 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
244 output(0)->mark_silence (false);
250 vector<Port *>::iterator out;
251 vector<Sample *>::iterator in;
252 Panner::iterator pan;
253 Sample* obufs[_noutputs];
255 /* the terrible silence ... */
257 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
258 obufs[o] = (*out)->get_buffer (nframes) + offset;
259 memset (obufs[o], 0, sizeof (Sample) * nframes);
260 (*out)->mark_silence (false);
265 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
266 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
271 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
276 /* io_lock, not taken: function must be called from Session::process() calltree */
278 if (_noutputs == 0) {
282 /* the panner can be empty if there are no inputs to the
283 route, but still outputs
286 if (_panner->bypassed() || _panner->empty()) {
287 deliver_output_no_pan (bufs, nbufs, nframes, offset);
291 if (_noutputs == 1) {
293 dst = output(0)->get_buffer (nframes) + offset;
295 if (gain_coeff == 0.0f) {
297 /* only one output, and gain was zero, so make it silent */
299 memset (dst, 0, sizeof (Sample) * nframes);
301 } else if (gain_coeff == 1.0f){
303 /* mix all buffers into the output */
307 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
309 for (n = 1; n < nbufs; ++n) {
312 for (jack_nframes_t n = 0; n < nframes; ++n) {
317 output(0)->mark_silence (false);
321 /* mix all buffers into the output, scaling them all by the gain */
327 for (jack_nframes_t n = 0; n < nframes; ++n) {
328 dst[n] = src[n] * gain_coeff;
331 for (n = 1; n < nbufs; ++n) {
334 for (jack_nframes_t n = 0; n < nframes; ++n) {
335 dst[n] += src[n] * gain_coeff;
339 output(0)->mark_silence (false);
346 vector<Port *>::iterator out;
347 vector<Sample *>::iterator in;
348 Panner::iterator pan;
349 Sample* obufs[_noutputs];
351 /* the terrible silence ... */
353 /* XXX this is wasteful but i see no way to avoid it */
355 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
356 obufs[o] = (*out)->get_buffer (nframes) + offset;
357 memset (obufs[o], 0, sizeof (Sample) * nframes);
358 (*out)->mark_silence (false);
363 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
364 Panner::iterator tmp;
369 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
371 if (tmp != _panner->end()) {
378 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
380 /* io_lock, not taken: function must be called from Session::process() calltree */
382 if (_noutputs == 0) {
386 if (_panner->bypassed() || _panner->empty()) {
387 deliver_output_no_pan (bufs, nbufs, nframes, offset);
393 gain_t pangain = _gain;
396 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
406 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
411 /* simple, non-automation panning to outputs */
413 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
414 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
416 pan (bufs, nbufs, nframes, offset, pangain);
421 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
423 /* io_lock, not taken: function must be called from Session::process() calltree */
425 if (_noutputs == 0) {
430 gain_t old_gain = _gain;
432 if (apply_gain_automation) {
434 /* gain has already been applied by automation code. do nothing here except
443 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
455 vector<Port*>::iterator o;
456 vector<Sample*> outs;
460 /* unlikely condition */
461 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
462 outs.push_back ((*o)->get_buffer (nframes) + offset);
466 /* reduce nbufs to the index of the last input buffer */
470 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
471 actual_gain = _gain * speed_quietning;
476 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
478 dst = (*o)->get_buffer (nframes) + offset;
479 src = bufs[min(nbufs,i)];
481 if (dg != _gain || actual_gain == 1.0f) {
482 memcpy (dst, src, sizeof (Sample) * nframes);
483 } else if (actual_gain == 0.0f) {
484 memset (dst, 0, sizeof (Sample) * nframes);
486 for (jack_nframes_t x = 0; x < nframes; ++x) {
487 dst[x] = src[x] * actual_gain;
491 (*o)->mark_silence (false);
495 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
499 if (apply_gain_automation) {
505 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
507 /* io_lock, not taken: function must be called from Session::process() calltree */
509 vector<Port *>::iterator i;
513 /* we require that bufs.size() >= 1 */
515 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
516 if (i == _inputs.end()) {
520 /* XXX always read the full extent of the port buffer that
521 we need. One day, we may use jack_port_get_buffer_at_offset()
522 or something similar. For now, this simple hack will
525 Hack? Why yes .. we only need to read nframes-worth of
526 data, but the data we want is at `offset' within the
530 last = (*i)->get_buffer (nframes+offset) + offset;
531 // the dest buffer's offset has already been applied
532 memcpy (bufs[n], last, sizeof (Sample) * nframes);
535 /* fill any excess outputs with the last input */
537 while (n < nbufs && last) {
538 // the dest buffer's offset has already been applied
539 memcpy (bufs[n], last, sizeof (Sample) * nframes);
545 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
546 jack_nframes_t nframes, jack_nframes_t offset)
548 vector<Sample*>& bufs = _session.get_passthru_buffers ();
549 uint32_t nbufs = n_process_buffers ();
551 collect_input (bufs, nbufs, nframes, offset);
553 for (uint32_t n = 0; n < nbufs; ++n) {
554 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
559 IO::drop_input_connection ()
561 _input_connection = 0;
562 input_connection_configuration_connection.disconnect();
563 input_connection_connection_connection.disconnect();
564 _session.set_dirty ();
568 IO::drop_output_connection ()
570 _output_connection = 0;
571 output_connection_configuration_connection.disconnect();
572 output_connection_connection_connection.disconnect();
573 _session.set_dirty ();
577 IO::disconnect_input (Port* our_port, string other_port, void* src)
579 if (other_port.length() == 0 || our_port == 0) {
584 Glib::Mutex::Lock em (_session.engine().process_lock());
587 Glib::Mutex::Lock lm (io_lock);
589 /* check that our_port is really one of ours */
591 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
595 /* disconnect it from the source */
597 if (_session.engine().disconnect (other_port, our_port->name())) {
598 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
602 drop_input_connection();
606 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
607 _session.set_dirty ();
613 IO::connect_input (Port* our_port, string other_port, void* src)
615 if (other_port.length() == 0 || our_port == 0) {
620 Glib::Mutex::Lock em(_session.engine().process_lock());
623 Glib::Mutex::Lock lm (io_lock);
625 /* check that our_port is really one of ours */
627 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
631 /* connect it to the source */
633 if (_session.engine().connect (other_port, our_port->name())) {
637 drop_input_connection ();
641 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
642 _session.set_dirty ();
647 IO::disconnect_output (Port* our_port, string other_port, void* src)
649 if (other_port.length() == 0 || our_port == 0) {
654 Glib::Mutex::Lock em(_session.engine().process_lock());
657 Glib::Mutex::Lock lm (io_lock);
659 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
663 /* disconnect it from the destination */
665 if (_session.engine().disconnect (our_port->name(), other_port)) {
666 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
670 drop_output_connection ();
674 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
675 _session.set_dirty ();
680 IO::connect_output (Port* our_port, string other_port, void* src)
682 if (other_port.length() == 0 || our_port == 0) {
687 Glib::Mutex::Lock em(_session.engine().process_lock());
690 Glib::Mutex::Lock lm (io_lock);
692 /* check that our_port is really one of ours */
694 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
698 /* connect it to the destination */
700 if (_session.engine().connect (our_port->name(), other_port)) {
704 drop_output_connection ();
708 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
709 _session.set_dirty ();
714 IO::set_input (Port* other_port, void* src)
716 /* this removes all but one ports, and connects that one port
717 to the specified source.
720 if (_input_minimum > 1 || _input_minimum == 0) {
721 /* sorry, you can't do this */
725 if (other_port == 0) {
726 if (_input_minimum < 0) {
727 return ensure_inputs (0, false, true, src);
733 if (ensure_inputs (1, true, true, src)) {
737 return connect_input (_inputs.front(), other_port->name(), src);
741 IO::remove_output_port (Port* port, void* src)
743 IOChange change (NoChange);
746 Glib::Mutex::Lock em(_session.engine().process_lock());
749 Glib::Mutex::Lock lm (io_lock);
751 if (_noutputs - 1 == (uint32_t) _output_minimum) {
752 /* sorry, you can't do this */
756 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
758 change = IOChange (change|ConfigurationChanged);
759 if (port->connected()) {
760 change = IOChange (change|ConnectionsChanged);
763 _session.engine().unregister_port (*i);
766 drop_output_connection ();
772 if (change != NoChange) {
773 setup_peak_meters ();
779 if (change != NoChange) {
780 output_changed (change, src); /* EMIT SIGNAL */
781 _session.set_dirty ();
789 IO::add_output_port (string destination, void* src)
795 Glib::Mutex::Lock em(_session.engine().process_lock());
798 Glib::Mutex::Lock lm (io_lock);
800 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
804 /* Create a new output port */
806 if (_output_maximum == 1) {
807 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
809 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
812 if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) {
813 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
817 _outputs.push_back (our_port);
818 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
820 drop_output_connection ();
821 setup_peak_meters ();
825 MoreOutputs (_noutputs); /* EMIT SIGNAL */
828 if (destination.length()) {
829 if (_session.engine().connect (our_port->name(), destination)) {
834 // pan_changed (src); /* EMIT SIGNAL */
835 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
836 _session.set_dirty ();
841 IO::remove_input_port (Port* port, void* src)
843 IOChange change (NoChange);
846 Glib::Mutex::Lock em(_session.engine().process_lock());
849 Glib::Mutex::Lock lm (io_lock);
851 if (((int)_ninputs - 1) < _input_minimum) {
852 /* sorry, you can't do this */
855 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
858 change = IOChange (change|ConfigurationChanged);
860 if (port->connected()) {
861 change = IOChange (change|ConnectionsChanged);
864 _session.engine().unregister_port (*i);
867 drop_input_connection ();
873 if (change != NoChange) {
874 setup_peak_meters ();
880 if (change != NoChange) {
881 input_changed (change, src);
882 _session.set_dirty ();
890 IO::add_input_port (string source, void* src)
896 Glib::Mutex::Lock em (_session.engine().process_lock());
899 Glib::Mutex::Lock lm (io_lock);
901 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
905 /* Create a new input port */
907 if (_input_maximum == 1) {
908 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
910 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
913 if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) {
914 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
918 _inputs.push_back (our_port);
919 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
921 drop_input_connection ();
922 setup_peak_meters ();
926 MoreOutputs (_ninputs); /* EMIT SIGNAL */
929 if (source.length()) {
931 if (_session.engine().connect (source, our_port->name())) {
936 // pan_changed (src); /* EMIT SIGNAL */
937 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
938 _session.set_dirty ();
944 IO::disconnect_inputs (void* src)
947 Glib::Mutex::Lock em (_session.engine().process_lock());
950 Glib::Mutex::Lock lm (io_lock);
952 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
953 _session.engine().disconnect (*i);
956 drop_input_connection ();
959 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
964 IO::disconnect_outputs (void* src)
967 Glib::Mutex::Lock em (_session.engine().process_lock());
970 Glib::Mutex::Lock lm (io_lock);
972 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
973 _session.engine().disconnect (*i);
976 drop_output_connection ();
980 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
981 _session.set_dirty ();
986 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
989 bool changed = false;
990 bool reduced = false;
992 /* remove unused ports */
994 while (_ninputs > n) {
995 _session.engine().unregister_port (_inputs.back());
1002 /* create any necessary new ports */
1004 while (_ninputs < n) {
1008 /* Create a new input port */
1010 if (_input_maximum == 1) {
1011 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1014 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1019 if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) {
1020 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1025 catch (AudioEngine::PortRegistrationFailure& err) {
1026 setup_peak_meters ();
1032 _inputs.push_back (input_port);
1033 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1039 drop_input_connection ();
1040 setup_peak_meters ();
1042 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1043 _session.set_dirty ();
1047 /* disconnect all existing ports so that we get a fresh start */
1049 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1050 _session.engine().disconnect (*i);
1058 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1060 bool in_changed = false;
1061 bool out_changed = false;
1062 bool in_reduced = false;
1063 bool out_reduced = false;
1064 bool need_pan_reset;
1066 if (_input_maximum >= 0) {
1067 nin = min (_input_maximum, (int) nin);
1070 if (_output_maximum >= 0) {
1071 nout = min (_output_maximum, (int) nout);
1074 if (nin == _ninputs && nout == _noutputs && !clear) {
1079 Glib::Mutex::Lock em (_session.engine().process_lock());
1080 Glib::Mutex::Lock lm (io_lock);
1084 if (_noutputs == nout) {
1085 need_pan_reset = false;
1087 need_pan_reset = true;
1090 /* remove unused ports */
1092 while (_ninputs > nin) {
1093 _session.engine().unregister_port (_inputs.back());
1100 while (_noutputs > nout) {
1101 _session.engine().unregister_port (_outputs.back());
1102 _outputs.pop_back();
1108 /* create any necessary new ports */
1110 while (_ninputs < nin) {
1114 /* Create a new input port */
1116 if (_input_maximum == 1) {
1117 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1120 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1124 if ((port = _session.engine().register_audio_input_port (buf)) == 0) {
1125 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1130 catch (AudioEngine::PortRegistrationFailure& err) {
1131 setup_peak_meters ();
1137 _inputs.push_back (port);
1142 /* create any necessary new ports */
1144 while (_noutputs < nout) {
1148 /* Create a new output port */
1150 if (_output_maximum == 1) {
1151 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1153 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1157 if ((port = _session.engine().register_audio_output_port (buf)) == 0) {
1158 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1163 catch (AudioEngine::PortRegistrationFailure& err) {
1164 setup_peak_meters ();
1170 _outputs.push_back (port);
1177 /* disconnect all existing ports so that we get a fresh start */
1179 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1180 _session.engine().disconnect (*i);
1183 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1184 _session.engine().disconnect (*i);
1188 if (in_changed || out_changed) {
1189 setup_peak_meters ();
1195 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1196 drop_output_connection ();
1197 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1201 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1202 drop_input_connection ();
1203 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1206 if (in_changed || out_changed) {
1207 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1208 _session.set_dirty ();
1215 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1217 bool changed = false;
1219 if (_input_maximum >= 0) {
1220 n = min (_input_maximum, (int) n);
1222 if (n == _ninputs && !clear) {
1228 Glib::Mutex::Lock em (_session.engine().process_lock());
1229 Glib::Mutex::Lock im (io_lock);
1230 changed = ensure_inputs_locked (n, clear, src);
1232 changed = ensure_inputs_locked (n, clear, src);
1236 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1237 _session.set_dirty ();
1244 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1247 bool changed = false;
1248 bool reduced = false;
1249 bool need_pan_reset;
1251 if (_noutputs == n) {
1252 need_pan_reset = false;
1254 need_pan_reset = true;
1257 /* remove unused ports */
1259 while (_noutputs > n) {
1261 _session.engine().unregister_port (_outputs.back());
1262 _outputs.pop_back();
1268 /* create any necessary new ports */
1270 while (_noutputs < n) {
1274 /* Create a new output port */
1276 if (_output_maximum == 1) {
1277 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1279 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1282 if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) {
1283 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1287 _outputs.push_back (output_port);
1288 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1291 setup_peak_meters ();
1293 if (need_pan_reset) {
1299 drop_output_connection ();
1300 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1301 _session.set_dirty ();
1305 /* disconnect all existing ports so that we get a fresh start */
1307 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1308 _session.engine().disconnect (*i);
1316 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1318 bool changed = false;
1320 if (_output_maximum >= 0) {
1321 n = min (_output_maximum, (int) n);
1322 if (n == _noutputs && !clear) {
1327 /* XXX caller should hold io_lock, but generally doesn't */
1330 Glib::Mutex::Lock em (_session.engine().process_lock());
1331 Glib::Mutex::Lock im (io_lock);
1332 changed = ensure_outputs_locked (n, clear, src);
1334 changed = ensure_outputs_locked (n, clear, src);
1338 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1345 IO::effective_gain () const
1347 if (gain_automation_playback()) {
1348 return _effective_gain;
1350 return _desired_gain;
1357 if (panners_legal) {
1358 if (!no_panner_reset) {
1359 _panner->reset (_noutputs, pans_required());
1362 panner_legal_c.disconnect ();
1363 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1368 IO::panners_became_legal ()
1370 _panner->reset (_noutputs, pans_required());
1371 _panner->load (); // automation
1372 panner_legal_c.disconnect ();
1377 IO::defer_pan_reset ()
1379 no_panner_reset = true;
1383 IO::allow_pan_reset ()
1385 no_panner_reset = false;
1391 IO::get_state (void)
1393 return state (true);
1397 IO::state (bool full_state)
1399 XMLNode* node = new XMLNode (state_node_name);
1402 bool need_ins = true;
1403 bool need_outs = true;
1404 LocaleGuard lg (X_("POSIX"));
1405 Glib::Mutex::Lock lm (io_lock);
1407 node->add_property("name", _name);
1408 snprintf (buf, sizeof(buf), "%" PRIu64, id());
1409 node->add_property("id", buf);
1413 if (_input_connection) {
1414 node->add_property ("input-connection", _input_connection->name());
1418 if (_output_connection) {
1419 node->add_property ("output-connection", _output_connection->name());
1424 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1426 const char **connections = (*i)->get_connections();
1428 if (connections && connections[0]) {
1431 for (int n = 0; connections && connections[n]; ++n) {
1436 /* if its a connection to our own port,
1437 return only the port name, not the
1438 whole thing. this allows connections
1439 to be re-established even when our
1440 client name is different.
1443 str += _session.engine().make_port_name_relative (connections[n]);
1455 node->add_property ("inputs", str);
1461 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1463 const char **connections = (*i)->get_connections();
1465 if (connections && connections[0]) {
1469 for (int n = 0; connections[n]; ++n) {
1474 str += _session.engine().make_port_name_relative (connections[n]);
1486 node->add_property ("outputs", str);
1489 node->add_child_nocopy (_panner->state (full_state));
1491 snprintf (buf, sizeof(buf), "%2.12f", gain());
1492 node->add_property ("gain", buf);
1494 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1500 node->add_property ("iolimits", buf);
1504 MIDI::channel_t chn;
1506 MIDI::byte additional;
1507 XMLNode* midi_node = 0;
1510 if (_midi_gain_control.get_control_info (chn, ev, additional)) {
1512 midi_node = node->add_child ("MIDI");
1514 child = midi_node->add_child ("gain");
1515 set_midi_node_info (child, ev, chn, additional);
1521 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1523 /* never store anything except Off for automation state in a template */
1524 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1526 node->add_property ("automation-state", buf);
1527 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1528 node->add_property ("automation-style", buf);
1530 /* XXX same for pan etc. */
1536 IO::connecting_became_legal ()
1540 if (pending_state_node == 0) {
1541 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1546 connection_legal_c.disconnect ();
1548 ret = make_connections (*pending_state_node);
1551 delete pending_state_node;
1552 pending_state_node = 0;
1559 IO::ports_became_legal ()
1563 if (pending_state_node == 0) {
1564 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1569 port_legal_c.disconnect ();
1571 ret = create_ports (*pending_state_node);
1573 if (connecting_legal) {
1574 delete pending_state_node;
1575 pending_state_node = 0;
1582 IO::set_state (const XMLNode& node)
1584 const XMLProperty* prop;
1585 XMLNodeConstIterator iter;
1586 XMLNodeList midi_kids;
1587 LocaleGuard lg (X_("POSIX"));
1589 /* force use of non-localized representation of decimal point,
1590 since we use it a lot in XML files and so forth.
1593 if (node.name() != state_node_name) {
1594 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1598 if ((prop = node.property ("name")) != 0) {
1599 _name = prop->value();
1600 _panner->set_name (_name);
1603 if ((prop = node.property ("id")) != 0) {
1604 sscanf (prop->value().c_str(), "%" PRIu64, &_id);
1607 if ((prop = node.property ("iolimits")) != 0) {
1608 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1615 if ((prop = node.property ("gain")) != 0) {
1616 set_gain (atof (prop->value().c_str()), this);
1617 _gain = _desired_gain;
1620 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1621 if ((*iter)->name() == "Panner") {
1622 _panner->set_state (**iter);
1626 midi_kids = node.children ("MIDI");
1628 for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) {
1631 XMLNodeConstIterator miter;
1634 kids = (*iter)->children ();
1636 for (miter = kids.begin(); miter != kids.end(); ++miter) {
1640 if (child->name() == "gain") {
1642 MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */
1643 MIDI::byte additional = 0; /* ditto */
1644 MIDI::channel_t chn = 0; /* ditto */
1646 if (get_midi_node_info (child, ev, chn, additional)) {
1647 _midi_gain_control.set_control_type (chn, ev, additional);
1649 error << string_compose(_("MIDI gain control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
1655 if ((prop = node.property ("automation-state")) != 0) {
1658 x = strtol (prop->value().c_str(), 0, 16);
1659 set_gain_automation_state (AutoState (x));
1662 if ((prop = node.property ("automation-style")) != 0) {
1665 x = strtol (prop->value().c_str(), 0, 16);
1666 set_gain_automation_style (AutoStyle (x));
1671 if (create_ports (node)) {
1677 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1680 if (panners_legal) {
1683 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1686 if (connecting_legal) {
1688 if (make_connections (node)) {
1694 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1697 if (!ports_legal || !connecting_legal) {
1698 pending_state_node = new XMLNode (node);
1705 IO::create_ports (const XMLNode& node)
1707 const XMLProperty* prop;
1709 int num_outputs = 0;
1711 if ((prop = node.property ("input-connection")) != 0) {
1713 Connection* c = _session.connection_by_name (prop->value());
1716 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1718 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1719 error << _("No input connections available as a replacement")
1723 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1728 num_inputs = c->nports();
1730 } else if ((prop = node.property ("inputs")) != 0) {
1732 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1735 if ((prop = node.property ("output-connection")) != 0) {
1736 Connection* c = _session.connection_by_name (prop->value());
1739 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1741 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1742 error << _("No output connections available as a replacement")
1746 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1751 num_outputs = c->nports ();
1753 } else if ((prop = node.property ("outputs")) != 0) {
1754 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1757 no_panner_reset = true;
1759 if (ensure_io (num_inputs, num_outputs, true, this)) {
1760 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1764 no_panner_reset = false;
1766 set_deferred_state ();
1773 IO::get_midi_node_info (XMLNode * node, MIDI::eventType & ev, MIDI::channel_t & chan, MIDI::byte & additional)
1776 const XMLProperty* prop;
1779 if ((prop = node->property ("event")) != 0) {
1780 sscanf (prop->value().c_str(), "0x%x", &xx);
1781 ev = (MIDI::eventType) xx;
1786 if (ok && ((prop = node->property ("channel")) != 0)) {
1787 sscanf (prop->value().c_str(), "%d", &xx);
1788 chan = (MIDI::channel_t) xx;
1793 if (ok && ((prop = node->property ("additional")) != 0)) {
1794 sscanf (prop->value().c_str(), "0x%x", &xx);
1795 additional = (MIDI::byte) xx;
1802 IO::set_midi_node_info (XMLNode * node, MIDI::eventType ev, MIDI::channel_t chan, MIDI::byte additional)
1806 snprintf (buf, sizeof(buf), "0x%x", ev);
1807 node->add_property ("event", buf);
1808 snprintf (buf, sizeof(buf), "%d", chan);
1809 node->add_property ("channel", buf);
1810 snprintf (buf, sizeof(buf), "0x%x", additional);
1811 node->add_property ("additional", buf);
1818 IO::make_connections (const XMLNode& node)
1820 const XMLProperty* prop;
1822 if ((prop = node.property ("input-connection")) != 0) {
1823 Connection* c = _session.connection_by_name (prop->value());
1826 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1828 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1829 error << _("No input connections available as a replacement")
1833 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1838 use_input_connection (*c, this);
1840 } else if ((prop = node.property ("inputs")) != 0) {
1841 if (set_inputs (prop->value())) {
1842 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1847 if ((prop = node.property ("output-connection")) != 0) {
1848 Connection* c = _session.connection_by_name (prop->value());
1851 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1853 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1854 error << _("No output connections available as a replacement")
1858 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1863 use_output_connection (*c, this);
1865 } else if ((prop = node.property ("outputs")) != 0) {
1866 if (set_outputs (prop->value())) {
1867 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1876 IO::set_inputs (const string& str)
1878 vector<string> ports;
1883 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1887 if (ensure_inputs (nports, true, true, this)) {
1891 string::size_type start, end, ostart;
1898 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1901 if ((end = str.find_first_of ('}', start)) == string::npos) {
1902 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1906 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1907 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1913 for (int x = 0; x < n; ++x) {
1914 connect_input (input (i), ports[x], this);
1926 IO::set_outputs (const string& str)
1928 vector<string> ports;
1933 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1937 if (ensure_outputs (nports, true, true, this)) {
1941 string::size_type start, end, ostart;
1948 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1951 if ((end = str.find_first_of ('}', start)) == string::npos) {
1952 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1956 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1957 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1963 for (int x = 0; x < n; ++x) {
1964 connect_output (output (i), ports[x], this);
1976 IO::parse_io_string (const string& str, vector<string>& ports)
1978 string::size_type pos, opos;
1980 if (str.length() == 0) {
1989 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1990 ports.push_back (str.substr (opos, pos - opos));
1994 if (opos < str.length()) {
1995 ports.push_back (str.substr(opos));
1998 return ports.size();
2002 IO::parse_gain_string (const string& str, vector<string>& ports)
2004 string::size_type pos, opos;
2010 while ((pos = str.find_first_of (',', opos)) != string::npos) {
2011 ports.push_back (str.substr (opos, pos - opos));
2015 if (opos < str.length()) {
2016 ports.push_back (str.substr(opos));
2019 return ports.size();
2023 IO::set_name (string name, void* src)
2025 if (name == _name) {
2029 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2030 string current_name = (*i)->short_name();
2031 current_name.replace (current_name.find (_name), _name.length(), name);
2032 (*i)->set_name (current_name);
2035 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2036 string current_name = (*i)->short_name();
2037 current_name.replace (current_name.find (_name), _name.length(), name);
2038 (*i)->set_name (current_name);
2042 name_changed (src); /* EMIT SIGNAL */
2048 IO::set_input_minimum (int n)
2054 IO::set_input_maximum (int n)
2060 IO::set_output_minimum (int n)
2062 _output_minimum = n;
2066 IO::set_output_maximum (int n)
2068 _output_maximum = n;
2072 IO::set_port_latency (jack_nframes_t nframes)
2074 Glib::Mutex::Lock lm (io_lock);
2076 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2077 (*i)->set_latency (nframes);
2082 IO::output_latency () const
2084 jack_nframes_t max_latency;
2085 jack_nframes_t latency;
2089 /* io lock not taken - must be protected by other means */
2091 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2092 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2093 max_latency = latency;
2101 IO::input_latency () const
2103 jack_nframes_t max_latency;
2104 jack_nframes_t latency;
2108 /* io lock not taken - must be protected by other means */
2110 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2111 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2112 max_latency = latency;
2120 IO::use_input_connection (Connection& c, void* src)
2125 Glib::Mutex::Lock lm (_session.engine().process_lock());
2126 Glib::Mutex::Lock lm2 (io_lock);
2130 drop_input_connection ();
2132 if (ensure_inputs (limit, false, false, src)) {
2136 /* first pass: check the current state to see what's correctly
2137 connected, and drop anything that we don't want.
2140 for (uint32_t n = 0; n < limit; ++n) {
2141 const Connection::PortList& pl = c.port_connections (n);
2143 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2145 if (!_inputs[n]->connected_to ((*i))) {
2147 /* clear any existing connections */
2149 _session.engine().disconnect (_inputs[n]);
2151 } else if (_inputs[n]->connected() > 1) {
2153 /* OK, it is connected to the port we want,
2154 but its also connected to other ports.
2155 Change that situation.
2158 /* XXX could be optimized to not drop
2162 _session.engine().disconnect (_inputs[n]);
2168 /* second pass: connect all requested ports where necessary */
2170 for (uint32_t n = 0; n < limit; ++n) {
2171 const Connection::PortList& pl = c.port_connections (n);
2173 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2175 if (!_inputs[n]->connected_to ((*i))) {
2177 if (_session.engine().connect (*i, _inputs[n]->name())) {
2185 _input_connection = &c;
2187 input_connection_configuration_connection = c.ConfigurationChanged.connect
2188 (mem_fun (*this, &IO::input_connection_configuration_changed));
2189 input_connection_connection_connection = c.ConnectionsChanged.connect
2190 (mem_fun (*this, &IO::input_connection_connection_changed));
2193 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2198 IO::use_output_connection (Connection& c, void* src)
2203 Glib::Mutex::Lock lm (_session.engine().process_lock());
2204 Glib::Mutex::Lock lm2 (io_lock);
2208 drop_output_connection ();
2210 if (ensure_outputs (limit, false, false, src)) {
2214 /* first pass: check the current state to see what's correctly
2215 connected, and drop anything that we don't want.
2218 for (uint32_t n = 0; n < limit; ++n) {
2220 const Connection::PortList& pl = c.port_connections (n);
2222 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2224 if (!_outputs[n]->connected_to ((*i))) {
2226 /* clear any existing connections */
2228 _session.engine().disconnect (_outputs[n]);
2230 } else if (_outputs[n]->connected() > 1) {
2232 /* OK, it is connected to the port we want,
2233 but its also connected to other ports.
2234 Change that situation.
2237 /* XXX could be optimized to not drop
2241 _session.engine().disconnect (_outputs[n]);
2246 /* second pass: connect all requested ports where necessary */
2248 for (uint32_t n = 0; n < limit; ++n) {
2250 const Connection::PortList& pl = c.port_connections (n);
2252 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2254 if (!_outputs[n]->connected_to ((*i))) {
2256 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2263 _output_connection = &c;
2265 output_connection_configuration_connection = c.ConfigurationChanged.connect
2266 (mem_fun (*this, &IO::output_connection_configuration_changed));
2267 output_connection_connection_connection = c.ConnectionsChanged.connect
2268 (mem_fun (*this, &IO::output_connection_connection_changed));
2271 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2277 IO::disable_connecting ()
2279 connecting_legal = false;
2284 IO::enable_connecting ()
2286 connecting_legal = true;
2287 return ConnectingLegal ();
2291 IO::disable_ports ()
2293 ports_legal = false;
2301 return PortsLegal ();
2305 IO::disable_panners (void)
2307 panners_legal = false;
2312 IO::reset_panners ()
2314 panners_legal = true;
2315 return PannersLegal ();
2319 IO::input_connection_connection_changed (int ignored)
2321 use_input_connection (*_input_connection, this);
2325 IO::input_connection_configuration_changed ()
2327 use_input_connection (*_input_connection, this);
2331 IO::output_connection_connection_changed (int ignored)
2333 use_output_connection (*_output_connection, this);
2337 IO::output_connection_configuration_changed ()
2339 use_output_connection (*_output_connection, this);
2342 IO::MIDIGainControl::MIDIGainControl (IO& i, MIDI::Port* port)
2343 : MIDI::Controllable (port, 0), io (i), setting(false)
2348 last_written = 0; /* XXX need a good out-of-bound-value */
2352 IO::MIDIGainControl::set_value (float val)
2354 if (midi_to_gain == 0) return;
2357 io.set_gain (midi_to_gain (val), this);
2362 IO::MIDIGainControl::send_feedback (gain_t gain)
2364 if (!setting && get_midi_feedback() && gain_to_midi) {
2365 MIDI::byte val = (MIDI::byte) (gain_to_midi (gain) * 127.0);
2366 MIDI::channel_t ch = 0;
2367 MIDI::eventType ev = MIDI::none;
2368 MIDI::byte additional = 0;
2369 MIDI::EventTwoBytes data;
2371 if (get_control_info (ch, ev, additional)) {
2372 data.controller_number = additional;
2376 io._session.send_midi_message (get_port(), ev, ch, data);
2378 //send_midi_feedback (gain_to_midi (gain));
2383 IO::MIDIGainControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, gain_t val, bool force)
2385 if (get_midi_feedback() && gain_to_midi && bufsize > 2) {
2386 MIDI::channel_t ch = 0;
2387 MIDI::eventType ev = MIDI::none;
2388 MIDI::byte additional = 0;
2391 if (get_control_info (ch, ev, additional)) {
2392 gm = (MIDI::byte) (gain_to_midi (val) * 127.0);
2394 if (gm != last_written) {
2395 *buf++ = (0xF0 & ev) | (0xF & ch);
2396 *buf++ = additional; /* controller number */
2408 IO::reset_peak_meters ()
2410 uint32_t limit = max (_ninputs, _noutputs);
2412 for (uint32_t i = 0; i < limit; ++i) {
2418 IO::setup_peak_meters ()
2420 uint32_t limit = max (_ninputs, _noutputs);
2422 while (_peak_power.size() < limit) {
2423 _peak_power.push_back (0);
2424 _visible_peak_power.push_back (0);
2429 IO::get_memento() const
2431 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2435 IO::restore_state (StateManager::State& state)
2440 StateManager::State*
2441 IO::state_factory (std::string why) const
2443 StateManager::State* state = new StateManager::State (why);
2448 Update the peak meters.
2450 The meter signal lock is taken to prevent modification of the
2451 Meter signal while updating the meters, taking the meter signal
2452 lock prior to taking the io_lock ensures that all IO will remain
2453 valid while metering.
2458 Glib::Mutex::Lock guard (m_meter_signal_lock);
2466 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2467 uint32_t limit = max (_ninputs, _noutputs);
2469 for (uint32_t n = 0; n < limit; ++n) {
2471 /* XXX we should use atomic exchange here */
2473 /* grab peak since last read */
2475 float new_peak = _peak_power[n];
2478 /* compute new visible value using falloff */
2480 if (new_peak > 0.0) {
2481 new_peak = coefficient_to_dB (new_peak);
2483 new_peak = minus_infinity();
2486 if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2487 _visible_peak_power[n] = new_peak;
2490 new_peak = _visible_peak_power[n] - _session.meter_falloff();
2491 _visible_peak_power[n] = max (new_peak, -INFINITY);
2497 IO::reset_midi_control (MIDI::Port* port, bool on)
2499 MIDI::channel_t chn;
2503 _midi_gain_control.get_control_info (chn, ev, extra);
2507 _midi_gain_control.midi_rebind (port, chn);
2509 _panner->reset_midi_control (port, on);
2514 IO::save_automation (const string& path)
2519 fullpath = _session.automation_dir();
2522 out.open (fullpath.c_str());
2525 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2529 out << X_("version ") << current_automation_version_number << endl;
2531 /* XXX use apply_to_points to get thread safety */
2533 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2534 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2543 IO::load_automation (const string& path)
2548 uint32_t linecnt = 0;
2550 LocaleGuard lg (X_("POSIX"));
2552 fullpath = _session.automation_dir();
2555 in.open (fullpath.c_str());
2558 fullpath = _session.automation_dir();
2559 fullpath += _session.snap_name();
2562 in.open (fullpath.c_str());
2564 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2569 clear_automation ();
2571 while (in.getline (line, sizeof(line), '\n')) {
2573 jack_nframes_t when;
2576 if (++linecnt == 1) {
2577 if (memcmp (line, "version", 7) == 0) {
2578 if (sscanf (line, "version %f", &version) != 1) {
2579 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2583 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2587 if (version != current_automation_version_number) {
2588 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2595 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2596 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2602 _gain_automation_curve.add (when, value, true);
2612 /* older (pre-1.0) versions of ardour used this */
2616 warning << _("dubious automation event found (and ignored)") << endmsg;
2620 _gain_automation_curve.save_state (_("loaded from disk"));
2626 IO::clear_automation ()
2628 Glib::Mutex::Lock lm (automation_lock);
2629 _gain_automation_curve.clear ();
2630 _panner->clear_automation ();
2634 IO::set_gain_automation_state (AutoState state)
2636 bool changed = false;
2639 Glib::Mutex::Lock lm (automation_lock);
2641 if (state != _gain_automation_curve.automation_state()) {
2643 last_automation_snapshot = 0;
2644 _gain_automation_curve.set_automation_state (state);
2647 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2653 _session.set_dirty ();
2654 gain_automation_state_changed (); /* EMIT SIGNAL */
2659 IO::set_gain_automation_style (AutoStyle style)
2661 bool changed = false;
2664 Glib::Mutex::Lock lm (automation_lock);
2666 if (style != _gain_automation_curve.automation_style()) {
2668 _gain_automation_curve.set_automation_style (style);
2673 gain_automation_style_changed (); /* EMIT SIGNAL */
2677 IO::inc_gain (gain_t factor, void *src)
2679 if (_desired_gain == 0.0f)
2680 set_gain (0.000001f + (0.000001f * factor), src);
2682 set_gain (_desired_gain + (_desired_gain * factor), src);
2686 IO::set_gain (gain_t val, void *src)
2688 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2689 if (val>1.99526231f) val=1.99526231f;
2692 Glib::Mutex::Lock dm (declick_lock);
2693 _desired_gain = val;
2696 if (_session.transport_stopped()) {
2697 _effective_gain = val;
2703 if (_session.get_midi_feedback()) {
2704 _midi_gain_control.send_feedback (_desired_gain);
2707 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2708 _gain_automation_curve.add (_session.transport_frame(), val);
2712 _session.set_dirty();
2716 IO::send_all_midi_feedback ()
2718 if (_session.get_midi_feedback()) {
2719 _midi_gain_control.send_feedback (_effective_gain);
2722 _panner->send_all_midi_feedback();
2727 IO::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize)
2729 if (_session.get_midi_feedback()) {
2730 if (gain_automation_playback ()) {
2731 buf = _midi_gain_control.write_feedback (buf, bufsize, _effective_gain);
2733 buf = _panner->write_midi_feedback (buf, bufsize);
2740 IO::start_gain_touch ()
2742 _gain_automation_curve.start_touch ();
2746 IO::end_gain_touch ()
2748 _gain_automation_curve.stop_touch ();
2752 IO::start_pan_touch (uint32_t which)
2754 if (which < _panner->size()) {
2755 (*_panner)[which]->automation().start_touch();
2760 IO::end_pan_touch (uint32_t which)
2762 if (which < _panner->size()) {
2763 (*_panner)[which]->automation().stop_touch();
2769 IO::automation_snapshot (jack_nframes_t now)
2771 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2773 if (gain_automation_recording()) {
2774 _gain_automation_curve.rt_add (now, gain());
2777 _panner->snapshot (now);
2779 last_automation_snapshot = now;
2784 IO::transport_stopped (jack_nframes_t frame)
2786 _gain_automation_curve.reposition_for_rt_add (frame);
2788 if (_gain_automation_curve.automation_state() != Off) {
2790 if (gain_automation_recording()) {
2791 _gain_automation_curve.save_state (_("automation write/touch"));
2794 /* the src=0 condition is a special signal to not propagate
2795 automation gain changes into the mix group when locating.
2798 set_gain (_gain_automation_curve.eval (frame), 0);
2801 _panner->transport_stopped (frame);
2805 IO::find_input_port_hole ()
2807 /* CALLER MUST HOLD IO LOCK */
2811 if (_inputs.empty()) {
2815 for (n = 1; n < UINT_MAX; ++n) {
2816 char buf[jack_port_name_size()];
2817 vector<Port*>::iterator i;
2819 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2821 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2822 if ((*i)->short_name() == buf) {
2827 if (i == _inputs.end()) {
2835 IO::find_output_port_hole ()
2837 /* CALLER MUST HOLD IO LOCK */
2841 if (_outputs.empty()) {
2845 for (n = 1; n < UINT_MAX; ++n) {
2846 char buf[jack_port_name_size()];
2847 vector<Port*>::iterator i;
2849 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2851 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2852 if ((*i)->short_name() == buf) {
2857 if (i == _outputs.end()) {