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/bundle.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 const string IO::state_node_name = "IO";
66 bool IO::connecting_legal = false;
67 bool IO::ports_legal = false;
68 bool IO::panners_legal = false;
69 sigc::signal<void> IO::Meter;
70 sigc::signal<int> IO::ConnectingLegal;
71 sigc::signal<int> IO::PortsLegal;
72 sigc::signal<int> IO::PannersLegal;
73 sigc::signal<void,ChanCount> IO::MoreChannels;
74 sigc::signal<int> IO::PortsCreated;
76 Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
78 /* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
79 others can be imagined.
83 static gain_t direct_control_to_gain (double fract) {
84 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
85 /* this maxes at +6dB */
86 return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
89 static double direct_gain_to_control (gain_t gain) {
90 /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
91 if (gain == 0) return 0.0;
93 return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
97 /** @param default_type The type of port that will be created by ensure_io
98 * and friends if no type is explicitly requested (to avoid breakage).
100 IO::IO (Session& s, const string& name,
101 int input_min, int input_max, int output_min, int output_max,
102 DataType default_type)
103 : Automatable (s, name),
104 _output_buffers (new BufferSet()),
105 _default_type (default_type),
106 _input_minimum (ChanCount::ZERO),
107 _input_maximum (ChanCount::INFINITE),
108 _output_minimum (ChanCount::ZERO),
109 _output_maximum (ChanCount::INFINITE)
111 _panner = new Panner (name, _session);
112 _meter = new PeakMeter (_session);
115 _input_minimum = ChanCount(_default_type, input_min);
117 if (input_max >= 0) {
118 _input_maximum = ChanCount(_default_type, input_max);
120 if (output_min > 0) {
121 _output_minimum = ChanCount(_default_type, output_min);
123 if (output_max >= 0) {
124 _output_maximum = ChanCount(_default_type, output_max);
131 pending_state_node = 0;
132 no_panner_reset = false;
133 _phase_invert = false;
136 boost::shared_ptr<AutomationList> gl(
137 new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
139 _gain_control = boost::shared_ptr<GainControl>(
140 new GainControl(X_("gaincontrol"), *this, gl));
142 add_control(_gain_control);
144 apply_gain_automation = false;
147 // IO::Meter is emitted from another thread so the
148 // Meter signal must be protected.
149 Glib::Mutex::Lock guard (m_meter_signal_lock);
150 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
153 // Connect to our own MoreChannels signal to connect output buffers
154 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
156 _session.add_controllable (_gain_control);
159 IO::IO (Session& s, const XMLNode& node, DataType dt)
160 : Automatable (s, "unnamed io"),
161 _output_buffers (new BufferSet()),
164 _meter = new PeakMeter (_session);
168 no_panner_reset = false;
174 apply_gain_automation = false;
176 boost::shared_ptr<AutomationList> gl(
177 new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
179 _gain_control = boost::shared_ptr<GainControl>(
180 new GainControl(X_("gaincontrol"), *this, gl));
182 add_control(_gain_control);
187 // IO::Meter is emitted from another thread so the
188 // Meter signal must be protected.
189 Glib::Mutex::Lock guard (m_meter_signal_lock);
190 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
193 // Connect to our own MoreChannels signal to connect output buffers
194 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
196 _session.add_controllable (_gain_control);
201 Glib::Mutex::Lock guard (m_meter_signal_lock);
203 Glib::Mutex::Lock lm (io_lock);
205 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
206 _session.engine().unregister_port (*i);
209 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
210 _session.engine().unregister_port (*i);
213 m_meter_connection.disconnect();
217 delete _output_buffers;
221 IO::silence (nframes_t nframes, nframes_t offset)
223 /* io_lock, not taken: function must be called from Session::process() calltree */
225 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
226 i->get_buffer().silence (nframes, offset);
230 /** Deliver bufs to the IO's Jack outputs.
232 * This function should automatically do whatever it necessary to correctly deliver bufs
233 * to the outputs, eg applying gain or pan or whatever else needs to be done.
236 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
238 // FIXME: type specific code doesn't actually need to be here, it will go away in time
240 /* ********** AUDIO ********** */
242 // Apply gain if gain automation isn't playing
243 if ( ! apply_gain_automation) {
245 gain_t dg = _gain; // desired gain
248 Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
256 if (dg != _gain || dg != 1.0)
257 Amp::run(bufs, nframes, _gain, dg, _phase_invert);
260 // Use the panner to distribute audio to output port buffers
261 if (_panner && !_panner->empty() && !_panner->bypassed()) {
262 _panner->distribute (bufs, output_buffers(), start_frame, end_frame, nframes, offset);
264 const DataType type = DataType::AUDIO;
266 // Copy any audio 1:1 to outputs
268 BufferSet::iterator o = output_buffers().begin(type);
269 BufferSet::iterator i = bufs.begin(type);
270 BufferSet::iterator prev = i;
272 while (i != bufs.end(type) && o != output_buffers().end (type)) {
273 o->read_from(*i, nframes, offset);
279 /* extra outputs get a copy of the last buffer */
281 while (o != output_buffers().end(type)) {
282 o->read_from(*prev, nframes, offset);
287 /* ********** MIDI ********** */
289 // No MIDI, we're done here
290 if (bufs.count().n_midi() == 0) {
294 const DataType type = DataType::MIDI;
296 // Copy any MIDI 1:1 to outputs
297 assert(bufs.count().n_midi() == output_buffers().count().n_midi());
298 BufferSet::iterator o = output_buffers().begin(type);
299 for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
300 o->read_from(*i, nframes, offset);
305 IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
307 assert(outs.available() >= n_inputs());
309 outs.set_count(n_inputs());
311 if (outs.count() == ChanCount::ZERO)
314 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
316 BufferSet::iterator o = outs.begin(*t);
317 for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
318 o->read_from(i->get_buffer(), nframes, offset);
325 IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
326 nframes_t nframes, nframes_t offset)
328 BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
330 collect_input (bufs, nframes, offset);
332 _meter->run(bufs, start_frame, end_frame, nframes, offset);
336 IO::drop_input_bundle ()
339 input_bundle_configuration_connection.disconnect();
340 input_bundle_connection_connection.disconnect();
341 _session.set_dirty ();
345 IO::drop_output_bundle ()
348 output_bundle_configuration_connection.disconnect();
349 output_bundle_connection_connection.disconnect();
350 _session.set_dirty ();
354 IO::disconnect_input (Port* our_port, string other_port, void* src)
356 if (other_port.length() == 0 || our_port == 0) {
361 BLOCK_PROCESS_CALLBACK ();
364 Glib::Mutex::Lock lm (io_lock);
366 /* check that our_port is really one of ours */
368 if ( ! _inputs.contains(our_port)) {
372 /* disconnect it from the source */
374 if (_session.engine().disconnect (other_port, our_port->name())) {
375 error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
379 drop_input_bundle ();
383 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
384 _session.set_dirty ();
390 IO::connect_input (Port* our_port, string other_port, void* src)
392 if (other_port.length() == 0 || our_port == 0) {
397 BLOCK_PROCESS_CALLBACK ();
400 Glib::Mutex::Lock lm (io_lock);
402 /* check that our_port is really one of ours */
404 if ( ! _inputs.contains(our_port) ) {
408 /* connect it to the source */
410 if (_session.engine().connect (other_port, our_port->name())) {
414 drop_input_bundle ();
418 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
419 _session.set_dirty ();
424 IO::disconnect_output (Port* our_port, string other_port, void* src)
426 if (other_port.length() == 0 || our_port == 0) {
431 BLOCK_PROCESS_CALLBACK ();
434 Glib::Mutex::Lock lm (io_lock);
436 /* check that our_port is really one of ours */
438 if ( ! _outputs.contains(our_port) ) {
442 /* disconnect it from the destination */
444 if (_session.engine().disconnect (our_port->name(), other_port)) {
445 error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
449 drop_output_bundle ();
453 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
454 _session.set_dirty ();
459 IO::connect_output (Port* our_port, string other_port, void* src)
461 if (other_port.length() == 0 || our_port == 0) {
466 BLOCK_PROCESS_CALLBACK ();
470 Glib::Mutex::Lock lm (io_lock);
472 /* check that our_port is really one of ours */
474 if ( ! _outputs.contains(our_port) ) {
478 /* connect it to the destination */
480 if (_session.engine().connect (our_port->name(), other_port)) {
484 drop_output_bundle ();
488 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
489 _session.set_dirty ();
494 IO::set_input (Port* other_port, void* src)
496 /* this removes all but one ports, and connects that one port
497 to the specified source.
500 if (_input_minimum.n_total() > 1) {
501 /* sorry, you can't do this */
505 if (other_port == 0) {
506 if (_input_minimum == ChanCount::ZERO) {
507 return ensure_inputs (ChanCount::ZERO, false, true, src);
513 if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
517 return connect_input (_inputs.port(0), other_port->name(), src);
521 IO::remove_output_port (Port* port, void* src)
523 IOChange change (NoChange);
526 BLOCK_PROCESS_CALLBACK ();
530 Glib::Mutex::Lock lm (io_lock);
532 if (n_outputs() <= _output_minimum) {
533 /* sorry, you can't do this */
537 if (_outputs.remove(port)) {
538 change = IOChange (change|ConfigurationChanged);
540 if (port->connected()) {
541 change = IOChange (change|ConnectionsChanged);
544 _session.engine().unregister_port (*port);
545 drop_output_bundle ();
547 setup_peak_meters ();
553 if (change != NoChange) {
554 output_changed (change, src);
555 _session.set_dirty ();
562 /** Add an output port.
564 * @param destination Name of input port to connect new port to.
565 * @param src Source for emitted ConfigurationChanged signal.
566 * @param type Data type of port. Default value (NIL) will use this IO's default type.
569 IO::add_output_port (string destination, void* src, DataType type)
574 if (type == DataType::NIL)
575 type = _default_type;
578 BLOCK_PROCESS_CALLBACK ();
582 Glib::Mutex::Lock lm (io_lock);
584 if (n_outputs() >= _output_maximum) {
588 /* Create a new output port */
590 // FIXME: naming scheme for differently typed ports?
591 if (_output_maximum.get(type) == 1) {
592 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
594 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
597 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
598 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
602 _outputs.add (our_port);
603 drop_output_bundle ();
604 setup_peak_meters ();
608 MoreChannels (n_outputs()); /* EMIT SIGNAL */
611 if (destination.length()) {
612 if (_session.engine().connect (our_port->name(), destination)) {
617 // pan_changed (src); /* EMIT SIGNAL */
618 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
619 _session.set_dirty ();
625 IO::remove_input_port (Port* port, void* src)
627 IOChange change (NoChange);
630 BLOCK_PROCESS_CALLBACK ();
634 Glib::Mutex::Lock lm (io_lock);
636 if (n_inputs() <= _input_minimum) {
637 /* sorry, you can't do this */
641 if (_inputs.remove(port)) {
642 change = IOChange (change|ConfigurationChanged);
644 if (port->connected()) {
645 change = IOChange (change|ConnectionsChanged);
648 _session.engine().unregister_port (*port);
649 drop_input_bundle ();
651 setup_peak_meters ();
657 if (change != NoChange) {
658 input_changed (change, src);
659 _session.set_dirty ();
667 /** Add an input port.
669 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
670 * @param destination Name of input port to connect new port to.
671 * @param src Source for emitted ConfigurationChanged signal.
674 IO::add_input_port (string source, void* src, DataType type)
679 if (type == DataType::NIL)
680 type = _default_type;
683 BLOCK_PROCESS_CALLBACK ();
686 Glib::Mutex::Lock lm (io_lock);
688 if (n_inputs() >= _input_maximum) {
692 /* Create a new input port */
694 // FIXME: naming scheme for differently typed ports?
695 if (_input_maximum.get(type) == 1) {
696 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
698 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
701 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
702 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
706 _inputs.add (our_port);
707 drop_input_bundle ();
708 setup_peak_meters ();
712 MoreChannels (n_inputs()); /* EMIT SIGNAL */
715 if (source.length()) {
717 if (_session.engine().connect (source, our_port->name())) {
722 // pan_changed (src); /* EMIT SIGNAL */
723 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
724 _session.set_dirty ();
730 IO::disconnect_inputs (void* src)
733 BLOCK_PROCESS_CALLBACK ();
736 Glib::Mutex::Lock lm (io_lock);
738 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
739 _session.engine().disconnect (*i);
742 drop_input_bundle ();
746 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
752 IO::disconnect_outputs (void* src)
755 BLOCK_PROCESS_CALLBACK ();
758 Glib::Mutex::Lock lm (io_lock);
760 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
761 _session.engine().disconnect (*i);
764 drop_output_bundle ();
768 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
769 _session.set_dirty ();
775 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
777 Port* input_port = 0;
778 bool changed = false;
781 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
783 const size_t n = count.get(*t);
785 /* remove unused ports */
786 for (size_t i = n_inputs().get(*t); i > n; --i) {
787 input_port = _inputs.port(*t, i-1);
790 _inputs.remove(input_port);
791 _session.engine().unregister_port (*input_port);
796 /* create any necessary new ports */
797 while (n_inputs().get(*t) < n) {
801 if (_input_maximum.get(*t) == 1) {
802 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
804 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
809 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
810 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
815 catch (AudioEngine::PortRegistrationFailure& err) {
816 setup_peak_meters ();
819 throw AudioEngine::PortRegistrationFailure();
822 _inputs.add (input_port);
828 drop_input_bundle ();
829 setup_peak_meters ();
831 MoreChannels (n_inputs()); /* EMIT SIGNAL */
832 _session.set_dirty ();
836 /* disconnect all existing ports so that we get a fresh start */
837 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
838 _session.engine().disconnect (*i);
845 /** Attach output_buffers to port buffers.
847 * Connected to IO's own MoreChannels signal.
850 IO::attach_buffers(ChanCount ignored)
852 _output_buffers->attach_buffers(_outputs);
856 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
858 bool in_changed = false;
859 bool out_changed = false;
860 bool need_pan_reset = false;
862 in = min (_input_maximum, in);
864 out = min (_output_maximum, out);
866 if (in == n_inputs() && out == n_outputs() && !clear) {
871 BLOCK_PROCESS_CALLBACK ();
872 Glib::Mutex::Lock lm (io_lock);
876 if (n_outputs() != out) {
877 need_pan_reset = true;
880 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
882 const size_t nin = in.get(*t);
883 const size_t nout = out.get(*t);
885 Port* output_port = 0;
886 Port* input_port = 0;
888 /* remove unused output ports */
889 for (size_t i = n_outputs().get(*t); i > nout; --i) {
890 output_port = _outputs.port(*t, i-1);
893 _outputs.remove(output_port);
894 _session.engine().unregister_port (*output_port);
899 /* remove unused input ports */
900 for (size_t i = n_inputs().get(*t); i > nin; --i) {
901 input_port = _inputs.port(*t, i-1);
904 _inputs.remove(input_port);
905 _session.engine().unregister_port (*input_port);
910 /* create any necessary new input ports */
912 while (n_inputs().get(*t) < nin) {
916 /* Create a new input port */
918 if (_input_maximum.get(*t) == 1) {
919 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
921 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
925 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
926 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
931 catch (AudioEngine::PortRegistrationFailure& err) {
932 setup_peak_meters ();
935 throw AudioEngine::PortRegistrationFailure();
942 /* create any necessary new output ports */
944 while (n_outputs().get(*t) < nout) {
948 /* Create a new output port */
950 if (_output_maximum.get(*t) == 1) {
951 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
953 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
957 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
958 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
963 catch (AudioEngine::PortRegistrationFailure& err) {
964 setup_peak_meters ();
967 throw AudioEngine::PortRegistrationFailure ();
977 /* disconnect all existing ports so that we get a fresh start */
979 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
980 _session.engine().disconnect (*i);
983 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
984 _session.engine().disconnect (*i);
988 if (in_changed || out_changed) {
989 setup_peak_meters ();
995 drop_output_bundle ();
996 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1000 drop_input_bundle ();
1001 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1004 if (in_changed || out_changed) {
1005 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1006 _session.set_dirty ();
1013 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1015 bool changed = false;
1017 count = min (_input_maximum, count);
1019 if (count == n_inputs() && !clear) {
1024 BLOCK_PROCESS_CALLBACK ();
1025 Glib::Mutex::Lock im (io_lock);
1026 changed = ensure_inputs_locked (count, clear, src);
1028 changed = ensure_inputs_locked (count, clear, src);
1032 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1033 _session.set_dirty ();
1039 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1041 Port* output_port = 0;
1042 bool changed = false;
1043 bool need_pan_reset = false;
1045 if (n_outputs() != count) {
1046 need_pan_reset = true;
1049 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1051 const size_t n = count.get(*t);
1053 /* remove unused ports */
1054 for (size_t i = n_outputs().get(*t); i > n; --i) {
1055 output_port = _outputs.port(*t, i-1);
1057 assert(output_port);
1058 _outputs.remove(output_port);
1059 _session.engine().unregister_port (*output_port);
1064 /* create any necessary new ports */
1065 while (n_outputs().get(*t) < n) {
1069 if (_output_maximum.get(*t) == 1) {
1070 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1072 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1075 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1076 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1080 _outputs.add (output_port);
1082 setup_peak_meters ();
1084 if (need_pan_reset) {
1091 drop_output_bundle ();
1092 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1093 _session.set_dirty ();
1097 /* disconnect all existing ports so that we get a fresh start */
1098 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1099 _session.engine().disconnect (*i);
1107 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1109 bool changed = false;
1111 if (_output_maximum < ChanCount::INFINITE) {
1112 count = min (_output_maximum, count);
1113 if (count == n_outputs() && !clear) {
1118 /* XXX caller should hold io_lock, but generally doesn't */
1121 BLOCK_PROCESS_CALLBACK ();
1122 Glib::Mutex::Lock im (io_lock);
1123 changed = ensure_outputs_locked (count, clear, src);
1125 changed = ensure_outputs_locked (count, clear, src);
1129 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1136 IO::effective_gain () const
1138 if (_gain_control->list()->automation_playback()) {
1139 return _gain_control->get_value();
1141 return _desired_gain;
1148 if (panners_legal) {
1149 if (!no_panner_reset) {
1150 _panner->reset (n_outputs().n_audio(), pans_required());
1153 panner_legal_c.disconnect ();
1154 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1159 IO::panners_became_legal ()
1161 _panner->reset (n_outputs().n_audio(), pans_required());
1162 _panner->load (); // automation
1163 panner_legal_c.disconnect ();
1168 IO::defer_pan_reset ()
1170 no_panner_reset = true;
1174 IO::allow_pan_reset ()
1176 no_panner_reset = false;
1182 IO::get_state (void)
1184 return state (true);
1188 IO::state (bool full_state)
1190 XMLNode* node = new XMLNode (state_node_name);
1193 bool need_ins = true;
1194 bool need_outs = true;
1195 LocaleGuard lg (X_("POSIX"));
1196 Glib::Mutex::Lock lm (io_lock);
1198 node->add_property("name", _name);
1199 id().print (buf, sizeof (buf));
1200 node->add_property("id", buf);
1204 if (_input_bundle) {
1205 node->add_property ("input-connection", _input_bundle->name());
1209 if (_output_bundle) {
1210 node->add_property ("output-connection", _output_bundle->name());
1215 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1217 const char **connections = i->get_connections();
1219 if (connections && connections[0]) {
1222 for (int n = 0; connections && connections[n]; ++n) {
1227 /* if its a connection to our own port,
1228 return only the port name, not the
1229 whole thing. this allows connections
1230 to be re-established even when our
1231 client name is different.
1234 str += _session.engine().make_port_name_relative (connections[n]);
1246 node->add_property ("inputs", str);
1252 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1254 const char **connections = i->get_connections();
1256 if (connections && connections[0]) {
1260 for (int n = 0; connections[n]; ++n) {
1265 str += _session.engine().make_port_name_relative (connections[n]);
1277 node->add_property ("outputs", str);
1280 node->add_child_nocopy (_panner->state (full_state));
1281 node->add_child_nocopy (_gain_control->get_state ());
1283 snprintf (buf, sizeof(buf), "%2.12f", gain());
1284 node->add_property ("gain", buf);
1286 // FIXME: this is NOT sufficient!
1287 const int in_min = (_input_minimum == ChanCount::ZERO) ? -1 : _input_minimum.get(_default_type);
1288 const int in_max = (_input_maximum == ChanCount::INFINITE) ? -1 : _input_maximum.get(_default_type);
1289 const int out_min = (_output_minimum == ChanCount::ZERO) ? -1 : _output_minimum.get(_default_type);
1290 const int out_max = (_output_maximum == ChanCount::INFINITE) ? -1 : _output_maximum.get(_default_type);
1292 snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", in_min, in_max, out_min, out_max);
1294 node->add_property ("iolimits", buf);
1299 node->add_child_nocopy (get_automation_state());
1305 IO::set_state (const XMLNode& node)
1307 const XMLProperty* prop;
1308 XMLNodeConstIterator iter;
1309 LocaleGuard lg (X_("POSIX"));
1311 /* force use of non-localized representation of decimal point,
1312 since we use it a lot in XML files and so forth.
1315 if (node.name() != state_node_name) {
1316 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1320 if ((prop = node.property ("name")) != 0) {
1321 _name = prop->value();
1322 /* used to set panner name with this, but no more */
1325 if ((prop = node.property ("id")) != 0) {
1326 _id = prop->value ();
1331 size_t out_min = -1;
1332 size_t out_max = -1;
1334 if ((prop = node.property ("iolimits")) != 0) {
1335 sscanf (prop->value().c_str(), "%zd,%zd,%zd,%zd",
1336 &in_min, &in_max, &out_min, &out_max);
1337 _input_minimum = ChanCount(_default_type, in_min);
1338 _input_maximum = ChanCount(_default_type, in_max);
1339 _output_minimum = ChanCount(_default_type, out_min);
1340 _output_maximum = ChanCount(_default_type, out_max);
1343 if ((prop = node.property ("gain")) != 0) {
1344 set_gain (atof (prop->value().c_str()), this);
1345 _gain = _desired_gain;
1348 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1349 /* old school automation handling */
1352 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1354 if ((*iter)->name() == "Panner") {
1356 _panner = new Panner (_name, _session);
1358 _panner->set_state (**iter);
1361 if ((*iter)->name() == X_("Automation")) {
1363 set_automation_state (*(*iter), ParamID(GainAutomation));
1366 if ((*iter)->name() == X_("controllable")) {
1367 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1368 _gain_control->set_state (**iter);
1375 if (create_ports (node)) {
1381 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1384 if (panners_legal) {
1387 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1390 if (connecting_legal) {
1392 if (make_connections (node)) {
1398 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1401 if (!ports_legal || !connecting_legal) {
1402 pending_state_node = new XMLNode (node);
1409 IO::load_automation (string path)
1414 uint32_t linecnt = 0;
1416 LocaleGuard lg (X_("POSIX"));
1418 fullpath = _session.automation_dir();
1421 in.open (fullpath.c_str());
1424 fullpath = _session.automation_dir();
1425 fullpath += _session.snap_name();
1429 in.open (fullpath.c_str());
1432 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1437 clear_automation ();
1439 while (in.getline (line, sizeof(line), '\n')) {
1444 if (++linecnt == 1) {
1445 if (memcmp (line, "version", 7) == 0) {
1446 if (sscanf (line, "version %f", &version) != 1) {
1447 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1451 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1458 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1459 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1465 _gain_control->list()->fast_simple_add (when, value);
1475 /* older (pre-1.0) versions of ardour used this */
1479 warning << _("dubious automation event found (and ignored)") << endmsg;
1487 IO::connecting_became_legal ()
1491 if (pending_state_node == 0) {
1492 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1497 connection_legal_c.disconnect ();
1499 ret = make_connections (*pending_state_node);
1502 delete pending_state_node;
1503 pending_state_node = 0;
1509 IO::ports_became_legal ()
1513 if (pending_state_node == 0) {
1514 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1519 port_legal_c.disconnect ();
1521 ret = create_ports (*pending_state_node);
1523 if (connecting_legal) {
1524 delete pending_state_node;
1525 pending_state_node = 0;
1532 IO::create_ports (const XMLNode& node)
1534 const XMLProperty* prop;
1536 int num_outputs = 0;
1538 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1539 * break the session file format.
1541 if ((prop = node.property ("input-connection")) != 0) {
1543 Bundle* c = _session.bundle_by_name (prop->value());
1546 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1548 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1549 error << _("No input bundles available as a replacement")
1553 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1558 num_inputs = c->nchannels();
1560 } else if ((prop = node.property ("inputs")) != 0) {
1562 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1565 if ((prop = node.property ("output-connection")) != 0) {
1566 Bundle* c = _session.bundle_by_name (prop->value());
1569 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1571 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1572 error << _("No output bundles available as a replacement")
1576 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1581 num_outputs = c->nchannels ();
1583 } else if ((prop = node.property ("outputs")) != 0) {
1584 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1587 no_panner_reset = true;
1589 // FIXME: audio-only
1590 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1591 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1595 no_panner_reset = false;
1597 set_deferred_state ();
1605 IO::make_connections (const XMLNode& node)
1607 const XMLProperty* prop;
1609 if ((prop = node.property ("input-connection")) != 0) {
1610 Bundle* c = _session.bundle_by_name (prop->value());
1613 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1615 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1616 error << _("No input connections available as a replacement")
1620 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1625 use_input_bundle (*c, this);
1627 } else if ((prop = node.property ("inputs")) != 0) {
1628 if (set_inputs (prop->value())) {
1629 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1634 if ((prop = node.property ("output-bundle")) != 0) {
1635 Bundle* c = _session.bundle_by_name (prop->value());
1638 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1640 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1641 error << _("No output bundles available as a replacement")
1645 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1650 use_output_bundle (*c, this);
1652 } else if ((prop = node.property ("outputs")) != 0) {
1653 if (set_outputs (prop->value())) {
1654 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1663 IO::set_inputs (const string& str)
1665 vector<string> ports;
1670 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1674 // FIXME: audio-only
1675 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1679 string::size_type start, end, ostart;
1686 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1689 if ((end = str.find_first_of ('}', start)) == string::npos) {
1690 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1694 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1695 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1701 for (int x = 0; x < n; ++x) {
1702 connect_input (input (i), ports[x], this);
1714 IO::set_outputs (const string& str)
1716 vector<string> ports;
1721 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1725 // FIXME: audio-only
1726 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1730 string::size_type start, end, ostart;
1737 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1740 if ((end = str.find_first_of ('}', start)) == string::npos) {
1741 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1745 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1746 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1752 for (int x = 0; x < n; ++x) {
1753 connect_output (output (i), ports[x], this);
1765 IO::parse_io_string (const string& str, vector<string>& ports)
1767 string::size_type pos, opos;
1769 if (str.length() == 0) {
1778 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1779 ports.push_back (str.substr (opos, pos - opos));
1783 if (opos < str.length()) {
1784 ports.push_back (str.substr(opos));
1787 return ports.size();
1791 IO::parse_gain_string (const string& str, vector<string>& ports)
1793 string::size_type pos, opos;
1799 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1800 ports.push_back (str.substr (opos, pos - opos));
1804 if (opos < str.length()) {
1805 ports.push_back (str.substr(opos));
1808 return ports.size();
1812 IO::set_name (const string& str)
1818 /* replace all colons in the name. i wish we didn't have to do this */
1821 if (replace_all (name, ":", "-")) {
1822 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1825 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1826 string current_name = i->short_name();
1827 current_name.replace (current_name.find (_name), _name.length(), name);
1828 i->set_name (current_name);
1831 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1832 string current_name = i->short_name();
1833 current_name.replace (current_name.find (_name), _name.length(), name);
1834 i->set_name (current_name);
1837 return SessionObject::set_name(name);
1841 IO::set_input_minimum (ChanCount n)
1847 IO::set_input_maximum (ChanCount n)
1853 IO::set_output_minimum (ChanCount n)
1855 _output_minimum = n;
1859 IO::set_output_maximum (ChanCount n)
1861 _output_maximum = n;
1865 IO::set_port_latency (nframes_t nframes)
1867 Glib::Mutex::Lock lm (io_lock);
1869 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1870 i->set_latency (nframes);
1875 IO::output_latency () const
1877 nframes_t max_latency;
1882 /* io lock not taken - must be protected by other means */
1884 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1885 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1886 max_latency = latency;
1894 IO::input_latency () const
1896 nframes_t max_latency;
1901 /* io lock not taken - must be protected by other means */
1903 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1904 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1905 max_latency = latency;
1913 IO::use_input_bundle (Bundle& c, void* src)
1918 BLOCK_PROCESS_CALLBACK ();
1919 Glib::Mutex::Lock lm2 (io_lock);
1921 limit = c.nchannels();
1923 drop_input_bundle ();
1925 // FIXME bundles only work for audio-only
1926 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1930 /* first pass: check the current state to see what's correctly
1931 connected, and drop anything that we don't want.
1934 for (uint32_t n = 0; n < limit; ++n) {
1935 const Bundle::PortList& pl = c.channel_ports (n);
1937 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1939 if (!_inputs.port(n)->connected_to ((*i))) {
1941 /* clear any existing connections */
1943 _session.engine().disconnect (*_inputs.port(n));
1945 } else if (_inputs.port(n)->connected() > 1) {
1947 /* OK, it is connected to the port we want,
1948 but its also connected to other ports.
1949 Change that situation.
1952 /* XXX could be optimized to not drop
1956 _session.engine().disconnect (*_inputs.port(n));
1962 /* second pass: connect all requested ports where necessary */
1964 for (uint32_t n = 0; n < limit; ++n) {
1965 const Bundle::PortList& pl = c.channel_ports (n);
1967 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1969 if (!_inputs.port(n)->connected_to ((*i))) {
1971 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
1981 input_bundle_configuration_connection = c.ConfigurationChanged.connect
1982 (mem_fun (*this, &IO::input_bundle_configuration_changed));
1983 input_bundle_connection_connection = c.PortsChanged.connect
1984 (mem_fun (*this, &IO::input_bundle_connection_changed));
1987 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
1992 IO::use_output_bundle (Bundle& c, void* src)
1997 BLOCK_PROCESS_CALLBACK ();
1998 Glib::Mutex::Lock lm2 (io_lock);
2000 limit = c.nchannels();
2002 drop_output_bundle ();
2004 // FIXME: audio-only
2005 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2009 /* first pass: check the current state to see what's correctly
2010 connected, and drop anything that we don't want.
2013 for (uint32_t n = 0; n < limit; ++n) {
2015 const Bundle::PortList& pl = c.channel_ports (n);
2017 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2019 if (!_outputs.port(n)->connected_to ((*i))) {
2021 /* clear any existing connections */
2023 _session.engine().disconnect (*_outputs.port(n));
2025 } else if (_outputs.port(n)->connected() > 1) {
2027 /* OK, it is connected to the port we want,
2028 but its also connected to other ports.
2029 Change that situation.
2032 /* XXX could be optimized to not drop
2036 _session.engine().disconnect (*_outputs.port(n));
2041 /* second pass: connect all requested ports where necessary */
2043 for (uint32_t n = 0; n < limit; ++n) {
2045 const Bundle::PortList& pl = c.channel_ports (n);
2047 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2049 if (!_outputs.port(n)->connected_to ((*i))) {
2051 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2058 _output_bundle = &c;
2060 output_bundle_configuration_connection = c.ConfigurationChanged.connect
2061 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2062 output_bundle_connection_connection = c.PortsChanged.connect
2063 (mem_fun (*this, &IO::output_bundle_connection_changed));
2066 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2072 IO::disable_connecting ()
2074 connecting_legal = false;
2079 IO::enable_connecting ()
2081 connecting_legal = true;
2082 return ConnectingLegal ();
2086 IO::disable_ports ()
2088 ports_legal = false;
2096 return PortsLegal ();
2100 IO::disable_panners (void)
2102 panners_legal = false;
2107 IO::reset_panners ()
2109 panners_legal = true;
2110 return PannersLegal ();
2114 IO::input_bundle_connection_changed (int ignored)
2116 use_input_bundle (*_input_bundle, this);
2120 IO::input_bundle_configuration_changed ()
2122 use_input_bundle (*_input_bundle, this);
2126 IO::output_bundle_connection_changed (int ignored)
2128 use_output_bundle (*_output_bundle, this);
2132 IO::output_bundle_configuration_changed ()
2134 use_output_bundle (*_output_bundle, this);
2138 IO::GainControl::set_value (float val)
2140 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2141 if (val > 1.99526231f)
2145 _io.set_gain (val, this);
2147 Changed(); /* EMIT SIGNAL */
2151 IO::GainControl::get_value (void) const
2153 return AutomationControl::get_value();
2157 IO::setup_peak_meters()
2159 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2160 _meter->configure_io(max_streams, max_streams);
2164 Update the peak meters.
2166 The meter signal lock is taken to prevent modification of the
2167 Meter signal while updating the meters, taking the meter signal
2168 lock prior to taking the io_lock ensures that all IO will remain
2169 valid while metering.
2174 Glib::Mutex::Lock guard (m_meter_signal_lock);
2176 Meter(); /* EMIT SIGNAL */
2182 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2184 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2189 IO::clear_automation ()
2191 Automatable::clear_automation (); // clears gain automation
2192 _panner->clear_automation ();
2196 IO::set_parameter_automation_state (ParamID param, AutoState state)
2198 // XXX: would be nice to get rid of this special hack
2200 if (param.type() == GainAutomation) {
2202 bool changed = false;
2205 Glib::Mutex::Lock lm (_automation_lock);
2207 boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2209 if (state != gain_auto->automation_state()) {
2211 _last_automation_snapshot = 0;
2212 gain_auto->set_automation_state (state);
2215 // FIXME: shouldn't this use Curve?
2216 set_gain (gain_auto->eval (_session.transport_frame()), this);
2222 _session.set_dirty ();
2226 Automatable::set_parameter_automation_state(param, state);
2231 IO::inc_gain (gain_t factor, void *src)
2233 if (_desired_gain == 0.0f)
2234 set_gain (0.000001f + (0.000001f * factor), src);
2236 set_gain (_desired_gain + (_desired_gain * factor), src);
2240 IO::set_gain (gain_t val, void *src)
2242 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2243 if (val > 1.99526231f)
2246 if (src != _gain_control.get()) {
2247 _gain_control->set_value(val);
2248 // bit twisty, this will come back and call us again
2249 // (this keeps control in sync with reality)
2254 Glib::Mutex::Lock dm (declick_lock);
2255 _desired_gain = val;
2258 if (_session.transport_stopped()) {
2262 if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2263 _gain_control->list()->add (_session.transport_frame(), val);
2267 _session.set_dirty();
2271 IO::start_pan_touch (uint32_t which)
2273 if (which < _panner->size()) {
2274 (*_panner)[which]->pan_control()->list()->start_touch();
2279 IO::end_pan_touch (uint32_t which)
2281 if (which < _panner->size()) {
2282 (*_panner)[which]->pan_control()->list()->stop_touch();
2288 IO::automation_snapshot (nframes_t now)
2290 Automatable::automation_snapshot (now);
2292 if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
2293 _panner->snapshot (now);
2298 IO::transport_stopped (nframes_t frame)
2300 _gain_control->list()->reposition_for_rt_add (frame);
2302 if (_gain_control->list()->automation_state() != Off) {
2304 /* the src=0 condition is a special signal to not propagate
2305 automation gain changes into the mix group when locating.
2308 // FIXME: shouldn't this use Curve?
2309 set_gain (_gain_control->list()->eval (frame), 0);
2312 _panner->transport_stopped (frame);
2316 IO::find_input_port_hole ()
2318 /* CALLER MUST HOLD IO LOCK */
2322 if (_inputs.empty()) {
2326 for (n = 1; n < UINT_MAX; ++n) {
2327 char buf[jack_port_name_size()];
2328 PortSet::iterator i = _inputs.begin();
2330 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2332 for ( ; i != _inputs.end(); ++i) {
2333 if (i->short_name() == buf) {
2338 if (i == _inputs.end()) {
2346 IO::find_output_port_hole ()
2348 /* CALLER MUST HOLD IO LOCK */
2352 if (_outputs.empty()) {
2356 for (n = 1; n < UINT_MAX; ++n) {
2357 char buf[jack_port_name_size()];
2358 PortSet::iterator i = _outputs.begin();
2360 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2362 for ( ; i != _outputs.end(); ++i) {
2363 if (i->short_name() == buf) {
2368 if (i == _outputs.end()) {
2377 IO::audio_input(uint32_t n) const
2379 return dynamic_cast<AudioPort*>(input(n));
2383 IO::audio_output(uint32_t n) const
2385 return dynamic_cast<AudioPort*>(output(n));
2389 IO::midi_input(uint32_t n) const
2391 return dynamic_cast<MidiPort*>(input(n));
2395 IO::midi_output(uint32_t n) const
2397 return dynamic_cast<MidiPort*>(output(n));
2401 IO::set_phase_invert (bool yn, void *src)
2403 if (_phase_invert != yn) {
2405 // phase_invert_changed (src); /* EMIT SIGNAL */
2410 IO::set_denormal_protection (bool yn, void *src)
2412 if (_denormal_protection != yn) {
2413 _denormal_protection = yn;
2414 // denormal_protection_changed (src); /* EMIT SIGNAL */
2419 IO::update_port_total_latencies ()
2421 /* io_lock, not taken: function must be called from Session::process() calltree */
2423 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2424 _session.engine().update_total_latency (*i);
2427 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2428 _session.engine().update_total_latency (*i);