diff options
author | Robin Gareus <robin@gareus.org> | 2016-04-08 18:21:46 +0200 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2016-04-08 18:21:46 +0200 |
commit | 6dd5d6df71acc5eacab5ef2e1b500b123ede4254 (patch) | |
tree | 1b160ae50897f97e1d96017a1485c12d249e4e2c /libs/ardour/plugin_insert.cc | |
parent | 681b65aa0b68c9e7a686de2d6ca0c18c61cb444b (diff) |
Latency compensation for plugin thru routing.
Diffstat (limited to 'libs/ardour/plugin_insert.cc')
-rw-r--r-- | libs/ardour/plugin_insert.cc | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 55b592561c..b522cb3379 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -331,6 +331,11 @@ PluginInsert::has_no_audio_inputs() const return _plugins[0]->get_info()->n_inputs.n_audio() == 0; } +framecnt_t +PluginInsert::plugin_latency () const { + return _plugins.front()->signal_latency (); +} + bool PluginInsert::is_midi_instrument() const { @@ -472,11 +477,28 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of PinMappings in_map (_in_map); PinMappings out_map (_out_map); ChanMapping thru_map (_thru_map); - if (_mapping_changed) { + if (_mapping_changed) { // ToDo use a counters, increment until match. _no_inplace = check_inplace (); _mapping_changed = false; } + if (_latency_changed) { + /* delaylines are configured with the max possible latency (as reported by the plugin) + * so this won't allocate memory (unless the plugin lied about its max latency) + * It may still 'click' though, since the fixed delaylines are not de-clicked. + * Then again plugin-latency changes are not click-free to begin with. + * + * This is also worst case, there is currently no concept of per-stream latency. + * + * e.g. Two identical latent plugins: + * 1st plugin: process left (latent), bypass right. + * 2nd plugin: bypass left, process right (latent). + * -> currently this yields 2 times latency of the plugin, + */ + _latency_changed = false; + _delaybuffers.set (ChanCount::max(bufs.count(), _configured_out), plugin_latency ()); + } + if (_match.method == Split && !_no_inplace) { // TODO: also use this optimization if one source-buffer // feeds _all_ *connected* inputs. @@ -600,7 +622,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of uint32_t in_idx = thru_map.get (*t, out, &valid); if (valid) { uint32_t m = out + natural_input_streams ().get (*t); - inplace_bufs.get (*t, m).read_from (bufs.get (*t, in_idx), nframes, offset, offset); + _delaybuffers.delay (*t, out, inplace_bufs.get (*t, m), bufs.get (*t, in_idx), nframes, offset, offset); used_outputs.set (*t, out, 1); // mark as used } } @@ -1419,6 +1441,9 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) PluginIoReConfigure (); /* EMIT SIGNAL */ } + _delaybuffers.configure (_configured_out, _plugins.front()->max_latency ()); + _latency_changed = true; + // we don't know the analysis window size, so we must work with the // current buffer size here. each request for data fills in these // buffers and the analyser makes sure it gets enough data for the @@ -2395,6 +2420,7 @@ PluginInsert::add_plugin (boost::shared_ptr<Plugin> plugin) plugin->ParameterChangedExternally.connect_same_thread (*this, boost::bind (&PluginInsert::parameter_changed_externally, this, _1, _2)); plugin->StartTouch.connect_same_thread (*this, boost::bind (&PluginInsert::start_touch, this, _1)); plugin->EndTouch.connect_same_thread (*this, boost::bind (&PluginInsert::end_touch, this, _1)); + plugin->LatencyChanged.connect_same_thread (*this, boost::bind (&PluginInsert::latency_changed, this, _1, _2)); // cache sidechain ports _cached_sidechain_pins.reset (); const ChanCount& nis (plugin->get_info()->n_inputs); @@ -2435,6 +2461,13 @@ PluginInsert::monitoring_changed () } void +PluginInsert::latency_changed (framecnt_t, framecnt_t) +{ + // this is called in RT context, LatencyChanged is emitted after run() + _latency_changed = true; +} + +void PluginInsert::start_touch (uint32_t param_id) { boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id)); |