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 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 (X_("gaincontrol"), *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;
128 _ignore_gain_on_deliver = false;
130 _gain_automation_state = Off;
131 _gain_automation_style = Absolute;
134 // IO::Meter is emitted from another thread so the
135 // Meter signal must be protected.
136 Glib::Mutex::Lock guard (m_meter_signal_lock);
137 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
144 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 (nframes_t nframes, 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, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
173 nframes_t declick = min ((nframes_t)128, 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 (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) {
209 if (invert_polarity) {
210 this_target = -target;
212 this_target = target;
215 if (this_target == 0.0) {
216 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
217 } else if (this_target != 1.0) {
218 for (nframes_t nx = declick; nx < nframes; ++nx) {
219 buffer[nx] *= this_target;
227 IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, nframes_t start, nframes_t end, nframes_t nframes, nframes_t offset)
231 /* io_lock, not taken: function must be called from Session::process() calltree */
233 if (_noutputs == 0) {
237 if (_noutputs == 1) {
239 dst = output(0)->get_buffer (nframes) + offset;
241 for (uint32_t n = 0; n < nbufs; ++n) {
242 if (bufs[n] != dst) {
243 memcpy (dst, bufs[n], sizeof (Sample) * nframes);
247 output(0)->mark_silence (false);
253 vector<Port *>::iterator out;
254 vector<Sample *>::iterator in;
255 Panner::iterator pan;
256 Sample* obufs[_noutputs];
258 /* the terrible silence ... */
260 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
261 obufs[o] = (*out)->get_buffer (nframes) + offset;
262 memset (obufs[o], 0, sizeof (Sample) * nframes);
263 (*out)->mark_silence (false);
268 for (pan = _panner->begin(), n = 0; n < nbufs; ++n, ++pan) {
269 (*pan)->distribute_automated (bufs[n], obufs, start, end, nframes, _session.pan_automation_buffer());
274 IO::pan (vector<Sample*>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset, gain_t gain_coeff)
279 /* io_lock, not taken: function must be called from Session::process() calltree */
281 if (_noutputs == 0) {
285 /* the panner can be empty if there are no inputs to the
286 route, but still outputs
289 if (_panner->bypassed() || _panner->empty()) {
290 deliver_output_no_pan (bufs, nbufs, nframes, offset);
294 if (_noutputs == 1) {
296 dst = output(0)->get_buffer (nframes) + offset;
298 if (gain_coeff == 0.0f) {
300 /* only one output, and gain was zero, so make it silent */
302 memset (dst, 0, sizeof (Sample) * nframes);
304 } else if (gain_coeff == 1.0f){
306 /* mix all buffers into the output */
310 memcpy (dst, bufs[0], sizeof (Sample) * nframes);
312 for (n = 1; n < nbufs; ++n) {
315 for (nframes_t n = 0; n < nframes; ++n) {
320 output(0)->mark_silence (false);
324 /* mix all buffers into the output, scaling them all by the gain */
330 for (nframes_t n = 0; n < nframes; ++n) {
331 dst[n] = src[n] * gain_coeff;
334 for (n = 1; n < nbufs; ++n) {
337 for (nframes_t n = 0; n < nframes; ++n) {
338 dst[n] += src[n] * gain_coeff;
342 output(0)->mark_silence (false);
349 vector<Port *>::iterator out;
350 vector<Sample *>::iterator in;
351 Panner::iterator pan;
352 Sample* obufs[_noutputs];
354 /* the terrible silence ... */
356 /* XXX this is wasteful but i see no way to avoid it */
358 for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
359 obufs[o] = (*out)->get_buffer (nframes) + offset;
360 memset (obufs[o], 0, sizeof (Sample) * nframes);
361 (*out)->mark_silence (false);
366 for (pan = _panner->begin(), n = 0; n < nbufs; ++n) {
367 Panner::iterator tmp;
372 (*pan)->distribute (bufs[n], obufs, gain_coeff, nframes);
374 if (tmp != _panner->end()) {
381 IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
383 /* io_lock, not taken: function must be called from Session::process() calltree */
385 if (_noutputs == 0) {
389 if (_panner->bypassed() || _panner->empty()) {
390 deliver_output_no_pan (bufs, nbufs, nframes, offset);
396 gain_t pangain = _gain;
399 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
409 apply_declick (bufs, nbufs, nframes, _gain, dg, false);
414 /* simple, non-automation panning to outputs */
416 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
417 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
419 pan (bufs, nbufs, nframes, offset, pangain);
424 IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
426 /* io_lock, not taken: function must be called from Session::process() calltree */
428 if (_noutputs == 0) {
433 gain_t old_gain = _gain;
435 if (apply_gain_automation || _ignore_gain_on_deliver) {
437 /* gain has already been applied by automation code. do nothing here except
446 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
458 vector<Port*>::iterator o;
459 vector<Sample*> outs;
463 /* unlikely condition */
464 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
465 outs.push_back ((*o)->get_buffer (nframes) + offset);
469 /* reduce nbufs to the index of the last input buffer */
473 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
474 actual_gain = _gain * speed_quietning;
479 for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
481 dst = (*o)->get_buffer (nframes) + offset;
482 src = bufs[min(nbufs,i)];
484 if (dg != _gain || actual_gain == 1.0f) {
485 memcpy (dst, src, sizeof (Sample) * nframes);
486 } else if (actual_gain == 0.0f) {
487 memset (dst, 0, sizeof (Sample) * nframes);
489 for (nframes_t x = 0; x < nframes; ++x) {
490 dst[x] = src[x] * actual_gain;
494 (*o)->mark_silence (false);
498 apply_declick (outs, outs.size(), nframes, _gain, dg, false);
502 if (apply_gain_automation || _ignore_gain_on_deliver) {
508 IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes, nframes_t offset)
510 /* io_lock, not taken: function must be called from Session::process() calltree */
512 vector<Port *>::iterator i;
516 /* we require that bufs.size() >= 1 */
518 for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
519 if (i == _inputs.end()) {
523 /* XXX always read the full extent of the port buffer that
524 we need. One day, we may use jack_port_get_buffer_at_offset()
525 or something similar. For now, this simple hack will
528 Hack? Why yes .. we only need to read nframes-worth of
529 data, but the data we want is at `offset' within the
533 last = (*i)->get_buffer (nframes+offset) + offset;
534 // the dest buffer's offset has already been applied
535 memcpy (bufs[n], last, sizeof (Sample) * nframes);
538 /* fill any excess outputs with the last input */
540 while (n < nbufs && last) {
541 // the dest buffer's offset has already been applied
542 memcpy (bufs[n], last, sizeof (Sample) * nframes);
548 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
549 nframes_t nframes, nframes_t offset)
551 vector<Sample*>& bufs = _session.get_passthru_buffers ();
552 uint32_t nbufs = n_process_buffers ();
554 collect_input (bufs, nbufs, nframes, offset);
556 for (uint32_t n = 0; n < nbufs; ++n) {
557 _peak_power[n] = Session::compute_peak (bufs[n], nframes, _peak_power[n]);
562 IO::drop_input_connection ()
564 _input_connection = 0;
565 input_connection_configuration_connection.disconnect();
566 input_connection_connection_connection.disconnect();
567 _session.set_dirty ();
571 IO::drop_output_connection ()
573 _output_connection = 0;
574 output_connection_configuration_connection.disconnect();
575 output_connection_connection_connection.disconnect();
576 _session.set_dirty ();
580 IO::disconnect_input (Port* our_port, string other_port, void* src)
582 if (other_port.length() == 0 || our_port == 0) {
587 Glib::Mutex::Lock em (_session.engine().process_lock());
590 Glib::Mutex::Lock lm (io_lock);
592 /* check that our_port is really one of ours */
594 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
598 /* disconnect it from the source */
600 if (_session.engine().disconnect (other_port, our_port->name())) {
601 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
605 drop_input_connection();
609 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
610 _session.set_dirty ();
616 IO::connect_input (Port* our_port, string other_port, void* src)
618 if (other_port.length() == 0 || our_port == 0) {
623 Glib::Mutex::Lock em(_session.engine().process_lock());
626 Glib::Mutex::Lock lm (io_lock);
628 /* check that our_port is really one of ours */
630 if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
634 /* connect it to the source */
636 if (_session.engine().connect (other_port, our_port->name())) {
640 drop_input_connection ();
644 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
645 _session.set_dirty ();
650 IO::disconnect_output (Port* our_port, string other_port, void* src)
652 if (other_port.length() == 0 || our_port == 0) {
657 Glib::Mutex::Lock em(_session.engine().process_lock());
660 Glib::Mutex::Lock lm (io_lock);
662 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
666 /* disconnect it from the destination */
668 if (_session.engine().disconnect (our_port->name(), other_port)) {
669 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
673 drop_output_connection ();
677 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
678 _session.set_dirty ();
683 IO::connect_output (Port* our_port, string other_port, void* src)
685 if (other_port.length() == 0 || our_port == 0) {
690 Glib::Mutex::Lock em(_session.engine().process_lock());
693 Glib::Mutex::Lock lm (io_lock);
695 /* check that our_port is really one of ours */
697 if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
701 /* connect it to the destination */
703 if (_session.engine().connect (our_port->name(), other_port)) {
707 drop_output_connection ();
711 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
712 _session.set_dirty ();
717 IO::set_input (Port* other_port, void* src)
719 /* this removes all but one ports, and connects that one port
720 to the specified source.
723 if (_input_minimum > 1 || _input_minimum == 0) {
724 /* sorry, you can't do this */
728 if (other_port == 0) {
729 if (_input_minimum < 0) {
730 return ensure_inputs (0, false, true, src);
736 if (ensure_inputs (1, true, true, src)) {
740 return connect_input (_inputs.front(), other_port->name(), src);
744 IO::remove_output_port (Port* port, void* src)
746 IOChange change (NoChange);
749 Glib::Mutex::Lock em(_session.engine().process_lock());
752 Glib::Mutex::Lock lm (io_lock);
754 if (_noutputs - 1 == (uint32_t) _output_minimum) {
755 /* sorry, you can't do this */
759 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
761 change = IOChange (change|ConfigurationChanged);
762 if (port->connected()) {
763 change = IOChange (change|ConnectionsChanged);
766 _session.engine().unregister_port (*i);
769 drop_output_connection ();
775 if (change != NoChange) {
776 setup_peak_meters ();
782 if (change != NoChange) {
783 output_changed (change, src); /* EMIT SIGNAL */
784 _session.set_dirty ();
791 /** Add an output port.
793 * @param destination Name of input port to connect new port to.
794 * @param src Source for emitted ConfigurationChanged signal.
795 * @param type Data type of port. Default value (NIL) will use this IO's default type.
798 IO::add_output_port (string destination, void* src, DataType type)
803 if (type == DataType::NIL)
804 type = _default_type;
807 Glib::Mutex::Lock em(_session.engine().process_lock());
810 Glib::Mutex::Lock lm (io_lock);
812 if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
816 /* Create a new output port */
818 // FIXME: naming scheme for differently typed ports?
819 if (_output_maximum == 1) {
820 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
822 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
825 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
826 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
830 _outputs.push_back (our_port);
831 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
833 drop_output_connection ();
834 setup_peak_meters ();
838 MoreOutputs (_noutputs); /* EMIT SIGNAL */
841 if (destination.length()) {
842 if (_session.engine().connect (our_port->name(), destination)) {
847 // pan_changed (src); /* EMIT SIGNAL */
848 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
849 _session.set_dirty ();
854 IO::remove_input_port (Port* port, void* src)
856 IOChange change (NoChange);
859 Glib::Mutex::Lock em(_session.engine().process_lock());
862 Glib::Mutex::Lock lm (io_lock);
864 if (((int)_ninputs - 1) < _input_minimum) {
865 /* sorry, you can't do this */
868 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
871 change = IOChange (change|ConfigurationChanged);
873 if (port->connected()) {
874 change = IOChange (change|ConnectionsChanged);
877 _session.engine().unregister_port (*i);
880 drop_input_connection ();
886 if (change != NoChange) {
887 setup_peak_meters ();
893 if (change != NoChange) {
894 input_changed (change, src);
895 _session.set_dirty ();
903 /** Add an input port.
905 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
906 * @param destination Name of input port to connect new port to.
907 * @param src Source for emitted ConfigurationChanged signal.
910 IO::add_input_port (string source, void* src, DataType type)
915 if (type == DataType::NIL)
916 type = _default_type;
919 Glib::Mutex::Lock em (_session.engine().process_lock());
922 Glib::Mutex::Lock lm (io_lock);
924 if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
928 /* Create a new input port */
930 // FIXME: naming scheme for differently typed ports?
931 if (_input_maximum == 1) {
932 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
934 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
937 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
938 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
942 _inputs.push_back (our_port);
943 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
945 drop_input_connection ();
946 setup_peak_meters ();
950 MoreOutputs (_ninputs); /* EMIT SIGNAL */
953 if (source.length()) {
955 if (_session.engine().connect (source, our_port->name())) {
960 // pan_changed (src); /* EMIT SIGNAL */
961 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
962 _session.set_dirty ();
968 IO::disconnect_inputs (void* src)
971 Glib::Mutex::Lock em (_session.engine().process_lock());
974 Glib::Mutex::Lock lm (io_lock);
976 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
977 _session.engine().disconnect (*i);
980 drop_input_connection ();
983 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
988 IO::disconnect_outputs (void* src)
991 Glib::Mutex::Lock em (_session.engine().process_lock());
994 Glib::Mutex::Lock lm (io_lock);
996 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
997 _session.engine().disconnect (*i);
1000 drop_output_connection ();
1004 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
1005 _session.set_dirty ();
1010 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
1013 bool changed = false;
1014 bool reduced = false;
1016 /* remove unused ports */
1018 while (_ninputs > n) {
1019 _session.engine().unregister_port (_inputs.back());
1026 /* create any necessary new ports */
1028 while (_ninputs < n) {
1032 /* Create a new input port (of the default type) */
1034 if (_input_maximum == 1) {
1035 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1038 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1043 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1044 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1049 catch (AudioEngine::PortRegistrationFailure& err) {
1050 setup_peak_meters ();
1056 _inputs.push_back (input_port);
1057 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1063 drop_input_connection ();
1064 setup_peak_meters ();
1066 MoreOutputs (_ninputs); /* EMIT SIGNAL */
1067 _session.set_dirty ();
1071 /* disconnect all existing ports so that we get a fresh start */
1073 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1074 _session.engine().disconnect (*i);
1082 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
1084 bool in_changed = false;
1085 bool out_changed = false;
1086 bool in_reduced = false;
1087 bool out_reduced = false;
1088 bool need_pan_reset;
1090 if (_input_maximum >= 0) {
1091 nin = min (_input_maximum, (int) nin);
1094 if (_output_maximum >= 0) {
1095 nout = min (_output_maximum, (int) nout);
1098 if (nin == _ninputs && nout == _noutputs && !clear) {
1103 Glib::Mutex::Lock em (_session.engine().process_lock());
1104 Glib::Mutex::Lock lm (io_lock);
1108 if (_noutputs == nout) {
1109 need_pan_reset = false;
1111 need_pan_reset = true;
1114 /* remove unused ports */
1116 while (_ninputs > nin) {
1117 _session.engine().unregister_port (_inputs.back());
1124 while (_noutputs > nout) {
1125 _session.engine().unregister_port (_outputs.back());
1126 _outputs.pop_back();
1132 /* create any necessary new ports (of the default type) */
1134 while (_ninputs < nin) {
1138 /* Create a new input port */
1140 if (_input_maximum == 1) {
1141 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
1144 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
1148 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
1149 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
1154 catch (AudioEngine::PortRegistrationFailure& err) {
1155 setup_peak_meters ();
1161 _inputs.push_back (port);
1166 /* create any necessary new ports */
1168 while (_noutputs < nout) {
1172 /* Create a new output port */
1174 if (_output_maximum == 1) {
1175 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1177 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1181 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1182 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1187 catch (AudioEngine::PortRegistrationFailure& err) {
1188 setup_peak_meters ();
1194 _outputs.push_back (port);
1201 /* disconnect all existing ports so that we get a fresh start */
1203 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1204 _session.engine().disconnect (*i);
1207 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1208 _session.engine().disconnect (*i);
1212 if (in_changed || out_changed) {
1213 setup_peak_meters ();
1219 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1220 drop_output_connection ();
1221 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1225 sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
1226 drop_input_connection ();
1227 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1230 if (in_changed || out_changed) {
1231 MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
1232 _session.set_dirty ();
1239 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1241 bool changed = false;
1243 if (_input_maximum >= 0) {
1244 n = min (_input_maximum, (int) n);
1246 if (n == _ninputs && !clear) {
1252 Glib::Mutex::Lock em (_session.engine().process_lock());
1253 Glib::Mutex::Lock im (io_lock);
1254 changed = ensure_inputs_locked (n, clear, src);
1256 changed = ensure_inputs_locked (n, clear, src);
1260 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1261 _session.set_dirty ();
1268 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1271 bool changed = false;
1272 bool reduced = false;
1273 bool need_pan_reset;
1275 if (_noutputs == n) {
1276 need_pan_reset = false;
1278 need_pan_reset = true;
1281 /* remove unused ports */
1283 while (_noutputs > n) {
1285 _session.engine().unregister_port (_outputs.back());
1286 _outputs.pop_back();
1292 /* create any necessary new ports */
1294 while (_noutputs < n) {
1298 /* Create a new output port */
1300 if (_output_maximum == 1) {
1301 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1303 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1306 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1307 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1311 _outputs.push_back (output_port);
1312 sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
1315 setup_peak_meters ();
1317 if (need_pan_reset) {
1323 drop_output_connection ();
1324 MoreOutputs (_noutputs); /* EMIT SIGNAL */
1325 _session.set_dirty ();
1329 /* disconnect all existing ports so that we get a fresh start */
1331 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1332 _session.engine().disconnect (*i);
1340 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1342 bool changed = false;
1344 if (_output_maximum >= 0) {
1345 n = min (_output_maximum, (int) n);
1346 if (n == _noutputs && !clear) {
1351 /* XXX caller should hold io_lock, but generally doesn't */
1354 Glib::Mutex::Lock em (_session.engine().process_lock());
1355 Glib::Mutex::Lock im (io_lock);
1356 changed = ensure_outputs_locked (n, clear, src);
1358 changed = ensure_outputs_locked (n, clear, src);
1362 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1369 IO::effective_gain () const
1371 if (gain_automation_playback()) {
1372 return _effective_gain;
1374 return _desired_gain;
1381 if (panners_legal) {
1382 if (!no_panner_reset) {
1383 _panner->reset (_noutputs, pans_required());
1386 panner_legal_c.disconnect ();
1387 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1392 IO::panners_became_legal ()
1394 _panner->reset (_noutputs, pans_required());
1395 _panner->load (); // automation
1396 panner_legal_c.disconnect ();
1401 IO::defer_pan_reset ()
1403 no_panner_reset = true;
1407 IO::allow_pan_reset ()
1409 no_panner_reset = false;
1415 IO::get_state (void)
1417 return state (true);
1421 IO::state (bool full_state)
1423 XMLNode* node = new XMLNode (state_node_name);
1426 bool need_ins = true;
1427 bool need_outs = true;
1428 LocaleGuard lg (X_("POSIX"));
1429 Glib::Mutex::Lock lm (io_lock);
1431 node->add_property("name", _name);
1432 id().print (buf, sizeof (buf));
1433 node->add_property("id", buf);
1437 if (_input_connection) {
1438 node->add_property ("input-connection", _input_connection->name());
1442 if (_output_connection) {
1443 node->add_property ("output-connection", _output_connection->name());
1448 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1450 const char **connections = (*i)->get_connections();
1452 if (connections && connections[0]) {
1455 for (int n = 0; connections && connections[n]; ++n) {
1460 /* if its a connection to our own port,
1461 return only the port name, not the
1462 whole thing. this allows connections
1463 to be re-established even when our
1464 client name is different.
1467 str += _session.engine().make_port_name_relative (connections[n]);
1479 node->add_property ("inputs", str);
1485 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1487 const char **connections = (*i)->get_connections();
1489 if (connections && connections[0]) {
1493 for (int n = 0; connections[n]; ++n) {
1498 str += _session.engine().make_port_name_relative (connections[n]);
1510 node->add_property ("outputs", str);
1513 node->add_child_nocopy (_panner->state (full_state));
1514 node->add_child_nocopy (_gain_control.get_state ());
1516 snprintf (buf, sizeof(buf), "%2.12f", gain());
1517 node->add_property ("gain", buf);
1519 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d",
1525 node->add_property ("iolimits", buf);
1530 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1532 /* never store anything except Off for automation state in a template */
1533 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1535 node->add_property ("automation-state", buf);
1536 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1537 node->add_property ("automation-style", buf);
1539 /* XXX same for pan etc. */
1545 IO::connecting_became_legal ()
1549 if (pending_state_node == 0) {
1550 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1555 connection_legal_c.disconnect ();
1557 ret = make_connections (*pending_state_node);
1560 delete pending_state_node;
1561 pending_state_node = 0;
1568 IO::ports_became_legal ()
1572 if (pending_state_node == 0) {
1573 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1578 port_legal_c.disconnect ();
1580 ret = create_ports (*pending_state_node);
1582 if (connecting_legal) {
1583 delete pending_state_node;
1584 pending_state_node = 0;
1591 IO::set_state (const XMLNode& node)
1593 const XMLProperty* prop;
1594 XMLNodeConstIterator iter;
1595 LocaleGuard lg (X_("POSIX"));
1597 /* force use of non-localized representation of decimal point,
1598 since we use it a lot in XML files and so forth.
1601 if (node.name() != state_node_name) {
1602 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1606 if ((prop = node.property ("name")) != 0) {
1607 _name = prop->value();
1608 _panner->set_name (_name);
1611 if ((prop = node.property ("id")) != 0) {
1612 _id = prop->value ();
1615 if ((prop = node.property ("iolimits")) != 0) {
1616 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1623 if ((prop = node.property ("gain")) != 0) {
1624 set_gain (atof (prop->value().c_str()), this);
1625 _gain = _desired_gain;
1628 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1630 if ((*iter)->name() == "Panner") {
1631 _panner->set_state (**iter);
1634 if ((*iter)->name() == X_("gaincontrol")) {
1635 _gain_control.set_state (**iter);
1636 _session.add_controllable (&_gain_control);
1640 if ((prop = node.property ("automation-state")) != 0) {
1643 x = strtol (prop->value().c_str(), 0, 16);
1644 set_gain_automation_state (AutoState (x));
1647 if ((prop = node.property ("automation-style")) != 0) {
1650 x = strtol (prop->value().c_str(), 0, 16);
1651 set_gain_automation_style (AutoStyle (x));
1656 if (create_ports (node)) {
1662 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1665 if (panners_legal) {
1668 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1671 if (connecting_legal) {
1673 if (make_connections (node)) {
1679 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1682 if (!ports_legal || !connecting_legal) {
1683 pending_state_node = new XMLNode (node);
1690 IO::create_ports (const XMLNode& node)
1692 const XMLProperty* prop;
1694 int num_outputs = 0;
1696 if ((prop = node.property ("input-connection")) != 0) {
1698 Connection* c = _session.connection_by_name (prop->value());
1701 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1703 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1704 error << _("No input connections available as a replacement")
1708 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1713 num_inputs = c->nports();
1715 } else if ((prop = node.property ("inputs")) != 0) {
1717 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1720 if ((prop = node.property ("output-connection")) != 0) {
1721 Connection* c = _session.connection_by_name (prop->value());
1724 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1726 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1727 error << _("No output connections available as a replacement")
1731 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1736 num_outputs = c->nports ();
1738 } else if ((prop = node.property ("outputs")) != 0) {
1739 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1742 no_panner_reset = true;
1744 if (ensure_io (num_inputs, num_outputs, true, this)) {
1745 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1749 no_panner_reset = false;
1751 set_deferred_state ();
1759 IO::make_connections (const XMLNode& node)
1761 const XMLProperty* prop;
1763 if ((prop = node.property ("input-connection")) != 0) {
1764 Connection* c = _session.connection_by_name (prop->value());
1767 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1769 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1770 error << _("No input connections available as a replacement")
1774 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1779 use_input_connection (*c, this);
1781 } else if ((prop = node.property ("inputs")) != 0) {
1782 if (set_inputs (prop->value())) {
1783 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1788 if ((prop = node.property ("output-connection")) != 0) {
1789 Connection* c = _session.connection_by_name (prop->value());
1792 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1794 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1795 error << _("No output connections available as a replacement")
1799 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1804 use_output_connection (*c, this);
1806 } else if ((prop = node.property ("outputs")) != 0) {
1807 if (set_outputs (prop->value())) {
1808 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1817 IO::set_inputs (const string& str)
1819 vector<string> ports;
1824 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1828 if (ensure_inputs (nports, true, true, this)) {
1832 string::size_type start, end, ostart;
1839 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1842 if ((end = str.find_first_of ('}', start)) == string::npos) {
1843 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1847 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1848 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1854 for (int x = 0; x < n; ++x) {
1855 connect_input (input (i), ports[x], this);
1867 IO::set_outputs (const string& str)
1869 vector<string> ports;
1874 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1878 if (ensure_outputs (nports, true, true, this)) {
1882 string::size_type start, end, ostart;
1889 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1892 if ((end = str.find_first_of ('}', start)) == string::npos) {
1893 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1897 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1898 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1904 for (int x = 0; x < n; ++x) {
1905 connect_output (output (i), ports[x], this);
1917 IO::parse_io_string (const string& str, vector<string>& ports)
1919 string::size_type pos, opos;
1921 if (str.length() == 0) {
1930 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1931 ports.push_back (str.substr (opos, pos - opos));
1935 if (opos < str.length()) {
1936 ports.push_back (str.substr(opos));
1939 return ports.size();
1943 IO::parse_gain_string (const string& str, vector<string>& ports)
1945 string::size_type pos, opos;
1951 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1952 ports.push_back (str.substr (opos, pos - opos));
1956 if (opos < str.length()) {
1957 ports.push_back (str.substr(opos));
1960 return ports.size();
1964 IO::set_name (string name, void* src)
1966 if (name == _name) {
1970 for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1971 string current_name = (*i)->short_name();
1972 current_name.replace (current_name.find (_name), _name.length(), name);
1973 (*i)->set_name (current_name);
1976 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1977 string current_name = (*i)->short_name();
1978 current_name.replace (current_name.find (_name), _name.length(), name);
1979 (*i)->set_name (current_name);
1983 name_changed (src); /* EMIT SIGNAL */
1989 IO::set_input_minimum (int n)
1995 IO::set_input_maximum (int n)
2001 IO::set_output_minimum (int n)
2003 _output_minimum = n;
2007 IO::set_output_maximum (int n)
2009 _output_maximum = n;
2013 IO::set_port_latency (nframes_t nframes)
2015 Glib::Mutex::Lock lm (io_lock);
2017 for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2018 (*i)->set_latency (nframes);
2023 IO::output_latency () const
2025 nframes_t max_latency;
2030 /* io lock not taken - must be protected by other means */
2032 for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2033 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2034 max_latency = latency;
2042 IO::input_latency () const
2044 nframes_t max_latency;
2049 /* io lock not taken - must be protected by other means */
2051 for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2052 if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
2053 max_latency = latency;
2061 IO::use_input_connection (Connection& c, void* src)
2066 Glib::Mutex::Lock lm (_session.engine().process_lock());
2067 Glib::Mutex::Lock lm2 (io_lock);
2071 drop_input_connection ();
2073 if (ensure_inputs (limit, false, false, src)) {
2077 /* first pass: check the current state to see what's correctly
2078 connected, and drop anything that we don't want.
2081 for (uint32_t n = 0; n < limit; ++n) {
2082 const Connection::PortList& pl = c.port_connections (n);
2084 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2086 if (!_inputs[n]->connected_to ((*i))) {
2088 /* clear any existing connections */
2090 _session.engine().disconnect (_inputs[n]);
2092 } else if (_inputs[n]->connected() > 1) {
2094 /* OK, it is connected to the port we want,
2095 but its also connected to other ports.
2096 Change that situation.
2099 /* XXX could be optimized to not drop
2103 _session.engine().disconnect (_inputs[n]);
2109 /* second pass: connect all requested ports where necessary */
2111 for (uint32_t n = 0; n < limit; ++n) {
2112 const Connection::PortList& pl = c.port_connections (n);
2114 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2116 if (!_inputs[n]->connected_to ((*i))) {
2118 if (_session.engine().connect (*i, _inputs[n]->name())) {
2126 _input_connection = &c;
2128 input_connection_configuration_connection = c.ConfigurationChanged.connect
2129 (mem_fun (*this, &IO::input_connection_configuration_changed));
2130 input_connection_connection_connection = c.ConnectionsChanged.connect
2131 (mem_fun (*this, &IO::input_connection_connection_changed));
2134 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2139 IO::use_output_connection (Connection& c, void* src)
2144 Glib::Mutex::Lock lm (_session.engine().process_lock());
2145 Glib::Mutex::Lock lm2 (io_lock);
2149 drop_output_connection ();
2151 if (ensure_outputs (limit, false, false, src)) {
2155 /* first pass: check the current state to see what's correctly
2156 connected, and drop anything that we don't want.
2159 for (uint32_t n = 0; n < limit; ++n) {
2161 const Connection::PortList& pl = c.port_connections (n);
2163 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2165 if (!_outputs[n]->connected_to ((*i))) {
2167 /* clear any existing connections */
2169 _session.engine().disconnect (_outputs[n]);
2171 } else if (_outputs[n]->connected() > 1) {
2173 /* OK, it is connected to the port we want,
2174 but its also connected to other ports.
2175 Change that situation.
2178 /* XXX could be optimized to not drop
2182 _session.engine().disconnect (_outputs[n]);
2187 /* second pass: connect all requested ports where necessary */
2189 for (uint32_t n = 0; n < limit; ++n) {
2191 const Connection::PortList& pl = c.port_connections (n);
2193 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2195 if (!_outputs[n]->connected_to ((*i))) {
2197 if (_session.engine().connect (_outputs[n]->name(), *i)) {
2204 _output_connection = &c;
2206 output_connection_configuration_connection = c.ConfigurationChanged.connect
2207 (mem_fun (*this, &IO::output_connection_configuration_changed));
2208 output_connection_connection_connection = c.ConnectionsChanged.connect
2209 (mem_fun (*this, &IO::output_connection_connection_changed));
2212 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2218 IO::disable_connecting ()
2220 connecting_legal = false;
2225 IO::enable_connecting ()
2227 connecting_legal = true;
2228 return ConnectingLegal ();
2232 IO::disable_ports ()
2234 ports_legal = false;
2242 return PortsLegal ();
2246 IO::disable_panners (void)
2248 panners_legal = false;
2253 IO::reset_panners ()
2255 panners_legal = true;
2256 return PannersLegal ();
2260 IO::input_connection_connection_changed (int ignored)
2262 use_input_connection (*_input_connection, this);
2266 IO::input_connection_configuration_changed ()
2268 use_input_connection (*_input_connection, this);
2272 IO::output_connection_connection_changed (int ignored)
2274 use_output_connection (*_output_connection, this);
2278 IO::output_connection_configuration_changed ()
2280 use_output_connection (*_output_connection, this);
2284 IO::GainControllable::set_value (float val)
2286 io.set_gain (direct_control_to_gain (val), this);
2290 IO::GainControllable::get_value (void) const
2292 return direct_gain_to_control (io.effective_gain());
2296 IO::reset_peak_meters ()
2298 uint32_t limit = max (_ninputs, _noutputs);
2300 for (uint32_t i = 0; i < limit; ++i) {
2306 IO::setup_peak_meters ()
2308 uint32_t limit = max (_ninputs, _noutputs);
2310 while (_peak_power.size() < limit) {
2311 _peak_power.push_back (0);
2312 _visible_peak_power.push_back (0);
2317 Update the peak meters.
2319 The meter signal lock is taken to prevent modification of the
2320 Meter signal while updating the meters, taking the meter signal
2321 lock prior to taking the io_lock ensures that all IO will remain
2322 valid while metering.
2327 Glib::Mutex::Lock guard (m_meter_signal_lock);
2335 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2336 uint32_t limit = max (_ninputs, _noutputs);
2338 for (uint32_t n = 0; n < limit; ++n) {
2340 /* XXX we should use atomic exchange here */
2342 /* grab peak since last read */
2344 float new_peak = _peak_power[n];
2347 /* compute new visible value using falloff */
2349 if (new_peak > 0.0) {
2350 new_peak = coefficient_to_dB (new_peak);
2352 new_peak = minus_infinity();
2355 if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
2356 _visible_peak_power[n] = new_peak;
2359 new_peak = _visible_peak_power[n] - Config->get_meter_falloff();
2360 _visible_peak_power[n] = max (new_peak, -INFINITY);
2366 IO::save_automation (const string& path)
2371 fullpath = _session.automation_dir();
2374 out.open (fullpath.c_str());
2377 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2381 out << X_("version ") << current_automation_version_number << endl;
2383 /* XXX use apply_to_points to get thread safety */
2385 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2386 out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2395 IO::load_automation (const string& path)
2400 uint32_t linecnt = 0;
2402 LocaleGuard lg (X_("POSIX"));
2404 fullpath = _session.automation_dir();
2407 in.open (fullpath.c_str());
2410 fullpath = _session.automation_dir();
2411 fullpath += _session.snap_name();
2414 in.open (fullpath.c_str());
2416 error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
2421 clear_automation ();
2423 while (in.getline (line, sizeof(line), '\n')) {
2428 if (++linecnt == 1) {
2429 if (memcmp (line, "version", 7) == 0) {
2430 if (sscanf (line, "version %f", &version) != 1) {
2431 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2435 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2439 if (version != current_automation_version_number) {
2440 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2447 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2448 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2454 _gain_automation_curve.add (when, value, true);
2464 /* older (pre-1.0) versions of ardour used this */
2468 warning << _("dubious automation event found (and ignored)") << endmsg;
2476 IO::clear_automation ()
2478 Glib::Mutex::Lock lm (automation_lock);
2479 _gain_automation_curve.clear ();
2480 _panner->clear_automation ();
2484 IO::set_gain_automation_state (AutoState state)
2486 bool changed = false;
2489 Glib::Mutex::Lock lm (automation_lock);
2491 if (state != _gain_automation_curve.automation_state()) {
2493 _gain_automation_curve.set_automation_state (state);
2496 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2502 _session.set_dirty ();
2503 gain_automation_state_changed (); /* EMIT SIGNAL */
2508 IO::set_gain_automation_style (AutoStyle style)
2510 bool changed = false;
2513 Glib::Mutex::Lock lm (automation_lock);
2515 if (style != _gain_automation_curve.automation_style()) {
2517 _gain_automation_curve.set_automation_style (style);
2522 gain_automation_style_changed (); /* EMIT SIGNAL */
2526 IO::inc_gain (gain_t factor, void *src)
2528 if (_desired_gain == 0.0f)
2529 set_gain (0.000001f + (0.000001f * factor), src);
2531 set_gain (_desired_gain + (_desired_gain * factor), src);
2535 IO::set_gain (gain_t val, void *src)
2537 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2538 if (val>1.99526231f) val=1.99526231f;
2541 Glib::Mutex::Lock dm (declick_lock);
2542 _desired_gain = val;
2545 if (_session.transport_stopped()) {
2546 _effective_gain = val;
2551 _gain_control.Changed (); /* EMIT SIGNAL */
2553 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2554 _gain_automation_curve.add (_session.transport_frame(), val);
2558 _session.set_dirty();
2562 IO::start_gain_touch ()
2564 _gain_automation_curve.start_touch ();
2568 IO::end_gain_touch ()
2570 _gain_automation_curve.stop_touch ();
2574 IO::start_pan_touch (uint32_t which)
2576 if (which < _panner->size()) {
2577 (*_panner)[which]->automation().start_touch();
2582 IO::end_pan_touch (uint32_t which)
2584 if (which < _panner->size()) {
2585 (*_panner)[which]->automation().stop_touch();
2591 IO::transport_stopped (nframes_t frame)
2593 _gain_automation_curve.reposition_for_rt_add (frame);
2595 if (_gain_automation_curve.automation_state() != Off) {
2597 /* the src=0 condition is a special signal to not propagate
2598 automation gain changes into the mix group when locating.
2601 set_gain (_gain_automation_curve.eval (frame), 0);
2604 _panner->transport_stopped (frame);
2608 IO::find_input_port_hole ()
2610 /* CALLER MUST HOLD IO LOCK */
2614 if (_inputs.empty()) {
2618 for (n = 1; n < UINT_MAX; ++n) {
2619 char buf[jack_port_name_size()];
2620 vector<Port*>::iterator i;
2622 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2624 for (i = _inputs.begin(); i != _inputs.end(); ++i) {
2625 if ((*i)->short_name() == buf) {
2630 if (i == _inputs.end()) {
2638 IO::find_output_port_hole ()
2640 /* CALLER MUST HOLD IO LOCK */
2644 if (_outputs.empty()) {
2648 for (n = 1; n < UINT_MAX; ++n) {
2649 char buf[jack_port_name_size()];
2650 vector<Port*>::iterator i;
2652 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2654 for (i = _outputs.begin(); i != _outputs.end(); ++i) {
2655 if ((*i)->short_name() == buf) {
2660 if (i == _outputs.end()) {