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);
129 pending_state_node = 0;
130 no_panner_reset = false;
131 _phase_invert = false;
134 boost::shared_ptr<AutomationList> gl(
135 new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
137 _gain_control = boost::shared_ptr<GainControl>(
138 new GainControl(X_("gaincontrol"), *this, gl));
140 add_control(_gain_control);
142 apply_gain_automation = false;
145 // IO::Meter is emitted from another thread so the
146 // Meter signal must be protected.
147 Glib::Mutex::Lock guard (m_meter_signal_lock);
148 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
151 // Connect to our own MoreChannels signal to connect output buffers
152 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
154 _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;
172 apply_gain_automation = false;
174 boost::shared_ptr<AutomationList> gl(
175 new AutomationList(Parameter(GainAutomation), 0.0, 2.0, 1.0));
177 _gain_control = boost::shared_ptr<GainControl>(
178 new GainControl(X_("gaincontrol"), *this, gl));
180 add_control(_gain_control);
185 // IO::Meter is emitted from another thread so the
186 // Meter signal must be protected.
187 Glib::Mutex::Lock guard (m_meter_signal_lock);
188 m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
191 // Connect to our own MoreChannels signal to connect output buffers
192 IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers));
194 _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_in_place(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 ()
338 _input_bundle.reset ();
339 input_bundle_configuration_connection.disconnect();
340 input_bundle_connection_connection.disconnect();
341 _session.set_dirty ();
345 IO::drop_output_bundle ()
347 _output_bundle.reset ();
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 == ConnectionsChanged) {
557 if (change != NoChange) {
558 output_changed (change, src);
559 _session.set_dirty ();
566 /** Add an output port.
568 * @param destination Name of input port to connect new port to.
569 * @param src Source for emitted ConfigurationChanged signal.
570 * @param type Data type of port. Default value (NIL) will use this IO's default type.
573 IO::add_output_port (string destination, void* src, DataType type)
578 if (type == DataType::NIL)
579 type = _default_type;
582 BLOCK_PROCESS_CALLBACK ();
586 Glib::Mutex::Lock lm (io_lock);
588 if (n_outputs() >= _output_maximum) {
592 /* Create a new output port */
594 // FIXME: naming scheme for differently typed ports?
595 if (_output_maximum.get(type) == 1) {
596 snprintf (name, sizeof (name), _("%s/out"), _name.c_str());
598 snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
601 if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
602 error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
606 _outputs.add (our_port);
607 drop_output_bundle ();
608 setup_peak_meters ();
612 MoreChannels (n_outputs()); /* EMIT SIGNAL */
615 if (destination.length()) {
616 if (_session.engine().connect (our_port->name(), destination)) {
621 // pan_changed (src); /* EMIT SIGNAL */
622 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
624 _session.set_dirty ();
630 IO::remove_input_port (Port* port, void* src)
632 IOChange change (NoChange);
635 BLOCK_PROCESS_CALLBACK ();
639 Glib::Mutex::Lock lm (io_lock);
641 if (n_inputs() <= _input_minimum) {
642 /* sorry, you can't do this */
646 if (_inputs.remove(port)) {
647 change = IOChange (change|ConfigurationChanged);
649 if (port->connected()) {
650 change = IOChange (change|ConnectionsChanged);
653 _session.engine().unregister_port (*port);
654 drop_input_bundle ();
656 setup_peak_meters ();
662 if (change == ConfigurationChanged) {
666 if (change != NoChange) {
667 input_changed (change, src);
668 _session.set_dirty ();
676 /** Add an input port.
678 * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created.
679 * @param destination Name of input port to connect new port to.
680 * @param src Source for emitted ConfigurationChanged signal.
683 IO::add_input_port (string source, void* src, DataType type)
688 if (type == DataType::NIL)
689 type = _default_type;
692 BLOCK_PROCESS_CALLBACK ();
695 Glib::Mutex::Lock lm (io_lock);
697 if (n_inputs() >= _input_maximum) {
701 /* Create a new input port */
703 // FIXME: naming scheme for differently typed ports?
704 if (_input_maximum.get(type) == 1) {
705 snprintf (name, sizeof (name), _("%s/in"), _name.c_str());
707 snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
710 if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
711 error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
715 _inputs.add (our_port);
716 drop_input_bundle ();
717 setup_peak_meters ();
721 MoreChannels (n_inputs()); /* EMIT SIGNAL */
724 if (source.length()) {
726 if (_session.engine().connect (source, our_port->name())) {
731 // pan_changed (src); /* EMIT SIGNAL */
732 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
734 _session.set_dirty ();
740 IO::disconnect_inputs (void* src)
743 BLOCK_PROCESS_CALLBACK ();
746 Glib::Mutex::Lock lm (io_lock);
748 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
749 _session.engine().disconnect (*i);
752 drop_input_bundle ();
756 input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
762 IO::disconnect_outputs (void* src)
765 BLOCK_PROCESS_CALLBACK ();
768 Glib::Mutex::Lock lm (io_lock);
770 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
771 _session.engine().disconnect (*i);
774 drop_output_bundle ();
778 output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
779 _session.set_dirty ();
785 IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
787 Port* input_port = 0;
788 bool changed = false;
791 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
793 const size_t n = count.get(*t);
795 /* remove unused ports */
796 for (size_t i = n_inputs().get(*t); i > n; --i) {
797 input_port = _inputs.port(*t, i-1);
800 _inputs.remove(input_port);
801 _session.engine().unregister_port (*input_port);
806 /* create any necessary new ports */
807 while (n_inputs().get(*t) < n) {
811 if (_input_maximum.get(*t) == 1) {
812 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
814 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
819 if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
820 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
825 catch (AudioEngine::PortRegistrationFailure& err) {
826 setup_peak_meters ();
829 throw AudioEngine::PortRegistrationFailure();
832 _inputs.add (input_port);
838 drop_input_bundle ();
839 setup_peak_meters ();
841 MoreChannels (n_inputs()); /* EMIT SIGNAL */
842 _session.set_dirty ();
846 /* disconnect all existing ports so that we get a fresh start */
847 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
848 _session.engine().disconnect (*i);
855 /** Attach output_buffers to port buffers.
857 * Connected to IO's own MoreChannels signal.
860 IO::attach_buffers(ChanCount ignored)
862 _output_buffers->attach_buffers(_outputs);
866 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
868 bool in_changed = false;
869 bool out_changed = false;
870 bool need_pan_reset = false;
872 in = min (_input_maximum, in);
874 out = min (_output_maximum, out);
876 if (in == n_inputs() && out == n_outputs() && !clear) {
881 BLOCK_PROCESS_CALLBACK ();
882 Glib::Mutex::Lock lm (io_lock);
886 if (n_outputs() != out) {
887 need_pan_reset = true;
890 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
892 const size_t nin = in.get(*t);
893 const size_t nout = out.get(*t);
895 Port* output_port = 0;
896 Port* input_port = 0;
898 /* remove unused output ports */
899 for (size_t i = n_outputs().get(*t); i > nout; --i) {
900 output_port = _outputs.port(*t, i-1);
903 _outputs.remove(output_port);
904 _session.engine().unregister_port (*output_port);
909 /* remove unused input ports */
910 for (size_t i = n_inputs().get(*t); i > nin; --i) {
911 input_port = _inputs.port(*t, i-1);
914 _inputs.remove(input_port);
915 _session.engine().unregister_port (*input_port);
920 /* create any necessary new input ports */
922 while (n_inputs().get(*t) < nin) {
926 /* Create a new input port */
928 if (_input_maximum.get(*t) == 1) {
929 snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str());
931 snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole());
935 if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
936 error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
941 catch (AudioEngine::PortRegistrationFailure& err) {
942 setup_peak_meters ();
945 throw AudioEngine::PortRegistrationFailure();
952 /* create any necessary new output ports */
954 while (n_outputs().get(*t) < nout) {
958 /* Create a new output port */
960 if (_output_maximum.get(*t) == 1) {
961 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
963 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
967 if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
968 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
973 catch (AudioEngine::PortRegistrationFailure& err) {
974 setup_peak_meters ();
977 throw AudioEngine::PortRegistrationFailure ();
987 /* disconnect all existing ports so that we get a fresh start */
989 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
990 _session.engine().disconnect (*i);
993 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
994 _session.engine().disconnect (*i);
998 if (in_changed || out_changed) {
999 setup_peak_meters ();
1005 drop_output_bundle ();
1006 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1010 drop_input_bundle ();
1011 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1014 if (in_changed || out_changed) {
1015 MoreChannels (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
1017 _session.set_dirty ();
1024 IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
1026 bool changed = false;
1028 count = min (_input_maximum, count);
1030 if (count == n_inputs() && !clear) {
1035 BLOCK_PROCESS_CALLBACK ();
1036 Glib::Mutex::Lock im (io_lock);
1037 changed = ensure_inputs_locked (count, clear, src);
1039 changed = ensure_inputs_locked (count, clear, src);
1043 input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1045 _session.set_dirty ();
1051 IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
1053 Port* output_port = 0;
1054 bool changed = false;
1055 bool need_pan_reset = false;
1057 if (n_outputs() != count) {
1058 need_pan_reset = true;
1061 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1063 const size_t n = count.get(*t);
1065 /* remove unused ports */
1066 for (size_t i = n_outputs().get(*t); i > n; --i) {
1067 output_port = _outputs.port(*t, i-1);
1069 assert(output_port);
1070 _outputs.remove(output_port);
1071 _session.engine().unregister_port (*output_port);
1076 /* create any necessary new ports */
1077 while (n_outputs().get(*t) < n) {
1081 if (_output_maximum.get(*t) == 1) {
1082 snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str());
1084 snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
1087 if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
1088 error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
1092 _outputs.add (output_port);
1094 setup_peak_meters ();
1096 if (need_pan_reset) {
1103 drop_output_bundle ();
1104 MoreChannels (n_outputs()); /* EMIT SIGNAL */
1105 _session.set_dirty ();
1109 /* disconnect all existing ports so that we get a fresh start */
1110 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1111 _session.engine().disconnect (*i);
1119 IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
1121 bool changed = false;
1123 if (_output_maximum < ChanCount::INFINITE) {
1124 count = min (_output_maximum, count);
1125 if (count == n_outputs() && !clear) {
1130 /* XXX caller should hold io_lock, but generally doesn't */
1133 BLOCK_PROCESS_CALLBACK ();
1134 Glib::Mutex::Lock im (io_lock);
1135 changed = ensure_outputs_locked (count, clear, src);
1137 changed = ensure_outputs_locked (count, clear, src);
1141 output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
1149 IO::effective_gain () const
1151 if (_gain_control->list()->automation_playback()) {
1152 return _gain_control->get_value();
1154 return _desired_gain;
1161 if (panners_legal) {
1162 if (!no_panner_reset) {
1163 _panner->reset (n_outputs().n_audio(), pans_required());
1166 panner_legal_c.disconnect ();
1167 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1172 IO::panners_became_legal ()
1174 _panner->reset (n_outputs().n_audio(), pans_required());
1175 _panner->load (); // automation
1176 panner_legal_c.disconnect ();
1181 IO::defer_pan_reset ()
1183 no_panner_reset = true;
1187 IO::allow_pan_reset ()
1189 no_panner_reset = false;
1195 IO::get_state (void)
1197 return state (true);
1201 IO::state (bool full_state)
1203 XMLNode* node = new XMLNode (state_node_name);
1206 bool need_ins = true;
1207 bool need_outs = true;
1208 LocaleGuard lg (X_("POSIX"));
1209 Glib::Mutex::Lock lm (io_lock);
1211 node->add_property("name", _name);
1212 id().print (buf, sizeof (buf));
1213 node->add_property("id", buf);
1217 if (_input_bundle && !_input_bundle->dynamic()) {
1218 node->add_property ("input-connection", _input_bundle->name());
1222 if (_output_bundle && !_output_bundle->dynamic()) {
1223 node->add_property ("output-connection", _output_bundle->name());
1228 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1230 const char **connections = i->get_connections();
1232 if (connections && connections[0]) {
1235 for (int n = 0; connections && connections[n]; ++n) {
1240 /* if its a connection to our own port,
1241 return only the port name, not the
1242 whole thing. this allows connections
1243 to be re-established even when our
1244 client name is different.
1247 str += _session.engine().make_port_name_relative (connections[n]);
1259 node->add_property ("inputs", str);
1265 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1267 const char **connections = i->get_connections();
1269 if (connections && connections[0]) {
1273 for (int n = 0; connections[n]; ++n) {
1278 str += _session.engine().make_port_name_relative (connections[n]);
1290 node->add_property ("outputs", str);
1293 node->add_child_nocopy (_panner->state (full_state));
1294 node->add_child_nocopy (_gain_control->get_state ());
1296 snprintf (buf, sizeof(buf), "%2.12f", gain());
1297 node->add_property ("gain", buf);
1299 /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
1303 int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
1304 int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
1306 snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
1308 node->add_property ("iolimits", buf);
1313 node->add_child_nocopy (get_automation_state());
1319 IO::set_state (const XMLNode& node)
1321 const XMLProperty* prop;
1322 XMLNodeConstIterator iter;
1323 LocaleGuard lg (X_("POSIX"));
1325 /* force use of non-localized representation of decimal point,
1326 since we use it a lot in XML files and so forth.
1329 if (node.name() != state_node_name) {
1330 error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
1334 if ((prop = node.property ("name")) != 0) {
1335 _name = prop->value();
1336 /* used to set panner name with this, but no more */
1339 if ((prop = node.property ("id")) != 0) {
1340 _id = prop->value ();
1348 if ((prop = node.property ("iolimits")) != 0) {
1349 sscanf (prop->value().c_str(), "%d,%d,%d,%d",
1350 &in_min, &in_max, &out_min, &out_max);
1352 /* Correct for the difference between the way we write things to session files and the
1353 way things are described by ChanCount; see comments in io.h about what the different
1354 ChanCount values mean. */
1357 _input_minimum = ChanCount::ZERO;
1359 _input_minimum = ChanCount (_default_type, in_min);
1363 _input_maximum = ChanCount::INFINITE;
1365 _input_maximum = ChanCount (_default_type, in_max);
1369 _output_minimum = ChanCount::ZERO;
1371 _output_minimum = ChanCount (_default_type, out_min);
1375 _output_maximum = ChanCount::INFINITE;
1377 _output_maximum = ChanCount (_default_type, out_max);
1381 if ((prop = node.property ("gain")) != 0) {
1382 set_gain (atof (prop->value().c_str()), this);
1383 _gain = _desired_gain;
1386 if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
1387 /* old school automation handling */
1390 for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
1392 if ((*iter)->name() == "Panner") {
1394 _panner = new Panner (_name, _session);
1396 _panner->set_state (**iter);
1399 if ((*iter)->name() == X_("Automation")) {
1401 set_automation_state (*(*iter), Parameter(GainAutomation));
1404 if ((*iter)->name() == X_("controllable")) {
1405 if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
1406 _gain_control->set_state (**iter);
1413 if (create_ports (node)) {
1419 port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
1422 if (panners_legal) {
1425 panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
1428 if (connecting_legal) {
1430 if (make_connections (node)) {
1436 connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
1439 if (!ports_legal || !connecting_legal) {
1440 pending_state_node = new XMLNode (node);
1447 IO::load_automation (string path)
1452 uint32_t linecnt = 0;
1454 LocaleGuard lg (X_("POSIX"));
1456 fullpath = _session.automation_dir();
1459 in.open (fullpath.c_str());
1462 fullpath = _session.automation_dir();
1463 fullpath += _session.snap_name();
1467 in.open (fullpath.c_str());
1470 error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
1475 clear_automation ();
1477 while (in.getline (line, sizeof(line), '\n')) {
1482 if (++linecnt == 1) {
1483 if (memcmp (line, "version", 7) == 0) {
1484 if (sscanf (line, "version %f", &version) != 1) {
1485 error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
1489 error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
1496 if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
1497 warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
1503 _gain_control->list()->fast_simple_add (when, value);
1513 /* older (pre-1.0) versions of ardour used this */
1517 warning << _("dubious automation event found (and ignored)") << endmsg;
1525 IO::connecting_became_legal ()
1529 if (pending_state_node == 0) {
1530 fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
1535 connection_legal_c.disconnect ();
1537 ret = make_connections (*pending_state_node);
1540 delete pending_state_node;
1541 pending_state_node = 0;
1547 IO::ports_became_legal ()
1551 if (pending_state_node == 0) {
1552 fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
1557 port_legal_c.disconnect ();
1559 ret = create_ports (*pending_state_node);
1561 if (connecting_legal) {
1562 delete pending_state_node;
1563 pending_state_node = 0;
1570 IO::create_ports (const XMLNode& node)
1572 const XMLProperty* prop;
1574 int num_outputs = 0;
1576 /* XXX: we could change *-connection to *-bundle, but it seems a bit silly to
1577 * break the session file format.
1579 if ((prop = node.property ("input-connection")) != 0) {
1581 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1584 error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1586 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1587 error << _("No input bundles available as a replacement")
1591 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1596 num_inputs = c->nchannels();
1598 } else if ((prop = node.property ("inputs")) != 0) {
1600 num_inputs = count (prop->value().begin(), prop->value().end(), '{');
1603 if ((prop = node.property ("output-connection")) != 0) {
1604 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1607 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1609 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1610 error << _("No output bundles available as a replacement")
1614 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1619 num_outputs = c->nchannels ();
1621 } else if ((prop = node.property ("outputs")) != 0) {
1622 num_outputs = count (prop->value().begin(), prop->value().end(), '{');
1625 no_panner_reset = true;
1627 // FIXME: audio-only
1628 if (ensure_io (ChanCount(DataType::AUDIO, num_inputs), ChanCount(DataType::AUDIO, num_outputs), true, this)) {
1629 error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
1633 no_panner_reset = false;
1635 set_deferred_state ();
1643 IO::make_connections (const XMLNode& node)
1645 const XMLProperty* prop;
1647 if ((prop = node.property ("input-connection")) != 0) {
1648 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1651 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
1653 if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
1654 error << _("No input connections available as a replacement")
1658 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
1663 connect_input_ports_to_bundle (c, this);
1665 } else if ((prop = node.property ("inputs")) != 0) {
1666 if (set_inputs (prop->value())) {
1667 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
1672 if ((prop = node.property ("output-bundle")) != 0) {
1673 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
1676 error << string_compose(_("Unknown bundle \"%1\" listed for output of %2"), prop->value(), _name) << endmsg;
1678 if ((c = _session.bundle_by_name (_("out 1"))) == 0) {
1679 error << _("No output bundles available as a replacement")
1683 info << string_compose (_("Bundle %1 was not available - \"out 1\" used instead"), prop->value())
1688 connect_output_ports_to_bundle (c, this);
1690 } else if ((prop = node.property ("outputs")) != 0) {
1691 if (set_outputs (prop->value())) {
1692 error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
1701 IO::set_inputs (const string& str)
1703 vector<string> ports;
1708 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1712 // FIXME: audio-only
1713 if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1717 string::size_type start, end, ostart;
1724 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1727 if ((end = str.find_first_of ('}', start)) == string::npos) {
1728 error << string_compose(_("IO: badly formed string in XML node for inputs \"%1\""), str) << endmsg;
1732 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1733 error << string_compose(_("bad input string in XML node \"%1\""), str) << endmsg;
1739 for (int x = 0; x < n; ++x) {
1740 connect_input (input (i), ports[x], this);
1752 IO::set_outputs (const string& str)
1754 vector<string> ports;
1759 if ((nports = count (str.begin(), str.end(), '{')) == 0) {
1763 // FIXME: audio-only
1764 if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
1768 string::size_type start, end, ostart;
1775 while ((start = str.find_first_of ('{', ostart)) != string::npos) {
1778 if ((end = str.find_first_of ('}', start)) == string::npos) {
1779 error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
1783 if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
1784 error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
1790 for (int x = 0; x < n; ++x) {
1791 connect_output (output (i), ports[x], this);
1803 IO::parse_io_string (const string& str, vector<string>& ports)
1805 string::size_type pos, opos;
1807 if (str.length() == 0) {
1816 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1817 ports.push_back (str.substr (opos, pos - opos));
1821 if (opos < str.length()) {
1822 ports.push_back (str.substr(opos));
1825 return ports.size();
1829 IO::parse_gain_string (const string& str, vector<string>& ports)
1831 string::size_type pos, opos;
1837 while ((pos = str.find_first_of (',', opos)) != string::npos) {
1838 ports.push_back (str.substr (opos, pos - opos));
1842 if (opos < str.length()) {
1843 ports.push_back (str.substr(opos));
1846 return ports.size();
1850 IO::set_name (const string& str)
1856 /* replace all colons in the name. i wish we didn't have to do this */
1859 if (replace_all (name, ":", "-")) {
1860 warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
1863 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1864 string current_name = i->short_name();
1865 current_name.replace (current_name.find (_name), _name.length(), name);
1866 i->set_name (current_name);
1869 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1870 string current_name = i->short_name();
1871 current_name.replace (current_name.find (_name), _name.length(), name);
1872 i->set_name (current_name);
1875 bool const r = SessionObject::set_name(name);
1883 IO::set_input_minimum (ChanCount n)
1889 IO::set_input_maximum (ChanCount n)
1895 IO::set_output_minimum (ChanCount n)
1897 _output_minimum = n;
1901 IO::set_output_maximum (ChanCount n)
1903 _output_maximum = n;
1907 IO::set_port_latency (nframes_t nframes)
1909 Glib::Mutex::Lock lm (io_lock);
1911 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1912 i->set_latency (nframes);
1917 IO::output_latency () const
1919 nframes_t max_latency;
1924 /* io lock not taken - must be protected by other means */
1926 for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
1927 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1928 max_latency = latency;
1936 IO::input_latency () const
1938 nframes_t max_latency;
1943 /* io lock not taken - must be protected by other means */
1945 for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
1946 if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
1947 max_latency = latency;
1955 IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
1960 BLOCK_PROCESS_CALLBACK ();
1961 Glib::Mutex::Lock lm2 (io_lock);
1963 limit = c->nchannels();
1965 drop_input_bundle ();
1967 // FIXME bundles only work for audio-only
1968 if (ensure_inputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
1972 /* first pass: check the current state to see what's correctly
1973 connected, and drop anything that we don't want.
1976 for (uint32_t n = 0; n < limit; ++n) {
1977 const Bundle::PortList& pl = c->channel_ports (n);
1979 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
1981 if (!_inputs.port(n)->connected_to ((*i))) {
1983 /* clear any existing connections */
1985 _session.engine().disconnect (*_inputs.port(n));
1987 } else if (_inputs.port(n)->connected() > 1) {
1989 /* OK, it is connected to the port we want,
1990 but its also connected to other ports.
1991 Change that situation.
1994 /* XXX could be optimized to not drop
1998 _session.engine().disconnect (*_inputs.port(n));
2004 /* second pass: connect all requested ports where necessary */
2006 for (uint32_t n = 0; n < limit; ++n) {
2007 const Bundle::PortList& pl = c->channel_ports (n);
2009 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2011 if (!_inputs.port(n)->connected_to ((*i))) {
2013 if (_session.engine().connect (*i, _inputs.port(n)->name())) {
2023 input_bundle_configuration_connection = c->ConfigurationChanged.connect
2024 (mem_fun (*this, &IO::input_bundle_configuration_changed));
2025 input_bundle_connection_connection = c->PortsChanged.connect
2026 (mem_fun (*this, &IO::input_bundle_connection_changed));
2029 input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
2034 IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
2039 BLOCK_PROCESS_CALLBACK ();
2040 Glib::Mutex::Lock lm2 (io_lock);
2042 limit = c->nchannels();
2044 drop_output_bundle ();
2046 // FIXME: audio-only
2047 if (ensure_outputs (ChanCount(DataType::AUDIO, limit), false, false, src)) {
2051 /* first pass: check the current state to see what's correctly
2052 connected, and drop anything that we don't want.
2055 for (uint32_t n = 0; n < limit; ++n) {
2057 const Bundle::PortList& pl = c->channel_ports (n);
2059 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2061 if (!_outputs.port(n)->connected_to ((*i))) {
2063 /* clear any existing connections */
2065 _session.engine().disconnect (*_outputs.port(n));
2067 } else if (_outputs.port(n)->connected() > 1) {
2069 /* OK, it is connected to the port we want,
2070 but its also connected to other ports.
2071 Change that situation.
2074 /* XXX could be optimized to not drop
2078 _session.engine().disconnect (*_outputs.port(n));
2083 /* second pass: connect all requested ports where necessary */
2085 for (uint32_t n = 0; n < limit; ++n) {
2087 const Bundle::PortList& pl = c->channel_ports (n);
2089 for (Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
2091 if (!_outputs.port(n)->connected_to ((*i))) {
2093 if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
2102 output_bundle_configuration_connection = c->ConfigurationChanged.connect
2103 (mem_fun (*this, &IO::output_bundle_configuration_changed));
2104 output_bundle_connection_connection = c->PortsChanged.connect
2105 (mem_fun (*this, &IO::output_bundle_connection_changed));
2108 output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
2114 IO::disable_connecting ()
2116 connecting_legal = false;
2121 IO::enable_connecting ()
2123 connecting_legal = true;
2124 return ConnectingLegal ();
2128 IO::disable_ports ()
2130 ports_legal = false;
2138 return PortsLegal ();
2142 IO::disable_panners (void)
2144 panners_legal = false;
2149 IO::reset_panners ()
2151 panners_legal = true;
2152 return PannersLegal ();
2156 IO::input_bundle_connection_changed (int ignored)
2158 connect_input_ports_to_bundle (_input_bundle, this);
2162 IO::input_bundle_configuration_changed ()
2164 connect_input_ports_to_bundle (_input_bundle, this);
2168 IO::output_bundle_connection_changed (int ignored)
2170 connect_output_ports_to_bundle (_output_bundle, this);
2174 IO::output_bundle_configuration_changed ()
2176 connect_output_ports_to_bundle (_output_bundle, this);
2180 IO::GainControl::set_value (float val)
2182 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2183 if (val > 1.99526231f)
2187 _io.set_gain (val, this);
2189 Changed(); /* EMIT SIGNAL */
2193 IO::GainControl::get_value (void) const
2195 return AutomationControl::get_value();
2199 IO::setup_peak_meters()
2201 ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
2202 _meter->configure_io(max_streams, max_streams);
2206 Update the peak meters.
2208 The meter signal lock is taken to prevent modification of the
2209 Meter signal while updating the meters, taking the meter signal
2210 lock prior to taking the io_lock ensures that all IO will remain
2211 valid while metering.
2216 Glib::Mutex::Lock guard (m_meter_signal_lock);
2218 Meter(); /* EMIT SIGNAL */
2224 // FIXME: Ugly. Meter should manage the lock, if it's necessary
2226 Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
2231 IO::clear_automation ()
2233 Automatable::clear_automation (); // clears gain automation
2234 _panner->clear_automation ();
2238 IO::set_parameter_automation_state (Parameter param, AutoState state)
2240 // XXX: would be nice to get rid of this special hack
2242 if (param.type() == GainAutomation) {
2244 bool changed = false;
2247 Glib::Mutex::Lock lm (_automation_lock);
2249 boost::shared_ptr<AutomationList> gain_auto = _gain_control->list();
2251 if (state != gain_auto->automation_state()) {
2253 _last_automation_snapshot = 0;
2254 gain_auto->set_automation_state (state);
2257 // FIXME: shouldn't this use Curve?
2258 set_gain (gain_auto->eval (_session.transport_frame()), this);
2264 _session.set_dirty ();
2268 Automatable::set_parameter_automation_state(param, state);
2273 IO::inc_gain (gain_t factor, void *src)
2275 if (_desired_gain == 0.0f)
2276 set_gain (0.000001f + (0.000001f * factor), src);
2278 set_gain (_desired_gain + (_desired_gain * factor), src);
2282 IO::set_gain (gain_t val, void *src)
2284 // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
2285 if (val > 1.99526231f)
2288 if (src != _gain_control.get()) {
2289 _gain_control->set_value(val);
2290 // bit twisty, this will come back and call us again
2291 // (this keeps control in sync with reality)
2296 Glib::Mutex::Lock dm (declick_lock);
2297 _desired_gain = val;
2300 if (_session.transport_stopped()) {
2304 if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) {
2305 _gain_control->list()->add (_session.transport_frame(), val);
2309 _session.set_dirty();
2313 IO::start_pan_touch (uint32_t which)
2315 if (which < _panner->size()) {
2316 (*_panner)[which]->pan_control()->list()->start_touch();
2321 IO::end_pan_touch (uint32_t which)
2323 if (which < _panner->size()) {
2324 (*_panner)[which]->pan_control()->list()->stop_touch();
2330 IO::automation_snapshot (nframes_t now)
2332 Automatable::automation_snapshot (now);
2334 if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
2335 _panner->snapshot (now);
2340 IO::transport_stopped (nframes_t frame)
2342 _gain_control->list()->reposition_for_rt_add (frame);
2344 if (_gain_control->list()->automation_state() != Off) {
2346 /* the src=0 condition is a special signal to not propagate
2347 automation gain changes into the mix group when locating.
2350 // FIXME: shouldn't this use Curve?
2351 set_gain (_gain_control->list()->eval (frame), 0);
2354 _panner->transport_stopped (frame);
2358 IO::find_input_port_hole ()
2360 /* CALLER MUST HOLD IO LOCK */
2364 if (_inputs.empty()) {
2368 for (n = 1; n < UINT_MAX; ++n) {
2369 char buf[jack_port_name_size()];
2370 PortSet::iterator i = _inputs.begin();
2372 snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
2374 for ( ; i != _inputs.end(); ++i) {
2375 if (i->short_name() == buf) {
2380 if (i == _inputs.end()) {
2388 IO::find_output_port_hole ()
2390 /* CALLER MUST HOLD IO LOCK */
2394 if (_outputs.empty()) {
2398 for (n = 1; n < UINT_MAX; ++n) {
2399 char buf[jack_port_name_size()];
2400 PortSet::iterator i = _outputs.begin();
2402 snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
2404 for ( ; i != _outputs.end(); ++i) {
2405 if (i->short_name() == buf) {
2410 if (i == _outputs.end()) {
2419 IO::audio_input(uint32_t n) const
2421 return dynamic_cast<AudioPort*>(input(n));
2425 IO::audio_output(uint32_t n) const
2427 return dynamic_cast<AudioPort*>(output(n));
2431 IO::midi_input(uint32_t n) const
2433 return dynamic_cast<MidiPort*>(input(n));
2437 IO::midi_output(uint32_t n) const
2439 return dynamic_cast<MidiPort*>(output(n));
2443 IO::set_phase_invert (bool yn, void *src)
2445 if (_phase_invert != yn) {
2447 // phase_invert_changed (src); /* EMIT SIGNAL */
2452 IO::set_denormal_protection (bool yn, void *src)
2454 if (_denormal_protection != yn) {
2455 _denormal_protection = yn;
2456 // denormal_protection_changed (src); /* EMIT SIGNAL */
2461 IO::update_port_total_latencies ()
2463 /* io_lock, not taken: function must be called from Session::process() calltree */
2465 for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
2466 _session.engine().update_total_latency (*i);
2469 for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
2470 _session.engine().update_total_latency (*i);
2476 * Setup bundles that describe our inputs and outputs.
2480 IO::setup_bundles ()
2484 snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
2485 _bundle_for_inputs->set_name (buf, 0);
2486 int const ins = n_inputs().n_total();
2487 _bundle_for_inputs->set_nchannels (ins);
2489 for (int i = 0; i < ins; ++i) {
2490 _bundle_for_inputs->add_port_to_channel (i, _inputs.port(i)->name ());
2493 snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
2494 _bundle_for_outputs->set_name (buf, 0);
2495 int const outs = n_outputs().n_total();
2496 _bundle_for_outputs->set_nchannels (outs);
2498 for (int i = 0; i < outs; ++i) {
2499 _bundle_for_outputs->add_port_to_channel (i, _outputs.port(i)->name ());
2505 * Create and setup bundles that describe our inputs and outputs.
2509 IO::create_bundles ()
2511 _bundle_for_inputs = boost::shared_ptr<Bundle> (
2512 new InputBundle ("", true)
2515 _bundle_for_outputs = boost::shared_ptr<Bundle> (
2516 new OutputBundle ("", true)
2522 boost::shared_ptr<Bundle>
2525 if (_input_bundle) {
2526 return _input_bundle;
2529 /* XXX: will only report the first bundle found; should really return a list, I think */
2531 /* check that _input_bundle is right wrt the connections that are currently made */
2533 /* make a vector of the first output connected to each of our inputs */
2534 std::vector<std::string> connected;
2535 for (uint32_t i = 0; i < _inputs.num_ports(); ++i) {
2536 const char** c = _inputs.port(i)->get_connections ();
2538 connected.push_back (c[0]);
2542 _input_bundle = _session.bundle_by_ports (connected);
2543 return _input_bundle;
2547 boost::shared_ptr<Bundle>
2550 if (_output_bundle) {
2551 return _output_bundle;
2554 /* XXX: will only report the first bundle found; should really return a list, I think */
2556 /* check that _output_bundle is right wrt the connections that are currently made */
2558 /* make a vector of the first input connected to each of our outputs */
2559 std::vector<std::string> connected;
2560 for (uint32_t i = 0; i < _outputs.num_ports(); ++i) {
2561 const char** c = _outputs.port(i)->get_connections ();
2563 connected.push_back (c[0]);
2567 _output_bundle = _session.bundle_by_ports (connected);
2568 return _output_bundle;