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 (*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);
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));
1517 snprintf (buf, sizeof(buf), "%2.12f", gain());
1518 node->add_property ("gain", buf);
1520 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1526 node->add_property ("iolimits", buf);
1531 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1533 /* never store anything except Off for automation state in a template */
1534 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1536 node->add_property ("automation-state", buf);
1537 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1538 node->add_property ("automation-style", buf);
1540 /* XXX same for pan etc. */
1546 IO::connecting_became_legal ()
1550 if (pending_state_node == 0) {
1551 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1556 connection_legal_c.disconnect ();
1558 ret = make_connections (*pending_state_node);
1561 delete pending_state_node;
1562 pending_state_node = 0;
1569 IO::ports_became_legal ()
1573 if (pending_state_node == 0) {
1574 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1579 port_legal_c.disconnect ();
1581 ret = create_ports (*pending_state_node);
1583 if (connecting_legal) {
1584 delete pending_state_node;
1585 pending_state_node = 0;
1592 IO::set_state (const XMLNode& node)
1594 const XMLProperty* prop;
1595 XMLNodeConstIterator iter;
1596 LocaleGuard lg (X_("POSIX"));
1598 /* force use of non-localized representation of decimal point,
1599 since we use it a lot in XML files and so forth.
1602 if (node.name() != state_node_name) {
1603 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1607 if ((prop = node.property ("name")) != 0) {
1608 _name = prop->value();
1609 _panner->set_name (_name);
1612 if ((prop = node.property ("id")) != 0) {
1613 _id = prop->value ();
1616 if ((prop = node.property ("iolimits")) != 0) {
1617 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1624 if ((prop = node.property ("gain")) != 0) {
1625 set_gain (atof (prop->value().c_str()), this);
1626 _gain = _desired_gain;
1629 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1630 if ((*iter)->name() == "Panner") {
1631 _panner->set_state (**iter);
1635 if ((prop = node.property ("automation-state")) != 0) {
1638 x = strtol (prop->value().c_str(), 0, 16);
1639 set_gain_automation_state (AutoState (x));
1642 if ((prop = node.property ("automation-style")) != 0) {
1645 x = strtol (prop->value().c_str(), 0, 16);
1646 set_gain_automation_style (AutoStyle (x));
1651 if (create_ports (node)) {
1657 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1660 if (panners_legal) {
1663 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1666 if (connecting_legal) {
1668 if (make_connections (node)) {
1674 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1677 if (!ports_legal || !connecting_legal) {
1678 pending_state_node = new XMLNode (node);
1685 IO::create_ports (const XMLNode& node)
1687 const XMLProperty* prop;
1689 int num_outputs = 0;
1691 if ((prop = node.property ("input-connection")) != 0) {
1693 Connection* c = _session.connection_by_name (prop->value());
1696 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1698 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1699 error << _("No input connections available as a replacement")
1703 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1708 num_inputs = c->nports();
1710 } else if ((prop = node.property ("inputs")) != 0) {
1712 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1715 if ((prop = node.property ("output-connection")) != 0) {
1716 Connection* c = _session.connection_by_name (prop->value());
1719 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1721 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1722 error << _("No output connections available as a replacement")
1726 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1731 num_outputs = c->nports ();
1733 } else if ((prop = node.property ("outputs")) != 0) {
1734 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1737 no_panner_reset = true;
1739 if (ensure_io (num_inputs, num_outputs, true, this)) {
1740 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1744 no_panner_reset = false;
1746 set_deferred_state ();
1754 IO::make_connections (const XMLNode& node)
1756 const XMLProperty* prop;
1758 if ((prop = node.property ("input-connection")) != 0) {
1759 Connection* c = _session.connection_by_name (prop->value());
1762 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1764 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1765 error << _("No input connections available as a replacement")
1769 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1774 use_input_connection (*c, this);
1776 } else if ((prop = node.property ("inputs")) != 0) {
1777 if (set_inputs (prop->value())) {
1778 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1783 if ((prop = node.property ("output-connection")) != 0) {
1784 Connection* c = _session.connection_by_name (prop->value());
1787 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1789 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1790 error << _("No output connections available as a replacement")
1794 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1799 use_output_connection (*c, this);
1801 } else if ((prop = node.property ("outputs")) != 0) {
1802 if (set_outputs (prop->value())) {
1803 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1812 IO::set_inputs (const string& str)
1814 vector<string> ports;
1819 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1823 if (ensure_inputs (nports, true, true, this)) {
1827 string::size_type start, end, ostart;
1834 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1837 if ((end = str.find_first_of ('}', start)) == string::npos) {
1838 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1842 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1843 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1849 for (int x = 0; x < n; ++x) {
1850 connect_input (input (i), ports[x], this);
1862 IO::set_outputs (const string& str)
1864 vector<string> ports;
1869 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1873 if (ensure_outputs (nports, true, true, this)) {
1877 string::size_type start, end, ostart;
1884 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1887 if ((end = str.find_first_of ('}', start)) == string::npos) {
1888 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1892 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1893 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1899 for (int x = 0; x < n; ++x) {
1900 connect_output (output (i), ports[x], this);
1912 IO::parse_io_string (const string& str, vector<string>& ports)
1914 string::size_type pos, opos;
1916 if (str.length() == 0) {
1925 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1926 ports.push_back (str.substr (opos, pos - opos));
1930 if (opos < str.length()) {
1931 ports.push_back (str.substr(opos));
1934 return ports.size();
1938 IO::parse_gain_string (const string& str, vector<string>& ports)
1940 string::size_type pos, opos;
1946 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1947 ports.push_back (str.substr (opos, pos - opos));
1951 if (opos < str.length()) {
1952 ports.push_back (str.substr(opos));
1955 return ports.size();
1959 IO::set_name (string name, void* src)
1961 if (name == _name) {
1965 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1966 string current_name = (*i)->short_name();
1967 current_name.replace (current_name.find (_name), _name.length(), name);
1968 (*i)->set_name (current_name);
1971 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1972 string current_name = (*i)->short_name();
1973 current_name.replace (current_name.find (_name), _name.length(), name);
1974 (*i)->set_name (current_name);
1978 name_changed (src); /* EMIT SIGNAL */
1984 IO::set_input_minimum (int n)
1990 IO::set_input_maximum (int n)
1996 IO::set_output_minimum (int n)
1998 _output_minimum = n;
2002 IO::set_output_maximum (int n)
2004 _output_maximum = n;
2008 IO::set_port_latency (nframes_t nframes)
2010 Glib::Mutex::Lock lm (io_lock);
2012 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2013 (*i)->set_latency (nframes);
2018 IO::output_latency () const
2020 nframes_t max_latency;
2025 /* io lock not taken - must be protected by other means */
2027 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2028 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2029 max_latency = latency;
2037 IO::input_latency () const
2039 nframes_t max_latency;
2044 /* io lock not taken - must be protected by other means */
2046 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2047 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2048 max_latency = latency;
2056 IO::use_input_connection (Connection& c, void* src)
2061 Glib::Mutex::Lock lm (_session.engine().process_lock());
2062 Glib::Mutex::Lock lm2 (io_lock);
2066 drop_input_connection ();
2068 if (ensure_inputs (limit, false, false, src)) {
2072 /* first pass: check the current state to see what's correctly
2073 connected, and drop anything that we don't want.
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 /* clear any existing connections */
2085 _session.engine().disconnect (_inputs[n]);
2087 } else if (_inputs[n]->connected() > 1) {
2089 /* OK, it is connected to the port we want,
2090 but its also connected to other ports.
2091 Change that situation.
2094 /* XXX could be optimized to not drop
2098 _session.engine().disconnect (_inputs[n]);
2104 /* second pass: connect all requested ports where necessary */
2106 for (uint32_t n = 0; n < limit; ++n) {
2107 const Connection::PortList& pl = c.port_connections (n);
2109 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2111 if (!_inputs[n]->connected_to ((*i))) {
2113 if (_session.engine().connect (*i, _inputs[n]->name())) {
2121 _input_connection = &c;
2123 input_connection_configuration_connection = c.ConfigurationChanged.connect
2124 (mem_fun (*this, &IO::input_connection_configuration_changed));
2125 input_connection_connection_connection = c.ConnectionsChanged.connect
2126 (mem_fun (*this, &IO::input_connection_connection_changed));
2129 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2134 IO::use_output_connection (Connection& c, void* src)
2139 Glib::Mutex::Lock lm (_session.engine().process_lock());
2140 Glib::Mutex::Lock lm2 (io_lock);
2144 drop_output_connection ();
2146 if (ensure_outputs (limit, false, false, src)) {
2150 /* first pass: check the current state to see what's correctly
2151 connected, and drop anything that we don't want.
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 /* clear any existing connections */
2164 _session.engine().disconnect (_outputs[n]);
2166 } else if (_outputs[n]->connected() > 1) {
2168 /* OK, it is connected to the port we want,
2169 but its also connected to other ports.
2170 Change that situation.
2173 /* XXX could be optimized to not drop
2177 _session.engine().disconnect (_outputs[n]);
2182 /* second pass: connect all requested ports where necessary */
2184 for (uint32_t n = 0; n < limit; ++n) {
2186 const Connection::PortList& pl = c.port_connections (n);
2188 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2190 if (!_outputs[n]->connected_to ((*i))) {
2192 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2199 _output_connection = &c;
2201 output_connection_configuration_connection = c.ConfigurationChanged.connect
2202 (mem_fun (*this, &IO::output_connection_configuration_changed));
2203 output_connection_connection_connection = c.ConnectionsChanged.connect
2204 (mem_fun (*this, &IO::output_connection_connection_changed));
2207 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2213 IO::disable_connecting ()
2215 connecting_legal = false;
2220 IO::enable_connecting ()
2222 connecting_legal = true;
2223 return ConnectingLegal ();
2227 IO::disable_ports ()
2229 ports_legal = false;
2237 return PortsLegal ();
2241 IO::disable_panners (void)
2243 panners_legal = false;
2248 IO::reset_panners ()
2250 panners_legal = true;
2251 return PannersLegal ();
2255 IO::input_connection_connection_changed (int ignored)
2257 use_input_connection (*_input_connection, this);
2261 IO::input_connection_configuration_changed ()
2263 use_input_connection (*_input_connection, this);
2267 IO::output_connection_connection_changed (int ignored)
2269 use_output_connection (*_output_connection, this);
2273 IO::output_connection_configuration_changed ()
2275 use_output_connection (*_output_connection, this);
2279 IO::GainControllable::set_value (float val)
2281 io.set_gain (direct_control_to_gain (val), this);
2285 IO::GainControllable::get_value (void) const
2287 return direct_gain_to_control (io.effective_gain());
2291 IO::reset_peak_meters ()
2293 uint32_t limit = max (_ninputs, _noutputs);
2295 for (uint32_t i = 0; i < limit; ++i) {
2301 IO::setup_peak_meters ()
2303 uint32_t limit = max (_ninputs, _noutputs);
2305 while (_peak_power.size() < limit) {
2306 _peak_power.push_back (0);
2307 _visible_peak_power.push_back (0);
2312 IO::get_memento() const
2314 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2318 IO::restore_state (StateManager::State& state)
2323 StateManager::State*
2324 IO::state_factory (std::string why) const
2326 StateManager::State* state = new StateManager::State (why);
2331 Update the peak meters.
2333 The meter signal lock is taken to prevent modification of the
2334 Meter signal while updating the meters, taking the meter signal
2335 lock prior to taking the io_lock ensures that all IO will remain
2336 valid while metering.
2341 Glib::Mutex::Lock guard (m_meter_signal_lock);
2349 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2350 uint32_t limit = max (_ninputs, _noutputs);
2352 for (uint32_t n = 0; n < limit; ++n) {
2354 /* XXX we should use atomic exchange here */
2356 /* grab peak since last read */
2358 float new_peak = _peak_power[n];
2361 /* compute new visible value using falloff */
2363 if (new_peak > 0.0) {
2364 new_peak = coefficient_to_dB (new_peak);
2366 new_peak = minus_infinity();
2369 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2370 _visible_peak_power[n] = new_peak;
2373 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2374 _visible_peak_power[n] = max (new_peak, -INFINITY);
2380 IO::save_automation (const string& path)
2385 fullpath = _session.automation_dir();
2388 out.open (fullpath.c_str());
2391 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2395 out << X_("version ") << current_automation_version_number << endl;
2397 /* XXX use apply_to_points to get thread safety */
2399 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2400 out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2409 IO::load_automation (const string& path)
2414 uint32_t linecnt = 0;
2416 LocaleGuard lg (X_("POSIX"));
2418 fullpath = _session.automation_dir();
2421 in.open (fullpath.c_str());
2424 fullpath = _session.automation_dir();
2425 fullpath += _session.snap_name();
2428 in.open (fullpath.c_str());
2430 error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
2435 clear_automation ();
2437 while (in.getline (line, sizeof(line), '\n')) {
2442 if (++linecnt == 1) {
2443 if (memcmp (line, "version", 7) == 0) {
2444 if (sscanf (line, "version %f", &version) != 1) {
2445 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2449 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2453 if (version != current_automation_version_number) {
2454 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2461 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2462 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2468 _gain_automation_curve.add (when, value, true);
2478 /* older (pre-1.0) versions of ardour used this */
2482 warning << _("dubious automation event found (and ignored)") << endmsg;
2486 _gain_automation_curve.save_state (_("loaded from disk"));
2492 IO::clear_automation ()
2494 Glib::Mutex::Lock lm (automation_lock);
2495 _gain_automation_curve.clear ();
2496 _panner->clear_automation ();
2500 IO::set_gain_automation_state (AutoState state)
2502 bool changed = false;
2505 Glib::Mutex::Lock lm (automation_lock);
2507 if (state != _gain_automation_curve.automation_state()) {
2509 last_automation_snapshot = 0;
2510 _gain_automation_curve.set_automation_state (state);
2513 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2519 _session.set_dirty ();
2520 gain_automation_state_changed (); /* EMIT SIGNAL */
2525 IO::set_gain_automation_style (AutoStyle style)
2527 bool changed = false;
2530 Glib::Mutex::Lock lm (automation_lock);
2532 if (style != _gain_automation_curve.automation_style()) {
2534 _gain_automation_curve.set_automation_style (style);
2539 gain_automation_style_changed (); /* EMIT SIGNAL */
2543 IO::inc_gain (gain_t factor, void *src)
2545 if (_desired_gain == 0.0f)
2546 set_gain (0.000001f + (0.000001f * factor), src);
2548 set_gain (_desired_gain + (_desired_gain * factor), src);
2552 IO::set_gain (gain_t val, void *src)
2554 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2555 if (val>1.99526231f) val=1.99526231f;
2558 Glib::Mutex::Lock dm (declick_lock);
2559 _desired_gain = val;
2562 if (_session.transport_stopped()) {
2563 _effective_gain = val;
2568 _gain_control.Changed (); /* EMIT SIGNAL */
2570 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2571 _gain_automation_curve.add (_session.transport_frame(), val);
2575 _session.set_dirty();
2579 IO::start_gain_touch ()
2581 _gain_automation_curve.start_touch ();
2585 IO::end_gain_touch ()
2587 _gain_automation_curve.stop_touch ();
2591 IO::start_pan_touch (uint32_t which)
2593 if (which < _panner->size()) {
2594 (*_panner)[which]->automation().start_touch();
2599 IO::end_pan_touch (uint32_t which)
2601 if (which < _panner->size()) {
2602 (*_panner)[which]->automation().stop_touch();
2608 IO::automation_snapshot (nframes_t now)
2610 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2612 if (gain_automation_recording()) {
2613 _gain_automation_curve.rt_add (now, gain());
2616 _panner->snapshot (now);
2618 last_automation_snapshot = now;
2623 IO::transport_stopped (nframes_t frame)
2625 _gain_automation_curve.reposition_for_rt_add (frame);
2627 if (_gain_automation_curve.automation_state() != Off) {
2629 if (gain_automation_recording()) {
2630 _gain_automation_curve.save_state (_("automation write/touch"));
2633 /* the src=0 condition is a special signal to not propagate
2634 automation gain changes into the mix group when locating.
2637 set_gain (_gain_automation_curve.eval (frame), 0);
2640 _panner->transport_stopped (frame);
2644 IO::find_input_port_hole ()
2646 /* CALLER MUST HOLD IO LOCK */
2650 if (_inputs.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/in %u"), _name.c_str(), n);
2660 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2661 if ((*i)->short_name() == buf) {
2666 if (i == _inputs.end()) {
2674 IO::find_output_port_hole ()
2676 /* CALLER MUST HOLD IO LOCK */
2680 if (_outputs.empty()) {
2684 for (n = 1; n < UINT_MAX; ++n) {
2685 char buf[jack_port_name_size()];
2686 vector<Port*>::iterator i;
2688 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2690 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2691 if ((*i)->short_name() == buf) {
2696 if (i == _outputs.end()) {