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.
25 #include <sigc++/bind.h>
27 #include <glibmm/thread.h>
29 #include <pbd/xml++.h>
31 #include <ardour/audioengine.h>
32 #include <ardour/io.h>
33 #include <ardour/port.h>
34 #include <ardour/audio_port.h>
35 #include <ardour/midi_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/buffer_set.h>
41 #include <ardour/meter.h>
42 #include <ardour/amp.h>
49 A bug in OS X's cmath that causes isnan() and isinf() to be
50 "undeclared". the following works around that
53 #if defined(__APPLE__) && defined(__MACH__)
54 extern "C" int isnan (double);
55 extern "C" int isinf (double);
60 using namespace ARDOUR;
64 static float current_automation_version_number = 1.0;
66 jack_nframes_t IO::_automation_interval = 0;
67 const string IO::state_node_name = "IO";
68 bool IO::connecting_legal = false;
69 bool IO::ports_legal = false;
70 bool IO::panners_legal = false;
71 sigc::signal<void> IO::Meter;
72 sigc::signal<int> IO::ConnectingLegal;
73 sigc::signal<int> IO::PortsLegal;
74 sigc::signal<int> IO::PannersLegal;
75 sigc::signal<void,ChanCount> IO::MoreChannels;
76 sigc::signal<int> IO::PortsCreated;
78 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
80 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
81 others can be imagined.
84 static gain_t direct_control_to_gain (double fract) {
85 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
86 /* this maxes at +6dB */
87 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
90 static double direct_gain_to_control (gain_t gain) {
91 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
92 if (gain == 0) return 0.0;
94 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
98 /** @param default_type The type of port that will be created by ensure_io
99 * and friends if no type is explicitly requested (to avoid breakage).
101 IO::IO (Session& s, string name,
102 int input_min, int input_max, int output_min, int output_max,
103 DataType default_type)
105 _output_buffers(new BufferSet()),
107 _default_type(default_type),
108 _gain_control (*this),
109 _gain_automation_curve (0.0, 2.0, 1.0),
110 _input_minimum (ChanCount::ZERO),
111 _input_maximum (ChanCount::INFINITE),
112 _output_minimum (ChanCount::ZERO),
113 _output_maximum (ChanCount::INFINITE)
115 _panner = new Panner (name, _session);
116 _meter = new PeakMeter (_session);
119 _input_minimum = ChanCount(_default_type, input_min);
121 if (input_max >= 0) {
122 _input_maximum = ChanCount(_default_type, input_max);
124 if (output_min > 0) {
125 _output_minimum = ChanCount(_default_type, output_min);
127 if (output_max >= 0) {
128 _output_maximum = ChanCount(_default_type, output_max);
133 _input_connection = 0;
134 _output_connection = 0;
135 pending_state_node = 0;
136 no_panner_reset = false;
137 _phase_invert = false;
140 apply_gain_automation = false;
142 last_automation_snapshot = 0;
144 _gain_automation_state = Off;
145 _gain_automation_style = Absolute;
148 // IO::Meter is emitted from another thread so the
149 // Meter signal must be protected.
150 Glib::Mutex::Lock guard (m_meter_signal_lock);
151 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
154 // Connect to our own MoreChannels signal to connect output buffers
155 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
160 Glib::Mutex::Lock guard (m_meter_signal_lock);
162 Glib::Mutex::Lock lm (io_lock);
164 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
165 _session.engine().unregister_port (*i);
168 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
169 _session.engine().unregister_port (*i);
172 m_meter_connection.disconnect();
176 delete _output_buffers;
180 IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
182 /* io_lock, not taken: function must be called from Session::process() calltree */
184 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
185 i->get_buffer().silence (nframes, offset);
189 /** Deliver bufs to the IO's Jack outputs.
191 * This function should automatically do whatever it necessary to correctly deliver bufs
192 * to the outputs, eg applying gain or pan or whatever else needs to be done.
195 IO::deliver_output (BufferSet& bufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset)
197 // FIXME: type specific code doesn't actually need to be here, it will go away in time
200 /* ********** AUDIO ********** */
202 // Apply gain if gain automation isn't playing
203 if ( ! apply_gain_automation) {
205 gain_t dg = _gain; // desired gain
208 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
215 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
218 // Use the panner to distribute audio to output port buffers
219 if (_panner && !_panner->empty() && !_panner->bypassed()) {
220 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
222 const DataType type = DataType::AUDIO;
224 // Copy any audio 1:1 to outputs
225 assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
226 BufferSet::iterator o = output_buffers().begin(type);
227 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
228 o->read_from(*i, nframes, offset);
233 /* ********** MIDI ********** */
235 // No MIDI, we're done here
236 if (bufs.count().get(DataType::MIDI) == 0) {
240 const DataType type = DataType::MIDI;
242 // Copy any MIDI 1:1 to outputs
243 assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
244 BufferSet::iterator o = output_buffers().begin(type);
245 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
246 o->read_from(*i, nframes, offset);
251 IO::collect_input (BufferSet& outs, jack_nframes_t nframes, jack_nframes_t offset)
253 assert(outs.available() >= n_inputs());
255 outs.set_count(n_inputs());
257 if (outs.count() == ChanCount::ZERO)
260 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
262 BufferSet::iterator o = outs.begin(*t);
263 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
264 o->read_from(i->get_buffer(), nframes, offset);
271 IO::just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame,
272 jack_nframes_t nframes, jack_nframes_t offset)
274 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
276 collect_input (bufs, nframes, offset);
278 _meter->run(bufs, nframes);
282 IO::drop_input_connection ()
284 _input_connection = 0;
285 input_connection_configuration_connection.disconnect();
286 input_connection_connection_connection.disconnect();
287 _session.set_dirty ();
291 IO::drop_output_connection ()
293 _output_connection = 0;
294 output_connection_configuration_connection.disconnect();
295 output_connection_connection_connection.disconnect();
296 _session.set_dirty ();
300 IO::disconnect_input (Port* our_port, string other_port, void* src)
302 if (other_port.length() == 0 || our_port == 0) {
307 Glib::Mutex::Lock em (_session.engine().process_lock());
310 Glib::Mutex::Lock lm (io_lock);
312 /* check that our_port is really one of ours */
314 if ( ! _inputs.contains(our_port)) {
318 /* disconnect it from the source */
320 if (_session.engine().disconnect (other_port, our_port->name())) {
321 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
325 drop_input_connection();
329 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
330 _session.set_dirty ();
336 IO::connect_input (Port* our_port, string other_port, void* src)
338 if (other_port.length() == 0 || our_port == 0) {
343 Glib::Mutex::Lock em(_session.engine().process_lock());
346 Glib::Mutex::Lock lm (io_lock);
348 /* check that our_port is really one of ours */
350 if ( ! _inputs.contains(our_port) ) {
354 /* connect it to the source */
356 if (_session.engine().connect (other_port, our_port->name())) {
360 drop_input_connection ();
364 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
365 _session.set_dirty ();
370 IO::disconnect_output (Port* our_port, string other_port, void* src)
372 if (other_port.length() == 0 || our_port == 0) {
377 Glib::Mutex::Lock em(_session.engine().process_lock());
380 Glib::Mutex::Lock lm (io_lock);
382 /* check that our_port is really one of ours */
384 if ( ! _outputs.contains(our_port) ) {
388 /* disconnect it from the destination */
390 if (_session.engine().disconnect (our_port->name(), other_port)) {
391 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
395 drop_output_connection ();
399 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
400 _session.set_dirty ();
405 IO::connect_output (Port* our_port, string other_port, void* src)
407 if (other_port.length() == 0 || our_port == 0) {
412 Glib::Mutex::Lock em(_session.engine().process_lock());
415 Glib::Mutex::Lock lm (io_lock);
417 /* check that our_port is really one of ours */
419 if ( ! _outputs.contains(our_port) ) {
423 /* connect it to the destination */
425 if (_session.engine().connect (our_port->name(), other_port)) {
429 drop_output_connection ();
433 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
434 _session.set_dirty ();
439 IO::set_input (Port* other_port, void* src)
441 /* this removes all but one ports, and connects that one port
442 to the specified source.
445 if (_input_minimum.get_total() > 1) {
446 /* sorry, you can't do this */
450 if (other_port == 0) {
451 if (_input_minimum == ChanCount::ZERO) {
452 return ensure_inputs (ChanCount::ZERO, false, true, src);
458 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
462 return connect_input (_inputs.port(0), other_port->name(), src);
466 IO::remove_output_port (Port* port, void* src)
468 IOChange change (NoChange);
471 Glib::Mutex::Lock em(_session.engine().process_lock());
474 Glib::Mutex::Lock lm (io_lock);
476 if (n_outputs() <= _output_minimum) {
477 /* sorry, you can't do this */
481 if (_outputs.remove(port)) {
482 change = IOChange (change|ConfigurationChanged);
484 if (port->connected()) {
485 change = IOChange (change|ConnectionsChanged);
488 _session.engine().unregister_port (*port);
489 drop_output_connection ();
491 setup_peak_meters ();
497 if (change != NoChange) {
498 output_changed (change, src);
499 _session.set_dirty ();
506 /** Add an output port.
508 * @param destination Name of input port to connect new port to.
509 * @param src Source for emitted ConfigurationChanged signal.
510 * @param type Data type of port. Default value (NIL) will use this IO's default type.
513 IO::add_output_port (string destination, void* src, DataType type)
518 if (type == DataType::NIL)
519 type = _default_type;
522 Glib::Mutex::Lock em(_session.engine().process_lock());
525 Glib::Mutex::Lock lm (io_lock);
527 if (n_outputs() >= _output_maximum) {
531 /* Create a new output port */
533 // FIXME: naming scheme for differently typed ports?
534 if (_output_maximum.get(type) == 1) {
535 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
537 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
540 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
541 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
545 _outputs.add (our_port);
546 drop_output_connection ();
547 setup_peak_meters ();
551 MoreChannels (n_outputs()); /* EMIT SIGNAL */
554 if (destination.length()) {
555 if (_session.engine().connect (our_port->name(), destination)) {
560 // pan_changed (src); /* EMIT SIGNAL */
561 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
562 _session.set_dirty ();
568 IO::remove_input_port (Port* port, void* src)
570 IOChange change (NoChange);
573 Glib::Mutex::Lock em(_session.engine().process_lock());
576 Glib::Mutex::Lock lm (io_lock);
578 if (n_inputs() <= _input_minimum) {
579 /* sorry, you can't do this */
583 if (_inputs.remove(port)) {
584 change = IOChange (change|ConfigurationChanged);
586 if (port->connected()) {
587 change = IOChange (change|ConnectionsChanged);
590 _session.engine().unregister_port (*port);
591 drop_input_connection ();
593 setup_peak_meters ();
599 if (change != NoChange) {
600 input_changed (change, src);
601 _session.set_dirty ();
609 /** Add an input port.
611 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
612 * @param destination Name of input port to connect new port to.
613 * @param src Source for emitted ConfigurationChanged signal.
616 IO::add_input_port (string source, void* src, DataType type)
621 if (type == DataType::NIL)
622 type = _default_type;
625 Glib::Mutex::Lock em (_session.engine().process_lock());
628 Glib::Mutex::Lock lm (io_lock);
630 if (n_inputs() >= _input_maximum) {
634 /* Create a new input port */
636 // FIXME: naming scheme for differently typed ports?
637 if (_input_maximum.get(type) == 1) {
638 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
640 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
643 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
644 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
648 _inputs.add (our_port);
649 drop_input_connection ();
650 setup_peak_meters ();
654 MoreChannels (n_inputs()); /* EMIT SIGNAL */
657 if (source.length()) {
659 if (_session.engine().connect (source, our_port->name())) {
664 // pan_changed (src); /* EMIT SIGNAL */
665 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
666 _session.set_dirty ();
672 IO::disconnect_inputs (void* src)
675 Glib::Mutex::Lock em (_session.engine().process_lock());
678 Glib::Mutex::Lock lm (io_lock);
680 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
681 _session.engine().disconnect (*i);
684 drop_input_connection ();
688 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
694 IO::disconnect_outputs (void* src)
697 Glib::Mutex::Lock em (_session.engine().process_lock());
700 Glib::Mutex::Lock lm (io_lock);
702 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
703 _session.engine().disconnect (*i);
706 drop_output_connection ();
710 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
711 _session.set_dirty ();
717 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
719 Port* input_port = 0;
720 bool changed = false;
723 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
725 const size_t n = count.get(*t);
727 /* remove unused ports */
728 for (size_t i = n_inputs().get(*t); i > n; --i) {
729 input_port = _inputs.port(*t, i-1);
732 _inputs.remove(input_port);
733 _session.engine().unregister_port (*input_port);
738 /* create any necessary new ports */
739 while (n_inputs().get(*t) < n) {
743 if (_input_maximum.get(*t) == 1) {
744 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
746 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
751 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
752 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
757 catch (AudioEngine::PortRegistrationFailure& err) {
758 setup_peak_meters ();
764 _inputs.add (input_port);
770 drop_input_connection ();
771 setup_peak_meters ();
773 MoreChannels (n_inputs()); /* EMIT SIGNAL */
774 _session.set_dirty ();
778 /* disconnect all existing ports so that we get a fresh start */
779 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
780 _session.engine().disconnect (*i);
787 /** Attach output_buffers to port buffers.
789 * Connected to IO's own MoreChannels signal.
792 IO::attach_buffers(ChanCount ignored)
794 _output_buffers->attach_buffers(_outputs);
798 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
800 bool in_changed = false;
801 bool out_changed = false;
802 bool need_pan_reset = false;
804 in = min (_input_maximum, in);
806 out = min (_output_maximum, out);
808 if (in == n_inputs() && out == n_outputs() && !clear) {
813 Glib::Mutex::Lock em (_session.engine().process_lock());
814 Glib::Mutex::Lock lm (io_lock);
818 if (n_outputs() != out) {
819 need_pan_reset = true;
822 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
824 const size_t nin = in.get(*t);
825 const size_t nout = out.get(*t);
827 Port* output_port = 0;
828 Port* input_port = 0;
830 /* remove unused output ports */
831 for (size_t i = n_outputs().get(*t); i > nout; --i) {
832 output_port = _outputs.port(*t, i-1);
835 _outputs.remove(output_port);
836 _session.engine().unregister_port (*output_port);
841 /* remove unused input ports */
842 for (size_t i = n_inputs().get(*t); i > nin; --i) {
843 input_port = _inputs.port(*t, i-1);
846 _inputs.remove(input_port);
847 _session.engine().unregister_port (*input_port);
852 /* create any necessary new input ports */
854 while (n_inputs().get(*t) < nin) {
858 /* Create a new input port */
860 if (_input_maximum.get(*t) == 1) {
861 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
863 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
867 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
868 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
873 catch (AudioEngine::PortRegistrationFailure& err) {
874 setup_peak_meters ();
884 /* create any necessary new output ports */
886 while (n_outputs().get(*t) < nout) {
890 /* Create a new output port */
892 if (_output_maximum.get(*t) == 1) {
893 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
895 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
899 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
900 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
905 catch (AudioEngine::PortRegistrationFailure& err) {
906 setup_peak_meters ();
919 /* disconnect all existing ports so that we get a fresh start */
921 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
922 _session.engine().disconnect (*i);
925 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
926 _session.engine().disconnect (*i);
930 if (in_changed || out_changed) {
931 setup_peak_meters ();
937 drop_output_connection ();
938 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
942 drop_input_connection ();
943 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
946 if (in_changed || out_changed) {
947 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
948 _session.set_dirty ();
955 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
957 bool changed = false;
959 count = min (_input_maximum, count);
961 if (count == n_inputs() && !clear) {
966 Glib::Mutex::Lock em (_session.engine().process_lock());
967 Glib::Mutex::Lock im (io_lock);
968 changed = ensure_inputs_locked (count, clear, src);
970 changed = ensure_inputs_locked (count, clear, src);
974 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
975 _session.set_dirty ();
981 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
983 Port* output_port = 0;
984 bool changed = false;
985 bool need_pan_reset = false;
987 if (n_outputs() != count) {
988 need_pan_reset = true;
991 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
993 const size_t n = count.get(*t);
995 /* remove unused ports */
996 for (size_t i = n_outputs().get(*t); i > n; --i) {
997 output_port = _outputs.port(*t, i-1);
1000 _outputs.remove(output_port);
1001 _session.engine().unregister_port (*output_port);
1006 /* create any necessary new ports */
1007 while (n_outputs().get(*t) < n) {
1011 if (_output_maximum.get(*t) == 1) {
1012 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1014 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1017 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1018 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1022 _outputs.add (output_port);
1024 setup_peak_meters ();
1026 if (need_pan_reset) {
1033 drop_output_connection ();
1034 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1035 _session.set_dirty ();
1039 /* disconnect all existing ports so that we get a fresh start */
1040 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1041 _session.engine().disconnect (*i);
1049 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1051 bool changed = false;
1053 if (_output_maximum < ChanCount::INFINITE) {
1054 count = min (_output_maximum, count);
1055 if (count == n_outputs() && !clear) {
1060 /* XXX caller should hold io_lock, but generally doesn't */
1063 Glib::Mutex::Lock em (_session.engine().process_lock());
1064 Glib::Mutex::Lock im (io_lock);
1065 changed = ensure_outputs_locked (count, clear, src);
1067 changed = ensure_outputs_locked (count, clear, src);
1071 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1078 IO::effective_gain () const
1080 if (gain_automation_playback()) {
1081 return _effective_gain;
1083 return _desired_gain;
1090 if (panners_legal) {
1091 if (!no_panner_reset) {
1092 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1095 panner_legal_c.disconnect ();
1096 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1101 IO::panners_became_legal ()
1103 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1104 _panner->load (); // automation
1105 panner_legal_c.disconnect ();
1110 IO::defer_pan_reset ()
1112 no_panner_reset = true;
1116 IO::allow_pan_reset ()
1118 no_panner_reset = false;
1124 IO::get_state (void)
1126 return state (true);
1130 IO::state (bool full_state)
1132 XMLNode* node = new XMLNode (state_node_name);
1135 bool need_ins = true;
1136 bool need_outs = true;
1137 LocaleGuard lg (X_("POSIX"));
1138 Glib::Mutex::Lock lm (io_lock);
1140 node->add_property("name", _name);
1142 node->add_property("id", buf);
1146 if (_input_connection) {
1147 node->add_property ("input-connection", _input_connection->name());
1151 if (_output_connection) {
1152 node->add_property ("output-connection", _output_connection->name());
1157 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1159 const char **connections = i->get_connections();
1161 if (connections && connections[0]) {
1164 for (int n = 0; connections && connections[n]; ++n) {
1169 /* if its a connection to our own port,
1170 return only the port name, not the
1171 whole thing. this allows connections
1172 to be re-established even when our
1173 client name is different.
1176 str += _session.engine().make_port_name_relative (connections[n]);
1188 node->add_property ("inputs", str);
1194 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1196 const char **connections = i->get_connections();
1198 if (connections && connections[0]) {
1202 for (int n = 0; connections[n]; ++n) {
1207 str += _session.engine().make_port_name_relative (connections[n]);
1219 node->add_property ("outputs", str);
1222 node->add_child_nocopy (_panner->state (full_state));
1224 snprintf (buf, sizeof(buf), "%2.12f", gain());
1225 node->add_property ("gain", buf);
1227 // FIXME: this is NOT sufficient!
1228 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1229 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1230 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1231 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1233 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1235 node->add_property ("iolimits", buf);
1240 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1242 /* never store anything except Off for automation state in a template */
1243 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1245 node->add_property ("automation-state", buf);
1246 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style());
1247 node->add_property ("automation-style", buf);
1249 /* XXX same for pan etc. */
1255 IO::connecting_became_legal ()
1259 if (pending_state_node == 0) {
1260 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1265 connection_legal_c.disconnect ();
1267 ret = make_connections (*pending_state_node);
1270 delete pending_state_node;
1271 pending_state_node = 0;
1278 IO::ports_became_legal ()
1282 if (pending_state_node == 0) {
1283 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1288 port_legal_c.disconnect ();
1290 ret = create_ports (*pending_state_node);
1292 if (connecting_legal) {
1293 delete pending_state_node;
1294 pending_state_node = 0;
1301 IO::set_state (const XMLNode& node)
1303 const XMLProperty* prop;
1304 XMLNodeConstIterator iter;
1305 LocaleGuard lg (X_("POSIX"));
1307 /* force use of non-localized representation of decimal point,
1308 since we use it a lot in XML files and so forth.
1311 if (node.name() != state_node_name) {
1312 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1316 if ((prop = node.property ("name")) != 0) {
1317 _name = prop->value();
1318 _panner->set_name (_name);
1321 if ((prop = node.property ("id")) != 0) {
1322 _id = prop->value ();
1327 size_t out_min = -1;
1328 size_t out_max = -1;
1330 if ((prop = node.property ("iolimits")) != 0) {
1331 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1332 &in_min, &in_max, &out_min, &out_max);
1333 _input_minimum = ChanCount(_default_type, in_min);
1334 _input_maximum = ChanCount(_default_type, in_max);
1335 _output_minimum = ChanCount(_default_type, out_min);
1336 _output_maximum = ChanCount(_default_type, out_max);
1339 if ((prop = node.property ("gain")) != 0) {
1340 set_gain (atof (prop->value().c_str()), this);
1341 _gain = _desired_gain;
1344 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1345 if ((*iter)->name() == "Panner") {
1346 _panner->set_state (**iter);
1350 if ((prop = node.property ("automation-state")) != 0) {
1353 x = strtol (prop->value().c_str(), 0, 16);
1354 set_gain_automation_state (AutoState (x));
1357 if ((prop = node.property ("automation-style")) != 0) {
1360 x = strtol (prop->value().c_str(), 0, 16);
1361 set_gain_automation_style (AutoStyle (x));
1366 if (create_ports (node)) {
1372 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1375 if (panners_legal) {
1378 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1381 if (connecting_legal) {
1383 if (make_connections (node)) {
1389 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1392 if (!ports_legal || !connecting_legal) {
1393 pending_state_node = new XMLNode (node);
1400 IO::create_ports (const XMLNode& node)
1402 const XMLProperty* prop;
1404 int num_outputs = 0;
1406 if ((prop = node.property ("input-connection")) != 0) {
1408 Connection* c = _session.connection_by_name (prop->value());
1411 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1413 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1414 error << _("No input connections available as a replacement")
1418 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1423 num_inputs = c->nports();
1425 } else if ((prop = node.property ("inputs")) != 0) {
1427 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1430 if ((prop = node.property ("output-connection")) != 0) {
1431 Connection* c = _session.connection_by_name (prop->value());
1434 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1436 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1437 error << _("No output connections available as a replacement")
1441 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1446 num_outputs = c->nports ();
1448 } else if ((prop = node.property ("outputs")) != 0) {
1449 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1452 no_panner_reset = true;
1454 // FIXME: audio-only
1455 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1456 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1460 no_panner_reset = false;
1462 set_deferred_state ();
1470 IO::make_connections (const XMLNode& node)
1472 const XMLProperty* prop;
1474 if ((prop = node.property ("input-connection")) != 0) {
1475 Connection* c = _session.connection_by_name (prop->value());
1478 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1480 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1481 error << _("No input connections available as a replacement")
1485 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1490 use_input_connection (*c, this);
1492 } else if ((prop = node.property ("inputs")) != 0) {
1493 if (set_inputs (prop->value())) {
1494 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1499 if ((prop = node.property ("output-connection")) != 0) {
1500 Connection* c = _session.connection_by_name (prop->value());
1503 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1505 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1506 error << _("No output connections available as a replacement")
1510 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1515 use_output_connection (*c, this);
1517 } else if ((prop = node.property ("outputs")) != 0) {
1518 if (set_outputs (prop->value())) {
1519 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1528 IO::set_inputs (const string& str)
1530 vector<string> ports;
1535 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1539 // FIXME: audio-only
1540 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1544 string::size_type start, end, ostart;
1551 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1554 if ((end = str.find_first_of ('}', start)) == string::npos) {
1555 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1559 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1560 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1566 for (int x = 0; x < n; ++x) {
1567 connect_input (input (i), ports[x], this);
1579 IO::set_outputs (const string& str)
1581 vector<string> ports;
1586 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1590 // FIXME: audio-only
1591 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1595 string::size_type start, end, ostart;
1602 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1605 if ((end = str.find_first_of ('}', start)) == string::npos) {
1606 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1610 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1611 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1617 for (int x = 0; x < n; ++x) {
1618 connect_output (output (i), ports[x], this);
1630 IO::parse_io_string (const string& str, vector<string>& ports)
1632 string::size_type pos, opos;
1634 if (str.length() == 0) {
1643 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1644 ports.push_back (str.substr (opos, pos - opos));
1648 if (opos < str.length()) {
1649 ports.push_back (str.substr(opos));
1652 return ports.size();
1656 IO::parse_gain_string (const string& str, vector<string>& ports)
1658 string::size_type pos, opos;
1664 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1665 ports.push_back (str.substr (opos, pos - opos));
1669 if (opos < str.length()) {
1670 ports.push_back (str.substr(opos));
1673 return ports.size();
1677 IO::set_name (string name, void* src)
1679 if (name == _name) {
1683 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1684 string current_name = i->short_name();
1685 current_name.replace (current_name.find (_name), _name.length(), name);
1686 i->set_name (current_name);
1689 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1690 string current_name = i->short_name();
1691 current_name.replace (current_name.find (_name), _name.length(), name);
1692 i->set_name (current_name);
1696 name_changed (src); /* EMIT SIGNAL */
1702 IO::set_input_minimum (int n)
1705 _input_minimum = ChanCount::ZERO;
1707 _input_minimum = ChanCount(_default_type, n);
1711 IO::set_input_maximum (int n)
1714 _input_maximum = ChanCount::INFINITE;
1716 _input_maximum = ChanCount(_default_type, n);
1720 IO::set_output_minimum (int n)
1723 _output_minimum = ChanCount::ZERO;
1725 _output_minimum = ChanCount(_default_type, n);
1729 IO::set_output_maximum (int n)
1732 _output_maximum = ChanCount::INFINITE;
1734 _output_maximum = ChanCount(_default_type, n);
1738 IO::set_input_minimum (ChanCount n)
1744 IO::set_input_maximum (ChanCount n)
1750 IO::set_output_minimum (ChanCount n)
1752 _output_minimum = n;
1756 IO::set_output_maximum (ChanCount n)
1758 _output_maximum = n;
1762 IO::set_port_latency (jack_nframes_t nframes)
1764 Glib::Mutex::Lock lm (io_lock);
1766 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1767 i->set_latency (nframes);
1772 IO::output_latency () const
1774 jack_nframes_t max_latency;
1775 jack_nframes_t latency;
1779 /* io lock not taken - must be protected by other means */
1781 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1782 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1783 max_latency = latency;
1791 IO::input_latency () const
1793 jack_nframes_t max_latency;
1794 jack_nframes_t latency;
1798 /* io lock not taken - must be protected by other means */
1800 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1801 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1802 max_latency = latency;
1810 IO::use_input_connection (Connection& c, void* src)
1815 Glib::Mutex::Lock lm (_session.engine().process_lock());
1816 Glib::Mutex::Lock lm2 (io_lock);
1820 drop_input_connection ();
1822 // FIXME connections only work for audio-only
1823 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1827 /* first pass: check the current state to see what's correctly
1828 connected, and drop anything that we don't want.
1831 for (uint32_t n = 0; n < limit; ++n) {
1832 const Connection::PortList& pl = c.port_connections (n);
1834 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1836 if (!_inputs.port(n)->connected_to ((*i))) {
1838 /* clear any existing connections */
1840 _session.engine().disconnect (*_inputs.port(n));
1842 } else if (_inputs.port(n)->connected() > 1) {
1844 /* OK, it is connected to the port we want,
1845 but its also connected to other ports.
1846 Change that situation.
1849 /* XXX could be optimized to not drop
1853 _session.engine().disconnect (*_inputs.port(n));
1859 /* second pass: connect all requested ports where necessary */
1861 for (uint32_t n = 0; n < limit; ++n) {
1862 const Connection::PortList& pl = c.port_connections (n);
1864 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1866 if (!_inputs.port(n)->connected_to ((*i))) {
1868 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1876 _input_connection = &c;
1878 input_connection_configuration_connection = c.ConfigurationChanged.connect
1879 (mem_fun (*this, &IO::input_connection_configuration_changed));
1880 input_connection_connection_connection = c.ConnectionsChanged.connect
1881 (mem_fun (*this, &IO::input_connection_connection_changed));
1884 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1889 IO::use_output_connection (Connection& c, void* src)
1894 Glib::Mutex::Lock lm (_session.engine().process_lock());
1895 Glib::Mutex::Lock lm2 (io_lock);
1899 drop_output_connection ();
1901 // FIXME: audio-only
1902 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1906 /* first pass: check the current state to see what's correctly
1907 connected, and drop anything that we don't want.
1910 for (uint32_t n = 0; n < limit; ++n) {
1912 const Connection::PortList& pl = c.port_connections (n);
1914 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1916 if (!_outputs.port(n)->connected_to ((*i))) {
1918 /* clear any existing connections */
1920 _session.engine().disconnect (*_outputs.port(n));
1922 } else if (_outputs.port(n)->connected() > 1) {
1924 /* OK, it is connected to the port we want,
1925 but its also connected to other ports.
1926 Change that situation.
1929 /* XXX could be optimized to not drop
1933 _session.engine().disconnect (*_outputs.port(n));
1938 /* second pass: connect all requested ports where necessary */
1940 for (uint32_t n = 0; n < limit; ++n) {
1942 const Connection::PortList& pl = c.port_connections (n);
1944 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1946 if (!_outputs.port(n)->connected_to ((*i))) {
1948 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
1955 _output_connection = &c;
1957 output_connection_configuration_connection = c.ConfigurationChanged.connect
1958 (mem_fun (*this, &IO::output_connection_configuration_changed));
1959 output_connection_connection_connection = c.ConnectionsChanged.connect
1960 (mem_fun (*this, &IO::output_connection_connection_changed));
1963 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
1969 IO::disable_connecting ()
1971 connecting_legal = false;
1976 IO::enable_connecting ()
1978 connecting_legal = true;
1979 return ConnectingLegal ();
1983 IO::disable_ports ()
1985 ports_legal = false;
1993 return PortsLegal ();
1997 IO::disable_panners (void)
1999 panners_legal = false;
2004 IO::reset_panners ()
2006 panners_legal = true;
2007 return PannersLegal ();
2011 IO::input_connection_connection_changed (int ignored)
2013 use_input_connection (*_input_connection, this);
2017 IO::input_connection_configuration_changed ()
2019 use_input_connection (*_input_connection, this);
2023 IO::output_connection_connection_changed (int ignored)
2025 use_output_connection (*_output_connection, this);
2029 IO::output_connection_configuration_changed ()
2031 use_output_connection (*_output_connection, this);
2035 IO::GainControllable::set_value (float val)
2037 io.set_gain (direct_control_to_gain (val), this);
2041 IO::GainControllable::get_value (void) const
2043 return direct_gain_to_control (io.effective_gain());
2047 IO::get_memento() const
2049 return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id);
2053 IO::restore_state (StateManager::State& state)
2058 StateManager::State*
2059 IO::state_factory (std::string why) const
2061 StateManager::State* state = new StateManager::State (why);
2066 IO::setup_peak_meters()
2068 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2072 Update the peak meters.
2074 The meter signal lock is taken to prevent modification of the
2075 Meter signal while updating the meters, taking the meter signal
2076 lock prior to taking the io_lock ensures that all IO will remain
2077 valid while metering.
2082 Glib::Mutex::Lock guard (m_meter_signal_lock);
2084 Meter(); /* EMIT SIGNAL */
2090 // FIXME: Remove this function and just connect signal directly to PeakMeter::meter
2092 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2097 IO::save_automation (const string& path)
2102 fullpath = _session.automation_dir();
2105 out.open (fullpath.c_str());
2108 error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg;
2112 out << X_("version ") << current_automation_version_number << endl;
2114 /* XXX use apply_to_points to get thread safety */
2116 for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) {
2117 out << "g " << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl;
2126 IO::load_automation (const string& path)
2131 uint32_t linecnt = 0;
2133 LocaleGuard lg (X_("POSIX"));
2135 fullpath = _session.automation_dir();
2138 in.open (fullpath.c_str());
2141 fullpath = _session.automation_dir();
2142 fullpath += _session.snap_name();
2145 in.open (fullpath.c_str());
2147 error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg;
2152 clear_automation ();
2154 while (in.getline (line, sizeof(line), '\n')) {
2156 jack_nframes_t when;
2159 if (++linecnt == 1) {
2160 if (memcmp (line, "version", 7) == 0) {
2161 if (sscanf (line, "version %f", &version) != 1) {
2162 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
2166 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
2170 if (version != current_automation_version_number) {
2171 error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg;
2178 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
2179 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
2185 _gain_automation_curve.add (when, value, true);
2195 /* older (pre-1.0) versions of ardour used this */
2199 warning << _("dubious automation event found (and ignored)") << endmsg;
2203 _gain_automation_curve.save_state (_("loaded from disk"));
2209 IO::clear_automation ()
2211 Glib::Mutex::Lock lm (automation_lock);
2212 _gain_automation_curve.clear ();
2213 _panner->clear_automation ();
2217 IO::set_gain_automation_state (AutoState state)
2219 bool changed = false;
2222 Glib::Mutex::Lock lm (automation_lock);
2224 if (state != _gain_automation_curve.automation_state()) {
2226 last_automation_snapshot = 0;
2227 _gain_automation_curve.set_automation_state (state);
2230 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2236 _session.set_dirty ();
2237 gain_automation_state_changed (); /* EMIT SIGNAL */
2242 IO::set_gain_automation_style (AutoStyle style)
2244 bool changed = false;
2247 Glib::Mutex::Lock lm (automation_lock);
2249 if (style != _gain_automation_curve.automation_style()) {
2251 _gain_automation_curve.set_automation_style (style);
2256 gain_automation_style_changed (); /* EMIT SIGNAL */
2260 IO::inc_gain (gain_t factor, void *src)
2262 if (_desired_gain == 0.0f)
2263 set_gain (0.000001f + (0.000001f * factor), src);
2265 set_gain (_desired_gain + (_desired_gain * factor), src);
2269 IO::set_gain (gain_t val, void *src)
2271 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2272 if (val>1.99526231f) val=1.99526231f;
2275 Glib::Mutex::Lock dm (declick_lock);
2276 _desired_gain = val;
2279 if (_session.transport_stopped()) {
2280 _effective_gain = val;
2285 _gain_control.Changed (); /* EMIT SIGNAL */
2287 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2288 _gain_automation_curve.add (_session.transport_frame(), val);
2292 _session.set_dirty();
2296 IO::start_gain_touch ()
2298 _gain_automation_curve.start_touch ();
2302 IO::end_gain_touch ()
2304 _gain_automation_curve.stop_touch ();
2308 IO::start_pan_touch (uint32_t which)
2310 if (which < _panner->size()) {
2311 (*_panner)[which]->automation().start_touch();
2316 IO::end_pan_touch (uint32_t which)
2318 if (which < _panner->size()) {
2319 (*_panner)[which]->automation().stop_touch();
2325 IO::automation_snapshot (jack_nframes_t now)
2327 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2329 if (gain_automation_recording()) {
2330 _gain_automation_curve.rt_add (now, gain());
2333 _panner->snapshot (now);
2335 last_automation_snapshot = now;
2340 IO::transport_stopped (jack_nframes_t frame)
2342 _gain_automation_curve.reposition_for_rt_add (frame);
2344 if (_gain_automation_curve.automation_state() != Off) {
2346 if (gain_automation_recording()) {
2347 _gain_automation_curve.save_state (_("automation write/touch"));
2350 /* the src=0 condition is a special signal to not propagate
2351 automation gain changes into the mix group when locating.
2354 set_gain (_gain_automation_curve.eval (frame), 0);
2357 _panner->transport_stopped (frame);
2361 IO::find_input_port_hole ()
2363 /* CALLER MUST HOLD IO LOCK */
2367 if (_inputs.empty()) {
2371 for (n = 1; n < UINT_MAX; ++n) {
2372 char buf[jack_port_name_size()];
2373 PortSet::iterator i = _inputs.begin();
2375 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2377 for ( ; i != _inputs.end(); ++i) {
2378 if (i->short_name() == buf) {
2383 if (i == _inputs.end()) {
2391 IO::find_output_port_hole ()
2393 /* CALLER MUST HOLD IO LOCK */
2397 if (_outputs.empty()) {
2401 for (n = 1; n < UINT_MAX; ++n) {
2402 char buf[jack_port_name_size()];
2403 PortSet::iterator i = _outputs.begin();
2405 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2407 for ( ; i != _outputs.end(); ++i) {
2408 if (i->short_name() == buf) {
2413 if (i == _outputs.end()) {
2422 IO::audio_input(uint32_t n) const
2424 return dynamic_cast<AudioPort*>(input(n));
2428 IO::audio_output(uint32_t n) const
2430 return dynamic_cast<AudioPort*>(output(n));
2434 IO::midi_input(uint32_t n) const
2436 return dynamic_cast<MidiPort*>(input(n));
2440 IO::midi_output(uint32_t n) const
2442 return dynamic_cast<MidiPort*>(output(n));
2446 IO::set_phase_invert (bool yn, void *src)
2448 if (_phase_invert != yn) {
2451 // phase_invert_changed (src); /* EMIT SIGNAL */