Updating latency to host | VST3 and ASPiK | Forum

Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
Updating latency to host
Avatar
Admin
July 11, 2021 - 7:45 am
Member Since: January 1, 2020
Forum Posts: 103
sp_UserOfflineSmall Offline

Hi, has anyone able to send an updated Plugin Delay Compensation value out to the DAW?

I've tried modifying

bool PluginCore::initPluginDescriptors() { 

pluginDescriptor.latencyInSamples = kLatencyInSamples;

}

to receive a latency variable as outlined in Chapter 18.7 of the Designing Audio Effects book.

 

But I'm finding that changing that variable has no effect other than upon the plugin first loading/initializing.

Calling pluginDescriptor.latencyInSamples = latentVariable; from elsewhere in plugincore.cpp also seems to have no impact. Testing in Reaper.

 

Thanks

Avatar
Admin
July 11, 2021 - 12:41 pm
Member Since: January 29, 2017
Forum Posts: 689
sp_UserOfflineSmall Offline

I am releasing a new ASPiK and RackAFX today (fingers crossed) when I saw your post; I thought I'd check this. 

The plugin latency is set in the plugindescription.h file, either during CMake (it is a field in the CMakeLists.txt file), or after the project has been created. For my test plugin I wrote:

const uint32_t kLatencyInSamples = 44100;

For VST3, this value is stored in the initialize( ) function in the variable m_uLatencyInSamples, in the vst3plugin.cpp file:

// --- setup needs

m_uLatencyInSamples = pluginCore->getLatencyInSamples();

hasSidechain = pluginCore->hasSidechain();

enableSAAVST3 = pluginCore->wantsVST3SampleAccurateAutomation();

sampleAccuracy = pluginCore->getVST3SampleAccuracyGranularity();

// --- base class initilizer tresult

result = SingleComponentEffect::initialize(context);

The m_uLatencyInSamples variable is then used for the query function you can find in the vst3plugin.h file:

/** base class override */

virtual uint32 PLUGIN_API getLatencySamples() override { return m_uLatencyInSamples; }

 

/** base class override for tailtime */

virtual uint32 PLUGIN_API getTailSamples() override ;

I setup Reaper as my debug client, and placed a breakpoint in the getLatencySamples( ) function, as well as the initialize( ) function where the m_u variable is set. On loading the plugin, the initialize( ) function was called first, then the getLatencySamples( ) function, where my breakpoint was hit and I watched the function return my value of 44100 correctly. For Reaper, this function will be called continuously as each buffer is processed, so the breakpoint is constantly being hit, and the value is constantly being returned. 

Reaper also shows me this value just to the right of the CPU% at the lower left of the plugin window frame, 44100 as expected.

What happens after that is in the Reaper code. If your plugin does have an actual latency (a delay line on the input for a lookahead compressor) then when you run the plugin, you should see the other audio tracks being delayed to compensate for your lag. 

There is some documentation about it that mentions restarting the component, but that is only if the latency changes due to your algorithm adapting to some new state. 

https://steinbergmedia.github.io/vst3_doc/vstinterfaces/classSteinberg_1_1Vst_1_1IAudioProcessor.html#af8884671ccefe68e0a86e72413a0fcf8

So, the value is being delivered to the host, which should then compensate for it, though that exact mechanism probably varies between DAWs.

Set breakpoints in your plugin to check on that as well. FWIW, that latency setting has been in VST3 forever and is only involved in the one function getLatencySamples( ) during operation.

Will 

 

 
Avatar
Admin
July 11, 2021 - 2:01 pm
Member Since: January 1, 2020
Forum Posts: 103
sp_UserOfflineSmall Offline

Hi Will, thanks very much for your time.

Changing the latency compensation during runtime via GUI linked variable is exactly what I am trying to do. 

I'd seen a little info on this at the forum https://forums.steinberg.net/t/reporting-latency-change/201601

 

But I don't know how or where to communicate with IComponentHandler to make the call to restartcomponent( kLatencyChanged ).

Avatar
Admin
July 11, 2021 - 5:42 pm
Member Since: January 29, 2017
Forum Posts: 689
sp_UserOfflineSmall Offline

ASPiK uses the SingleComponentEffect base class, so that the controller and processor are combined (this is mainly do make the VST3 shell plugins as identical as possible to the AU and AAX versions, at least with respect to the generalized architecture).

If you look at the base classes for SingleComponentEffect() you can see that it inherits EditControllerEx1, which inherits from EditController, which is the object that has pointers to the IComponentHandler. This means that the VST3Plugin object has direct access to the IComponentHandler, either as a derived member or with the function getComponentHandler( ). See the class definition for EditController (in the file vsteditcontroller.h in the VST SDK).

Now as far as where to put it - you can't place it anywhere that would be called by the validator which runs after you compile, and you stated that it would come from a GUI control.

The VST3Plugin::process( ) function calls another function doControlUpdate( ) to update the plugin parameters from GUI changes. I did a quick test with this and there are a few options on how to handle it. I would go ahead and let the variable binding do its job so that your PluginParameter object has the new latency value. Then, detect that it has changed at the end of the doControlUpdate( ) function, or within the function itself. To test this, I used my delay plugin and used the delay type switch as proof of concept. When I change it to ping-pong, I also change the latency and update the component handler. I placed this code in the loop that starts with:

if(queue->getPoint(queue->getPointCount() - 1, /* last update point */

sampleOffset, /* sample offset */

value) == kResultTrue) /* value = [0..1] */

and catch the control ID for the delay-type switch, alter the m_uPluginLatency variable, and restart the handler (ignore the comment that says "false = do not apply taper" - I need to delete that comment)

 

piParam->setControlValueNormalized(value, true); // false = do not apply taper

if (piParam->getControlID() == controlID::delayType)

{

     if (value > 0)

     {

          m_uLatencyInSamples = 123456;

          componentHandler->restartComponent(kLatencyChanged);

     }

}

Running this in Reaper, and toggling the delay-type showed an updated latency time.

You will need to code this in a way that makes sense to you. The setParameterNormalized( ) function call will convert the VST3 normalized parameters into plain values, so you should be able to just grab the value from the plugin parameter as:

piParam->getControlValue( ) and write that to m_uLatencyInSamples, then call the restartComponent( ) function. 

Will 

Avatar
Admin
July 13, 2021 - 3:33 pm
Member Since: January 1, 2020
Forum Posts: 103
sp_UserOfflineSmall Offline

Yes massive thanks for that code Will. Working perfectly, testing on Win7 in Reaper, VSTHost & Ableton 10.

Thanks also for the additional good info's regarding vst3plugin.

Cheers

Avatar
Admin
July 13, 2021 - 5:13 pm
Member Since: January 29, 2017
Forum Posts: 689
sp_UserOfflineSmall Offline

Great! Glad to hear you are up and running.

Will 

Forum Timezone: America/New_York

Most Users Ever Online: 152

Currently Online:
12 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Chaes: 56

Skyler: 48

StevieD: 46

Derek: 46

Frodson: 45

Peter: 43

TheSmile: 43

Nickolai: 43

clau_ste: 39

jeanlecode: 37

Member Stats:

Guest Posters: 1

Members: 768

Moderators: 1

Admins: 6

Forum Stats:

Groups: 13

Forums: 42

Topics: 842

Posts: 3347

Moderators: W Pirkle: 689