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.
27 #include <sigc++/bind.h>
29 #include <glibmm/thread.h>
31 #include <pbd/xml++.h>
33 #include <ardour/audioengine.h>
34 #include <ardour/io.h>
35 #include <ardour/port.h>
36 #include <ardour/connection.h>
37 #include <ardour/session.h>
38 #include <ardour/cycle_timer.h>
39 #include <ardour/panner.h>
40 #include <ardour/dB.h>
47 A bug in OS X's cmath that causes isnan() and isinf() to be
48 "undeclared". the following works around that
51 #if defined(__APPLE__) && defined(__MACH__)
52 extern "C" int isnan (double);
53 extern "C" int isinf (double);
58 using namespace ARDOUR;
62 static float current_automation_version_number = 1.0;
64 nframes_t IO::_automation_interval = 0;
65 const string IO::state_node_name = "IO";
66 bool IO::connecting_legal = false;
67 bool IO::ports_legal = false;
68 bool IO::panners_legal = false;
69 sigc::signal<void> IO::Meter;
70 sigc::signal<int> IO::ConnectingLegal;
71 sigc::signal<int> IO::PortsLegal;
72 sigc::signal<int> IO::PannersLegal;
73 sigc::signal<void,uint32_t> IO::MoreOutputs;
74 sigc::signal<int> IO::PortsCreated;
76 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
78 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
79 others can be imagined.
82 static gain_t direct_control_to_gain (double fract) {
83 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
84 /* this maxes at +6dB */
85 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
88 static double direct_gain_to_control (gain_t gain) {
89 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
90 if (gain == 0) return 0.0;
92 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
95 static bool sort_ports_by_name (Port* a, Port* b)
97 return a->name() < b->name();
101 /** @param default_type The type of port that will be created by ensure_io
102 * and friends if no type is explicitly requested (to avoid breakage).
104 IO::IO (Session& s, string name,
105 int input_min, int input_max, int output_min, int output_max,
106 DataType default_type)
109 _default_type(default_type),
110 _gain_control (X_("gaincontrol"), *this),
111 _gain_automation_curve (0.0, 2.0, 1.0),
112 _input_minimum (input_min),
113 _input_maximum (input_max),
114 _output_minimum (output_min),
115 _output_maximum (output_max)
117 _panner = new Panner (name, _session);
120 _input_connection = 0;
121 _output_connection = 0;
122 pending_state_node = 0;
125 no_panner_reset = false;
128 apply_gain_automation = false;
130 last_automation_snapshot = 0;
132 _gain_automation_state = Off;
133 _gain_automation_style = Absolute;
136 // IO::Meter is emitted from another thread so the
137 // Meter signal must be protected.
138 Glib::Mutex::Lock guard (m_meter_signal_lock);
139 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
146 Glib::Mutex::Lock guard (m_meter_signal_lock);
148 Glib::Mutex::Lock lm (io_lock);
149 vector<Port *>::iterator i;
151 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
152 _session.engine().unregister_port (*i);
155 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
156 _session.engine().unregister_port (*i);
159 m_meter_connection.disconnect();
163 IO::silence (nframes_t nframes, nframes_t offset)
165 /* io_lock, not taken: function must be called from Session::process() calltree */
167 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
168 (*i)->silence (nframes, offset);
173 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
175 nframes_t declick = min ((nframes_t)128, nframes);
178 double fractional_shift;
179 double fractional_pos;
180 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
182 if (nframes == 0) return;
184 fractional_shift = -1.0/declick;
186 if (target < initial) {
187 /* fade out: remove more and more of delta from initial */
188 delta = -(initial - target);
190 /* fade in: add more and more of delta from initial */
191 delta = target - initial;
194 for (uint32_t n = 0; n < nbufs; ++n) {
197 fractional_pos = 1.0;
199 for (nframes_t nx = 0; nx < declick; ++nx) {
200 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
201 fractional_pos += fractional_shift;
204 /* now ensure the rest of the buffer has the target value
205 applied, if necessary.
208 if (declick != nframes) {
211 if (invert_polarity) {
212 this_target = -target;
214 this_target = target;
217 if (this_target == 0.0) {
218 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
219 } else if (this_target != 1.0) {
220 for (nframes_t nx = declick; nx < nframes; ++nx) {
221 buffer[nx] *= this_target;
229 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
233 /* io_lock, not taken: function must be called from Session::process() calltree */
235 if (_noutputs == 0) {
239 if (_noutputs == 1) {
241 dst = output(0)->get_buffer (nframes) + offset;
243 for (uint32_t n = 0; n < nbufs; ++n) {
244 if (bufs[n] != dst) {
245 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
249 output(0)->mark_silence (false);
255 vector<Port *>::iterator out;
256 vector<Sample *>::iterator in;
257 Panner::iterator pan;
258 Sample* obufs[_noutputs];
260 /* the terrible silence ... */
262 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
263 obufs[o] = (*out)->get_buffer (nframes) + offset;
264 memset (obufs[o], 0, sizeof (Sample) * nframes);
265 (*out)->mark_silence (false);
270 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
271 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
276 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
281 /* io_lock, not taken: function must be called from Session::process() calltree */
283 if (_noutputs == 0) {
287 /* the panner can be empty if there are no inputs to the
288 route, but still outputs
291 if (_panner->bypassed() || _panner->empty()) {
292 deliver_output_no_pan (bufs, nbufs, nframes, offset);
296 if (_noutputs == 1) {
298 dst = output(0)->get_buffer (nframes) + offset;
300 if (gain_coeff == 0.0f) {
302 /* only one output, and gain was zero, so make it silent */
304 memset (dst, 0, sizeof (Sample) * nframes);
306 } else if (gain_coeff == 1.0f){
308 /* mix all buffers into the output */
312 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
314 for (n = 1; n < nbufs; ++n) {
317 for (nframes_t n = 0; n < nframes; ++n) {
322 output(0)->mark_silence (false);
326 /* mix all buffers into the output, scaling them all by the gain */
332 for (nframes_t n = 0; n < nframes; ++n) {
333 dst[n] = src[n] * gain_coeff;
336 for (n = 1; n < nbufs; ++n) {
339 for (nframes_t n = 0; n < nframes; ++n) {
340 dst[n] += src[n] * gain_coeff;
344 output(0)->mark_silence (false);
351 vector<Port *>::iterator out;
352 vector<Sample *>::iterator in;
353 Panner::iterator pan;
354 Sample* obufs[_noutputs];
356 /* the terrible silence ... */
358 /* XXX this is wasteful but i see no way to avoid it */
360 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
361 obufs[o] = (*out)->get_buffer (nframes) + offset;
362 memset (obufs[o], 0, sizeof (Sample) * nframes);
363 (*out)->mark_silence (false);
368 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
369 Panner::iterator tmp;
374 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
376 if (tmp != _panner->end()) {
383 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
385 /* io_lock, not taken: function must be called from Session::process() calltree */
387 if (_noutputs == 0) {
391 if (_panner->bypassed() || _panner->empty()) {
392 deliver_output_no_pan (bufs, nbufs, nframes, offset);
398 gain_t pangain = _gain;
401 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
411 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
416 /* simple, non-automation panning to outputs */
418 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
419 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
421 pan (bufs, nbufs, nframes, offset, pangain);
426 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
428 /* io_lock, not taken: function must be called from Session::process() calltree */
430 if (_noutputs == 0) {
435 gain_t old_gain = _gain;
437 if (apply_gain_automation) {
439 /* gain has already been applied by automation code. do nothing here except
448 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
460 vector<Port*>::iterator o;
461 vector<Sample*> outs;
465 /* unlikely condition */
466 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
467 outs.push_back ((*o)->get_buffer (nframes) + offset);
471 /* reduce nbufs to the index of the last input buffer */
475 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
476 actual_gain = _gain * speed_quietning;
481 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
483 dst = (*o)->get_buffer (nframes) + offset;
484 src = bufs[min(nbufs,i)];
486 if (dg != _gain || actual_gain == 1.0f) {
487 memcpy (dst, src, sizeof (Sample) * nframes);
488 } else if (actual_gain == 0.0f) {
489 memset (dst, 0, sizeof (Sample) * nframes);
491 for (nframes_t x = 0; x < nframes; ++x) {
492 dst[x] = src[x] * actual_gain;
496 (*o)->mark_silence (false);
500 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
504 if (apply_gain_automation) {
510 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
512 /* io_lock, not taken: function must be called from Session::process() calltree */
514 vector<Port *>::iterator i;
518 /* we require that bufs.size() >= 1 */
520 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
521 if (i == _inputs.end()) {
525 /* XXX always read the full extent of the port buffer that
526 we need. One day, we may use jack_port_get_buffer_at_offset()
527 or something similar. For now, this simple hack will
530 Hack? Why yes .. we only need to read nframes-worth of
531 data, but the data we want is at `offset' within the
535 last = (*i)->get_buffer (nframes+offset) + offset;
536 // the dest buffer's offset has already been applied
537 memcpy (bufs[n], last, sizeof (Sample) * nframes);
540 /* fill any excess outputs with the last input */
542 while (n < nbufs && last) {
543 // the dest buffer's offset has already been applied
544 memcpy (bufs[n], last, sizeof (Sample) * nframes);
550 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
551 nframes_t nframes, nframes_t offset)
553 vector<Sample*>& bufs = _session.get_passthru_buffers ();
554 uint32_t nbufs = n_process_buffers ();
556 collect_input (bufs, nbufs, nframes, offset);
558 for (uint32_t n = 0; n < nbufs; ++n) {
559 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
564 IO::drop_input_connection ()
566 _input_connection = 0;
567 input_connection_configuration_connection.disconnect();
568 input_connection_connection_connection.disconnect();
569 _session.set_dirty ();
573 IO::drop_output_connection ()
575 _output_connection = 0;
576 output_connection_configuration_connection.disconnect();
577 output_connection_connection_connection.disconnect();
578 _session.set_dirty ();
582 IO::disconnect_input (Port* our_port, string other_port, void* src)
584 if (other_port.length() == 0 || our_port == 0) {
589 Glib::Mutex::Lock em (_session.engine().process_lock());
592 Glib::Mutex::Lock lm (io_lock);
594 /* check that our_port is really one of ours */
596 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
600 /* disconnect it from the source */
602 if (_session.engine().disconnect (other_port, our_port->name())) {
603 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
607 drop_input_connection();
611 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
612 _session.set_dirty ();
618 IO::connect_input (Port* our_port, string other_port, void* src)
620 if (other_port.length() == 0 || our_port == 0) {
625 Glib::Mutex::Lock em(_session.engine().process_lock());
628 Glib::Mutex::Lock lm (io_lock);
630 /* check that our_port is really one of ours */
632 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
636 /* connect it to the source */
638 if (_session.engine().connect (other_port, our_port->name())) {
642 drop_input_connection ();
646 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
647 _session.set_dirty ();
652 IO::disconnect_output (Port* our_port, string other_port, void* src)
654 if (other_port.length() == 0 || our_port == 0) {
659 Glib::Mutex::Lock em(_session.engine().process_lock());
662 Glib::Mutex::Lock lm (io_lock);
664 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
668 /* disconnect it from the destination */
670 if (_session.engine().disconnect (our_port->name(), other_port)) {
671 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
675 drop_output_connection ();
679 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
680 _session.set_dirty ();
685 IO::connect_output (Port* our_port, string other_port, void* src)
687 if (other_port.length() == 0 || our_port == 0) {
692 Glib::Mutex::Lock em(_session.engine().process_lock());
695 Glib::Mutex::Lock lm (io_lock);
697 /* check that our_port is really one of ours */
699 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
703 /* connect it to the destination */
705 if (_session.engine().connect (our_port->name(), other_port)) {
709 drop_output_connection ();
713 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
714 _session.set_dirty ();
719 IO::set_input (Port* other_port, void* src)
721 /* this removes all but one ports, and connects that one port
722 to the specified source.
725 if (_input_minimum > 1 || _input_minimum == 0) {
726 /* sorry, you can't do this */
730 if (other_port == 0) {
731 if (_input_minimum < 0) {
732 return ensure_inputs (0, false, true, src);
738 if (ensure_inputs (1, true, true, src)) {
742 return connect_input (_inputs.front(), other_port->name(), src);
746 IO::remove_output_port (Port* port, void* src)
748 IOChange change (NoChange);
751 Glib::Mutex::Lock em(_session.engine().process_lock());
754 Glib::Mutex::Lock lm (io_lock);
756 if (_noutputs - 1 == (uint32_t) _output_minimum) {
757 /* sorry, you can't do this */
761 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
763 change = IOChange (change|ConfigurationChanged);
764 if (port->connected()) {
765 change = IOChange (change|ConnectionsChanged);
768 _session.engine().unregister_port (*i);
771 drop_output_connection ();
777 if (change != NoChange) {
778 setup_peak_meters ();
784 if (change != NoChange) {
785 output_changed (change, src); /* EMIT SIGNAL */
786 _session.set_dirty ();
793 /** Add an output port.
795 * @param destination Name of input port to connect new port to.
796 * @param src Source for emitted ConfigurationChanged signal.
797 * @param type Data type of port. Default value (NIL) will use this IO's default type.
800 IO::add_output_port (string destination, void* src, DataType type)
805 if (type == DataType::NIL)
806 type = _default_type;
809 Glib::Mutex::Lock em(_session.engine().process_lock());
812 Glib::Mutex::Lock lm (io_lock);
814 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
818 /* Create a new output port */
820 // FIXME: naming scheme for differently typed ports?
821 if (_output_maximum == 1) {
822 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
824 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
827 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
828 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
832 _outputs.push_back (our_port);
833 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
835 drop_output_connection ();
836 setup_peak_meters ();
840 MoreOutputs (_noutputs); /* EMIT SIGNAL */
843 if (destination.length()) {
844 if (_session.engine().connect (our_port->name(), destination)) {
849 // pan_changed (src); /* EMIT SIGNAL */
850 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
851 _session.set_dirty ();
856 IO::remove_input_port (Port* port, void* src)
858 IOChange change (NoChange);
861 Glib::Mutex::Lock em(_session.engine().process_lock());
864 Glib::Mutex::Lock lm (io_lock);
866 if (((int)_ninputs - 1) < _input_minimum) {
867 /* sorry, you can't do this */
870 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
873 change = IOChange (change|ConfigurationChanged);
875 if (port->connected()) {
876 change = IOChange (change|ConnectionsChanged);
879 _session.engine().unregister_port (*i);
882 drop_input_connection ();
888 if (change != NoChange) {
889 setup_peak_meters ();
895 if (change != NoChange) {
896 input_changed (change, src);
897 _session.set_dirty ();
905 /** Add an input port.
907 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
908 * @param destination Name of input port to connect new port to.
909 * @param src Source for emitted ConfigurationChanged signal.
912 IO::add_input_port (string source, void* src, DataType type)
917 if (type == DataType::NIL)
918 type = _default_type;
921 Glib::Mutex::Lock em (_session.engine().process_lock());
924 Glib::Mutex::Lock lm (io_lock);
926 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
930 /* Create a new input port */
932 // FIXME: naming scheme for differently typed ports?
933 if (_input_maximum == 1) {
934 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
936 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
939 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
940 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
944 _inputs.push_back (our_port);
945 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
947 drop_input_connection ();
948 setup_peak_meters ();
952 MoreOutputs (_ninputs); /* EMIT SIGNAL */
955 if (source.length()) {
957 if (_session.engine().connect (source, our_port->name())) {
962 // pan_changed (src); /* EMIT SIGNAL */
963 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
964 _session.set_dirty ();
970 IO::disconnect_inputs (void* src)
973 Glib::Mutex::Lock em (_session.engine().process_lock());
976 Glib::Mutex::Lock lm (io_lock);
978 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
979 _session.engine().disconnect (*i);
982 drop_input_connection ();
985 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
990 IO::disconnect_outputs (void* src)
993 Glib::Mutex::Lock em (_session.engine().process_lock());
996 Glib::Mutex::Lock lm (io_lock);
998 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
999 _session.engine().disconnect (*i);
1002 drop_output_connection ();
1006 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1007 _session.set_dirty ();
1012 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1015 bool changed = false;
1016 bool reduced = false;
1018 /* remove unused ports */
1020 while (_ninputs > n) {
1021 _session.engine().unregister_port (_inputs.back());
1028 /* create any necessary new ports */
1030 while (_ninputs < n) {
1034 /* Create a new input port (of the default type) */
1036 if (_input_maximum == 1) {
1037 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1040 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1045 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1046 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1051 catch (AudioEngine::PortRegistrationFailure& err) {
1052 setup_peak_meters ();
1058 _inputs.push_back (input_port);
1059 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1065 drop_input_connection ();
1066 setup_peak_meters ();
1068 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1069 _session.set_dirty ();
1073 /* disconnect all existing ports so that we get a fresh start */
1075 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1076 _session.engine().disconnect (*i);
1084 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1086 bool in_changed = false;
1087 bool out_changed = false;
1088 bool in_reduced = false;
1089 bool out_reduced = false;
1090 bool need_pan_reset;
1092 if (_input_maximum >= 0) {
1093 nin = min (_input_maximum, (int) nin);
1096 if (_output_maximum >= 0) {
1097 nout = min (_output_maximum, (int) nout);
1100 if (nin == _ninputs && nout == _noutputs && !clear) {
1105 Glib::Mutex::Lock em (_session.engine().process_lock());
1106 Glib::Mutex::Lock lm (io_lock);
1110 if (_noutputs == nout) {
1111 need_pan_reset = false;
1113 need_pan_reset = true;
1116 /* remove unused ports */
1118 while (_ninputs > nin) {
1119 _session.engine().unregister_port (_inputs.back());
1126 while (_noutputs > nout) {
1127 _session.engine().unregister_port (_outputs.back());
1128 _outputs.pop_back();
1134 /* create any necessary new ports (of the default type) */
1136 while (_ninputs < nin) {
1140 /* Create a new input port */
1142 if (_input_maximum == 1) {
1143 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1146 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1150 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1151 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1156 catch (AudioEngine::PortRegistrationFailure& err) {
1157 setup_peak_meters ();
1163 _inputs.push_back (port);
1168 /* create any necessary new ports */
1170 while (_noutputs < nout) {
1174 /* Create a new output port */
1176 if (_output_maximum == 1) {
1177 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1179 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1183 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1184 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1189 catch (AudioEngine::PortRegistrationFailure& err) {
1190 setup_peak_meters ();
1196 _outputs.push_back (port);
1203 /* disconnect all existing ports so that we get a fresh start */
1205 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1206 _session.engine().disconnect (*i);
1209 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1210 _session.engine().disconnect (*i);
1214 if (in_changed || out_changed) {
1215 setup_peak_meters ();
1221 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1222 drop_output_connection ();
1223 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1227 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1228 drop_input_connection ();
1229 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1232 if (in_changed || out_changed) {
1233 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1234 _session.set_dirty ();
1241 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1243 bool changed = false;
1245 if (_input_maximum >= 0) {
1246 n = min (_input_maximum, (int) n);
1248 if (n == _ninputs && !clear) {
1254 Glib::Mutex::Lock em (_session.engine().process_lock());
1255 Glib::Mutex::Lock im (io_lock);
1256 changed = ensure_inputs_locked (n, clear, src);
1258 changed = ensure_inputs_locked (n, clear, src);
1262 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1263 _session.set_dirty ();
1270 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1273 bool changed = false;
1274 bool reduced = false;
1275 bool need_pan_reset;
1277 if (_noutputs == n) {
1278 need_pan_reset = false;
1280 need_pan_reset = true;
1283 /* remove unused ports */
1285 while (_noutputs > n) {
1287 _session.engine().unregister_port (_outputs.back());
1288 _outputs.pop_back();
1294 /* create any necessary new ports */
1296 while (_noutputs < n) {
1300 /* Create a new output port */
1302 if (_output_maximum == 1) {
1303 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1305 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1308 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1309 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1313 _outputs.push_back (output_port);
1314 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1317 setup_peak_meters ();
1319 if (need_pan_reset) {
1325 drop_output_connection ();
1326 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1327 _session.set_dirty ();
1331 /* disconnect all existing ports so that we get a fresh start */
1333 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1334 _session.engine().disconnect (*i);
1342 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1344 bool changed = false;
1346 if (_output_maximum >= 0) {
1347 n = min (_output_maximum, (int) n);
1348 if (n == _noutputs && !clear) {
1353 /* XXX caller should hold io_lock, but generally doesn't */
1356 Glib::Mutex::Lock em (_session.engine().process_lock());
1357 Glib::Mutex::Lock im (io_lock);
1358 changed = ensure_outputs_locked (n, clear, src);
1360 changed = ensure_outputs_locked (n, clear, src);
1364 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1371 IO::effective_gain () const
1373 if (gain_automation_playback()) {
1374 return _effective_gain;
1376 return _desired_gain;
1383 if (panners_legal) {
1384 if (!no_panner_reset) {
1385 _panner->reset (_noutputs, pans_required());
1388 panner_legal_c.disconnect ();
1389 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1394 IO::panners_became_legal ()
1396 _panner->reset (_noutputs, pans_required());
1397 _panner->load (); // automation
1398 panner_legal_c.disconnect ();
1403 IO::defer_pan_reset ()
1405 no_panner_reset = true;
1409 IO::allow_pan_reset ()
1411 no_panner_reset = false;
1417 IO::get_state (void)
1419 return state (true);
1423 IO::state (bool full_state)
1425 XMLNode* node = new XMLNode (state_node_name);
1428 bool need_ins = true;
1429 bool need_outs = true;
1430 LocaleGuard lg (X_("POSIX"));
1431 Glib::Mutex::Lock lm (io_lock);
1433 node->add_property("name", _name);
1434 id().print (buf, sizeof (buf));
1435 node->add_property("id", buf);
1439 if (_input_connection) {
1440 node->add_property ("input-connection", _input_connection->name());
1444 if (_output_connection) {
1445 node->add_property ("output-connection", _output_connection->name());
1450 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1452 const char **connections = (*i)->get_connections();
1454 if (connections && connections[0]) {
1457 for (int n = 0; connections && connections[n]; ++n) {
1462 /* if its a connection to our own port,
1463 return only the port name, not the
1464 whole thing. this allows connections
1465 to be re-established even when our
1466 client name is different.
1469 str += _session.engine().make_port_name_relative (connections[n]);
1481 node->add_property ("inputs", str);
1487 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1489 const char **connections = (*i)->get_connections();
1491 if (connections && connections[0]) {
1495 for (int n = 0; connections[n]; ++n) {
1500 str += _session.engine().make_port_name_relative (connections[n]);
1512 node->add_property ("outputs", str);
1515 node->add_child_nocopy (_panner->state (full_state));
1516 node->add_child_nocopy (_gain_control.get_state ());
1518 snprintf (buf, sizeof(buf), "%2.12f", gain());
1519 node->add_property ("gain", buf);
1521 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1527 node->add_property ("iolimits", buf);
1532 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1534 /* never store anything except Off for automation state in a template */
1535 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1537 node->add_property ("automation-state", buf);
1538 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1539 node->add_property ("automation-style", buf);
1541 /* XXX same for pan etc. */
1547 IO::connecting_became_legal ()
1551 if (pending_state_node == 0) {
1552 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1557 connection_legal_c.disconnect ();
1559 ret = make_connections (*pending_state_node);
1562 delete pending_state_node;
1563 pending_state_node = 0;
1570 IO::ports_became_legal ()
1574 if (pending_state_node == 0) {
1575 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1580 port_legal_c.disconnect ();
1582 ret = create_ports (*pending_state_node);
1584 if (connecting_legal) {
1585 delete pending_state_node;
1586 pending_state_node = 0;
1593 IO::set_state (const XMLNode& node)
1595 const XMLProperty* prop;
1596 XMLNodeConstIterator iter;
1597 LocaleGuard lg (X_("POSIX"));
1599 /* force use of non-localized representation of decimal point,
1600 since we use it a lot in XML files and so forth.
1603 if (node.name() != state_node_name) {
1604 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1608 if ((prop = node.property ("name")) != 0) {
1609 _name = prop->value();
1610 _panner->set_name (_name);
1613 if ((prop = node.property ("id")) != 0) {
1614 _id = prop->value ();
1617 if ((prop = node.property ("iolimits")) != 0) {
1618 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1625 if ((prop = node.property ("gain")) != 0) {
1626 set_gain (atof (prop->value().c_str()), this);
1627 _gain = _desired_gain;
1630 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1632 if ((*iter)->name() == "Panner") {
1633 _panner->set_state (**iter);
1636 if ((*iter)->name() == X_("gaincontrol")) {
1637 _gain_control.set_state (**iter);
1638 _session.add_controllable (&_gain_control);
1642 if ((prop = node.property ("automation-state")) != 0) {
1645 x = strtol (prop->value().c_str(), 0, 16);
1646 set_gain_automation_state (AutoState (x));
1649 if ((prop = node.property ("automation-style")) != 0) {
1652 x = strtol (prop->value().c_str(), 0, 16);
1653 set_gain_automation_style (AutoStyle (x));
1658 if (create_ports (node)) {
1664 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1667 if (panners_legal) {
1670 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1673 if (connecting_legal) {
1675 if (make_connections (node)) {
1681 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1684 if (!ports_legal || !connecting_legal) {
1685 pending_state_node = new XMLNode (node);
1692 IO::create_ports (const XMLNode& node)
1694 const XMLProperty* prop;
1696 int num_outputs = 0;
1698 if ((prop = node.property ("input-connection")) != 0) {
1700 Connection* c = _session.connection_by_name (prop->value());
1703 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1705 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1706 error << _("No input connections available as a replacement")
1710 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1715 num_inputs = c->nports();
1717 } else if ((prop = node.property ("inputs")) != 0) {
1719 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1722 if ((prop = node.property ("output-connection")) != 0) {
1723 Connection* c = _session.connection_by_name (prop->value());
1726 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1728 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1729 error << _("No output connections available as a replacement")
1733 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1738 num_outputs = c->nports ();
1740 } else if ((prop = node.property ("outputs")) != 0) {
1741 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1744 no_panner_reset = true;
1746 if (ensure_io (num_inputs, num_outputs, true, this)) {
1747 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1751 no_panner_reset = false;
1753 set_deferred_state ();
1761 IO::make_connections (const XMLNode& node)
1763 const XMLProperty* prop;
1765 if ((prop = node.property ("input-connection")) != 0) {
1766 Connection* c = _session.connection_by_name (prop->value());
1769 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1771 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1772 error << _("No input connections available as a replacement")
1776 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1781 use_input_connection (*c, this);
1783 } else if ((prop = node.property ("inputs")) != 0) {
1784 if (set_inputs (prop->value())) {
1785 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1790 if ((prop = node.property ("output-connection")) != 0) {
1791 Connection* c = _session.connection_by_name (prop->value());
1794 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1796 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1797 error << _("No output connections available as a replacement")
1801 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1806 use_output_connection (*c, this);
1808 } else if ((prop = node.property ("outputs")) != 0) {
1809 if (set_outputs (prop->value())) {
1810 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1819 IO::set_inputs (const string& str)
1821 vector<string> ports;
1826 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1830 if (ensure_inputs (nports, true, true, this)) {
1834 string::size_type start, end, ostart;
1841 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1844 if ((end = str.find_first_of ('}', start)) == string::npos) {
1845 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1849 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1850 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1856 for (int x = 0; x < n; ++x) {
1857 connect_input (input (i), ports[x], this);
1869 IO::set_outputs (const string& str)
1871 vector<string> ports;
1876 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1880 if (ensure_outputs (nports, true, true, this)) {
1884 string::size_type start, end, ostart;
1891 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1894 if ((end = str.find_first_of ('}', start)) == string::npos) {
1895 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1899 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1900 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1906 for (int x = 0; x < n; ++x) {
1907 connect_output (output (i), ports[x], this);
1919 IO::parse_io_string (const string& str, vector<string>& ports)
1921 string::size_type pos, opos;
1923 if (str.length() == 0) {
1932 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1933 ports.push_back (str.substr (opos, pos - opos));
1937 if (opos < str.length()) {
1938 ports.push_back (str.substr(opos));
1941 return ports.size();
1945 IO::parse_gain_string (const string& str, vector<string>& ports)
1947 string::size_type pos, opos;
1953 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1954 ports.push_back (str.substr (opos, pos - opos));
1958 if (opos < str.length()) {
1959 ports.push_back (str.substr(opos));
1962 return ports.size();
1966 IO::set_name (string name, void* src)
1968 if (name == _name) {
1972 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1973 string current_name = (*i)->short_name();
1974 current_name.replace (current_name.find (_name), _name.length(), name);
1975 (*i)->set_name (current_name);
1978 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1979 string current_name = (*i)->short_name();
1980 current_name.replace (current_name.find (_name), _name.length(), name);
1981 (*i)->set_name (current_name);
1985 name_changed (src); /* EMIT SIGNAL */
1991 IO::set_input_minimum (int n)
1997 IO::set_input_maximum (int n)
2003 IO::set_output_minimum (int n)
2005 _output_minimum = n;
2009 IO::set_output_maximum (int n)
2011 _output_maximum = n;
2015 IO::set_port_latency (nframes_t nframes)
2017 Glib::Mutex::Lock lm (io_lock);
2019 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2020 (*i)->set_latency (nframes);
2025 IO::output_latency () const
2027 nframes_t max_latency;
2032 /* io lock not taken - must be protected by other means */
2034 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2035 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2036 max_latency = latency;
2044 IO::input_latency () const
2046 nframes_t max_latency;
2051 /* io lock not taken - must be protected by other means */
2053 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2054 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2055 max_latency = latency;
2063 IO::use_input_connection (Connection& c, void* src)
2068 Glib::Mutex::Lock lm (_session.engine().process_lock());
2069 Glib::Mutex::Lock lm2 (io_lock);
2073 drop_input_connection ();
2075 if (ensure_inputs (limit, false, false, src)) {
2079 /* first pass: check the current state to see what's correctly
2080 connected, and drop anything that we don't want.
2083 for (uint32_t n = 0; n < limit; ++n) {
2084 const Connection::PortList& pl = c.port_connections (n);
2086 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2088 if (!_inputs[n]->connected_to ((*i))) {
2090 /* clear any existing connections */
2092 _session.engine().disconnect (_inputs[n]);
2094 } else if (_inputs[n]->connected() > 1) {
2096 /* OK, it is connected to the port we want,
2097 but its also connected to other ports.
2098 Change that situation.
2101 /* XXX could be optimized to not drop
2105 _session.engine().disconnect (_inputs[n]);
2111 /* second pass: connect all requested ports where necessary */
2113 for (uint32_t n = 0; n < limit; ++n) {
2114 const Connection::PortList& pl = c.port_connections (n);
2116 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2118 if (!_inputs[n]->connected_to ((*i))) {
2120 if (_session.engine().connect (*i, _inputs[n]->name())) {
2128 _input_connection = &c;
2130 input_connection_configuration_connection = c.ConfigurationChanged.connect
2131 (mem_fun (*this, &IO::input_connection_configuration_changed));
2132 input_connection_connection_connection = c.ConnectionsChanged.connect
2133 (mem_fun (*this, &IO::input_connection_connection_changed));
2136 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2141 IO::use_output_connection (Connection& c, void* src)
2146 Glib::Mutex::Lock lm (_session.engine().process_lock());
2147 Glib::Mutex::Lock lm2 (io_lock);
2151 drop_output_connection ();
2153 if (ensure_outputs (limit, false, false, src)) {
2157 /* first pass: check the current state to see what's correctly
2158 connected, and drop anything that we don't want.
2161 for (uint32_t n = 0; n < limit; ++n) {
2163 const Connection::PortList& pl = c.port_connections (n);
2165 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2167 if (!_outputs[n]->connected_to ((*i))) {
2169 /* clear any existing connections */
2171 _session.engine().disconnect (_outputs[n]);
2173 } else if (_outputs[n]->connected() > 1) {
2175 /* OK, it is connected to the port we want,
2176 but its also connected to other ports.
2177 Change that situation.
2180 /* XXX could be optimized to not drop
2184 _session.engine().disconnect (_outputs[n]);
2189 /* second pass: connect all requested ports where necessary */
2191 for (uint32_t n = 0; n < limit; ++n) {
2193 const Connection::PortList& pl = c.port_connections (n);
2195 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2197 if (!_outputs[n]->connected_to ((*i))) {
2199 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2206 _output_connection = &c;
2208 output_connection_configuration_connection = c.ConfigurationChanged.connect
2209 (mem_fun (*this, &IO::output_connection_configuration_changed));
2210 output_connection_connection_connection = c.ConnectionsChanged.connect
2211 (mem_fun (*this, &IO::output_connection_connection_changed));
2214 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2220 IO::disable_connecting ()
2222 connecting_legal = false;
2227 IO::enable_connecting ()
2229 connecting_legal = true;
2230 return ConnectingLegal ();
2234 IO::disable_ports ()
2236 ports_legal = false;
2244 return PortsLegal ();
2248 IO::disable_panners (void)
2250 panners_legal = false;
2255 IO::reset_panners ()
2257 panners_legal = true;
2258 return PannersLegal ();
2262 IO::input_connection_connection_changed (int ignored)
2264 use_input_connection (*_input_connection, this);
2268 IO::input_connection_configuration_changed ()
2270 use_input_connection (*_input_connection, this);
2274 IO::output_connection_connection_changed (int ignored)
2276 use_output_connection (*_output_connection, this);
2280 IO::output_connection_configuration_changed ()
2282 use_output_connection (*_output_connection, this);
2286 IO::GainControllable::set_value (float val)
2288 io.set_gain (direct_control_to_gain (val), this);
2292 IO::GainControllable::get_value (void) const
2294 return direct_gain_to_control (io.effective_gain());
2298 IO::reset_peak_meters ()
2300 uint32_t limit = max (_ninputs, _noutputs);
2302 for (uint32_t i = 0; i < limit; ++i) {
2308 IO::setup_peak_meters ()
2310 uint32_t limit = max (_ninputs, _noutputs);
2312 while (_peak_power.size() < limit) {
2313 _peak_power.push_back (0);
2314 _visible_peak_power.push_back (0);
2319 IO::get_memento() const
2321 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2325 IO::restore_state (StateManager::State& state)
2330 StateManager::State*
2331 IO::state_factory (std::string why) const
2333 StateManager::State* state = new StateManager::State (why);
2338 Update the peak meters.
2340 The meter signal lock is taken to prevent modification of the
2341 Meter signal while updating the meters, taking the meter signal
2342 lock prior to taking the io_lock ensures that all IO will remain
2343 valid while metering.
2348 Glib::Mutex::Lock guard (m_meter_signal_lock);
2356 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2357 uint32_t limit = max (_ninputs, _noutputs);
2359 for (uint32_t n = 0; n < limit; ++n) {
2361 /* XXX we should use atomic exchange here */
2363 /* grab peak since last read */
2365 float new_peak = _peak_power[n];
2368 /* compute new visible value using falloff */
2370 if (new_peak > 0.0) {
2371 new_peak = coefficient_to_dB (new_peak);
2373 new_peak = minus_infinity();
2376 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2377 _visible_peak_power[n] = new_peak;
2380 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2381 _visible_peak_power[n] = max (new_peak, -INFINITY);
2387 IO::save_automation (const string& path)
2392 fullpath = _session.automation_dir();
2395 out.open (fullpath.c_str());
2398 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2402 out << X_("version ") << current_automation_version_number << endl;
2404 /* XXX use apply_to_points to get thread safety */
2406 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2407 out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2416 IO::load_automation (const string& path)
2421 uint32_t linecnt = 0;
2423 LocaleGuard lg (X_("POSIX"));
2425 fullpath = _session.automation_dir();
2428 in.open (fullpath.c_str());
2431 fullpath = _session.automation_dir();
2432 fullpath += _session.snap_name();
2435 in.open (fullpath.c_str());
2437 error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
2442 clear_automation ();
2444 while (in.getline (line, sizeof(line), '\n')) {
2449 if (++linecnt == 1) {
2450 if (memcmp (line, "version", 7) == 0) {
2451 if (sscanf (line, "version %f", &version) != 1) {
2452 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2456 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2460 if (version != current_automation_version_number) {
2461 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2468 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2469 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2475 _gain_automation_curve.add (when, value, true);
2485 /* older (pre-1.0) versions of ardour used this */
2489 warning << _("dubious automation event found (and ignored)") << endmsg;
2493 _gain_automation_curve.save_state (_("loaded from disk"));
2499 IO::clear_automation ()
2501 Glib::Mutex::Lock lm (automation_lock);
2502 _gain_automation_curve.clear ();
2503 _panner->clear_automation ();
2507 IO::set_gain_automation_state (AutoState state)
2509 bool changed = false;
2512 Glib::Mutex::Lock lm (automation_lock);
2514 if (state != _gain_automation_curve.automation_state()) {
2516 last_automation_snapshot = 0;
2517 _gain_automation_curve.set_automation_state (state);
2520 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2526 _session.set_dirty ();
2527 gain_automation_state_changed (); /* EMIT SIGNAL */
2532 IO::set_gain_automation_style (AutoStyle style)
2534 bool changed = false;
2537 Glib::Mutex::Lock lm (automation_lock);
2539 if (style != _gain_automation_curve.automation_style()) {
2541 _gain_automation_curve.set_automation_style (style);
2546 gain_automation_style_changed (); /* EMIT SIGNAL */
2550 IO::inc_gain (gain_t factor, void *src)
2552 if (_desired_gain == 0.0f)
2553 set_gain (0.000001f + (0.000001f * factor), src);
2555 set_gain (_desired_gain + (_desired_gain * factor), src);
2559 IO::set_gain (gain_t val, void *src)
2561 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2562 if (val>1.99526231f) val=1.99526231f;
2565 Glib::Mutex::Lock dm (declick_lock);
2566 _desired_gain = val;
2569 if (_session.transport_stopped()) {
2570 _effective_gain = val;
2575 _gain_control.Changed (); /* EMIT SIGNAL */
2577 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2578 _gain_automation_curve.add (_session.transport_frame(), val);
2582 _session.set_dirty();
2586 IO::start_gain_touch ()
2588 _gain_automation_curve.start_touch ();
2592 IO::end_gain_touch ()
2594 _gain_automation_curve.stop_touch ();
2598 IO::start_pan_touch (uint32_t which)
2600 if (which < _panner->size()) {
2601 (*_panner)[which]->automation().start_touch();
2606 IO::end_pan_touch (uint32_t which)
2608 if (which < _panner->size()) {
2609 (*_panner)[which]->automation().stop_touch();
2615 IO::automation_snapshot (nframes_t now)
2617 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2619 if (gain_automation_recording()) {
2620 _gain_automation_curve.rt_add (now, gain());
2623 _panner->snapshot (now);
2625 last_automation_snapshot = now;
2630 IO::transport_stopped (nframes_t frame)
2632 _gain_automation_curve.reposition_for_rt_add (frame);
2634 if (_gain_automation_curve.automation_state() != Off) {
2636 if (gain_automation_recording()) {
2637 _gain_automation_curve.save_state (_("automation write/touch"));
2640 /* the src=0 condition is a special signal to not propagate
2641 automation gain changes into the mix group when locating.
2644 set_gain (_gain_automation_curve.eval (frame), 0);
2647 _panner->transport_stopped (frame);
2651 IO::find_input_port_hole ()
2653 /* CALLER MUST HOLD IO LOCK */
2657 if (_inputs.empty()) {
2661 for (n = 1; n < UINT_MAX; ++n) {
2662 char buf[jack_port_name_size()];
2663 vector<Port*>::iterator i;
2665 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2667 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2668 if ((*i)->short_name() == buf) {
2673 if (i == _inputs.end()) {
2681 IO::find_output_port_hole ()
2683 /* CALLER MUST HOLD IO LOCK */
2687 if (_outputs.empty()) {
2691 for (n = 1; n < UINT_MAX; ++n) {
2692 char buf[jack_port_name_size()];
2693 vector<Port*>::iterator i;
2695 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2697 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2698 if ((*i)->short_name() == buf) {
2703 if (i == _outputs.end()) {