outline a "NoSampleAccurateControl" LV2 feature:

Since control-ports have a fixed value for the current process-block,
Ardour splits a plugin's run() process cycle on every automation event
to facilitate sample-accurate automation.

Since automation is interpolated between events, this ensures that each
explicit automation point is reached (not interpolated).

Plugins where this is not required and which favor a fixed block-size,
can now specify an optional Feature: NoSampleAccurateControl.

One example: a convolution plugin with smoothed gain control.
This commit is contained in:
Robin Gareus 2015-12-06 13:49:16 +01:00
parent bc15146560
commit 065d7c852a
2 changed files with 32 additions and 0 deletions

View File

@ -97,6 +97,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
void cleanup ();
int set_block_size (pframes_t);
bool requires_fixed_sized_buffers () const;
int connect_and_run (BufferSet& bufs,
ChanMapping in, ChanMapping out,
@ -178,6 +179,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
uint32_t _patch_port_in_index;
uint32_t _patch_port_out_index;
URIMap& _uri_map;
bool _no_sample_accurate_ctrl;
friend const void* lv2plugin_get_port_value(const char* port_symbol,
void* user_data,

View File

@ -155,6 +155,7 @@ public:
LilvNode* units_midiNote;
LilvNode* patch_writable;
LilvNode* patch_Message;
LilvNode* lv2_noSampleAccurateCtrl;
#ifdef HAVE_LV2_1_2_0
LilvNode* bufz_powerOf2BlockLength;
LilvNode* bufz_fixedBlockLength;
@ -286,6 +287,7 @@ LV2Plugin::LV2Plugin (AudioEngine& engine,
, _patch_port_in_index((uint32_t)-1)
, _patch_port_out_index((uint32_t)-1)
, _uri_map(URIMap::instance())
, _no_sample_accurate_ctrl (false)
{
init(c_plugin, rate);
}
@ -300,6 +302,7 @@ LV2Plugin::LV2Plugin (const LV2Plugin& other)
, _patch_port_in_index((uint32_t)-1)
, _patch_port_out_index((uint32_t)-1)
, _uri_map(URIMap::instance())
, _no_sample_accurate_ctrl (false)
{
init(other._impl->plugin, other._sample_rate);
@ -481,6 +484,12 @@ LV2Plugin::init(const void* c_plugin, framecnt_t rate)
throw failed_constructor();
}
lilv_nodes_free(required_features);
LilvNodes* optional_features = lilv_plugin_get_optional_features (plugin);
if (lilv_nodes_contains (optional_features, _world.lv2_noSampleAccurateCtrl)) {
_no_sample_accurate_ctrl = true;
}
lilv_nodes_free(optional_features);
#endif
#ifdef HAVE_LILV_0_16_0
@ -685,6 +694,25 @@ LV2Plugin::set_block_size (pframes_t nframes)
return 0;
}
bool
LV2Plugin::requires_fixed_sized_buffers () const
{
/* This controls if Ardour will split the plugin's run()
* on automation events in order to pass sample-accurate automation
* via standard control-ports.
*
* When returning true Ardour will *not* sub-divide the process-cycle.
* Automation events that happen between cycle-start and cycle-end will be
* ignored (ctrl values are interpolated to cycle-start).
* NB. Atom Sequences are still sample accurate.
*
* Note: This does not guarantee a fixed block-size.
* e.g The process cycle may be split when looping, also
* the period-size may change any time: see set_block_size()
*/
return _no_sample_accurate_ctrl;
}
LV2Plugin::~LV2Plugin ()
{
DEBUG_TRACE(DEBUG::LV2, string_compose("%1 destroy\n", name()));
@ -2448,6 +2476,7 @@ LV2World::LV2World()
units_db = lilv_new_uri(world, LV2_UNITS__db);
patch_writable = lilv_new_uri(world, LV2_PATCH__writable);
patch_Message = lilv_new_uri(world, LV2_PATCH__Message);
lv2_noSampleAccurateCtrl = lilv_new_uri(world, LV2_CORE_PREFIX "NoSampleAccurateCtrl"); // XXX
#ifdef HAVE_LV2_1_2_0
bufz_powerOf2BlockLength = lilv_new_uri(world, LV2_BUF_SIZE__powerOf2BlockLength);
bufz_fixedBlockLength = lilv_new_uri(world, LV2_BUF_SIZE__fixedBlockLength);
@ -2463,6 +2492,7 @@ LV2World::~LV2World()
lilv_node_free(bufz_fixedBlockLength);
lilv_node_free(bufz_powerOf2BlockLength);
#endif
lilv_node_free(lv2_noSampleAccurateCtrl);
lilv_node_free(patch_Message);
lilv_node_free(patch_writable);
lilv_node_free(units_hz);