summaryrefslogtreecommitdiff
path: root/libs/ardour/io.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/io.cc')
-rw-r--r--libs/ardour/io.cc261
1 files changed, 122 insertions, 139 deletions
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 7e77996d39..3e5b138fb7 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -102,36 +102,27 @@ static double direct_gain_to_control (gain_t gain) {
* and friends if no type is explicitly requested (to avoid breakage).
*/
IO::IO (Session& s, const string& name,
- int input_min, int input_max, int output_min, int output_max,
- DataType default_type)
- : SessionObject(s, name),
- AutomatableControls (s),
- _output_buffers (new BufferSet()),
- _active(true),
- _default_type (default_type),
- _input_minimum (ChanCount::ZERO),
- _input_maximum (ChanCount::INFINITE),
- _output_minimum (ChanCount::ZERO),
- _output_maximum (ChanCount::INFINITE)
-{
- _panner = new Panner (name, _session);
- _meter = new PeakMeter (_session);
-
- if (input_min > 0) {
- _input_minimum = ChanCount(_default_type, input_min);
- }
- if (input_max >= 0) {
- _input_maximum = ChanCount(_default_type, input_max);
- }
- if (output_min > 0) {
- _output_minimum = ChanCount(_default_type, output_min);
- }
- if (output_max >= 0) {
- _output_maximum = ChanCount(_default_type, output_max);
- }
+ DataType default_type,
+ ChanCount in_min, ChanCount in_max, ChanCount out_min, ChanCount out_max)
+ : SessionObject (s, name)
+ , AutomatableControls (s)
+ , _output_buffers (new BufferSet())
+ , _active (true)
+ , _default_type (default_type)
+ , _amp (new Amp(s, *this))
+ , _meter (new PeakMeter(s))
+ , _panner (new Panner(name, s))
+ , _input_minimum (ChanCount::ZERO)
+ , _input_maximum (ChanCount::INFINITE)
+ , _output_minimum (ChanCount::ZERO)
+ , _output_maximum (ChanCount::INFINITE)
+{
+ _input_minimum = in_min;
+ _output_minimum = out_min;
+ _input_maximum = in_max;
+ _output_maximum = out_max;
_gain = 1.0;
- _desired_gain = 1.0;
pending_state_node = 0;
no_panner_reset = false;
_phase_invert = false;
@@ -143,8 +134,6 @@ IO::IO (Session& s, const string& name,
_gain_control = boost::shared_ptr<GainControl>( new GainControl( X_("gaincontrol"), this, Evoral::Parameter(GainAutomation), gl ));
add_control(_gain_control);
-
- apply_gain_automation = false;
{
// IO::Meter is emitted from another thread so the
@@ -162,21 +151,18 @@ IO::IO (Session& s, const string& name,
}
IO::IO (Session& s, const XMLNode& node, DataType dt)
- : SessionObject(s, "unnamed io"),
- AutomatableControls (s),
- _output_buffers (new BufferSet()),
- _active(true),
- _default_type (dt)
-{
- _meter = new PeakMeter (_session);
- _panner = 0;
+ : SessionObject(s, "unnamed io")
+ , AutomatableControls (s)
+ , _output_buffers (new BufferSet())
+ , _active(true)
+ , _default_type (dt)
+ , _amp (new Amp(s, *this))
+ , _meter(new PeakMeter (_session))
+{
deferred_state = 0;
no_panner_reset = false;
- _desired_gain = 1.0;
_gain = 1.0;
- apply_gain_automation = false;
-
boost::shared_ptr<AutomationList> gl(
new AutomationList(Evoral::Parameter(GainAutomation)));
@@ -218,9 +204,6 @@ IO::~IO ()
}
m_meter_connection.disconnect();
-
- delete _meter;
- delete _panner;
}
void
@@ -241,12 +224,26 @@ IO::silence (nframes_t nframes)
void
IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
{
- // FIXME: type specific code doesn't actually need to be here, it will go away in time
+ // Attach output buffers to port buffers
+ output_buffers().attach_buffers (_outputs, nframes, _output_offset);
- /* ********** AUDIO ********** */
+ // Use the panner to distribute audio to output port buffers
+ if (_panner && _panner->npanners() && !_panner->bypassed()) {
+
+ _panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes);
- // Apply gain if gain automation isn't playing
- if ( ! apply_gain_automation) {
+ // Do a 1:1 copy of data to output ports
+ } else {
+ if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) {
+ copy_to_outputs (bufs, DataType::AUDIO, nframes);
+ }
+ if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) {
+ copy_to_outputs (bufs, DataType::MIDI, nframes);
+ }
+ }
+
+ // Apply gain to output buffers if gain automation isn't playing
+ if ( ! _amp->apply_gain_automation()) {
gain_t dg = _gain; // desired gain
@@ -254,44 +251,17 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
if (dm.locked()) {
- dg = _desired_gain;
+ dg = _gain_control->user_float();
}
}
if (dg != _gain || dg != 1.0) {
- Amp::run_in_place(bufs, nframes, _gain, dg, _phase_invert);
+ Amp::apply_gain(output_buffers(), nframes, _gain, dg, _phase_invert);
_gain = dg;
}
}
- /* do this so that any processing that comes after deliver_outputs()
- can use the output buffers.
- */
-
- output_buffers().attach_buffers (_outputs, nframes, _output_offset);
-
- // Use the panner to distribute audio to output port buffers
-
- if (0 && _panner && _panner->npanners() && !_panner->bypassed()) {
-
- /* blech .. we shouldn't be creating and tearing this down every process()
- cycle. XXX fix me to not waste cycles and do memory allocation etc.
- */
-
- _panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes);
-
- } else {
-
- /* do a 1:1 copy of data to output ports */
-
- if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) {
- copy_to_outputs (bufs, DataType::AUDIO, nframes);
- }
- if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) {
- copy_to_outputs (bufs, DataType::MIDI, nframes);
- }
- }
}
void
@@ -302,9 +272,8 @@ IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes)
PortSet::iterator o = _outputs.begin(type);
BufferSet::iterator i = bufs.begin(type);
BufferSet::iterator prev = i;
-
+
while (i != bufs.end(type) && o != _outputs.end (type)) {
-
Buffer& port_buffer (o->get_buffer (nframes));
port_buffer.read_from (*i, nframes, _output_offset);
prev = i;
@@ -312,8 +281,7 @@ IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes)
++o;
}
- /* extra outputs get a copy of the last buffer */
-
+ // Copy last buffer to any extra outputs
while (o != _outputs.end(type)) {
Buffer& port_buffer (o->get_buffer (nframes));
port_buffer.read_from (*prev, nframes, _output_offset);
@@ -894,14 +862,19 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
bool out_changed = false;
bool need_pan_reset = false;
- in = min (_input_maximum, in);
+ assert(in != ChanCount::INFINITE);
+ assert(out != ChanCount::INFINITE);
- out = min (_output_maximum, out);
+ in = ChanCount::min (_input_maximum, in);
+ out = ChanCount::min (_output_maximum, out);
if (in == n_inputs() && out == n_outputs() && !clear) {
return 0;
}
+ _configured_inputs = in;
+ _configured_outputs = out;
+
{
BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm (io_lock);
@@ -943,9 +916,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
}
/* create any necessary new input ports */
-
while (n_inputs().get(*t) < nin) {
-
string portname = build_legal_port_name (*t, true);
try {
@@ -959,7 +930,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
setup_peak_meters ();
reset_panner ();
/* pass it on */
- throw AudioEngine::PortRegistrationFailure();
+ throw err;
}
_inputs.add (port);
@@ -983,7 +954,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
setup_peak_meters ();
reset_panner ();
/* pass it on */
- throw AudioEngine::PortRegistrationFailure ();
+ throw err;
}
_outputs.add (port);
@@ -1124,7 +1095,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
{
bool changed = false;
- if (_output_maximum < ChanCount::INFINITE) {
+ if (_output_maximum != ChanCount::INFINITE) {
count = min (_output_maximum, count);
if (count == n_outputs() && !clear) {
return 0;
@@ -1152,11 +1123,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
gain_t
IO::effective_gain () const
{
- if (_gain_control->automation_playback()) {
- return _gain_control->get_value();
- } else {
- return _desired_gain;
- }
+ return _gain_control->get_value();
}
void
@@ -1305,16 +1272,10 @@ IO::state (bool full_state)
snprintf (buf, sizeof(buf), "%2.12f", gain());
node->add_property ("gain", buf);
- /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
- as -1.
- */
-
- int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
- int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
-
- snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
-
- node->add_property ("iolimits", buf);
+ /* port counts */
+
+ node->add_child_nocopy(*n_inputs().state("Inputs"));
+ node->add_child_nocopy(*n_outputs().state("Outputs"));
/* automation */
@@ -1358,9 +1319,9 @@ IO::set_state (const XMLNode& node)
sscanf (prop->value().c_str(), "%d,%d,%d,%d",
&in_min, &in_max, &out_min, &out_max);
- /* Correct for the difference between the way we write things to session files and the
- way things are described by ChanCount; see comments in io.h about what the different
- ChanCount values mean. */
+ // Legacy numbers:
+ // minimum == -1 => minimum == 0
+ // maximum == -1 => maximum == infinity
if (in_min < 0) {
_input_minimum = ChanCount::ZERO;
@@ -1389,7 +1350,7 @@ IO::set_state (const XMLNode& node)
if ((prop = node.property ("gain")) != 0) {
set_gain (atof (prop->value().c_str()), this);
- _gain = _desired_gain;
+ _gain = _gain_control->user_float();
}
if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
@@ -1400,16 +1361,16 @@ IO::set_state (const XMLNode& node)
// Old school Panner.
if ((*iter)->name() == "Panner") {
- if (_panner == 0) {
- _panner = new Panner (_name, _session);
+ if (!_panner) {
+ _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
}
_panner->set_state (**iter);
}
if ((*iter)->name() == "Processor") {
if ((*iter)->property ("type") && ((*iter)->property ("type")->value() == "panner" ) ) {
- if (_panner == 0) {
- _panner = new Panner (_name, _session);
+ if (!_panner) {
+ _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
}
_panner->set_state (**iter);
}
@@ -1427,6 +1388,8 @@ IO::set_state (const XMLNode& node)
}
}
+ get_port_counts (node);
+
if (ports_legal) {
if (create_ports (node)) {
@@ -1438,8 +1401,10 @@ IO::set_state (const XMLNode& node)
port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
}
- if( !_panner )
- _panner = new Panner( _name, _session );
+ if (!_panner) {
+ _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
+ }
+
if (panners_legal) {
reset_panner ();
} else {
@@ -1573,6 +1538,7 @@ IO::ports_became_legal ()
port_legal_c.disconnect ();
+ get_port_counts (*pending_state_node);
ret = create_ports (*pending_state_node);
if (connecting_legal) {
@@ -1676,48 +1642,64 @@ IO::find_possible_bundle (const string &desired_name, const string &default_name
}
int
-IO::create_ports (const XMLNode& node)
+IO::get_port_counts (const XMLNode& node)
{
XMLProperty const * prop;
- uint32_t num_inputs = 0;
- uint32_t num_outputs = 0;
+ XMLNodeConstIterator iter;
+ ChanCount num_inputs = n_inputs();
+ ChanCount num_outputs = n_outputs();
+
+ for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
+ if ((*iter)->name() == X_("Inputs")) {
+ num_inputs = ChanCount::max(num_inputs, ChanCount(**iter));
+ } else if ((*iter)->name() == X_("Outputs")) {
+ num_outputs = ChanCount::max(num_inputs, ChanCount(**iter));
+ }
+ }
if ((prop = node.property ("input-connection")) != 0) {
boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value(), _("in"), _("input"));
-
if (c) {
- num_inputs = c->nchannels ();
- } else {
- num_inputs = 0;
+ num_inputs = ChanCount::max(num_inputs, ChanCount(c->type(), c->nchannels()));
}
} else if ((prop = node.property ("inputs")) != 0) {
- num_inputs = count (prop->value().begin(), prop->value().end(), '{');
+ num_inputs = ChanCount::max(num_inputs, ChanCount(_default_type,
+ count (prop->value().begin(), prop->value().end(), '{')));
}
if ((prop = node.property ("output-connection")) != 0) {
- boost::shared_ptr<Bundle> c = find_possible_bundle(prop->value(), _("out"), _("output"));
-
+ boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value(), _("out"), _("output"));
if (c) {
- num_outputs = c->nchannels ();
- } else {
- num_outputs = 0;
+ num_outputs = ChanCount::max(num_outputs, ChanCount(c->type(), c->nchannels()));
}
} else if ((prop = node.property ("outputs")) != 0) {
- num_outputs = count (prop->value().begin(), prop->value().end(), '{');
+ num_outputs = ChanCount::max(num_outputs, ChanCount(_default_type,
+ count (prop->value().begin(), prop->value().end(), '{')));
}
+
+ _configured_inputs = num_inputs;
+ _configured_outputs = num_outputs;
+ _input_minimum = ChanCount::min(_input_minimum, num_inputs);
+ _input_maximum = ChanCount::max(_input_maximum, num_inputs);
+ _output_minimum = ChanCount::min(_output_minimum, num_outputs);
+ _output_maximum = ChanCount::max(_output_maximum, num_outputs);
+
+ return 0;
+}
+
+int
+IO::create_ports (const XMLNode& node)
+{
no_panner_reset = true;
- if (ensure_io (ChanCount (_default_type, num_inputs),
- ChanCount (_default_type, num_outputs),
- true, this)) {
-
+ if (ensure_io (_input_minimum, _output_minimum, true, this)) {
error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
return -1;
}
@@ -1730,7 +1712,6 @@ IO::create_ports (const XMLNode& node)
return 0;
}
-
int
IO::make_connections (const XMLNode& node)
{
@@ -2282,8 +2263,8 @@ IO::meter ()
void
IO::clear_automation ()
{
- data().clear (); // clears gain automation
- _panner->data().clear();
+ data().clear_controls (); // clears gain automation
+ _panner->data().clear_controls ();
}
void
@@ -2325,10 +2306,12 @@ IO::set_parameter_automation_state (Evoral::Parameter param, AutoState state)
void
IO::inc_gain (gain_t factor, void *src)
{
- if (_desired_gain == 0.0f)
+ float desired_gain = _gain_control->user_float();
+ if (desired_gain == 0.0f) {
set_gain (0.000001f + (0.000001f * factor), src);
- else
- set_gain (_desired_gain + (_desired_gain * factor), src);
+ } else {
+ set_gain (desired_gain + (desired_gain * factor), src);
+ }
}
void
@@ -2350,7 +2333,7 @@ IO::set_gain (gain_t val, void *src)
{
Glib::Mutex::Lock dm (declick_lock);
- _desired_gain = val;
+ _gain_control->set_float(val, false);
}
if (_session.transport_stopped()) {
@@ -2470,7 +2453,7 @@ IO::build_legal_port_name (DataType type, bool in)
}
snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
-
+
return string (buf2);
}