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>
30 #include <pbd/replace_all.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/io.h>
34 #include <ardour/port.h>
35 #include <ardour/audio_port.h>
36 #include <ardour/midi_port.h>
37 #include <ardour/connection.h>
38 #include <ardour/session.h>
39 #include <ardour/cycle_timer.h>
40 #include <ardour/panner.h>
41 #include <ardour/buffer_set.h>
42 #include <ardour/meter.h>
43 #include <ardour/amp.h>
50 A bug in OS X's cmath that causes isnan() and isinf() to be
51 "undeclared". the following works around that
54 #if defined(__APPLE__) && defined(__MACH__)
55 extern "C" int isnan (double);
56 extern "C" int isinf (double);
59 #define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
62 using namespace ARDOUR;
65 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 (X_("gaincontrol"), *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));
157 _session.add_controllable (&_gain_control);
160 IO::IO (Session& s, const XMLNode& node, DataType dt)
162 _output_buffers(new BufferSet()),
164 _gain_control (X_("gaincontrol"), *this),
165 _gain_automation_curve (0, 0, 0) // all reset in set_state()
168 _meter = new PeakMeter (_session);
172 no_panner_reset = false;
175 _input_connection = 0;
176 _output_connection = 0;
178 apply_gain_automation = false;
183 // IO::Meter is emitted from another thread so the
184 // Meter signal must be protected.
185 Glib::Mutex::Lock guard (m_meter_signal_lock);
186 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
189 // Connect to our own MoreChannels signal to connect output buffers
190 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
192 _session.add_controllable (&_gain_control);
197 Glib::Mutex::Lock guard (m_meter_signal_lock);
199 Glib::Mutex::Lock lm (io_lock);
201 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
202 _session.engine().unregister_port (*i);
205 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
206 _session.engine().unregister_port (*i);
209 m_meter_connection.disconnect();
213 delete _output_buffers;
217 IO::silence (nframes_t nframes, nframes_t offset)
219 /* io_lock, not taken: function must be called from Session::process() calltree */
221 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
222 i->get_buffer().silence (nframes, offset);
226 /** Deliver bufs to the IO's Jack outputs.
228 * This function should automatically do whatever it necessary to correctly deliver bufs
229 * to the outputs, eg applying gain or pan or whatever else needs to be done.
232 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
234 // FIXME: type specific code doesn't actually need to be here, it will go away in time
236 /* ********** AUDIO ********** */
238 // Apply gain if gain automation isn't playing
239 if ( ! apply_gain_automation) {
241 gain_t dg = _gain; // desired gain
244 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
252 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
255 // Use the panner to distribute audio to output port buffers
256 if (_panner && !_panner->empty() && !_panner->bypassed()) {
257 _panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
259 const DataType type = DataType::AUDIO;
261 // Copy any audio 1:1 to outputs
262 assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
263 BufferSet::iterator o = output_buffers().begin(type);
264 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
265 o->read_from(*i, nframes, offset);
270 /* ********** MIDI ********** */
272 // No MIDI, we're done here
273 if (bufs.count().get(DataType::MIDI) == 0) {
277 const DataType type = DataType::MIDI;
279 // Copy any MIDI 1:1 to outputs
280 assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
281 BufferSet::iterator o = output_buffers().begin(type);
282 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
283 o->read_from(*i, nframes, offset);
288 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
290 assert(outs.available() >= n_inputs());
292 outs.set_count(n_inputs());
294 if (outs.count() == ChanCount::ZERO)
297 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
299 BufferSet::iterator o = outs.begin(*t);
300 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
301 o->read_from(i->get_buffer(), nframes, offset);
308 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
309 nframes_t nframes, nframes_t offset)
311 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
313 collect_input (bufs, nframes, offset);
315 _meter->run(bufs, nframes);
319 IO::drop_input_connection ()
321 _input_connection = 0;
322 input_connection_configuration_connection.disconnect();
323 input_connection_connection_connection.disconnect();
324 _session.set_dirty ();
328 IO::drop_output_connection ()
330 _output_connection = 0;
331 output_connection_configuration_connection.disconnect();
332 output_connection_connection_connection.disconnect();
333 _session.set_dirty ();
337 IO::disconnect_input (Port* our_port, string other_port, void* src)
339 if (other_port.length() == 0 || our_port == 0) {
344 BLOCK_PROCESS_CALLBACK ();
347 Glib::Mutex::Lock lm (io_lock);
349 /* check that our_port is really one of ours */
351 if ( ! _inputs.contains(our_port)) {
355 /* disconnect it from the source */
357 if (_session.engine().disconnect (other_port, our_port->name())) {
358 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
362 drop_input_connection();
366 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
367 _session.set_dirty ();
373 IO::connect_input (Port* our_port, string other_port, void* src)
375 if (other_port.length() == 0 || our_port == 0) {
380 BLOCK_PROCESS_CALLBACK ();
383 Glib::Mutex::Lock lm (io_lock);
385 /* check that our_port is really one of ours */
387 if ( ! _inputs.contains(our_port) ) {
391 /* connect it to the source */
393 if (_session.engine().connect (other_port, our_port->name())) {
397 drop_input_connection ();
401 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
402 _session.set_dirty ();
407 IO::disconnect_output (Port* our_port, string other_port, void* src)
409 if (other_port.length() == 0 || our_port == 0) {
414 BLOCK_PROCESS_CALLBACK ();
417 Glib::Mutex::Lock lm (io_lock);
419 /* check that our_port is really one of ours */
421 if ( ! _outputs.contains(our_port) ) {
425 /* disconnect it from the destination */
427 if (_session.engine().disconnect (our_port->name(), other_port)) {
428 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
432 drop_output_connection ();
436 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
437 _session.set_dirty ();
442 IO::connect_output (Port* our_port, string other_port, void* src)
444 if (other_port.length() == 0 || our_port == 0) {
449 BLOCK_PROCESS_CALLBACK ();
453 Glib::Mutex::Lock lm (io_lock);
455 /* check that our_port is really one of ours */
457 if ( ! _outputs.contains(our_port) ) {
461 /* connect it to the destination */
463 if (_session.engine().connect (our_port->name(), other_port)) {
467 drop_output_connection ();
471 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
472 _session.set_dirty ();
477 IO::set_input (Port* other_port, void* src)
479 /* this removes all but one ports, and connects that one port
480 to the specified source.
483 if (_input_minimum.get_total() > 1) {
484 /* sorry, you can't do this */
488 if (other_port == 0) {
489 if (_input_minimum == ChanCount::ZERO) {
490 return ensure_inputs (ChanCount::ZERO, false, true, src);
496 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
500 return connect_input (_inputs.port(0), other_port->name(), src);
504 IO::remove_output_port (Port* port, void* src)
506 IOChange change (NoChange);
509 BLOCK_PROCESS_CALLBACK ();
513 Glib::Mutex::Lock lm (io_lock);
515 if (n_outputs() <= _output_minimum) {
516 /* sorry, you can't do this */
520 if (_outputs.remove(port)) {
521 change = IOChange (change|ConfigurationChanged);
523 if (port->connected()) {
524 change = IOChange (change|ConnectionsChanged);
527 _session.engine().unregister_port (*port);
528 drop_output_connection ();
530 setup_peak_meters ();
536 if (change != NoChange) {
537 output_changed (change, src);
538 _session.set_dirty ();
545 /** Add an output port.
547 * @param destination Name of input port to connect new port to.
548 * @param src Source for emitted ConfigurationChanged signal.
549 * @param type Data type of port. Default value (NIL) will use this IO's default type.
552 IO::add_output_port (string destination, void* src, DataType type)
557 if (type == DataType::NIL)
558 type = _default_type;
561 BLOCK_PROCESS_CALLBACK ();
565 Glib::Mutex::Lock lm (io_lock);
567 if (n_outputs() >= _output_maximum) {
571 /* Create a new output port */
573 // FIXME: naming scheme for differently typed ports?
574 if (_output_maximum.get(type) == 1) {
575 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
577 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
580 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
581 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
585 _outputs.add (our_port);
586 drop_output_connection ();
587 setup_peak_meters ();
591 MoreChannels (n_outputs()); /* EMIT SIGNAL */
594 if (destination.length()) {
595 if (_session.engine().connect (our_port->name(), destination)) {
600 // pan_changed (src); /* EMIT SIGNAL */
601 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
602 _session.set_dirty ();
608 IO::remove_input_port (Port* port, void* src)
610 IOChange change (NoChange);
613 BLOCK_PROCESS_CALLBACK ();
617 Glib::Mutex::Lock lm (io_lock);
619 if (n_inputs() <= _input_minimum) {
620 /* sorry, you can't do this */
624 if (_inputs.remove(port)) {
625 change = IOChange (change|ConfigurationChanged);
627 if (port->connected()) {
628 change = IOChange (change|ConnectionsChanged);
631 _session.engine().unregister_port (*port);
632 drop_input_connection ();
634 setup_peak_meters ();
640 if (change != NoChange) {
641 input_changed (change, src);
642 _session.set_dirty ();
650 /** Add an input port.
652 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
653 * @param destination Name of input port to connect new port to.
654 * @param src Source for emitted ConfigurationChanged signal.
657 IO::add_input_port (string source, void* src, DataType type)
662 if (type == DataType::NIL)
663 type = _default_type;
666 BLOCK_PROCESS_CALLBACK ();
669 Glib::Mutex::Lock lm (io_lock);
671 if (n_inputs() >= _input_maximum) {
675 /* Create a new input port */
677 // FIXME: naming scheme for differently typed ports?
678 if (_input_maximum.get(type) == 1) {
679 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
681 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
684 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
685 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
689 _inputs.add (our_port);
690 drop_input_connection ();
691 setup_peak_meters ();
695 MoreChannels (n_inputs()); /* EMIT SIGNAL */
698 if (source.length()) {
700 if (_session.engine().connect (source, our_port->name())) {
705 // pan_changed (src); /* EMIT SIGNAL */
706 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
707 _session.set_dirty ();
713 IO::disconnect_inputs (void* src)
716 BLOCK_PROCESS_CALLBACK ();
719 Glib::Mutex::Lock lm (io_lock);
721 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
722 _session.engine().disconnect (*i);
725 drop_input_connection ();
729 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
735 IO::disconnect_outputs (void* src)
738 BLOCK_PROCESS_CALLBACK ();
741 Glib::Mutex::Lock lm (io_lock);
743 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
744 _session.engine().disconnect (*i);
747 drop_output_connection ();
751 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
752 _session.set_dirty ();
758 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
760 Port* input_port = 0;
761 bool changed = false;
764 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
766 const size_t n = count.get(*t);
768 /* remove unused ports */
769 for (size_t i = n_inputs().get(*t); i > n; --i) {
770 input_port = _inputs.port(*t, i-1);
773 _inputs.remove(input_port);
774 _session.engine().unregister_port (*input_port);
779 /* create any necessary new ports */
780 while (n_inputs().get(*t) < n) {
784 if (_input_maximum.get(*t) == 1) {
785 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
787 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
792 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
793 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
798 catch (AudioEngine::PortRegistrationFailure& err) {
799 setup_peak_meters ();
802 throw AudioEngine::PortRegistrationFailure();
805 _inputs.add (input_port);
811 drop_input_connection ();
812 setup_peak_meters ();
814 MoreChannels (n_inputs()); /* EMIT SIGNAL */
815 _session.set_dirty ();
819 /* disconnect all existing ports so that we get a fresh start */
820 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
821 _session.engine().disconnect (*i);
828 /** Attach output_buffers to port buffers.
830 * Connected to IO's own MoreChannels signal.
833 IO::attach_buffers(ChanCount ignored)
835 _output_buffers->attach_buffers(_outputs);
839 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
841 bool in_changed = false;
842 bool out_changed = false;
843 bool need_pan_reset = false;
845 in = min (_input_maximum, in);
847 out = min (_output_maximum, out);
849 if (in == n_inputs() && out == n_outputs() && !clear) {
854 BLOCK_PROCESS_CALLBACK ();
855 Glib::Mutex::Lock lm (io_lock);
859 if (n_outputs() != out) {
860 need_pan_reset = true;
863 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
865 const size_t nin = in.get(*t);
866 const size_t nout = out.get(*t);
868 Port* output_port = 0;
869 Port* input_port = 0;
871 /* remove unused output ports */
872 for (size_t i = n_outputs().get(*t); i > nout; --i) {
873 output_port = _outputs.port(*t, i-1);
876 _outputs.remove(output_port);
877 _session.engine().unregister_port (*output_port);
882 /* remove unused input ports */
883 for (size_t i = n_inputs().get(*t); i > nin; --i) {
884 input_port = _inputs.port(*t, i-1);
887 _inputs.remove(input_port);
888 _session.engine().unregister_port (*input_port);
893 /* create any necessary new input ports */
895 while (n_inputs().get(*t) < nin) {
899 /* Create a new input port */
901 if (_input_maximum.get(*t) == 1) {
902 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
904 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
908 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
909 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
914 catch (AudioEngine::PortRegistrationFailure& err) {
915 setup_peak_meters ();
918 throw AudioEngine::PortRegistrationFailure();
925 /* create any necessary new output ports */
927 while (n_outputs().get(*t) < nout) {
931 /* Create a new output port */
933 if (_output_maximum.get(*t) == 1) {
934 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
936 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
940 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
941 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
946 catch (AudioEngine::PortRegistrationFailure& err) {
947 setup_peak_meters ();
950 throw AudioEngine::PortRegistrationFailure ();
960 /* disconnect all existing ports so that we get a fresh start */
962 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
963 _session.engine().disconnect (*i);
966 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
967 _session.engine().disconnect (*i);
971 if (in_changed || out_changed) {
972 setup_peak_meters ();
978 drop_output_connection ();
979 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
983 drop_input_connection ();
984 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
987 if (in_changed || out_changed) {
988 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
989 _session.set_dirty ();
996 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
998 bool changed = false;
1000 count = min (_input_maximum, count);
1002 if (count == n_inputs() && !clear) {
1007 BLOCK_PROCESS_CALLBACK ();
1008 Glib::Mutex::Lock im (io_lock);
1009 changed = ensure_inputs_locked (count, clear, src);
1011 changed = ensure_inputs_locked (count, clear, src);
1015 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1016 _session.set_dirty ();
1022 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1024 Port* output_port = 0;
1025 bool changed = false;
1026 bool need_pan_reset = false;
1028 if (n_outputs() != count) {
1029 need_pan_reset = true;
1032 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1034 const size_t n = count.get(*t);
1036 /* remove unused ports */
1037 for (size_t i = n_outputs().get(*t); i > n; --i) {
1038 output_port = _outputs.port(*t, i-1);
1040 assert(output_port);
1041 _outputs.remove(output_port);
1042 _session.engine().unregister_port (*output_port);
1047 /* create any necessary new ports */
1048 while (n_outputs().get(*t) < n) {
1052 if (_output_maximum.get(*t) == 1) {
1053 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1055 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1058 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1059 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1063 _outputs.add (output_port);
1065 setup_peak_meters ();
1067 if (need_pan_reset) {
1074 drop_output_connection ();
1075 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1076 _session.set_dirty ();
1080 /* disconnect all existing ports so that we get a fresh start */
1081 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1082 _session.engine().disconnect (*i);
1090 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1092 bool changed = false;
1094 if (_output_maximum < ChanCount::INFINITE) {
1095 count = min (_output_maximum, count);
1096 if (count == n_outputs() && !clear) {
1101 /* XXX caller should hold io_lock, but generally doesn't */
1104 BLOCK_PROCESS_CALLBACK ();
1105 Glib::Mutex::Lock im (io_lock);
1106 changed = ensure_outputs_locked (count, clear, src);
1108 changed = ensure_outputs_locked (count, clear, src);
1112 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1119 IO::effective_gain () const
1121 if (gain_automation_playback()) {
1122 return _effective_gain;
1124 return _desired_gain;
1131 if (panners_legal) {
1132 if (!no_panner_reset) {
1133 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1136 panner_legal_c.disconnect ();
1137 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1142 IO::panners_became_legal ()
1144 _panner->reset (n_outputs().get(DataType::AUDIO), pans_required());
1145 _panner->load (); // automation
1146 panner_legal_c.disconnect ();
1151 IO::defer_pan_reset ()
1153 no_panner_reset = true;
1157 IO::allow_pan_reset ()
1159 no_panner_reset = false;
1165 IO::get_state (void)
1167 return state (true);
1171 IO::state (bool full_state)
1173 XMLNode* node = new XMLNode (state_node_name);
1176 bool need_ins = true;
1177 bool need_outs = true;
1178 LocaleGuard lg (X_("POSIX"));
1179 Glib::Mutex::Lock lm (io_lock);
1181 node->add_property("name", _name);
1182 id().print (buf, sizeof (buf));
1183 node->add_property("id", buf);
1187 if (_input_connection) {
1188 node->add_property ("input-connection", _input_connection->name());
1192 if (_output_connection) {
1193 node->add_property ("output-connection", _output_connection->name());
1198 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1200 const char **connections = i->get_connections();
1202 if (connections && connections[0]) {
1205 for (int n = 0; connections && connections[n]; ++n) {
1210 /* if its a connection to our own port,
1211 return only the port name, not the
1212 whole thing. this allows connections
1213 to be re-established even when our
1214 client name is different.
1217 str += _session.engine().make_port_name_relative (connections[n]);
1229 node->add_property ("inputs", str);
1235 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1237 const char **connections = i->get_connections();
1239 if (connections && connections[0]) {
1243 for (int n = 0; connections[n]; ++n) {
1248 str += _session.engine().make_port_name_relative (connections[n]);
1260 node->add_property ("outputs", str);
1263 node->add_child_nocopy (_panner->state (full_state));
1264 node->add_child_nocopy (_gain_control.get_state ());
1266 snprintf (buf, sizeof(buf), "%2.12f", gain());
1267 node->add_property ("gain", buf);
1269 // FIXME: this is NOT sufficient!
1270 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1271 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1272 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1273 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1275 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1277 node->add_property ("iolimits", buf);
1283 XMLNode* autonode = new XMLNode (X_("Automation"));
1284 autonode->add_child_nocopy (get_automation_state());
1285 node->add_child_nocopy (*autonode);
1287 snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
1289 /* never store anything except Off for automation state in a template */
1290 snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
1297 IO::set_state (const XMLNode& node)
1299 const XMLProperty* prop;
1300 XMLNodeConstIterator iter;
1301 LocaleGuard lg (X_("POSIX"));
1303 /* force use of non-localized representation of decimal point,
1304 since we use it a lot in XML files and so forth.
1307 if (node.name() != state_node_name) {
1308 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1312 if ((prop = node.property ("name")) != 0) {
1313 _name = prop->value();
1314 /* used to set panner name with this, but no more */
1317 if ((prop = node.property ("id")) != 0) {
1318 _id = prop->value ();
1323 size_t out_min = -1;
1324 size_t out_max = -1;
1326 if ((prop = node.property ("iolimits")) != 0) {
1327 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1328 &in_min, &in_max, &out_min, &out_max);
1329 _input_minimum = ChanCount(_default_type, in_min);
1330 _input_maximum = ChanCount(_default_type, in_max);
1331 _output_minimum = ChanCount(_default_type, out_min);
1332 _output_maximum = ChanCount(_default_type, out_max);
1335 if ((prop = node.property ("gain")) != 0) {
1336 set_gain (atof (prop->value().c_str()), this);
1337 _gain = _desired_gain;
1340 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1341 /* old school automation handling */
1344 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1346 if ((*iter)->name() == "Panner") {
1348 _panner = new Panner (_name, _session);
1350 _panner->set_state (**iter);
1353 if ((*iter)->name() == X_("Automation")) {
1355 set_automation_state (*(*iter)->children().front());
1358 if ((*iter)->name() == X_("controllable")) {
1359 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1360 _gain_control.set_state (**iter);
1367 if (create_ports (node)) {
1373 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1376 if (panners_legal) {
1379 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1382 if (connecting_legal) {
1384 if (make_connections (node)) {
1390 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1393 if (!ports_legal || !connecting_legal) {
1394 pending_state_node = new XMLNode (node);
1397 last_automation_snapshot = 0;
1403 IO::set_automation_state (const XMLNode& node)
1405 return _gain_automation_curve.set_state (node);
1409 IO::get_automation_state ()
1411 return (_gain_automation_curve.get_state ());
1415 IO::load_automation (string path)
1420 uint32_t linecnt = 0;
1422 LocaleGuard lg (X_("POSIX"));
1424 fullpath = _session.automation_dir();
1427 in.open (fullpath.c_str());
1430 fullpath = _session.automation_dir();
1431 fullpath += _session.snap_name();
1435 in.open (fullpath.c_str());
1438 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1443 clear_automation ();
1445 while (in.getline (line, sizeof(line), '\n')) {
1447 jack_nframes_t when;
1450 if (++linecnt == 1) {
1451 if (memcmp (line, "version", 7) == 0) {
1452 if (sscanf (line, "version %f", &version) != 1) {
1453 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1457 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1464 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1465 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1471 _gain_automation_curve.fast_simple_add (when, value);
1481 /* older (pre-1.0) versions of ardour used this */
1485 warning << _("dubious automation event found (and ignored)") << endmsg;
1493 IO::connecting_became_legal ()
1497 if (pending_state_node == 0) {
1498 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1503 connection_legal_c.disconnect ();
1505 ret = make_connections (*pending_state_node);
1508 delete pending_state_node;
1509 pending_state_node = 0;
1515 IO::ports_became_legal ()
1519 if (pending_state_node == 0) {
1520 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1525 port_legal_c.disconnect ();
1527 ret = create_ports (*pending_state_node);
1529 if (connecting_legal) {
1530 delete pending_state_node;
1531 pending_state_node = 0;
1538 IO::create_ports (const XMLNode& node)
1540 const XMLProperty* prop;
1542 int num_outputs = 0;
1544 if ((prop = node.property ("input-connection")) != 0) {
1546 Connection* c = _session.connection_by_name (prop->value());
1549 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1551 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1552 error << _("No input connections available as a replacement")
1556 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1561 num_inputs = c->nports();
1563 } else if ((prop = node.property ("inputs")) != 0) {
1565 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1568 if ((prop = node.property ("output-connection")) != 0) {
1569 Connection* c = _session.connection_by_name (prop->value());
1572 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1574 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1575 error << _("No output connections available as a replacement")
1579 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1584 num_outputs = c->nports ();
1586 } else if ((prop = node.property ("outputs")) != 0) {
1587 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1590 no_panner_reset = true;
1592 // FIXME: audio-only
1593 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1594 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1598 no_panner_reset = false;
1600 set_deferred_state ();
1608 IO::make_connections (const XMLNode& node)
1610 const XMLProperty* prop;
1612 if ((prop = node.property ("input-connection")) != 0) {
1613 Connection* c = _session.connection_by_name (prop->value());
1616 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1618 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
1619 error << _("No input connections available as a replacement")
1623 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
1628 use_input_connection (*c, this);
1630 } else if ((prop = node.property ("inputs")) != 0) {
1631 if (set_inputs (prop->value())) {
1632 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1637 if ((prop = node.property ("output-connection")) != 0) {
1638 Connection* c = _session.connection_by_name (prop->value());
1641 error << string_compose(_("Unknown connection \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1643 if ((c = _session.connection_by_name (_("out 1"))) == 0) {
1644 error << _("No output connections available as a replacement")
1648 info << string_compose (_("Connection %1 was not available - \"out 1\" used instead"), prop->value())
1653 use_output_connection (*c, this);
1655 } else if ((prop = node.property ("outputs")) != 0) {
1656 if (set_outputs (prop->value())) {
1657 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1666 IO::set_inputs (const string& str)
1668 vector<string> ports;
1673 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1677 // FIXME: audio-only
1678 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1682 string::size_type start, end, ostart;
1689 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1692 if ((end = str.find_first_of ('}', start)) == string::npos) {
1693 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1697 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1698 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1704 for (int x = 0; x < n; ++x) {
1705 connect_input (input (i), ports[x], this);
1717 IO::set_outputs (const string& str)
1719 vector<string> ports;
1724 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1728 // FIXME: audio-only
1729 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1733 string::size_type start, end, ostart;
1740 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1743 if ((end = str.find_first_of ('}', start)) == string::npos) {
1744 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1748 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1749 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1755 for (int x = 0; x < n; ++x) {
1756 connect_output (output (i), ports[x], this);
1768 IO::parse_io_string (const string& str, vector<string>& ports)
1770 string::size_type pos, opos;
1772 if (str.length() == 0) {
1781 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1782 ports.push_back (str.substr (opos, pos - opos));
1786 if (opos < str.length()) {
1787 ports.push_back (str.substr(opos));
1790 return ports.size();
1794 IO::parse_gain_string (const string& str, vector<string>& ports)
1796 string::size_type pos, opos;
1802 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1803 ports.push_back (str.substr (opos, pos - opos));
1807 if (opos < str.length()) {
1808 ports.push_back (str.substr(opos));
1811 return ports.size();
1815 IO::set_name (string name, void* src)
1817 if (name == _name) {
1821 /* replace all colons in the name. i wish we didn't have to do this */
1823 if (replace_all (name, ":", "-")) {
1824 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1827 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1828 string current_name = i->short_name();
1829 current_name.replace (current_name.find (_name), _name.length(), name);
1830 i->set_name (current_name);
1833 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1834 string current_name = i->short_name();
1835 current_name.replace (current_name.find (_name), _name.length(), name);
1836 i->set_name (current_name);
1840 name_changed (src); /* EMIT SIGNAL */
1846 IO::set_input_minimum (ChanCount n)
1852 IO::set_input_maximum (ChanCount n)
1858 IO::set_output_minimum (ChanCount n)
1860 _output_minimum = n;
1864 IO::set_output_maximum (ChanCount n)
1866 _output_maximum = n;
1870 IO::set_port_latency (nframes_t nframes)
1872 Glib::Mutex::Lock lm (io_lock);
1874 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1875 i->set_latency (nframes);
1880 IO::output_latency () const
1882 nframes_t max_latency;
1887 /* io lock not taken - must be protected by other means */
1889 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1890 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1891 max_latency = latency;
1899 IO::input_latency () const
1901 nframes_t max_latency;
1906 /* io lock not taken - must be protected by other means */
1908 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1909 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1910 max_latency = latency;
1918 IO::use_input_connection (Connection& c, void* src)
1923 BLOCK_PROCESS_CALLBACK ();
1924 Glib::Mutex::Lock lm2 (io_lock);
1928 drop_input_connection ();
1930 // FIXME connections only work for audio-only
1931 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1935 /* first pass: check the current state to see what's correctly
1936 connected, and drop anything that we don't want.
1939 for (uint32_t n = 0; n < limit; ++n) {
1940 const Connection::PortList& pl = c.port_connections (n);
1942 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1944 if (!_inputs.port(n)->connected_to ((*i))) {
1946 /* clear any existing connections */
1948 _session.engine().disconnect (*_inputs.port(n));
1950 } else if (_inputs.port(n)->connected() > 1) {
1952 /* OK, it is connected to the port we want,
1953 but its also connected to other ports.
1954 Change that situation.
1957 /* XXX could be optimized to not drop
1961 _session.engine().disconnect (*_inputs.port(n));
1967 /* second pass: connect all requested ports where necessary */
1969 for (uint32_t n = 0; n < limit; ++n) {
1970 const Connection::PortList& pl = c.port_connections (n);
1972 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1974 if (!_inputs.port(n)->connected_to ((*i))) {
1976 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1984 _input_connection = &c;
1986 input_connection_configuration_connection = c.ConfigurationChanged.connect
1987 (mem_fun (*this, &IO::input_connection_configuration_changed));
1988 input_connection_connection_connection = c.ConnectionsChanged.connect
1989 (mem_fun (*this, &IO::input_connection_connection_changed));
1992 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1997 IO::use_output_connection (Connection& c, void* src)
2002 BLOCK_PROCESS_CALLBACK ();
2003 Glib::Mutex::Lock lm2 (io_lock);
2007 drop_output_connection ();
2009 // FIXME: audio-only
2010 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2014 /* first pass: check the current state to see what's correctly
2015 connected, and drop anything that we don't want.
2018 for (uint32_t n = 0; n < limit; ++n) {
2020 const Connection::PortList& pl = c.port_connections (n);
2022 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2024 if (!_outputs.port(n)->connected_to ((*i))) {
2026 /* clear any existing connections */
2028 _session.engine().disconnect (*_outputs.port(n));
2030 } else if (_outputs.port(n)->connected() > 1) {
2032 /* OK, it is connected to the port we want,
2033 but its also connected to other ports.
2034 Change that situation.
2037 /* XXX could be optimized to not drop
2041 _session.engine().disconnect (*_outputs.port(n));
2046 /* second pass: connect all requested ports where necessary */
2048 for (uint32_t n = 0; n < limit; ++n) {
2050 const Connection::PortList& pl = c.port_connections (n);
2052 for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2054 if (!_outputs.port(n)->connected_to ((*i))) {
2056 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2063 _output_connection = &c;
2065 output_connection_configuration_connection = c.ConfigurationChanged.connect
2066 (mem_fun (*this, &IO::output_connection_configuration_changed));
2067 output_connection_connection_connection = c.ConnectionsChanged.connect
2068 (mem_fun (*this, &IO::output_connection_connection_changed));
2071 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2077 IO::disable_connecting ()
2079 connecting_legal = false;
2084 IO::enable_connecting ()
2086 connecting_legal = true;
2087 return ConnectingLegal ();
2091 IO::disable_ports ()
2093 ports_legal = false;
2101 return PortsLegal ();
2105 IO::disable_panners (void)
2107 panners_legal = false;
2112 IO::reset_panners ()
2114 panners_legal = true;
2115 return PannersLegal ();
2119 IO::input_connection_connection_changed (int ignored)
2121 use_input_connection (*_input_connection, this);
2125 IO::input_connection_configuration_changed ()
2127 use_input_connection (*_input_connection, this);
2131 IO::output_connection_connection_changed (int ignored)
2133 use_output_connection (*_output_connection, this);
2137 IO::output_connection_configuration_changed ()
2139 use_output_connection (*_output_connection, this);
2143 IO::GainControllable::set_value (float val)
2145 io.set_gain (direct_control_to_gain (val), this);
2149 IO::GainControllable::get_value (void) const
2151 return direct_gain_to_control (io.effective_gain());
2155 IO::setup_peak_meters()
2157 _meter->setup(std::max(_inputs.count(), _outputs.count()));
2161 Update the peak meters.
2163 The meter signal lock is taken to prevent modification of the
2164 Meter signal while updating the meters, taking the meter signal
2165 lock prior to taking the io_lock ensures that all IO will remain
2166 valid while metering.
2171 Glib::Mutex::Lock guard (m_meter_signal_lock);
2173 Meter(); /* EMIT SIGNAL */
2179 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2181 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2186 IO::clear_automation ()
2188 Glib::Mutex::Lock lm (automation_lock);
2189 _gain_automation_curve.clear ();
2190 _panner->clear_automation ();
2194 IO::set_gain_automation_state (AutoState state)
2196 bool changed = false;
2199 Glib::Mutex::Lock lm (automation_lock);
2201 if (state != _gain_automation_curve.automation_state()) {
2203 last_automation_snapshot = 0;
2204 _gain_automation_curve.set_automation_state (state);
2207 set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
2213 _session.set_dirty ();
2214 gain_automation_state_changed (); /* EMIT SIGNAL */
2219 IO::set_gain_automation_style (AutoStyle style)
2221 bool changed = false;
2224 Glib::Mutex::Lock lm (automation_lock);
2226 if (style != _gain_automation_curve.automation_style()) {
2228 _gain_automation_curve.set_automation_style (style);
2233 gain_automation_style_changed (); /* EMIT SIGNAL */
2237 IO::inc_gain (gain_t factor, void *src)
2239 if (_desired_gain == 0.0f)
2240 set_gain (0.000001f + (0.000001f * factor), src);
2242 set_gain (_desired_gain + (_desired_gain * factor), src);
2246 IO::set_gain (gain_t val, void *src)
2248 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2249 if (val>1.99526231f) val=1.99526231f;
2252 Glib::Mutex::Lock dm (declick_lock);
2253 _desired_gain = val;
2256 if (_session.transport_stopped()) {
2257 _effective_gain = val;
2262 _gain_control.Changed (); /* EMIT SIGNAL */
2264 if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
2265 _gain_automation_curve.add (_session.transport_frame(), val);
2269 _session.set_dirty();
2273 IO::start_gain_touch ()
2275 _gain_automation_curve.start_touch ();
2279 IO::end_gain_touch ()
2281 _gain_automation_curve.stop_touch ();
2285 IO::start_pan_touch (uint32_t which)
2287 if (which < _panner->size()) {
2288 (*_panner)[which]->automation().start_touch();
2293 IO::end_pan_touch (uint32_t which)
2295 if (which < _panner->size()) {
2296 (*_panner)[which]->automation().stop_touch();
2302 IO::automation_snapshot (nframes_t now)
2304 if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
2306 if (gain_automation_recording()) {
2307 _gain_automation_curve.rt_add (now, gain());
2310 _panner->snapshot (now);
2312 last_automation_snapshot = now;
2317 IO::transport_stopped (nframes_t frame)
2319 _gain_automation_curve.reposition_for_rt_add (frame);
2321 if (_gain_automation_curve.automation_state() != Off) {
2323 /* the src=0 condition is a special signal to not propagate
2324 automation gain changes into the mix group when locating.
2327 set_gain (_gain_automation_curve.eval (frame), 0);
2330 _panner->transport_stopped (frame);
2334 IO::find_input_port_hole ()
2336 /* CALLER MUST HOLD IO LOCK */
2340 if (_inputs.empty()) {
2344 for (n = 1; n < UINT_MAX; ++n) {
2345 char buf[jack_port_name_size()];
2346 PortSet::iterator i = _inputs.begin();
2348 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2350 for ( ; i != _inputs.end(); ++i) {
2351 if (i->short_name() == buf) {
2356 if (i == _inputs.end()) {
2364 IO::find_output_port_hole ()
2366 /* CALLER MUST HOLD IO LOCK */
2370 if (_outputs.empty()) {
2374 for (n = 1; n < UINT_MAX; ++n) {
2375 char buf[jack_port_name_size()];
2376 PortSet::iterator i = _outputs.begin();
2378 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2380 for ( ; i != _outputs.end(); ++i) {
2381 if (i->short_name() == buf) {
2386 if (i == _outputs.end()) {
2395 IO::audio_input(uint32_t n) const
2397 return dynamic_cast<AudioPort*>(input(n));
2401 IO::audio_output(uint32_t n) const
2403 return dynamic_cast<AudioPort*>(output(n));
2407 IO::midi_input(uint32_t n) const
2409 return dynamic_cast<MidiPort*>(input(n));
2413 IO::midi_output(uint32_t n) const
2415 return dynamic_cast<MidiPort*>(output(n));
2419 IO::set_phase_invert (bool yn, void *src)
2421 if (_phase_invert != yn) {
2424 // phase_invert_changed (src); /* EMIT SIGNAL */