2 Copyright (C) 2000-2006 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.
24 #include <sigc++/bind.h>
26 #include <glibmm/thread.h>
28 #include <pbd/xml++.h>
30 #include <ardour/audioengine.h>
31 #include <ardour/io.h>
32 #include <ardour/port.h>
33 #include <ardour/audio_port.h>
34 #include <ardour/midi_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/buffer_set.h>
40 #include <ardour/meter.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 jack_nframes_t IO::_automation_interval = 0;
65 const string IO::state_node_name = "IO";
66 bool IO::connecting_legal = false;
67 bool IO::ports_legal = false;
68 bool IO::panners_legal = false;
69 sigc::signal<void> IO::Meter;
70 sigc::signal<int> IO::ConnectingLegal;
71 sigc::signal<int> IO::PortsLegal;
72 sigc::signal<int> IO::PannersLegal;
73 sigc::signal<void,ChanCount> IO::MoreChannels;
74 sigc::signal<int> IO::PortsCreated;
76 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
78 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
79 others can be imagined.
82 static gain_t direct_control_to_gain (double fract) {
83 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
84 /* this maxes at +6dB */
85 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
88 static double direct_gain_to_control (gain_t gain) {
89 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
90 if (gain == 0) return 0.0;
92 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
96 /** @param default_type The type of port that will be created by ensure_io
97 * and friends if no type is explicitly requested (to avoid breakage).
99 IO::IO (Session& s, string name,
100 int input_min, int input_max, int output_min, int output_max,
101 DataType default_type)
103 _output_buffers(new BufferSet()),
105 _default_type(default_type),
106 _gain_control (*this),
107 _gain_automation_curve (0.0, 2.0, 1.0),
108 _input_minimum (_default_type, input_min),
109 _input_maximum (_default_type, input_max),
110 _output_minimum (_default_type, output_min),
111 _output_maximum (_default_type, output_max)
113 _panner = new Panner (name, _session);
114 _meter = new PeakMeter (_session);
118 _input_connection = 0;
119 _output_connection = 0;
120 pending_state_node = 0;
121 no_panner_reset = false;
124 apply_gain_automation = false;
126 last_automation_snapshot = 0;
128 _gain_automation_state = Off;
129 _gain_automation_style = Absolute;
132 // IO::Meter is emitted from another thread so the
133 // Meter signal must be protected.
134 Glib::Mutex::Lock guard (m_meter_signal_lock);
135 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
138 // Connect to our own MoreChannels signal to connect output buffers
139 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
144 Glib::Mutex::Lock guard (m_meter_signal_lock);
145 Glib::Mutex::Lock lm (io_lock);
147 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
148 _session.engine().unregister_port (*i);
151 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
152 _session.engine().unregister_port (*i);
155 m_meter_connection.disconnect();
159 delete _output_buffers;
163 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
165 /* io_lock, not taken: function must be called from Session::process() calltree */
167 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
168 i->silence (nframes, offset);
173 IO::pan_automated (BufferSet& bufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset)
175 _panner->distribute_automated(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
179 IO::pan (BufferSet& bufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff)
181 /* the panner can be empty if there are no inputs to the route, but still outputs */
182 if (_panner->bypassed() || _panner->empty()) {
184 deliver_output_no_pan (bufs, nframes, offset);
187 _panner->distribute(bufs, output_buffers(), nframes, offset, gain_coeff);
192 IO::deliver_output (BufferSet& bufs, jack_nframes_t nframes, jack_nframes_t offset)
196 /* io_lock, not taken: function must be called from Session::process() calltree */
198 if (n_outputs().get(DataType::AUDIO) == 0) {
202 if (_panner->bypassed() || _panner->empty()) {
203 deliver_output_no_pan (bufs, nbufs, nframes, offset);
209 gain_t pangain = _gain;
212 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
222 Declicker::run (bufs, nbufs, nframes, _gain, dg, false);
227 /* simple, non-automation panning to outputs */
229 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
230 pan (bufs, nbufs, nframes, offset, pangain * speed_quietning);
232 pan (bufs, nbufs, nframes, offset, pangain);
238 IO::deliver_output_no_pan (BufferSet& bufs, jack_nframes_t nframes, jack_nframes_t offset)
242 /* io_lock, not taken: function must be called from Session::process() calltree */
244 if (n_outputs().get(DataType::AUDIO) == 0) {
249 gain_t old_gain = _gain;
251 if (apply_gain_automation) {
253 /* gain has already been applied by automation code. do nothing here except
262 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
274 vector<Sample*> outs;
278 /* unlikely condition */
280 for (PortSet::audio_iterator o = _outputs.audio_begin(); o != _outputs.audio_end(); ++o, ++i) {
281 outs.push_back ((*o)->get_audio_buffer().data (nframes, offset));
285 /* reduce nbufs to the index of the last input buffer */
289 if (_session.transport_speed() > 1.5f || _session.transport_speed() < -1.5f) {
290 actual_gain = _gain * speed_quietning;
296 for (PortSet::audio_iterator o = _outputs.audio_begin(); o != _outputs.audio_end(); ++o, ++i) {
298 dst = (*o)->get_audio_buffer().data(nframes, offset);
299 src = bufs[min(nbufs,i)];
301 if (dg != _gain || actual_gain == 1.0f) {
302 memcpy (dst, src, sizeof (Sample) * nframes);
303 } else if (actual_gain == 0.0f) {
304 memset (dst, 0, sizeof (Sample) * nframes);
306 for (jack_nframes_t x = 0; x < nframes; ++x) {
307 dst[x] = src[x] * actual_gain;
311 (*o)->mark_silence (false);
315 Declicker::run (outs, outs.size(), nframes, _gain, dg, false);
319 if (apply_gain_automation) {
326 IO::collect_input (BufferSet& outs, jack_nframes_t nframes, jack_nframes_t offset)
328 outs.set_count(n_inputs());
330 if (outs.count() == ChanCount::ZERO)
333 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
335 BufferSet::iterator o = outs.begin(*t);
336 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
337 o->read_from(i->get_buffer(), nframes, offset);
344 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
345 jack_nframes_t nframes, jack_nframes_t offset)
347 BufferSet& bufs = _session.get_scratch_buffers ();
348 ChanCount nbufs = n_process_buffers ();
350 collect_input (bufs, nframes, offset);
352 _meter->run(bufs, nframes);
356 IO::drop_input_connection ()
358 _input_connection = 0;
359 input_connection_configuration_connection.disconnect();
360 input_connection_connection_connection.disconnect();
361 _session.set_dirty ();
365 IO::drop_output_connection ()
367 _output_connection = 0;
368 output_connection_configuration_connection.disconnect();
369 output_connection_connection_connection.disconnect();
370 _session.set_dirty ();
374 IO::disconnect_input (Port* our_port, string other_port, void* src)
376 if (other_port.length() == 0 || our_port == 0) {
381 Glib::Mutex::Lock em (_session.engine().process_lock());
384 Glib::Mutex::Lock lm (io_lock);
386 /* check that our_port is really one of ours */
388 if ( ! _inputs.contains(our_port)) {
392 /* disconnect it from the source */
394 if (_session.engine().disconnect (other_port, our_port->name())) {
395 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
399 drop_input_connection();
403 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
404 _session.set_dirty ();
410 IO::connect_input (Port* our_port, string other_port, void* src)
412 if (other_port.length() == 0 || our_port == 0) {
417 Glib::Mutex::Lock em(_session.engine().process_lock());
420 Glib::Mutex::Lock lm (io_lock);
422 /* check that our_port is really one of ours */
424 if ( ! _inputs.contains(our_port) ) {
428 /* connect it to the source */
430 if (_session.engine().connect (other_port, our_port->name())) {
434 drop_input_connection ();
438 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
439 _session.set_dirty ();
444 IO::disconnect_output (Port* our_port, string other_port, void* src)
446 if (other_port.length() == 0 || our_port == 0) {
451 Glib::Mutex::Lock em(_session.engine().process_lock());
454 Glib::Mutex::Lock lm (io_lock);
456 /* check that our_port is really one of ours */
458 if ( ! _outputs.contains(our_port) ) {
462 /* disconnect it from the destination */
464 if (_session.engine().disconnect (our_port->name(), other_port)) {
465 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
469 drop_output_connection ();
473 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
474 _session.set_dirty ();
479 IO::connect_output (Port* our_port, string other_port, void* src)
481 if (other_port.length() == 0 || our_port == 0) {
486 Glib::Mutex::Lock em(_session.engine().process_lock());
489 Glib::Mutex::Lock lm (io_lock);
491 /* check that our_port is really one of ours */
493 if ( ! _outputs.contains(our_port) ) {
497 /* connect it to the destination */
499 if (_session.engine().connect (our_port->name(), other_port)) {
503 drop_output_connection ();
507 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
508 _session.set_dirty ();
513 IO::set_input (Port* other_port, void* src)
515 /* this removes all but one ports, and connects that one port
516 to the specified source.
519 if (_input_minimum.get_total() > 1) {
520 /* sorry, you can't do this */
524 if (other_port == 0) {
525 if (_input_minimum == ChanCount::ZERO) {
526 return ensure_inputs (0, false, true, src);
532 if (ensure_inputs (1, true, true, src)) {
536 return connect_input (_inputs.port(0), other_port->name(), src);
540 IO::remove_output_port (Port* port, void* src)
544 IOChange change (NoChange);
547 Glib::Mutex::Lock em(_session.engine().process_lock());
550 Glib::Mutex::Lock lm (io_lock);
552 if (_noutputs - 1 == (uint32_t) _output_minimum) {
553 /* sorry, you can't do this */
557 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
559 change = IOChange (change|ConfigurationChanged);
560 if (port->connected()) {
561 change = IOChange (change|ConnectionsChanged);
564 _session.engine().unregister_port (*i);
567 drop_output_connection ();
573 if (change != NoChange) {
574 setup_peak_meters ();
580 if (change != NoChange) {
581 output_changed (change, src); /* EMIT SIGNAL */
582 _session.set_dirty ();
589 /** Add an output port.
591 * @param destination Name of input port to connect new port to.
592 * @param src Source for emitted ConfigurationChanged signal.
593 * @param type Data type of port. Default value (NIL) will use this IO's default type.
596 IO::add_output_port (string destination, void* src, DataType type)
601 if (type == DataType::NIL)
602 type = _default_type;
605 Glib::Mutex::Lock em(_session.engine().process_lock());
608 Glib::Mutex::Lock lm (io_lock);
610 if (n_outputs() >= _output_maximum) {
614 /* Create a new output port */
616 // FIXME: naming scheme for differently typed ports?
617 if (_output_maximum.get_total() == 1) {
618 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
620 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
623 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
624 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
628 _outputs.add_port (our_port);
629 drop_output_connection ();
630 setup_peak_meters ();
634 MoreChannels (n_outputs()); /* EMIT SIGNAL */
637 if (destination.length()) {
638 if (_session.engine().connect (our_port->name(), destination)) {
643 // pan_changed (src); /* EMIT SIGNAL */
644 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
645 _session.set_dirty ();
651 IO::remove_input_port (Port* port, void* src)
655 IOChange change (NoChange);
658 Glib::Mutex::Lock em(_session.engine().process_lock());
661 Glib::Mutex::Lock lm (io_lock);
663 if (((int)_ninputs - 1) < _input_minimum) {
664 /* sorry, you can't do this */
667 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
670 change = IOChange (change|ConfigurationChanged);
672 if (port->connected()) {
673 change = IOChange (change|ConnectionsChanged);
676 _session.engine().unregister_port (*i);
679 drop_input_connection ();
685 if (change != NoChange) {
686 setup_peak_meters ();
692 if (change != NoChange) {
693 input_changed (change, src);
694 _session.set_dirty ();
702 /** Add an input port.
704 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
705 * @param destination Name of input port to connect new port to.
706 * @param src Source for emitted ConfigurationChanged signal.
709 IO::add_input_port (string source, void* src, DataType type)
714 if (type == DataType::NIL)
715 type = _default_type;
718 Glib::Mutex::Lock em (_session.engine().process_lock());
721 Glib::Mutex::Lock lm (io_lock);
723 if (n_inputs() >= _input_maximum) {
727 /* Create a new input port */
729 // FIXME: naming scheme for differently typed ports?
730 if (_input_maximum.get_total() == 1) {
731 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
733 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
736 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
737 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
741 _inputs.add_port(our_port);
742 drop_input_connection ();
743 setup_peak_meters ();
747 MoreChannels (n_inputs()); /* EMIT SIGNAL */
750 if (source.length()) {
752 if (_session.engine().connect (source, our_port->name())) {
757 // pan_changed (src); /* EMIT SIGNAL */
758 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
759 _session.set_dirty ();
765 IO::disconnect_inputs (void* src)
768 Glib::Mutex::Lock em (_session.engine().process_lock());
771 Glib::Mutex::Lock lm (io_lock);
773 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
774 _session.engine().disconnect (*i);
777 drop_input_connection ();
781 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
787 IO::disconnect_outputs (void* src)
790 Glib::Mutex::Lock em (_session.engine().process_lock());
793 Glib::Mutex::Lock lm (io_lock);
795 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
796 _session.engine().disconnect (*i);
799 drop_output_connection ();
803 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
804 _session.set_dirty ();
810 IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
813 bool changed = false;
815 /* remove unused ports */
817 while (n_inputs().get(_default_type) > n) {
820 _session.engine().unregister_port (_inputs.back());
827 /* create any necessary new ports */
829 while (n_inputs().get(_default_type) < n) {
833 /* Create a new input port (of the default type) */
835 if (_input_maximum.get_total() == 1) {
836 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
839 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
844 if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) {
845 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
850 catch (AudioEngine::PortRegistrationFailure& err) {
851 setup_peak_meters ();
857 _inputs.add_port (input_port);
862 drop_input_connection ();
863 setup_peak_meters ();
865 MoreChannels (n_inputs()); /* EMIT SIGNAL */
866 _session.set_dirty ();
870 /* disconnect all existing ports so that we get a fresh start */
872 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
873 _session.engine().disconnect (*i);
880 /** Attach output_buffers to port buffers.
882 * Connected to IOs own MoreChannels signal.
885 IO::attach_buffers(ChanCount ignored)
887 _output_buffers->attach_buffers(_outputs);
891 IO::ensure_io (const ChanCount& in, const ChanCount& out, bool clear, void* src)
894 uint32_t nin = in.get(_default_type);
895 uint32_t nout = out.get(_default_type);
897 // We only deal with one type still. Sorry about your luck.
898 assert(nin == in.get_total());
899 assert(nout == out.get_total());
901 return ensure_io(nin, nout, clear, src);
905 IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
907 bool in_changed = false;
908 bool out_changed = false;
911 nin = min (_input_maximum.get(_default_type), static_cast<size_t>(nin));
913 nout = min (_output_maximum.get(_default_type), static_cast<size_t>(nout));
915 if (nin == n_inputs().get(_default_type) && nout == n_outputs().get(_default_type) && !clear) {
920 Glib::Mutex::Lock em (_session.engine().process_lock());
921 Glib::Mutex::Lock lm (io_lock);
925 if (n_outputs().get(_default_type) == nout) {
926 need_pan_reset = false;
928 need_pan_reset = true;
931 /* remove unused ports */
933 while (n_inputs().get(_default_type) > nin) {
936 _session.engine().unregister_port (_inputs.back());
942 while (n_outputs().get(_default_type) > nout) {
945 _session.engine().unregister_port (_outputs.back());
948 out_changed = true;*/
951 /* create any necessary new ports (of the default type) */
953 while (n_inputs().get(_default_type) < nin) {
957 /* Create a new input port */
959 if (_input_maximum.get_total() == 1) {
960 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
963 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
967 if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) {
968 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
973 catch (AudioEngine::PortRegistrationFailure& err) {
974 setup_peak_meters ();
980 _inputs.add_port (port);
984 /* create any necessary new ports */
986 while (n_outputs().get(_default_type) < nout) {
990 /* Create a new output port */
992 if (_output_maximum.get_total() == 1) {
993 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
995 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
999 if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1000 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1005 catch (AudioEngine::PortRegistrationFailure& err) {
1006 setup_peak_meters ();
1012 _outputs.add_port (port);
1018 /* disconnect all existing ports so that we get a fresh start */
1020 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1021 _session.engine().disconnect (*i);
1024 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1025 _session.engine().disconnect (*i);
1029 if (in_changed || out_changed) {
1030 setup_peak_meters ();
1036 drop_output_connection ();
1037 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1041 drop_input_connection ();
1042 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1045 if (in_changed || out_changed) {
1046 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1047 _session.set_dirty ();
1054 IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
1056 bool changed = false;
1058 n = min (_input_maximum.get(_default_type), static_cast<size_t>(n));
1060 if (n == n_inputs().get(_default_type) && !clear) {
1065 Glib::Mutex::Lock em (_session.engine().process_lock());
1066 Glib::Mutex::Lock im (io_lock);
1067 changed = ensure_inputs_locked (n, clear, src);
1069 changed = ensure_inputs_locked (n, clear, src);
1073 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1074 _session.set_dirty ();
1080 IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
1083 bool changed = false;
1084 bool need_pan_reset;
1086 if (n_outputs().get(_default_type) == n) {
1087 need_pan_reset = false;
1089 need_pan_reset = true;
1092 /* remove unused ports */
1094 while (n_outputs().get(_default_type) > n) {
1097 _session.engine().unregister_port (_outputs.back());
1098 _outputs.pop_back();
1104 /* create any necessary new ports */
1106 while (n_outputs().get(_default_type) < n) {
1110 /* Create a new output port */
1112 if (_output_maximum.get(_default_type) == 1) {
1113 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1115 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1118 if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) {
1119 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1123 _outputs.add_port (output_port);
1125 setup_peak_meters ();
1127 if (need_pan_reset) {
1133 drop_output_connection ();
1134 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1135 _session.set_dirty ();
1139 /* disconnect all existing ports so that we get a fresh start */
1141 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1142 _session.engine().disconnect (*i);
1150 IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
1152 bool changed = false;
1154 if (_output_maximum < ChanCount::INFINITE) {
1155 n = min (_output_maximum.get(_default_type), static_cast<size_t>(n));
1156 if (n == n_outputs().get(_default_type) && !clear) {
1161 /* XXX caller should hold io_lock, but generally doesn't */
1164 Glib::Mutex::Lock em (_session.engine().process_lock());
1165 Glib::Mutex::Lock im (io_lock);
1166 changed = ensure_outputs_locked (n, clear, src);
1168 changed = ensure_outputs_locked (n, clear, src);
1172 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1178 IO::effective_gain () const
1180 if (gain_automation_playback()) {
1181 return _effective_gain;
1183 return _desired_gain;
1190 if (panners_legal) {
1191 if (!no_panner_reset) {
1192 _panner->reset (n_outputs().get(_default_type), pans_required());
1195 panner_legal_c.disconnect ();
1196 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1201 IO::panners_became_legal ()
1203 _panner->reset (n_outputs().get(_default_type), pans_required());
1204 _panner->load (); // automation
1205 panner_legal_c.disconnect ();
1210 IO::defer_pan_reset ()
1212 no_panner_reset = true;
1216 IO::allow_pan_reset ()
1218 no_panner_reset = false;
1224 IO::get_state (void)
1226 return state (true);
1230 IO::state (bool full_state)
1232 XMLNode* node = new XMLNode (state_node_name);
1235 bool need_ins = true;
1236 bool need_outs = true;
1237 LocaleGuard lg (X_("POSIX"));
1238 Glib::Mutex::Lock lm (io_lock);
1240 node->add_property("name", _name);
1242 node->add_property("id", buf);
1246 if (_input_connection) {
1247 node->add_property ("input-connection", _input_connection->name());
1251 if (_output_connection) {
1252 node->add_property ("output-connection", _output_connection->name());
1257 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1259 const char **connections = i->get_connections();
1261 if (connections && connections[0]) {
1264 for (int n = 0; connections && connections[n]; ++n) {
1269 /* if its a connection to our own port,
1270 return only the port name, not the
1271 whole thing. this allows connections
1272 to be re-established even when our
1273 client name is different.
1276 str += _session.engine().make_port_name_relative (connections[n]);
1288 node->add_property ("inputs", str);
1294 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1296 const char **connections = i->get_connections();
1298 if (connections && connections[0]) {
1302 for (int n = 0; connections[n]; ++n) {
1307 str += _session.engine().make_port_name_relative (connections[n]);
1319 node->add_property ("outputs", str);
1322 node->add_child_nocopy (_panner->state (full_state));
1324 snprintf (buf, sizeof(buf), "%2.12f", gain());
1325 node->add_property ("gain", buf);
1327 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1328 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1329 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1330 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1332 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1334 node->add_property ("iolimits", buf);
1339 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1341 /* never store anything except Off for automation state in a template */
1342 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1344 node->add_property ("automation-state", buf);
1345 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1346 node->add_property ("automation-style", buf);
1348 /* XXX same for pan etc. */
1354 IO::connecting_became_legal ()
1358 if (pending_state_node == 0) {
1359 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1364 connection_legal_c.disconnect ();
1366 ret = make_connections (*pending_state_node);
1369 delete pending_state_node;
1370 pending_state_node = 0;
1377 IO::ports_became_legal ()
1381 if (pending_state_node == 0) {
1382 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1387 port_legal_c.disconnect ();
1389 ret = create_ports (*pending_state_node);
1391 if (connecting_legal) {
1392 delete pending_state_node;
1393 pending_state_node = 0;
1400 IO::set_state (const XMLNode& node)
1402 const XMLProperty* prop;
1403 XMLNodeConstIterator iter;
1404 LocaleGuard lg (X_("POSIX"));
1406 /* force use of non-localized representation of decimal point,
1407 since we use it a lot in XML files and so forth.
1410 if (node.name() != state_node_name) {
1411 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1415 if ((prop = node.property ("name")) != 0) {
1416 _name = prop->value();
1417 _panner->set_name (_name);
1420 if ((prop = node.property ("id")) != 0) {
1421 _id = prop->value ();
1426 size_t out_min = -1;
1427 size_t out_max = -1;
1429 if ((prop = node.property ("iolimits")) != 0) {
1430 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1431 &in_min, &in_max, &out_min, &out_max);
1432 _input_minimum = ChanCount(_default_type, in_min);
1433 _input_maximum = ChanCount(_default_type, in_max);
1434 _output_minimum = ChanCount(_default_type, out_min);
1435 _output_maximum = ChanCount(_default_type, out_max);
1438 if ((prop = node.property ("gain")) != 0) {
1439 set_gain (atof (prop->value().c_str()), this);
1440 _gain = _desired_gain;
1443 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1444 if ((*iter)->name() == "Panner") {
1445 _panner->set_state (**iter);
1449 if ((prop = node.property ("automation-state")) != 0) {
1452 x = strtol (prop->value().c_str(), 0, 16);
1453 set_gain_automation_state (AutoState (x));
1456 if ((prop = node.property ("automation-style")) != 0) {
1459 x = strtol (prop->value().c_str(), 0, 16);
1460 set_gain_automation_style (AutoStyle (x));
1465 if (create_ports (node)) {
1471 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1474 if (panners_legal) {
1477 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1480 if (connecting_legal) {
1482 if (make_connections (node)) {
1488 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1491 if (!ports_legal || !connecting_legal) {
1492 pending_state_node = new XMLNode (node);
1499 IO::create_ports (const XMLNode& node)
1501 const XMLProperty* prop;
1503 int num_outputs = 0;
1505 if ((prop = node.property ("input-connection")) != 0) {
1507 Connection* c = _session.connection_by_name (prop->value());
1510 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1512 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1513 error << _("No input connections available as a replacement")
1517 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1522 num_inputs = c->nports();
1524 } else if ((prop = node.property ("inputs")) != 0) {
1526 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1529 if ((prop = node.property ("output-connection")) != 0) {
1530 Connection* c = _session.connection_by_name (prop->value());
1533 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1535 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1536 error << _("No output connections available as a replacement")
1540 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1545 num_outputs = c->nports ();
1547 } else if ((prop = node.property ("outputs")) != 0) {
1548 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1551 no_panner_reset = true;
1553 if (ensure_io (num_inputs, num_outputs, true, this)) {
1554 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1558 no_panner_reset = false;
1560 set_deferred_state ();
1568 IO::make_connections (const XMLNode& node)
1570 const XMLProperty* prop;
1572 if ((prop = node.property ("input-connection")) != 0) {
1573 Connection* c = _session.connection_by_name (prop->value());
1576 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1578 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1579 error << _("No input connections available as a replacement")
1583 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1588 use_input_connection (*c, this);
1590 } else if ((prop = node.property ("inputs")) != 0) {
1591 if (set_inputs (prop->value())) {
1592 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1597 if ((prop = node.property ("output-connection")) != 0) {
1598 Connection* c = _session.connection_by_name (prop->value());
1601 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1603 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1604 error << _("No output connections available as a replacement")
1608 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1613 use_output_connection (*c, this);
1615 } else if ((prop = node.property ("outputs")) != 0) {
1616 if (set_outputs (prop->value())) {
1617 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1626 IO::set_inputs (const string& str)
1628 vector<string> ports;
1633 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1637 if (ensure_inputs (nports, true, true, this)) {
1641 string::size_type start, end, ostart;
1648 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1651 if ((end = str.find_first_of ('}', start)) == string::npos) {
1652 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1656 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1657 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1663 for (int x = 0; x < n; ++x) {
1664 connect_input (input (i), ports[x], this);
1676 IO::set_outputs (const string& str)
1678 vector<string> ports;
1683 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1687 if (ensure_outputs (nports, true, true, this)) {
1691 string::size_type start, end, ostart;
1698 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1701 if ((end = str.find_first_of ('}', start)) == string::npos) {
1702 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1706 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1707 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1713 for (int x = 0; x < n; ++x) {
1714 connect_output (output (i), ports[x], this);
1726 IO::parse_io_string (const string& str, vector<string>& ports)
1728 string::size_type pos, opos;
1730 if (str.length() == 0) {
1739 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1740 ports.push_back (str.substr (opos, pos - opos));
1744 if (opos < str.length()) {
1745 ports.push_back (str.substr(opos));
1748 return ports.size();
1752 IO::parse_gain_string (const string& str, vector<string>& ports)
1754 string::size_type pos, opos;
1760 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1761 ports.push_back (str.substr (opos, pos - opos));
1765 if (opos < str.length()) {
1766 ports.push_back (str.substr(opos));
1769 return ports.size();
1773 IO::set_name (string name, void* src)
1775 if (name == _name) {
1779 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1780 string current_name = i->short_name();
1781 current_name.replace (current_name.find (_name), _name.length(), name);
1782 i->set_name (current_name);
1785 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1786 string current_name = i->short_name();
1787 current_name.replace (current_name.find (_name), _name.length(), name);
1788 i->set_name (current_name);
1792 name_changed (src); /* EMIT SIGNAL */
1798 IO::set_input_minimum (int n)
1801 _input_minimum = ChanCount::ZERO;
1803 _input_minimum = ChanCount(_default_type, n);
1807 IO::set_input_maximum (int n)
1810 _input_maximum = ChanCount::INFINITE;
1812 _input_maximum = ChanCount(_default_type, n);
1816 IO::set_output_minimum (int n)
1819 _output_minimum = ChanCount::ZERO;
1821 _output_minimum = ChanCount(_default_type, n);
1825 IO::set_output_maximum (int n)
1828 _output_maximum = ChanCount::INFINITE;
1830 _output_maximum = ChanCount(_default_type, n);
1834 IO::set_input_minimum (ChanCount n)
1840 IO::set_input_maximum (ChanCount n)
1846 IO::set_output_minimum (ChanCount n)
1848 _output_minimum = n;
1852 IO::set_output_maximum (ChanCount n)
1854 _output_maximum = n;
1858 IO::set_port_latency (jack_nframes_t nframes)
1860 Glib::Mutex::Lock lm (io_lock);
1862 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1863 i->set_latency (nframes);
1868 IO::output_latency () const
1870 jack_nframes_t max_latency;
1871 jack_nframes_t latency;
1875 /* io lock not taken - must be protected by other means */
1877 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1878 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1879 max_latency = latency;
1887 IO::input_latency () const
1889 jack_nframes_t max_latency;
1890 jack_nframes_t latency;
1894 /* io lock not taken - must be protected by other means */
1896 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1897 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1898 max_latency = latency;
1906 IO::use_input_connection (Connection& c, void* src)
1911 Glib::Mutex::Lock lm (_session.engine().process_lock());
1912 Glib::Mutex::Lock lm2 (io_lock);
1916 drop_input_connection ();
1918 if (ensure_inputs (limit, false, false, src)) {
1922 /* first pass: check the current state to see what's correctly
1923 connected, and drop anything that we don't want.
1926 for (uint32_t n = 0; n < limit; ++n) {
1927 const Connection::PortList& pl = c.port_connections (n);
1929 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1931 if (!_inputs.port(n)->connected_to ((*i))) {
1933 /* clear any existing connections */
1935 _session.engine().disconnect (*_inputs.port(n));
1937 } else if (_inputs.port(n)->connected() > 1) {
1939 /* OK, it is connected to the port we want,
1940 but its also connected to other ports.
1941 Change that situation.
1944 /* XXX could be optimized to not drop
1948 _session.engine().disconnect (*_inputs.port(n));
1954 /* second pass: connect all requested ports where necessary */
1956 for (uint32_t n = 0; n < limit; ++n) {
1957 const Connection::PortList& pl = c.port_connections (n);
1959 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1961 if (!_inputs.port(n)->connected_to ((*i))) {
1963 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1971 _input_connection = &c;
1973 input_connection_configuration_connection = c.ConfigurationChanged.connect
1974 (mem_fun (*this, &IO::input_connection_configuration_changed));
1975 input_connection_connection_connection = c.ConnectionsChanged.connect
1976 (mem_fun (*this, &IO::input_connection_connection_changed));
1979 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1984 IO::use_output_connection (Connection& c, void* src)
1989 Glib::Mutex::Lock lm (_session.engine().process_lock());
1990 Glib::Mutex::Lock lm2 (io_lock);
1994 drop_output_connection ();
1996 if (ensure_outputs (limit, false, false, src)) {
2000 /* first pass: check the current state to see what's correctly
2001 connected, and drop anything that we don't want.
2004 for (uint32_t n = 0; n < limit; ++n) {
2006 const Connection::PortList& pl = c.port_connections (n);
2008 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2010 if (!_outputs.port(n)->connected_to ((*i))) {
2012 /* clear any existing connections */
2014 _session.engine().disconnect (*_outputs.port(n));
2016 } else if (_outputs.port(n)->connected() > 1) {
2018 /* OK, it is connected to the port we want,
2019 but its also connected to other ports.
2020 Change that situation.
2023 /* XXX could be optimized to not drop
2027 _session.engine().disconnect (*_outputs.port(n));
2032 /* second pass: connect all requested ports where necessary */
2034 for (uint32_t n = 0; n < limit; ++n) {
2036 const Connection::PortList& pl = c.port_connections (n);
2038 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2040 if (!_outputs.port(n)->connected_to ((*i))) {
2042 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2049 _output_connection = &c;
2051 output_connection_configuration_connection = c.ConfigurationChanged.connect
2052 (mem_fun (*this, &IO::output_connection_configuration_changed));
2053 output_connection_connection_connection = c.ConnectionsChanged.connect
2054 (mem_fun (*this, &IO::output_connection_connection_changed));
2057 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2063 IO::disable_connecting ()
2065 connecting_legal = false;
2070 IO::enable_connecting ()
2072 connecting_legal = true;
2073 return ConnectingLegal ();
2077 IO::disable_ports ()
2079 ports_legal = false;
2087 return PortsLegal ();
2091 IO::disable_panners (void)
2093 panners_legal = false;
2098 IO::reset_panners ()
2100 panners_legal = true;
2101 return PannersLegal ();
2105 IO::input_connection_connection_changed (int ignored)
2107 use_input_connection (*_input_connection, this);
2111 IO::input_connection_configuration_changed ()
2113 use_input_connection (*_input_connection, this);
2117 IO::output_connection_connection_changed (int ignored)
2119 use_output_connection (*_output_connection, this);
2123 IO::output_connection_configuration_changed ()
2125 use_output_connection (*_output_connection, this);
2129 IO::GainControllable::set_value (float val)
2131 io.set_gain (direct_control_to_gain (val), this);
2135 IO::GainControllable::get_value (void) const
2137 return direct_gain_to_control (io.effective_gain());
2141 IO::get_memento() const
2143 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2147 IO::restore_state (StateManager::State& state)
2152 StateManager::State*
2153 IO::state_factory (std::string why) const
2155 StateManager::State* state = new StateManager::State (why);
2160 IO::setup_peak_meters()
2162 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2166 Update the peak meters.
2168 The meter signal lock is taken to prevent modification of the
2169 Meter signal while updating the meters, taking the meter signal
2170 lock prior to taking the io_lock ensures that all IO will remain
2171 valid while metering.
2176 Glib::Mutex::Lock guard (m_meter_signal_lock);
2178 Meter(); /* EMIT SIGNAL */
2184 // FIXME: Remove this function and just connect signal directly to PeakMeter::meter
2186 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2191 IO::save_automation (const string& path)
2196 fullpath = _session.automation_dir();
2199 out.open (fullpath.c_str());
2202 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2206 out << X_("version ") << current_automation_version_number << endl;
2208 /* XXX use apply_to_points to get thread safety */
2210 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2211 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2220 IO::load_automation (const string& path)
2225 uint32_t linecnt = 0;
2227 LocaleGuard lg (X_("POSIX"));
2229 fullpath = _session.automation_dir();
2232 in.open (fullpath.c_str());
2235 fullpath = _session.automation_dir();
2236 fullpath += _session.snap_name();
2239 in.open (fullpath.c_str());
2241 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
2246 clear_automation ();
2248 while (in.getline (line, sizeof(line), '\n')) {
2250 jack_nframes_t when;
2253 if (++linecnt == 1) {
2254 if (memcmp (line, "version", 7) == 0) {
2255 if (sscanf (line, "version %f", &version) != 1) {
2256 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2260 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2264 if (version != current_automation_version_number) {
2265 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2272 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2273 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2279 _gain_automation_curve.add (when, value, true);
2289 /* older (pre-1.0) versions of ardour used this */
2293 warning << _("dubious automation event found (and ignored)") << endmsg;
2297 _gain_automation_curve.save_state (_("loaded from disk"));
2303 IO::clear_automation ()
2305 Glib::Mutex::Lock lm (automation_lock);
2306 _gain_automation_curve.clear ();
2307 _panner->clear_automation ();
2311 IO::set_gain_automation_state (AutoState state)
2313 bool changed = false;
2316 Glib::Mutex::Lock lm (automation_lock);
2318 if (state != _gain_automation_curve.automation_state()) {
2320 last_automation_snapshot = 0;
2321 _gain_automation_curve.set_automation_state (state);
2324 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2330 _session.set_dirty ();
2331 gain_automation_state_changed (); /* EMIT SIGNAL */
2336 IO::set_gain_automation_style (AutoStyle style)
2338 bool changed = false;
2341 Glib::Mutex::Lock lm (automation_lock);
2343 if (style != _gain_automation_curve.automation_style()) {
2345 _gain_automation_curve.set_automation_style (style);
2350 gain_automation_style_changed (); /* EMIT SIGNAL */
2354 IO::inc_gain (gain_t factor, void *src)
2356 if (_desired_gain == 0.0f)
2357 set_gain (0.000001f + (0.000001f * factor), src);
2359 set_gain (_desired_gain + (_desired_gain * factor), src);
2363 IO::set_gain (gain_t val, void *src)
2365 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2366 if (val>1.99526231f) val=1.99526231f;
2369 Glib::Mutex::Lock dm (declick_lock);
2370 _desired_gain = val;
2373 if (_session.transport_stopped()) {
2374 _effective_gain = val;
2379 _gain_control.Changed (); /* EMIT SIGNAL */
2381 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2382 _gain_automation_curve.add (_session.transport_frame(), val);
2386 _session.set_dirty();
2390 IO::start_gain_touch ()
2392 _gain_automation_curve.start_touch ();
2396 IO::end_gain_touch ()
2398 _gain_automation_curve.stop_touch ();
2402 IO::start_pan_touch (uint32_t which)
2404 if (which < _panner->size()) {
2405 (*_panner)[which]->automation().start_touch();
2410 IO::end_pan_touch (uint32_t which)
2412 if (which < _panner->size()) {
2413 (*_panner)[which]->automation().stop_touch();
2419 IO::automation_snapshot (jack_nframes_t now)
2421 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2423 if (gain_automation_recording()) {
2424 _gain_automation_curve.rt_add (now, gain());
2427 _panner->snapshot (now);
2429 last_automation_snapshot = now;
2434 IO::transport_stopped (jack_nframes_t frame)
2436 _gain_automation_curve.reposition_for_rt_add (frame);
2438 if (_gain_automation_curve.automation_state() != Off) {
2440 if (gain_automation_recording()) {
2441 _gain_automation_curve.save_state (_("automation write/touch"));
2444 /* the src=0 condition is a special signal to not propagate
2445 automation gain changes into the mix group when locating.
2448 set_gain (_gain_automation_curve.eval (frame), 0);
2451 _panner->transport_stopped (frame);
2455 IO::find_input_port_hole ()
2457 /* CALLER MUST HOLD IO LOCK */
2461 if (_inputs.empty()) {
2465 for (n = 1; n < UINT_MAX; ++n) {
2466 char buf[jack_port_name_size()];
2467 PortSet::iterator i = _inputs.begin();
2469 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2471 for ( ; i != _inputs.end(); ++i) {
2472 if (i->short_name() == buf) {
2477 if (i == _inputs.end()) {
2485 IO::find_output_port_hole ()
2487 /* CALLER MUST HOLD IO LOCK */
2491 if (_outputs.empty()) {
2495 for (n = 1; n < UINT_MAX; ++n) {
2496 char buf[jack_port_name_size()];
2497 PortSet::iterator i = _outputs.begin();
2499 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2501 for ( ; i != _outputs.end(); ++i) {
2502 if (i->short_name() == buf) {
2507 if (i == _outputs.end()) {
2516 IO::audio_input(uint32_t n) const
2518 return dynamic_cast<AudioPort*>(input(n));
2522 IO::audio_output(uint32_t n) const
2524 return dynamic_cast<AudioPort*>(output(n));
2528 IO::midi_input(uint32_t n) const
2530 return dynamic_cast<MidiPort*>(input(n));
2534 IO::midi_output(uint32_t n) const
2536 return dynamic_cast<MidiPort*>(output(n));