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 [0 .. 1.0] control values to a gain coefficient.
78 others can be imagined.
81 static gain_t direct_control_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_control (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 _gain_control (*this),
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)
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 apply_gain_automation = false;
125 last_automation_snapshot = 0;
127 _gain_automation_state = Off;
128 _gain_automation_style = Absolute;
131 // IO::Meter is emitted from another thread so the
132 // Meter signal must be protected.
133 Glib::Mutex::Lock guard (m_meter_signal_lock);
134 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
141 Glib::Mutex::Lock guard (m_meter_signal_lock);
142 Glib::Mutex::Lock lm (io_lock);
143 vector<Port *>::iterator i;
145 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
146 _session.engine().unregister_port (*i);
149 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
150 _session.engine().unregister_port (*i);
153 m_meter_connection.disconnect();
157 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
159 /* io_lock, not taken: function must be called from Session::process() calltree */
161 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
162 (*i)->silence (nframes, offset);
167 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
169 jack_nframes_t declick = min ((jack_nframes_t)4096, nframes);
172 double fractional_shift;
173 double fractional_pos;
174 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
176 if (nframes == 0) return;
178 fractional_shift = -1.0/declick;
180 if (target < initial) {
181 /* fade out: remove more and more of delta from initial */
182 delta = -(initial - target);
184 /* fade in: add more and more of delta from initial */
185 delta = target - initial;
188 for (uint32_t n = 0; n < nbufs; ++n) {
191 fractional_pos = 1.0;
193 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
194 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
195 fractional_pos += fractional_shift;
198 /* now ensure the rest of the buffer has the target value
199 applied, if necessary.
202 if (declick != nframes) {
204 if (invert_polarity) {
209 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
210 } else if (target != 1.0) {
211 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
212 buffer[nx] *= target;
220 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)
224 /* io_lock, not taken: function must be called from Session::process() calltree */
226 if (_noutputs == 0) {
230 if (_noutputs == 1) {
232 dst = output(0)->get_buffer (nframes) + offset;
234 for (uint32_t n = 0; n < nbufs; ++n) {
235 if (bufs[n] != dst) {
236 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
240 output(0)->mark_silence (false);
246 vector<Port *>::iterator out;
247 vector<Sample *>::iterator in;
248 Panner::iterator pan;
249 Sample* obufs[_noutputs];
251 /* the terrible silence ... */
253 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
254 obufs[o] = (*out)->get_buffer (nframes) + offset;
255 memset (obufs[o], 0, sizeof (Sample) * nframes);
256 (*out)->mark_silence (false);
261 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
262 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
267 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
272 /* io_lock, not taken: function must be called from Session::process() calltree */
274 if (_noutputs == 0) {
278 /* the panner can be empty if there are no inputs to the
279 route, but still outputs
282 if (_panner->bypassed() || _panner->empty()) {
283 deliver_output_no_pan (bufs, nbufs, nframes, offset);
287 if (_noutputs == 1) {
289 dst = output(0)->get_buffer (nframes) + offset;
291 if (gain_coeff == 0.0f) {
293 /* only one output, and gain was zero, so make it silent */
295 memset (dst, 0, sizeof (Sample) * nframes);
297 } else if (gain_coeff == 1.0f){
299 /* mix all buffers into the output */
303 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
305 for (n = 1; n < nbufs; ++n) {
308 for (jack_nframes_t n = 0; n < nframes; ++n) {
313 output(0)->mark_silence (false);
317 /* mix all buffers into the output, scaling them all by the gain */
323 for (jack_nframes_t n = 0; n < nframes; ++n) {
324 dst[n] = src[n] * gain_coeff;
327 for (n = 1; n < nbufs; ++n) {
330 for (jack_nframes_t n = 0; n < nframes; ++n) {
331 dst[n] += src[n] * gain_coeff;
335 output(0)->mark_silence (false);
342 vector<Port *>::iterator out;
343 vector<Sample *>::iterator in;
344 Panner::iterator pan;
345 Sample* obufs[_noutputs];
347 /* the terrible silence ... */
349 /* XXX this is wasteful but i see no way to avoid it */
351 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
352 obufs[o] = (*out)->get_buffer (nframes) + offset;
353 memset (obufs[o], 0, sizeof (Sample) * nframes);
354 (*out)->mark_silence (false);
359 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
360 Panner::iterator tmp;
365 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
367 if (tmp != _panner->end()) {
374 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
376 /* io_lock, not taken: function must be called from Session::process() calltree */
378 if (_noutputs == 0) {
382 if (_panner->bypassed() || _panner->empty()) {
383 deliver_output_no_pan (bufs, nbufs, nframes, offset);
389 gain_t pangain = _gain;
392 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
402 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
407 /* simple, non-automation panning to outputs */
409 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
410 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
412 pan (bufs, nbufs, nframes, offset, pangain);
417 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
419 /* io_lock, not taken: function must be called from Session::process() calltree */
421 if (_noutputs == 0) {
426 gain_t old_gain = _gain;
428 if (apply_gain_automation) {
430 /* gain has already been applied by automation code. do nothing here except
439 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
451 vector<Port*>::iterator o;
452 vector<Sample*> outs;
456 /* unlikely condition */
457 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
458 outs.push_back ((*o)->get_buffer (nframes) + offset);
462 /* reduce nbufs to the index of the last input buffer */
466 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
467 actual_gain = _gain * speed_quietning;
472 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
474 dst = (*o)->get_buffer (nframes) + offset;
475 src = bufs[min(nbufs,i)];
477 if (dg != _gain || actual_gain == 1.0f) {
478 memcpy (dst, src, sizeof (Sample) * nframes);
479 } else if (actual_gain == 0.0f) {
480 memset (dst, 0, sizeof (Sample) * nframes);
482 for (jack_nframes_t x = 0; x < nframes; ++x) {
483 dst[x] = src[x] * actual_gain;
487 (*o)->mark_silence (false);
491 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
495 if (apply_gain_automation) {
501 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
503 /* io_lock, not taken: function must be called from Session::process() calltree */
505 vector<Port *>::iterator i;
509 /* we require that bufs.size() >= 1 */
511 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
512 if (i == _inputs.end()) {
516 /* XXX always read the full extent of the port buffer that
517 we need. One day, we may use jack_port_get_buffer_at_offset()
518 or something similar. For now, this simple hack will
521 Hack? Why yes .. we only need to read nframes-worth of
522 data, but the data we want is at `offset' within the
526 last = (*i)->get_buffer (nframes+offset) + offset;
527 // the dest buffer's offset has already been applied
528 memcpy (bufs[n], last, sizeof (Sample) * nframes);
531 /* fill any excess outputs with the last input */
533 while (n < nbufs && last) {
534 // the dest buffer's offset has already been applied
535 memcpy (bufs[n], last, sizeof (Sample) * nframes);
541 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
542 jack_nframes_t nframes, jack_nframes_t offset)
544 vector<Sample*>& bufs = _session.get_passthru_buffers ();
545 uint32_t nbufs = n_process_buffers ();
547 collect_input (bufs, nbufs, nframes, offset);
549 for (uint32_t n = 0; n < nbufs; ++n) {
550 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
555 IO::drop_input_connection ()
557 _input_connection = 0;
558 input_connection_configuration_connection.disconnect();
559 input_connection_connection_connection.disconnect();
560 _session.set_dirty ();
564 IO::drop_output_connection ()
566 _output_connection = 0;
567 output_connection_configuration_connection.disconnect();
568 output_connection_connection_connection.disconnect();
569 _session.set_dirty ();
573 IO::disconnect_input (Port* our_port, string other_port, void* src)
575 if (other_port.length() == 0 || our_port == 0) {
580 Glib::Mutex::Lock em (_session.engine().process_lock());
583 Glib::Mutex::Lock lm (io_lock);
585 /* check that our_port is really one of ours */
587 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
591 /* disconnect it from the source */
593 if (_session.engine().disconnect (other_port, our_port->name())) {
594 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
598 drop_input_connection();
602 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
603 _session.set_dirty ();
609 IO::connect_input (Port* our_port, string other_port, void* src)
611 if (other_port.length() == 0 || our_port == 0) {
616 Glib::Mutex::Lock em(_session.engine().process_lock());
619 Glib::Mutex::Lock lm (io_lock);
621 /* check that our_port is really one of ours */
623 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
627 /* connect it to the source */
629 if (_session.engine().connect (other_port, our_port->name())) {
633 drop_input_connection ();
637 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
638 _session.set_dirty ();
643 IO::disconnect_output (Port* our_port, string other_port, void* src)
645 if (other_port.length() == 0 || our_port == 0) {
650 Glib::Mutex::Lock em(_session.engine().process_lock());
653 Glib::Mutex::Lock lm (io_lock);
655 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
659 /* disconnect it from the destination */
661 if (_session.engine().disconnect (our_port->name(), other_port)) {
662 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
666 drop_output_connection ();
670 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
671 _session.set_dirty ();
676 IO::connect_output (Port* our_port, string other_port, void* src)
678 if (other_port.length() == 0 || our_port == 0) {
683 Glib::Mutex::Lock em(_session.engine().process_lock());
686 Glib::Mutex::Lock lm (io_lock);
688 /* check that our_port is really one of ours */
690 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
694 /* connect it to the destination */
696 if (_session.engine().connect (our_port->name(), other_port)) {
700 drop_output_connection ();
704 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
705 _session.set_dirty ();
710 IO::set_input (Port* other_port, void* src)
712 /* this removes all but one ports, and connects that one port
713 to the specified source.
716 if (_input_minimum > 1 || _input_minimum == 0) {
717 /* sorry, you can't do this */
721 if (other_port == 0) {
722 if (_input_minimum < 0) {
723 return ensure_inputs (0, false, true, src);
729 if (ensure_inputs (1, true, true, src)) {
733 return connect_input (_inputs.front(), other_port->name(), src);
737 IO::remove_output_port (Port* port, void* src)
739 IOChange change (NoChange);
742 Glib::Mutex::Lock em(_session.engine().process_lock());
745 Glib::Mutex::Lock lm (io_lock);
747 if (_noutputs - 1 == (uint32_t) _output_minimum) {
748 /* sorry, you can't do this */
752 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
754 change = IOChange (change|ConfigurationChanged);
755 if (port->connected()) {
756 change = IOChange (change|ConnectionsChanged);
759 _session.engine().unregister_port (*i);
762 drop_output_connection ();
768 if (change != NoChange) {
769 setup_peak_meters ();
775 if (change != NoChange) {
776 output_changed (change, src); /* EMIT SIGNAL */
777 _session.set_dirty ();
785 IO::add_output_port (string destination, void* src)
791 Glib::Mutex::Lock em(_session.engine().process_lock());
794 Glib::Mutex::Lock lm (io_lock);
796 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
800 /* Create a new output port */
802 if (_output_maximum == 1) {
803 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
805 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
808 if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) {
809 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
813 _outputs.push_back (our_port);
814 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
816 drop_output_connection ();
817 setup_peak_meters ();
821 MoreOutputs (_noutputs); /* EMIT SIGNAL */
824 if (destination.length()) {
825 if (_session.engine().connect (our_port->name(), destination)) {
830 // pan_changed (src); /* EMIT SIGNAL */
831 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
832 _session.set_dirty ();
837 IO::remove_input_port (Port* port, void* src)
839 IOChange change (NoChange);
842 Glib::Mutex::Lock em(_session.engine().process_lock());
845 Glib::Mutex::Lock lm (io_lock);
847 if (((int)_ninputs - 1) < _input_minimum) {
848 /* sorry, you can't do this */
851 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
854 change = IOChange (change|ConfigurationChanged);
856 if (port->connected()) {
857 change = IOChange (change|ConnectionsChanged);
860 _session.engine().unregister_port (*i);
863 drop_input_connection ();
869 if (change != NoChange) {
870 setup_peak_meters ();
876 if (change != NoChange) {
877 input_changed (change, src);
878 _session.set_dirty ();
886 IO::add_input_port (string source, void* src)
892 Glib::Mutex::Lock em (_session.engine().process_lock());
895 Glib::Mutex::Lock lm (io_lock);
897 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
901 /* Create a new input port */
903 if (_input_maximum == 1) {
904 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
906 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
909 if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) {
910 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
914 _inputs.push_back (our_port);
915 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
917 drop_input_connection ();
918 setup_peak_meters ();
922 MoreOutputs (_ninputs); /* EMIT SIGNAL */
925 if (source.length()) {
927 if (_session.engine().connect (source, our_port->name())) {
932 // pan_changed (src); /* EMIT SIGNAL */
933 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
934 _session.set_dirty ();
940 IO::disconnect_inputs (void* src)
943 Glib::Mutex::Lock em (_session.engine().process_lock());
946 Glib::Mutex::Lock lm (io_lock);
948 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
949 _session.engine().disconnect (*i);
952 drop_input_connection ();
955 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
960 IO::disconnect_outputs (void* src)
963 Glib::Mutex::Lock em (_session.engine().process_lock());
966 Glib::Mutex::Lock lm (io_lock);
968 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
969 _session.engine().disconnect (*i);
972 drop_output_connection ();
976 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
977 _session.set_dirty ();
982 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
985 bool changed = false;
986 bool reduced = false;
988 /* remove unused ports */
990 while (_ninputs > n) {
991 _session.engine().unregister_port (_inputs.back());
998 /* create any necessary new ports */
1000 while (_ninputs < n) {
1004 /* Create a new input port */
1006 if (_input_maximum == 1) {
1007 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1010 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1015 if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) {
1016 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1021 catch (AudioEngine::PortRegistrationFailure& err) {
1022 setup_peak_meters ();
1028 _inputs.push_back (input_port);
1029 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1035 drop_input_connection ();
1036 setup_peak_meters ();
1038 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1039 _session.set_dirty ();
1043 /* disconnect all existing ports so that we get a fresh start */
1045 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1046 _session.engine().disconnect (*i);
1054 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1056 bool in_changed = false;
1057 bool out_changed = false;
1058 bool in_reduced = false;
1059 bool out_reduced = false;
1060 bool need_pan_reset;
1062 if (_input_maximum >= 0) {
1063 nin = min (_input_maximum, (int) nin);
1066 if (_output_maximum >= 0) {
1067 nout = min (_output_maximum, (int) nout);
1070 if (nin == _ninputs && nout == _noutputs && !clear) {
1075 Glib::Mutex::Lock em (_session.engine().process_lock());
1076 Glib::Mutex::Lock lm (io_lock);
1080 if (_noutputs == nout) {
1081 need_pan_reset = false;
1083 need_pan_reset = true;
1086 /* remove unused ports */
1088 while (_ninputs > nin) {
1089 _session.engine().unregister_port (_inputs.back());
1096 while (_noutputs > nout) {
1097 _session.engine().unregister_port (_outputs.back());
1098 _outputs.pop_back();
1104 /* create any necessary new ports */
1106 while (_ninputs < nin) {
1110 /* Create a new input port */
1112 if (_input_maximum == 1) {
1113 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1116 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1120 if ((port = _session.engine().register_audio_input_port (buf)) == 0) {
1121 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1126 catch (AudioEngine::PortRegistrationFailure& err) {
1127 setup_peak_meters ();
1133 _inputs.push_back (port);
1138 /* create any necessary new ports */
1140 while (_noutputs < nout) {
1144 /* Create a new output port */
1146 if (_output_maximum == 1) {
1147 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1149 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1153 if ((port = _session.engine().register_audio_output_port (buf)) == 0) {
1154 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1159 catch (AudioEngine::PortRegistrationFailure& err) {
1160 setup_peak_meters ();
1166 _outputs.push_back (port);
1173 /* disconnect all existing ports so that we get a fresh start */
1175 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1176 _session.engine().disconnect (*i);
1179 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1180 _session.engine().disconnect (*i);
1184 if (in_changed || out_changed) {
1185 setup_peak_meters ();
1191 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1192 drop_output_connection ();
1193 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1197 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1198 drop_input_connection ();
1199 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1202 if (in_changed || out_changed) {
1203 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1204 _session.set_dirty ();
1211 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1213 bool changed = false;
1215 if (_input_maximum >= 0) {
1216 n = min (_input_maximum, (int) n);
1218 if (n == _ninputs && !clear) {
1224 Glib::Mutex::Lock em (_session.engine().process_lock());
1225 Glib::Mutex::Lock im (io_lock);
1226 changed = ensure_inputs_locked (n, clear, src);
1228 changed = ensure_inputs_locked (n, clear, src);
1232 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1233 _session.set_dirty ();
1240 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1243 bool changed = false;
1244 bool reduced = false;
1245 bool need_pan_reset;
1247 if (_noutputs == n) {
1248 need_pan_reset = false;
1250 need_pan_reset = true;
1253 /* remove unused ports */
1255 while (_noutputs > n) {
1257 _session.engine().unregister_port (_outputs.back());
1258 _outputs.pop_back();
1264 /* create any necessary new ports */
1266 while (_noutputs < n) {
1270 /* Create a new output port */
1272 if (_output_maximum == 1) {
1273 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1275 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1278 if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) {
1279 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1283 _outputs.push_back (output_port);
1284 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1287 setup_peak_meters ();
1289 if (need_pan_reset) {
1295 drop_output_connection ();
1296 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1297 _session.set_dirty ();
1301 /* disconnect all existing ports so that we get a fresh start */
1303 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1304 _session.engine().disconnect (*i);
1312 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1314 bool changed = false;
1316 if (_output_maximum >= 0) {
1317 n = min (_output_maximum, (int) n);
1318 if (n == _noutputs && !clear) {
1323 /* XXX caller should hold io_lock, but generally doesn't */
1326 Glib::Mutex::Lock em (_session.engine().process_lock());
1327 Glib::Mutex::Lock im (io_lock);
1328 changed = ensure_outputs_locked (n, clear, src);
1330 changed = ensure_outputs_locked (n, clear, src);
1334 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1341 IO::effective_gain () const
1343 if (gain_automation_playback()) {
1344 return _effective_gain;
1346 return _desired_gain;
1353 if (panners_legal) {
1354 if (!no_panner_reset) {
1355 _panner->reset (_noutputs, pans_required());
1358 panner_legal_c.disconnect ();
1359 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1364 IO::panners_became_legal ()
1366 _panner->reset (_noutputs, pans_required());
1367 _panner->load (); // automation
1368 panner_legal_c.disconnect ();
1373 IO::defer_pan_reset ()
1375 no_panner_reset = true;
1379 IO::allow_pan_reset ()
1381 no_panner_reset = false;
1387 IO::get_state (void)
1389 return state (true);
1393 IO::state (bool full_state)
1395 XMLNode* node = new XMLNode (state_node_name);
1398 bool need_ins = true;
1399 bool need_outs = true;
1400 LocaleGuard lg (X_("POSIX"));
1401 Glib::Mutex::Lock lm (io_lock);
1403 node->add_property("name", _name);
1405 node->add_property("id", buf);
1409 if (_input_connection) {
1410 node->add_property ("input-connection", _input_connection->name());
1414 if (_output_connection) {
1415 node->add_property ("output-connection", _output_connection->name());
1420 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1422 const char **connections = (*i)->get_connections();
1424 if (connections && connections[0]) {
1427 for (int n = 0; connections && connections[n]; ++n) {
1432 /* if its a connection to our own port,
1433 return only the port name, not the
1434 whole thing. this allows connections
1435 to be re-established even when our
1436 client name is different.
1439 str += _session.engine().make_port_name_relative (connections[n]);
1451 node->add_property ("inputs", str);
1457 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1459 const char **connections = (*i)->get_connections();
1461 if (connections && connections[0]) {
1465 for (int n = 0; connections[n]; ++n) {
1470 str += _session.engine().make_port_name_relative (connections[n]);
1482 node->add_property ("outputs", str);
1485 node->add_child_nocopy (_panner->state (full_state));
1487 snprintf (buf, sizeof(buf), "%2.12f", gain());
1488 node->add_property ("gain", buf);
1490 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1496 node->add_property ("iolimits", buf);
1501 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1503 /* never store anything except Off for automation state in a template */
1504 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1506 node->add_property ("automation-state", buf);
1507 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1508 node->add_property ("automation-style", buf);
1510 /* XXX same for pan etc. */
1516 IO::connecting_became_legal ()
1520 if (pending_state_node == 0) {
1521 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1526 connection_legal_c.disconnect ();
1528 ret = make_connections (*pending_state_node);
1531 delete pending_state_node;
1532 pending_state_node = 0;
1539 IO::ports_became_legal ()
1543 if (pending_state_node == 0) {
1544 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1549 port_legal_c.disconnect ();
1551 ret = create_ports (*pending_state_node);
1553 if (connecting_legal) {
1554 delete pending_state_node;
1555 pending_state_node = 0;
1562 IO::set_state (const XMLNode& node)
1564 const XMLProperty* prop;
1565 XMLNodeConstIterator iter;
1566 LocaleGuard lg (X_("POSIX"));
1568 /* force use of non-localized representation of decimal point,
1569 since we use it a lot in XML files and so forth.
1572 if (node.name() != state_node_name) {
1573 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1577 if ((prop = node.property ("name")) != 0) {
1578 _name = prop->value();
1579 _panner->set_name (_name);
1582 if ((prop = node.property ("id")) != 0) {
1583 _id = prop->value ();
1586 if ((prop = node.property ("iolimits")) != 0) {
1587 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1594 if ((prop = node.property ("gain")) != 0) {
1595 set_gain (atof (prop->value().c_str()), this);
1596 _gain = _desired_gain;
1599 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1600 if ((*iter)->name() == "Panner") {
1601 _panner->set_state (**iter);
1605 if ((prop = node.property ("automation-state")) != 0) {
1608 x = strtol (prop->value().c_str(), 0, 16);
1609 set_gain_automation_state (AutoState (x));
1612 if ((prop = node.property ("automation-style")) != 0) {
1615 x = strtol (prop->value().c_str(), 0, 16);
1616 set_gain_automation_style (AutoStyle (x));
1621 if (create_ports (node)) {
1627 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1630 if (panners_legal) {
1633 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1636 if (connecting_legal) {
1638 if (make_connections (node)) {
1644 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1647 if (!ports_legal || !connecting_legal) {
1648 pending_state_node = new XMLNode (node);
1655 IO::create_ports (const XMLNode& node)
1657 const XMLProperty* prop;
1659 int num_outputs = 0;
1661 if ((prop = node.property ("input-connection")) != 0) {
1663 Connection* c = _session.connection_by_name (prop->value());
1666 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1668 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1669 error << _("No input connections available as a replacement")
1673 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1678 num_inputs = c->nports();
1680 } else if ((prop = node.property ("inputs")) != 0) {
1682 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1685 if ((prop = node.property ("output-connection")) != 0) {
1686 Connection* c = _session.connection_by_name (prop->value());
1689 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1691 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1692 error << _("No output connections available as a replacement")
1696 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1701 num_outputs = c->nports ();
1703 } else if ((prop = node.property ("outputs")) != 0) {
1704 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1707 no_panner_reset = true;
1709 if (ensure_io (num_inputs, num_outputs, true, this)) {
1710 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1714 no_panner_reset = false;
1716 set_deferred_state ();
1724 IO::make_connections (const XMLNode& node)
1726 const XMLProperty* prop;
1728 if ((prop = node.property ("input-connection")) != 0) {
1729 Connection* c = _session.connection_by_name (prop->value());
1732 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1734 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1735 error << _("No input connections available as a replacement")
1739 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1744 use_input_connection (*c, this);
1746 } else if ((prop = node.property ("inputs")) != 0) {
1747 if (set_inputs (prop->value())) {
1748 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1753 if ((prop = node.property ("output-connection")) != 0) {
1754 Connection* c = _session.connection_by_name (prop->value());
1757 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1759 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1760 error << _("No output connections available as a replacement")
1764 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1769 use_output_connection (*c, this);
1771 } else if ((prop = node.property ("outputs")) != 0) {
1772 if (set_outputs (prop->value())) {
1773 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1782 IO::set_inputs (const string& str)
1784 vector<string> ports;
1789 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1793 if (ensure_inputs (nports, true, true, this)) {
1797 string::size_type start, end, ostart;
1804 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1807 if ((end = str.find_first_of ('}', start)) == string::npos) {
1808 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1812 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1813 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1819 for (int x = 0; x < n; ++x) {
1820 connect_input (input (i), ports[x], this);
1832 IO::set_outputs (const string& str)
1834 vector<string> ports;
1839 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1843 if (ensure_outputs (nports, true, true, this)) {
1847 string::size_type start, end, ostart;
1854 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1857 if ((end = str.find_first_of ('}', start)) == string::npos) {
1858 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1862 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1863 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1869 for (int x = 0; x < n; ++x) {
1870 connect_output (output (i), ports[x], this);
1882 IO::parse_io_string (const string& str, vector<string>& ports)
1884 string::size_type pos, opos;
1886 if (str.length() == 0) {
1895 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1896 ports.push_back (str.substr (opos, pos - opos));
1900 if (opos < str.length()) {
1901 ports.push_back (str.substr(opos));
1904 return ports.size();
1908 IO::parse_gain_string (const string& str, vector<string>& ports)
1910 string::size_type pos, opos;
1916 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1917 ports.push_back (str.substr (opos, pos - opos));
1921 if (opos < str.length()) {
1922 ports.push_back (str.substr(opos));
1925 return ports.size();
1929 IO::set_name (string name, void* src)
1931 if (name == _name) {
1935 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1936 string current_name = (*i)->short_name();
1937 current_name.replace (current_name.find (_name), _name.length(), name);
1938 (*i)->set_name (current_name);
1941 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1942 string current_name = (*i)->short_name();
1943 current_name.replace (current_name.find (_name), _name.length(), name);
1944 (*i)->set_name (current_name);
1948 name_changed (src); /* EMIT SIGNAL */
1954 IO::set_input_minimum (int n)
1960 IO::set_input_maximum (int n)
1966 IO::set_output_minimum (int n)
1968 _output_minimum = n;
1972 IO::set_output_maximum (int n)
1974 _output_maximum = n;
1978 IO::set_port_latency (jack_nframes_t nframes)
1980 Glib::Mutex::Lock lm (io_lock);
1982 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1983 (*i)->set_latency (nframes);
1988 IO::output_latency () const
1990 jack_nframes_t max_latency;
1991 jack_nframes_t latency;
1995 /* io lock not taken - must be protected by other means */
1997 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1998 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
1999 max_latency = latency;
2007 IO::input_latency () const
2009 jack_nframes_t max_latency;
2010 jack_nframes_t latency;
2014 /* io lock not taken - must be protected by other means */
2016 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2017 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2018 max_latency = latency;
2026 IO::use_input_connection (Connection& c, void* src)
2031 Glib::Mutex::Lock lm (_session.engine().process_lock());
2032 Glib::Mutex::Lock lm2 (io_lock);
2036 drop_input_connection ();
2038 if (ensure_inputs (limit, false, false, src)) {
2042 /* first pass: check the current state to see what's correctly
2043 connected, and drop anything that we don't want.
2046 for (uint32_t n = 0; n < limit; ++n) {
2047 const Connection::PortList& pl = c.port_connections (n);
2049 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2051 if (!_inputs[n]->connected_to ((*i))) {
2053 /* clear any existing connections */
2055 _session.engine().disconnect (_inputs[n]);
2057 } else if (_inputs[n]->connected() > 1) {
2059 /* OK, it is connected to the port we want,
2060 but its also connected to other ports.
2061 Change that situation.
2064 /* XXX could be optimized to not drop
2068 _session.engine().disconnect (_inputs[n]);
2074 /* second pass: connect all requested ports where necessary */
2076 for (uint32_t n = 0; n < limit; ++n) {
2077 const Connection::PortList& pl = c.port_connections (n);
2079 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2081 if (!_inputs[n]->connected_to ((*i))) {
2083 if (_session.engine().connect (*i, _inputs[n]->name())) {
2091 _input_connection = &c;
2093 input_connection_configuration_connection = c.ConfigurationChanged.connect
2094 (mem_fun (*this, &IO::input_connection_configuration_changed));
2095 input_connection_connection_connection = c.ConnectionsChanged.connect
2096 (mem_fun (*this, &IO::input_connection_connection_changed));
2099 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2104 IO::use_output_connection (Connection& c, void* src)
2109 Glib::Mutex::Lock lm (_session.engine().process_lock());
2110 Glib::Mutex::Lock lm2 (io_lock);
2114 drop_output_connection ();
2116 if (ensure_outputs (limit, false, false, src)) {
2120 /* first pass: check the current state to see what's correctly
2121 connected, and drop anything that we don't want.
2124 for (uint32_t n = 0; n < limit; ++n) {
2126 const Connection::PortList& pl = c.port_connections (n);
2128 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2130 if (!_outputs[n]->connected_to ((*i))) {
2132 /* clear any existing connections */
2134 _session.engine().disconnect (_outputs[n]);
2136 } else if (_outputs[n]->connected() > 1) {
2138 /* OK, it is connected to the port we want,
2139 but its also connected to other ports.
2140 Change that situation.
2143 /* XXX could be optimized to not drop
2147 _session.engine().disconnect (_outputs[n]);
2152 /* second pass: connect all requested ports where necessary */
2154 for (uint32_t n = 0; n < limit; ++n) {
2156 const Connection::PortList& pl = c.port_connections (n);
2158 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2160 if (!_outputs[n]->connected_to ((*i))) {
2162 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2169 _output_connection = &c;
2171 output_connection_configuration_connection = c.ConfigurationChanged.connect
2172 (mem_fun (*this, &IO::output_connection_configuration_changed));
2173 output_connection_connection_connection = c.ConnectionsChanged.connect
2174 (mem_fun (*this, &IO::output_connection_connection_changed));
2177 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2183 IO::disable_connecting ()
2185 connecting_legal = false;
2190 IO::enable_connecting ()
2192 connecting_legal = true;
2193 return ConnectingLegal ();
2197 IO::disable_ports ()
2199 ports_legal = false;
2207 return PortsLegal ();
2211 IO::disable_panners (void)
2213 panners_legal = false;
2218 IO::reset_panners ()
2220 panners_legal = true;
2221 return PannersLegal ();
2225 IO::input_connection_connection_changed (int ignored)
2227 use_input_connection (*_input_connection, this);
2231 IO::input_connection_configuration_changed ()
2233 use_input_connection (*_input_connection, this);
2237 IO::output_connection_connection_changed (int ignored)
2239 use_output_connection (*_output_connection, this);
2243 IO::output_connection_configuration_changed ()
2245 use_output_connection (*_output_connection, this);
2249 IO::GainControllable::set_value (float val)
2251 io.set_gain (direct_control_to_gain (val), this);
2255 IO::GainControllable::get_value (void) const
2257 return direct_gain_to_control (io.effective_gain());
2261 IO::reset_peak_meters ()
2263 uint32_t limit = max (_ninputs, _noutputs);
2265 for (uint32_t i = 0; i < limit; ++i) {
2271 IO::setup_peak_meters ()
2273 uint32_t limit = max (_ninputs, _noutputs);
2275 while (_peak_power.size() < limit) {
2276 _peak_power.push_back (0);
2277 _visible_peak_power.push_back (0);
2282 IO::get_memento() const
2284 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2288 IO::restore_state (StateManager::State& state)
2293 StateManager::State*
2294 IO::state_factory (std::string why) const
2296 StateManager::State* state = new StateManager::State (why);
2301 Update the peak meters.
2303 The meter signal lock is taken to prevent modification of the
2304 Meter signal while updating the meters, taking the meter signal
2305 lock prior to taking the io_lock ensures that all IO will remain
2306 valid while metering.
2311 Glib::Mutex::Lock guard (m_meter_signal_lock);
2319 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2320 uint32_t limit = max (_ninputs, _noutputs);
2322 for (uint32_t n = 0; n < limit; ++n) {
2324 /* XXX we should use atomic exchange here */
2326 /* grab peak since last read */
2328 float new_peak = _peak_power[n];
2331 /* compute new visible value using falloff */
2333 if (new_peak > 0.0) {
2334 new_peak = coefficient_to_dB (new_peak);
2336 new_peak = minus_infinity();
2339 if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2340 _visible_peak_power[n] = new_peak;
2343 new_peak = _visible_peak_power[n] - _session.meter_falloff();
2344 _visible_peak_power[n] = max (new_peak, -INFINITY);
2350 IO::save_automation (const string& path)
2355 fullpath = _session.automation_dir();
2358 out.open (fullpath.c_str());
2361 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2365 out << X_("version ") << current_automation_version_number << endl;
2367 /* XXX use apply_to_points to get thread safety */
2369 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2370 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2379 IO::load_automation (const string& path)
2384 uint32_t linecnt = 0;
2386 LocaleGuard lg (X_("POSIX"));
2388 fullpath = _session.automation_dir();
2391 in.open (fullpath.c_str());
2394 fullpath = _session.automation_dir();
2395 fullpath += _session.snap_name();
2398 in.open (fullpath.c_str());
2400 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2405 clear_automation ();
2407 while (in.getline (line, sizeof(line), '\n')) {
2409 jack_nframes_t when;
2412 if (++linecnt == 1) {
2413 if (memcmp (line, "version", 7) == 0) {
2414 if (sscanf (line, "version %f", &version) != 1) {
2415 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2419 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2423 if (version != current_automation_version_number) {
2424 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2431 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2432 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2438 _gain_automation_curve.add (when, value, true);
2448 /* older (pre-1.0) versions of ardour used this */
2452 warning << _("dubious automation event found (and ignored)") << endmsg;
2456 _gain_automation_curve.save_state (_("loaded from disk"));
2462 IO::clear_automation ()
2464 Glib::Mutex::Lock lm (automation_lock);
2465 _gain_automation_curve.clear ();
2466 _panner->clear_automation ();
2470 IO::set_gain_automation_state (AutoState state)
2472 bool changed = false;
2475 Glib::Mutex::Lock lm (automation_lock);
2477 if (state != _gain_automation_curve.automation_state()) {
2479 last_automation_snapshot = 0;
2480 _gain_automation_curve.set_automation_state (state);
2483 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2489 _session.set_dirty ();
2490 gain_automation_state_changed (); /* EMIT SIGNAL */
2495 IO::set_gain_automation_style (AutoStyle style)
2497 bool changed = false;
2500 Glib::Mutex::Lock lm (automation_lock);
2502 if (style != _gain_automation_curve.automation_style()) {
2504 _gain_automation_curve.set_automation_style (style);
2509 gain_automation_style_changed (); /* EMIT SIGNAL */
2513 IO::inc_gain (gain_t factor, void *src)
2515 if (_desired_gain == 0.0f)
2516 set_gain (0.000001f + (0.000001f * factor), src);
2518 set_gain (_desired_gain + (_desired_gain * factor), src);
2522 IO::set_gain (gain_t val, void *src)
2524 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2525 if (val>1.99526231f) val=1.99526231f;
2528 Glib::Mutex::Lock dm (declick_lock);
2529 _desired_gain = val;
2532 if (_session.transport_stopped()) {
2533 _effective_gain = val;
2538 _gain_control.Changed (); /* EMIT SIGNAL */
2540 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2541 _gain_automation_curve.add (_session.transport_frame(), val);
2545 _session.set_dirty();
2549 IO::start_gain_touch ()
2551 _gain_automation_curve.start_touch ();
2555 IO::end_gain_touch ()
2557 _gain_automation_curve.stop_touch ();
2561 IO::start_pan_touch (uint32_t which)
2563 if (which < _panner->size()) {
2564 (*_panner)[which]->automation().start_touch();
2569 IO::end_pan_touch (uint32_t which)
2571 if (which < _panner->size()) {
2572 (*_panner)[which]->automation().stop_touch();
2578 IO::automation_snapshot (jack_nframes_t now)
2580 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2582 if (gain_automation_recording()) {
2583 _gain_automation_curve.rt_add (now, gain());
2586 _panner->snapshot (now);
2588 last_automation_snapshot = now;
2593 IO::transport_stopped (jack_nframes_t frame)
2595 _gain_automation_curve.reposition_for_rt_add (frame);
2597 if (_gain_automation_curve.automation_state() != Off) {
2599 if (gain_automation_recording()) {
2600 _gain_automation_curve.save_state (_("automation write/touch"));
2603 /* the src=0 condition is a special signal to not propagate
2604 automation gain changes into the mix group when locating.
2607 set_gain (_gain_automation_curve.eval (frame), 0);
2610 _panner->transport_stopped (frame);
2614 IO::find_input_port_hole ()
2616 /* CALLER MUST HOLD IO LOCK */
2620 if (_inputs.empty()) {
2624 for (n = 1; n < UINT_MAX; ++n) {
2625 char buf[jack_port_name_size()];
2626 vector<Port*>::iterator i;
2628 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2630 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2631 if ((*i)->short_name() == buf) {
2636 if (i == _inputs.end()) {
2644 IO::find_output_port_hole ()
2646 /* CALLER MUST HOLD IO LOCK */
2650 if (_outputs.empty()) {
2654 for (n = 1; n < UINT_MAX; ++n) {
2655 char buf[jack_port_name_size()];
2656 vector<Port*>::iterator i;
2658 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2660 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2661 if ((*i)->short_name() == buf) {
2666 if (i == _outputs.end()) {