2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include <glibmm/thread.h>
30 #include <pbd/xml++.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/connection.h>
36 #include <ardour/session.h>
37 #include <ardour/cycle_timer.h>
38 #include <ardour/panner.h>
39 #include <ardour/dB.h>
46 A bug in OS X's cmath that causes isnan() and isinf() to be
47 "undeclared". the following works around that
50 #if defined(__APPLE__) && defined(__MACH__)
51 extern "C" int isnan (double);
52 extern "C" int isinf (double);
57 using namespace ARDOUR;
61 static float current_automation_version_number = 1.0;
63 jack_nframes_t IO::_automation_interval = 0;
64 const string IO::state_node_name = "IO";
65 bool IO::connecting_legal = false;
66 bool IO::ports_legal = false;
67 bool IO::panners_legal = false;
68 sigc::signal<void> IO::Meter;
69 sigc::signal<int> IO::ConnectingLegal;
70 sigc::signal<int> IO::PortsLegal;
71 sigc::signal<int> IO::PannersLegal;
72 sigc::signal<void,uint32_t> IO::MoreOutputs;
73 sigc::signal<int> IO::PortsCreated;
75 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
77 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
78 others can be imagined.
81 static gain_t direct_control_to_gain (double fract) {
82 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
83 /* this maxes at +6dB */
84 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
87 static double direct_gain_to_control (gain_t gain) {
88 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
89 if (gain == 0) return 0.0;
91 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
94 static bool sort_ports_by_name (Port* a, Port* b)
96 return a->name() < b->name();
100 /** @param default_type The type of port that will be created by ensure_io
101 * and friends if no type is explicitly requested (to avoid breakage).
103 IO::IO (Session& s, string name,
104 int input_min, int input_max, int output_min, int output_max,
105 DataType default_type)
108 _default_type(default_type),
109 _gain_control (*this),
110 _gain_automation_curve (0.0, 2.0, 1.0),
111 _input_minimum (input_min),
112 _input_maximum (input_max),
113 _output_minimum (output_min),
114 _output_maximum (output_max)
116 _panner = new Panner (name, _session);
119 _input_connection = 0;
120 _output_connection = 0;
121 pending_state_node = 0;
124 no_panner_reset = false;
127 apply_gain_automation = false;
129 last_automation_snapshot = 0;
131 _gain_automation_state = Off;
132 _gain_automation_style = Absolute;
135 // IO::Meter is emitted from another thread so the
136 // Meter signal must be protected.
137 Glib::Mutex::Lock guard (m_meter_signal_lock);
138 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
145 Glib::Mutex::Lock guard (m_meter_signal_lock);
146 Glib::Mutex::Lock lm (io_lock);
147 vector<Port *>::iterator i;
149 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
150 _session.engine().unregister_port (*i);
153 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
154 _session.engine().unregister_port (*i);
157 m_meter_connection.disconnect();
161 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
163 /* io_lock, not taken: function must be called from Session::process() calltree */
165 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
166 (*i)->silence (nframes, offset);
171 IO::apply_declick (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
173 jack_nframes_t declick = min ((jack_nframes_t)4096, nframes);
176 double fractional_shift;
177 double fractional_pos;
178 gain_t polscale = invert_polarity ? -1.0f : 1.0f;
180 if (nframes == 0) return;
182 fractional_shift = -1.0/declick;
184 if (target < initial) {
185 /* fade out: remove more and more of delta from initial */
186 delta = -(initial - target);
188 /* fade in: add more and more of delta from initial */
189 delta = target - initial;
192 for (uint32_t n = 0; n < nbufs; ++n) {
195 fractional_pos = 1.0;
197 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
198 buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
199 fractional_pos += fractional_shift;
202 /* now ensure the rest of the buffer has the target value
203 applied, if necessary.
206 if (declick != nframes) {
208 if (invert_polarity) {
213 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
214 } else if (target != 1.0) {
215 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
216 buffer[nx] *= target;
224 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, jack_nframes_t offset)
228 /* io_lock, not taken: function must be called from Session::process() calltree */
230 if (_noutputs == 0) {
234 if (_noutputs == 1) {
236 dst = output(0)->get_buffer (nframes) + offset;
238 for (uint32_t n = 0; n < nbufs; ++n) {
239 if (bufs[n] != dst) {
240 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
244 output(0)->mark_silence (false);
250 vector<Port *>::iterator out;
251 vector<Sample *>::iterator in;
252 Panner::iterator pan;
253 Sample* obufs[_noutputs];
255 /* the terrible silence ... */
257 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
258 obufs[o] = (*out)->get_buffer (nframes) + offset;
259 memset (obufs[o], 0, sizeof (Sample) * nframes);
260 (*out)->mark_silence (false);
265 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
266 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
271 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
276 /* io_lock, not taken: function must be called from Session::process() calltree */
278 if (_noutputs == 0) {
282 /* the panner can be empty if there are no inputs to the
283 route, but still outputs
286 if (_panner->bypassed() || _panner->empty()) {
287 deliver_output_no_pan (bufs, nbufs, nframes, offset);
291 if (_noutputs == 1) {
293 dst = output(0)->get_buffer (nframes) + offset;
295 if (gain_coeff == 0.0f) {
297 /* only one output, and gain was zero, so make it silent */
299 memset (dst, 0, sizeof (Sample) * nframes);
301 } else if (gain_coeff == 1.0f){
303 /* mix all buffers into the output */
307 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
309 for (n = 1; n < nbufs; ++n) {
312 for (jack_nframes_t n = 0; n < nframes; ++n) {
317 output(0)->mark_silence (false);
321 /* mix all buffers into the output, scaling them all by the gain */
327 for (jack_nframes_t n = 0; n < nframes; ++n) {
328 dst[n] = src[n] * gain_coeff;
331 for (n = 1; n < nbufs; ++n) {
334 for (jack_nframes_t n = 0; n < nframes; ++n) {
335 dst[n] += src[n] * gain_coeff;
339 output(0)->mark_silence (false);
346 vector<Port *>::iterator out;
347 vector<Sample *>::iterator in;
348 Panner::iterator pan;
349 Sample* obufs[_noutputs];
351 /* the terrible silence ... */
353 /* XXX this is wasteful but i see no way to avoid it */
355 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
356 obufs[o] = (*out)->get_buffer (nframes) + offset;
357 memset (obufs[o], 0, sizeof (Sample) * nframes);
358 (*out)->mark_silence (false);
363 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
364 Panner::iterator tmp;
369 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
371 if (tmp != _panner->end()) {
378 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
380 /* io_lock, not taken: function must be called from Session::process() calltree */
382 if (_noutputs == 0) {
386 if (_panner->bypassed() || _panner->empty()) {
387 deliver_output_no_pan (bufs, nbufs, nframes, offset);
393 gain_t pangain = _gain;
396 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
406 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
411 /* simple, non-automation panning to outputs */
413 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
414 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
416 pan (bufs, nbufs, nframes, offset, pangain);
421 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
423 /* io_lock, not taken: function must be called from Session::process() calltree */
425 if (_noutputs == 0) {
430 gain_t old_gain = _gain;
432 if (apply_gain_automation) {
434 /* gain has already been applied by automation code. do nothing here except
443 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
455 vector<Port*>::iterator o;
456 vector<Sample*> outs;
460 /* unlikely condition */
461 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
462 outs.push_back ((*o)->get_buffer (nframes) + offset);
466 /* reduce nbufs to the index of the last input buffer */
470 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
471 actual_gain = _gain * speed_quietning;
476 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
478 dst = (*o)->get_buffer (nframes) + offset;
479 src = bufs[min(nbufs,i)];
481 if (dg != _gain || actual_gain == 1.0f) {
482 memcpy (dst, src, sizeof (Sample) * nframes);
483 } else if (actual_gain == 0.0f) {
484 memset (dst, 0, sizeof (Sample) * nframes);
486 for (jack_nframes_t x = 0; x < nframes; ++x) {
487 dst[x] = src[x] * actual_gain;
491 (*o)->mark_silence (false);
495 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
499 if (apply_gain_automation) {
505 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset)
507 /* io_lock, not taken: function must be called from Session::process() calltree */
509 vector<Port *>::iterator i;
513 /* we require that bufs.size() >= 1 */
515 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
516 if (i == _inputs.end()) {
520 /* XXX always read the full extent of the port buffer that
521 we need. One day, we may use jack_port_get_buffer_at_offset()
522 or something similar. For now, this simple hack will
525 Hack? Why yes .. we only need to read nframes-worth of
526 data, but the data we want is at `offset' within the
530 last = (*i)->get_buffer (nframes+offset) + offset;
531 // the dest buffer's offset has already been applied
532 memcpy (bufs[n], last, sizeof (Sample) * nframes);
535 /* fill any excess outputs with the last input */
537 while (n < nbufs && last) {
538 // the dest buffer's offset has already been applied
539 memcpy (bufs[n], last, sizeof (Sample) * nframes);
545 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
546 jack_nframes_t nframes, jack_nframes_t offset)
548 vector<Sample*>& bufs = _session.get_passthru_buffers ();
549 uint32_t nbufs = n_process_buffers ();
551 collect_input (bufs, nbufs, nframes, offset);
553 for (uint32_t n = 0; n < nbufs; ++n) {
554 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
559 IO::drop_input_connection ()
561 _input_connection = 0;
562 input_connection_configuration_connection.disconnect();
563 input_connection_connection_connection.disconnect();
564 _session.set_dirty ();
568 IO::drop_output_connection ()
570 _output_connection = 0;
571 output_connection_configuration_connection.disconnect();
572 output_connection_connection_connection.disconnect();
573 _session.set_dirty ();
577 IO::disconnect_input (Port* our_port, string other_port, void* src)
579 if (other_port.length() == 0 || our_port == 0) {
584 Glib::Mutex::Lock em (_session.engine().process_lock());
587 Glib::Mutex::Lock lm (io_lock);
589 /* check that our_port is really one of ours */
591 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
595 /* disconnect it from the source */
597 if (_session.engine().disconnect (other_port, our_port->name())) {
598 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
602 drop_input_connection();
606 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
607 _session.set_dirty ();
613 IO::connect_input (Port* our_port, string other_port, void* src)
615 if (other_port.length() == 0 || our_port == 0) {
620 Glib::Mutex::Lock em(_session.engine().process_lock());
623 Glib::Mutex::Lock lm (io_lock);
625 /* check that our_port is really one of ours */
627 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
631 /* connect it to the source */
633 if (_session.engine().connect (other_port, our_port->name())) {
637 drop_input_connection ();
641 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
642 _session.set_dirty ();
647 IO::disconnect_output (Port* our_port, string other_port, void* src)
649 if (other_port.length() == 0 || our_port == 0) {
654 Glib::Mutex::Lock em(_session.engine().process_lock());
657 Glib::Mutex::Lock lm (io_lock);
659 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
663 /* disconnect it from the destination */
665 if (_session.engine().disconnect (our_port->name(), other_port)) {
666 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
670 drop_output_connection ();
674 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
675 _session.set_dirty ();
680 IO::connect_output (Port* our_port, string other_port, void* src)
682 if (other_port.length() == 0 || our_port == 0) {
687 Glib::Mutex::Lock em(_session.engine().process_lock());
690 Glib::Mutex::Lock lm (io_lock);
692 /* check that our_port is really one of ours */
694 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
698 /* connect it to the destination */
700 if (_session.engine().connect (our_port->name(), other_port)) {
704 drop_output_connection ();
708 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
709 _session.set_dirty ();
714 IO::set_input (Port* other_port, void* src)
716 /* this removes all but one ports, and connects that one port
717 to the specified source.
720 if (_input_minimum > 1 || _input_minimum == 0) {
721 /* sorry, you can't do this */
725 if (other_port == 0) {
726 if (_input_minimum < 0) {
727 return ensure_inputs (0, false, true, src);
733 if (ensure_inputs (1, true, true, src)) {
737 return connect_input (_inputs.front(), other_port->name(), src);
741 IO::remove_output_port (Port* port, void* src)
743 IOChange change (NoChange);
746 Glib::Mutex::Lock em(_session.engine().process_lock());
749 Glib::Mutex::Lock lm (io_lock);
751 if (_noutputs - 1 == (uint32_t) _output_minimum) {
752 /* sorry, you can't do this */
756 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
758 change = IOChange (change|ConfigurationChanged);
759 if (port->connected()) {
760 change = IOChange (change|ConnectionsChanged);
763 _session.engine().unregister_port (*i);
766 drop_output_connection ();
772 if (change != NoChange) {
773 setup_peak_meters ();
779 if (change != NoChange) {
780 output_changed (change, src); /* EMIT SIGNAL */
781 _session.set_dirty ();
788 /** Add an output port.
790 * @param destination Name of input port to connect new port to.
791 * @param src Source for emitted ConfigurationChanged signal.
792 * @param type Data type of port. Default value (NIL) will use this IO's default type.
795 IO::add_output_port (string destination, void* src, DataType type)
800 if (type == DataType::NIL)
801 type = _default_type;
804 Glib::Mutex::Lock em(_session.engine().process_lock());
807 Glib::Mutex::Lock lm (io_lock);
809 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
813 /* Create a new output port */
815 // FIXME: naming scheme for differently typed ports?
816 if (_output_maximum == 1) {
817 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
819 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
822 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
823 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
827 _outputs.push_back (our_port);
828 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
830 drop_output_connection ();
831 setup_peak_meters ();
835 MoreOutputs (_noutputs); /* EMIT SIGNAL */
838 if (destination.length()) {
839 if (_session.engine().connect (our_port->name(), destination)) {
844 // pan_changed (src); /* EMIT SIGNAL */
845 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
846 _session.set_dirty ();
851 IO::remove_input_port (Port* port, void* src)
853 IOChange change (NoChange);
856 Glib::Mutex::Lock em(_session.engine().process_lock());
859 Glib::Mutex::Lock lm (io_lock);
861 if (((int)_ninputs - 1) < _input_minimum) {
862 /* sorry, you can't do this */
865 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
868 change = IOChange (change|ConfigurationChanged);
870 if (port->connected()) {
871 change = IOChange (change|ConnectionsChanged);
874 _session.engine().unregister_port (*i);
877 drop_input_connection ();
883 if (change != NoChange) {
884 setup_peak_meters ();
890 if (change != NoChange) {
891 input_changed (change, src);
892 _session.set_dirty ();
900 /** Add an input port.
902 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
903 * @param destination Name of input port to connect new port to.
904 * @param src Source for emitted ConfigurationChanged signal.
907 IO::add_input_port (string source, void* src, DataType type)
912 if (type == DataType::NIL)
913 type = _default_type;
916 Glib::Mutex::Lock em (_session.engine().process_lock());
919 Glib::Mutex::Lock lm (io_lock);
921 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
925 /* Create a new input port */
927 // FIXME: naming scheme for differently typed ports?
928 if (_input_maximum == 1) {
929 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
931 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
934 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
935 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
939 _inputs.push_back (our_port);
940 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
942 drop_input_connection ();
943 setup_peak_meters ();
947 MoreOutputs (_ninputs); /* EMIT SIGNAL */
950 if (source.length()) {
952 if (_session.engine().connect (source, our_port->name())) {
957 // pan_changed (src); /* EMIT SIGNAL */
958 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
959 _session.set_dirty ();
965 IO::disconnect_inputs (void* src)
968 Glib::Mutex::Lock em (_session.engine().process_lock());
971 Glib::Mutex::Lock lm (io_lock);
973 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
974 _session.engine().disconnect (*i);
977 drop_input_connection ();
980 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
985 IO::disconnect_outputs (void* src)
988 Glib::Mutex::Lock em (_session.engine().process_lock());
991 Glib::Mutex::Lock lm (io_lock);
993 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
994 _session.engine().disconnect (*i);
997 drop_output_connection ();
1001 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1002 _session.set_dirty ();
1007 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1010 bool changed = false;
1011 bool reduced = false;
1013 /* remove unused ports */
1015 while (_ninputs > n) {
1016 _session.engine().unregister_port (_inputs.back());
1023 /* create any necessary new ports */
1025 while (_ninputs < n) {
1029 /* Create a new input port (of the default type) */
1031 if (_input_maximum == 1) {
1032 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1035 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1040 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1041 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1046 catch (AudioEngine::PortRegistrationFailure& err) {
1047 setup_peak_meters ();
1053 _inputs.push_back (input_port);
1054 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1060 drop_input_connection ();
1061 setup_peak_meters ();
1063 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1064 _session.set_dirty ();
1068 /* disconnect all existing ports so that we get a fresh start */
1070 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1071 _session.engine().disconnect (*i);
1079 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1081 bool in_changed = false;
1082 bool out_changed = false;
1083 bool in_reduced = false;
1084 bool out_reduced = false;
1085 bool need_pan_reset;
1087 if (_input_maximum >= 0) {
1088 nin = min (_input_maximum, (int) nin);
1091 if (_output_maximum >= 0) {
1092 nout = min (_output_maximum, (int) nout);
1095 if (nin == _ninputs && nout == _noutputs && !clear) {
1100 Glib::Mutex::Lock em (_session.engine().process_lock());
1101 Glib::Mutex::Lock lm (io_lock);
1105 if (_noutputs == nout) {
1106 need_pan_reset = false;
1108 need_pan_reset = true;
1111 /* remove unused ports */
1113 while (_ninputs > nin) {
1114 _session.engine().unregister_port (_inputs.back());
1121 while (_noutputs > nout) {
1122 _session.engine().unregister_port (_outputs.back());
1123 _outputs.pop_back();
1129 /* create any necessary new ports (of the default type) */
1131 while (_ninputs < nin) {
1135 /* Create a new input port */
1137 if (_input_maximum == 1) {
1138 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1141 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1145 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1146 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1151 catch (AudioEngine::PortRegistrationFailure& err) {
1152 setup_peak_meters ();
1158 _inputs.push_back (port);
1163 /* create any necessary new ports */
1165 while (_noutputs < nout) {
1169 /* Create a new output port */
1171 if (_output_maximum == 1) {
1172 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1174 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1178 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1179 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1184 catch (AudioEngine::PortRegistrationFailure& err) {
1185 setup_peak_meters ();
1191 _outputs.push_back (port);
1198 /* disconnect all existing ports so that we get a fresh start */
1200 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1201 _session.engine().disconnect (*i);
1204 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1205 _session.engine().disconnect (*i);
1209 if (in_changed || out_changed) {
1210 setup_peak_meters ();
1216 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1217 drop_output_connection ();
1218 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1222 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1223 drop_input_connection ();
1224 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1227 if (in_changed || out_changed) {
1228 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1229 _session.set_dirty ();
1236 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1238 bool changed = false;
1240 if (_input_maximum >= 0) {
1241 n = min (_input_maximum, (int) n);
1243 if (n == _ninputs && !clear) {
1249 Glib::Mutex::Lock em (_session.engine().process_lock());
1250 Glib::Mutex::Lock im (io_lock);
1251 changed = ensure_inputs_locked (n, clear, src);
1253 changed = ensure_inputs_locked (n, clear, src);
1257 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1258 _session.set_dirty ();
1265 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1268 bool changed = false;
1269 bool reduced = false;
1270 bool need_pan_reset;
1272 if (_noutputs == n) {
1273 need_pan_reset = false;
1275 need_pan_reset = true;
1278 /* remove unused ports */
1280 while (_noutputs > n) {
1282 _session.engine().unregister_port (_outputs.back());
1283 _outputs.pop_back();
1289 /* create any necessary new ports */
1291 while (_noutputs < n) {
1295 /* Create a new output port */
1297 if (_output_maximum == 1) {
1298 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1300 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1303 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1304 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1308 _outputs.push_back (output_port);
1309 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1312 setup_peak_meters ();
1314 if (need_pan_reset) {
1320 drop_output_connection ();
1321 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1322 _session.set_dirty ();
1326 /* disconnect all existing ports so that we get a fresh start */
1328 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1329 _session.engine().disconnect (*i);
1337 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1339 bool changed = false;
1341 if (_output_maximum >= 0) {
1342 n = min (_output_maximum, (int) n);
1343 if (n == _noutputs && !clear) {
1348 /* XXX caller should hold io_lock, but generally doesn't */
1351 Glib::Mutex::Lock em (_session.engine().process_lock());
1352 Glib::Mutex::Lock im (io_lock);
1353 changed = ensure_outputs_locked (n, clear, src);
1355 changed = ensure_outputs_locked (n, clear, src);
1359 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1366 IO::effective_gain () const
1368 if (gain_automation_playback()) {
1369 return _effective_gain;
1371 return _desired_gain;
1378 if (panners_legal) {
1379 if (!no_panner_reset) {
1380 _panner->reset (_noutputs, pans_required());
1383 panner_legal_c.disconnect ();
1384 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1389 IO::panners_became_legal ()
1391 _panner->reset (_noutputs, pans_required());
1392 _panner->load (); // automation
1393 panner_legal_c.disconnect ();
1398 IO::defer_pan_reset ()
1400 no_panner_reset = true;
1404 IO::allow_pan_reset ()
1406 no_panner_reset = false;
1412 IO::get_state (void)
1414 return state (true);
1418 IO::state (bool full_state)
1420 XMLNode* node = new XMLNode (state_node_name);
1423 bool need_ins = true;
1424 bool need_outs = true;
1425 LocaleGuard lg (X_("POSIX"));
1426 Glib::Mutex::Lock lm (io_lock);
1428 node->add_property("name", _name);
1430 node->add_property("id", buf);
1434 if (_input_connection) {
1435 node->add_property ("input-connection", _input_connection->name());
1439 if (_output_connection) {
1440 node->add_property ("output-connection", _output_connection->name());
1445 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1447 const char **connections = (*i)->get_connections();
1449 if (connections && connections[0]) {
1452 for (int n = 0; connections && connections[n]; ++n) {
1457 /* if its a connection to our own port,
1458 return only the port name, not the
1459 whole thing. this allows connections
1460 to be re-established even when our
1461 client name is different.
1464 str += _session.engine().make_port_name_relative (connections[n]);
1476 node->add_property ("inputs", str);
1482 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1484 const char **connections = (*i)->get_connections();
1486 if (connections && connections[0]) {
1490 for (int n = 0; connections[n]; ++n) {
1495 str += _session.engine().make_port_name_relative (connections[n]);
1507 node->add_property ("outputs", str);
1510 node->add_child_nocopy (_panner->state (full_state));
1512 snprintf (buf, sizeof(buf), "%2.12f", gain());
1513 node->add_property ("gain", buf);
1515 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1521 node->add_property ("iolimits", buf);
1526 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1528 /* never store anything except Off for automation state in a template */
1529 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1531 node->add_property ("automation-state", buf);
1532 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1533 node->add_property ("automation-style", buf);
1535 /* XXX same for pan etc. */
1541 IO::connecting_became_legal ()
1545 if (pending_state_node == 0) {
1546 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1551 connection_legal_c.disconnect ();
1553 ret = make_connections (*pending_state_node);
1556 delete pending_state_node;
1557 pending_state_node = 0;
1564 IO::ports_became_legal ()
1568 if (pending_state_node == 0) {
1569 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1574 port_legal_c.disconnect ();
1576 ret = create_ports (*pending_state_node);
1578 if (connecting_legal) {
1579 delete pending_state_node;
1580 pending_state_node = 0;
1587 IO::set_state (const XMLNode& node)
1589 const XMLProperty* prop;
1590 XMLNodeConstIterator iter;
1591 LocaleGuard lg (X_("POSIX"));
1593 /* force use of non-localized representation of decimal point,
1594 since we use it a lot in XML files and so forth.
1597 if (node.name() != state_node_name) {
1598 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1602 if ((prop = node.property ("name")) != 0) {
1603 _name = prop->value();
1604 _panner->set_name (_name);
1607 if ((prop = node.property ("id")) != 0) {
1608 _id = prop->value ();
1611 if ((prop = node.property ("iolimits")) != 0) {
1612 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1619 if ((prop = node.property ("gain")) != 0) {
1620 set_gain (atof (prop->value().c_str()), this);
1621 _gain = _desired_gain;
1624 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1625 if ((*iter)->name() == "Panner") {
1626 _panner->set_state (**iter);
1630 if ((prop = node.property ("automation-state")) != 0) {
1633 x = strtol (prop->value().c_str(), 0, 16);
1634 set_gain_automation_state (AutoState (x));
1637 if ((prop = node.property ("automation-style")) != 0) {
1640 x = strtol (prop->value().c_str(), 0, 16);
1641 set_gain_automation_style (AutoStyle (x));
1646 if (create_ports (node)) {
1652 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1655 if (panners_legal) {
1658 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1661 if (connecting_legal) {
1663 if (make_connections (node)) {
1669 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1672 if (!ports_legal || !connecting_legal) {
1673 pending_state_node = new XMLNode (node);
1680 IO::create_ports (const XMLNode& node)
1682 const XMLProperty* prop;
1684 int num_outputs = 0;
1686 if ((prop = node.property ("input-connection")) != 0) {
1688 Connection* c = _session.connection_by_name (prop->value());
1691 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1693 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1694 error << _("No input connections available as a replacement")
1698 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1703 num_inputs = c->nports();
1705 } else if ((prop = node.property ("inputs")) != 0) {
1707 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1710 if ((prop = node.property ("output-connection")) != 0) {
1711 Connection* c = _session.connection_by_name (prop->value());
1714 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1716 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1717 error << _("No output connections available as a replacement")
1721 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1726 num_outputs = c->nports ();
1728 } else if ((prop = node.property ("outputs")) != 0) {
1729 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1732 no_panner_reset = true;
1734 if (ensure_io (num_inputs, num_outputs, true, this)) {
1735 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1739 no_panner_reset = false;
1741 set_deferred_state ();
1749 IO::make_connections (const XMLNode& node)
1751 const XMLProperty* prop;
1753 if ((prop = node.property ("input-connection")) != 0) {
1754 Connection* c = _session.connection_by_name (prop->value());
1757 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1759 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1760 error << _("No input connections available as a replacement")
1764 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1769 use_input_connection (*c, this);
1771 } else if ((prop = node.property ("inputs")) != 0) {
1772 if (set_inputs (prop->value())) {
1773 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1778 if ((prop = node.property ("output-connection")) != 0) {
1779 Connection* c = _session.connection_by_name (prop->value());
1782 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1784 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1785 error << _("No output connections available as a replacement")
1789 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1794 use_output_connection (*c, this);
1796 } else if ((prop = node.property ("outputs")) != 0) {
1797 if (set_outputs (prop->value())) {
1798 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1807 IO::set_inputs (const string& str)
1809 vector<string> ports;
1814 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1818 if (ensure_inputs (nports, true, true, this)) {
1822 string::size_type start, end, ostart;
1829 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1832 if ((end = str.find_first_of ('}', start)) == string::npos) {
1833 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1837 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1838 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1844 for (int x = 0; x < n; ++x) {
1845 connect_input (input (i), ports[x], this);
1857 IO::set_outputs (const string& str)
1859 vector<string> ports;
1864 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1868 if (ensure_outputs (nports, true, true, this)) {
1872 string::size_type start, end, ostart;
1879 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1882 if ((end = str.find_first_of ('}', start)) == string::npos) {
1883 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1887 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1888 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1894 for (int x = 0; x < n; ++x) {
1895 connect_output (output (i), ports[x], this);
1907 IO::parse_io_string (const string& str, vector<string>& ports)
1909 string::size_type pos, opos;
1911 if (str.length() == 0) {
1920 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1921 ports.push_back (str.substr (opos, pos - opos));
1925 if (opos < str.length()) {
1926 ports.push_back (str.substr(opos));
1929 return ports.size();
1933 IO::parse_gain_string (const string& str, vector<string>& ports)
1935 string::size_type pos, opos;
1941 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1942 ports.push_back (str.substr (opos, pos - opos));
1946 if (opos < str.length()) {
1947 ports.push_back (str.substr(opos));
1950 return ports.size();
1954 IO::set_name (string name, void* src)
1956 if (name == _name) {
1960 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1961 string current_name = (*i)->short_name();
1962 current_name.replace (current_name.find (_name), _name.length(), name);
1963 (*i)->set_name (current_name);
1966 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1967 string current_name = (*i)->short_name();
1968 current_name.replace (current_name.find (_name), _name.length(), name);
1969 (*i)->set_name (current_name);
1973 name_changed (src); /* EMIT SIGNAL */
1979 IO::set_input_minimum (int n)
1985 IO::set_input_maximum (int n)
1991 IO::set_output_minimum (int n)
1993 _output_minimum = n;
1997 IO::set_output_maximum (int n)
1999 _output_maximum = n;
2003 IO::set_port_latency (jack_nframes_t nframes)
2005 Glib::Mutex::Lock lm (io_lock);
2007 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2008 (*i)->set_latency (nframes);
2013 IO::output_latency () const
2015 jack_nframes_t max_latency;
2016 jack_nframes_t latency;
2020 /* io lock not taken - must be protected by other means */
2022 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2023 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2024 max_latency = latency;
2032 IO::input_latency () const
2034 jack_nframes_t max_latency;
2035 jack_nframes_t latency;
2039 /* io lock not taken - must be protected by other means */
2041 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2042 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2043 max_latency = latency;
2051 IO::use_input_connection (Connection& c, void* src)
2056 Glib::Mutex::Lock lm (_session.engine().process_lock());
2057 Glib::Mutex::Lock lm2 (io_lock);
2061 drop_input_connection ();
2063 if (ensure_inputs (limit, false, false, src)) {
2067 /* first pass: check the current state to see what's correctly
2068 connected, and drop anything that we don't want.
2071 for (uint32_t n = 0; n < limit; ++n) {
2072 const Connection::PortList& pl = c.port_connections (n);
2074 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2076 if (!_inputs[n]->connected_to ((*i))) {
2078 /* clear any existing connections */
2080 _session.engine().disconnect (_inputs[n]);
2082 } else if (_inputs[n]->connected() > 1) {
2084 /* OK, it is connected to the port we want,
2085 but its also connected to other ports.
2086 Change that situation.
2089 /* XXX could be optimized to not drop
2093 _session.engine().disconnect (_inputs[n]);
2099 /* second pass: connect all requested ports where necessary */
2101 for (uint32_t n = 0; n < limit; ++n) {
2102 const Connection::PortList& pl = c.port_connections (n);
2104 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2106 if (!_inputs[n]->connected_to ((*i))) {
2108 if (_session.engine().connect (*i, _inputs[n]->name())) {
2116 _input_connection = &c;
2118 input_connection_configuration_connection = c.ConfigurationChanged.connect
2119 (mem_fun (*this, &IO::input_connection_configuration_changed));
2120 input_connection_connection_connection = c.ConnectionsChanged.connect
2121 (mem_fun (*this, &IO::input_connection_connection_changed));
2124 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2129 IO::use_output_connection (Connection& c, void* src)
2134 Glib::Mutex::Lock lm (_session.engine().process_lock());
2135 Glib::Mutex::Lock lm2 (io_lock);
2139 drop_output_connection ();
2141 if (ensure_outputs (limit, false, false, src)) {
2145 /* first pass: check the current state to see what's correctly
2146 connected, and drop anything that we don't want.
2149 for (uint32_t n = 0; n < limit; ++n) {
2151 const Connection::PortList& pl = c.port_connections (n);
2153 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2155 if (!_outputs[n]->connected_to ((*i))) {
2157 /* clear any existing connections */
2159 _session.engine().disconnect (_outputs[n]);
2161 } else if (_outputs[n]->connected() > 1) {
2163 /* OK, it is connected to the port we want,
2164 but its also connected to other ports.
2165 Change that situation.
2168 /* XXX could be optimized to not drop
2172 _session.engine().disconnect (_outputs[n]);
2177 /* second pass: connect all requested ports where necessary */
2179 for (uint32_t n = 0; n < limit; ++n) {
2181 const Connection::PortList& pl = c.port_connections (n);
2183 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2185 if (!_outputs[n]->connected_to ((*i))) {
2187 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2194 _output_connection = &c;
2196 output_connection_configuration_connection = c.ConfigurationChanged.connect
2197 (mem_fun (*this, &IO::output_connection_configuration_changed));
2198 output_connection_connection_connection = c.ConnectionsChanged.connect
2199 (mem_fun (*this, &IO::output_connection_connection_changed));
2202 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2208 IO::disable_connecting ()
2210 connecting_legal = false;
2215 IO::enable_connecting ()
2217 connecting_legal = true;
2218 return ConnectingLegal ();
2222 IO::disable_ports ()
2224 ports_legal = false;
2232 return PortsLegal ();
2236 IO::disable_panners (void)
2238 panners_legal = false;
2243 IO::reset_panners ()
2245 panners_legal = true;
2246 return PannersLegal ();
2250 IO::input_connection_connection_changed (int ignored)
2252 use_input_connection (*_input_connection, this);
2256 IO::input_connection_configuration_changed ()
2258 use_input_connection (*_input_connection, this);
2262 IO::output_connection_connection_changed (int ignored)
2264 use_output_connection (*_output_connection, this);
2268 IO::output_connection_configuration_changed ()
2270 use_output_connection (*_output_connection, this);
2274 IO::GainControllable::set_value (float val)
2276 io.set_gain (direct_control_to_gain (val), this);
2280 IO::GainControllable::get_value (void) const
2282 return direct_gain_to_control (io.effective_gain());
2286 IO::reset_peak_meters ()
2288 uint32_t limit = max (_ninputs, _noutputs);
2290 for (uint32_t i = 0; i < limit; ++i) {
2296 IO::setup_peak_meters ()
2298 uint32_t limit = max (_ninputs, _noutputs);
2300 while (_peak_power.size() < limit) {
2301 _peak_power.push_back (0);
2302 _visible_peak_power.push_back (0);
2307 IO::get_memento() const
2309 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2313 IO::restore_state (StateManager::State& state)
2318 StateManager::State*
2319 IO::state_factory (std::string why) const
2321 StateManager::State* state = new StateManager::State (why);
2326 Update the peak meters.
2328 The meter signal lock is taken to prevent modification of the
2329 Meter signal while updating the meters, taking the meter signal
2330 lock prior to taking the io_lock ensures that all IO will remain
2331 valid while metering.
2336 Glib::Mutex::Lock guard (m_meter_signal_lock);
2344 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2345 uint32_t limit = max (_ninputs, _noutputs);
2347 for (uint32_t n = 0; n < limit; ++n) {
2349 /* XXX we should use atomic exchange here */
2351 /* grab peak since last read */
2353 float new_peak = _peak_power[n];
2356 /* compute new visible value using falloff */
2358 if (new_peak > 0.0) {
2359 new_peak = coefficient_to_dB (new_peak);
2361 new_peak = minus_infinity();
2364 if (_session.meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2365 _visible_peak_power[n] = new_peak;
2368 new_peak = _visible_peak_power[n] - _session.meter_falloff();
2369 _visible_peak_power[n] = max (new_peak, -INFINITY);
2375 IO::save_automation (const string& path)
2380 fullpath = _session.automation_dir();
2383 out.open (fullpath.c_str());
2386 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2390 out << X_("version ") << current_automation_version_number << endl;
2392 /* XXX use apply_to_points to get thread safety */
2394 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2395 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2404 IO::load_automation (const string& path)
2409 uint32_t linecnt = 0;
2411 LocaleGuard lg (X_("POSIX"));
2413 fullpath = _session.automation_dir();
2416 in.open (fullpath.c_str());
2419 fullpath = _session.automation_dir();
2420 fullpath += _session.snap_name();
2423 in.open (fullpath.c_str());
2425 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2430 clear_automation ();
2432 while (in.getline (line, sizeof(line), '\n')) {
2434 jack_nframes_t when;
2437 if (++linecnt == 1) {
2438 if (memcmp (line, "version", 7) == 0) {
2439 if (sscanf (line, "version %f", &version) != 1) {
2440 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2444 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2448 if (version != current_automation_version_number) {
2449 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2456 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2457 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2463 _gain_automation_curve.add (when, value, true);
2473 /* older (pre-1.0) versions of ardour used this */
2477 warning << _("dubious automation event found (and ignored)") << endmsg;
2481 _gain_automation_curve.save_state (_("loaded from disk"));
2487 IO::clear_automation ()
2489 Glib::Mutex::Lock lm (automation_lock);
2490 _gain_automation_curve.clear ();
2491 _panner->clear_automation ();
2495 IO::set_gain_automation_state (AutoState state)
2497 bool changed = false;
2500 Glib::Mutex::Lock lm (automation_lock);
2502 if (state != _gain_automation_curve.automation_state()) {
2504 last_automation_snapshot = 0;
2505 _gain_automation_curve.set_automation_state (state);
2508 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2514 _session.set_dirty ();
2515 gain_automation_state_changed (); /* EMIT SIGNAL */
2520 IO::set_gain_automation_style (AutoStyle style)
2522 bool changed = false;
2525 Glib::Mutex::Lock lm (automation_lock);
2527 if (style != _gain_automation_curve.automation_style()) {
2529 _gain_automation_curve.set_automation_style (style);
2534 gain_automation_style_changed (); /* EMIT SIGNAL */
2538 IO::inc_gain (gain_t factor, void *src)
2540 if (_desired_gain == 0.0f)
2541 set_gain (0.000001f + (0.000001f * factor), src);
2543 set_gain (_desired_gain + (_desired_gain * factor), src);
2547 IO::set_gain (gain_t val, void *src)
2549 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2550 if (val>1.99526231f) val=1.99526231f;
2553 Glib::Mutex::Lock dm (declick_lock);
2554 _desired_gain = val;
2557 if (_session.transport_stopped()) {
2558 _effective_gain = val;
2563 _gain_control.Changed (); /* EMIT SIGNAL */
2565 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2566 _gain_automation_curve.add (_session.transport_frame(), val);
2570 _session.set_dirty();
2574 IO::start_gain_touch ()
2576 _gain_automation_curve.start_touch ();
2580 IO::end_gain_touch ()
2582 _gain_automation_curve.stop_touch ();
2586 IO::start_pan_touch (uint32_t which)
2588 if (which < _panner->size()) {
2589 (*_panner)[which]->automation().start_touch();
2594 IO::end_pan_touch (uint32_t which)
2596 if (which < _panner->size()) {
2597 (*_panner)[which]->automation().stop_touch();
2603 IO::automation_snapshot (jack_nframes_t now)
2605 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2607 if (gain_automation_recording()) {
2608 _gain_automation_curve.rt_add (now, gain());
2611 _panner->snapshot (now);
2613 last_automation_snapshot = now;
2618 IO::transport_stopped (jack_nframes_t frame)
2620 _gain_automation_curve.reposition_for_rt_add (frame);
2622 if (_gain_automation_curve.automation_state() != Off) {
2624 if (gain_automation_recording()) {
2625 _gain_automation_curve.save_state (_("automation write/touch"));
2628 /* the src=0 condition is a special signal to not propagate
2629 automation gain changes into the mix group when locating.
2632 set_gain (_gain_automation_curve.eval (frame), 0);
2635 _panner->transport_stopped (frame);
2639 IO::find_input_port_hole ()
2641 /* CALLER MUST HOLD IO LOCK */
2645 if (_inputs.empty()) {
2649 for (n = 1; n < UINT_MAX; ++n) {
2650 char buf[jack_port_name_size()];
2651 vector<Port*>::iterator i;
2653 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2655 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2656 if ((*i)->short_name() == buf) {
2661 if (i == _inputs.end()) {
2669 IO::find_output_port_hole ()
2671 /* CALLER MUST HOLD IO LOCK */
2675 if (_outputs.empty()) {
2679 for (n = 1; n < UINT_MAX; ++n) {
2680 char buf[jack_port_name_size()];
2681 vector<Port*>::iterator i;
2683 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2685 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2686 if ((*i)->short_name() == buf) {
2691 if (i == _outputs.end()) {