CPLUG icon indicating copy to clipboard operation
CPLUG copied to clipboard

Changing latency and parameters dynamically

Open Photosounder opened this issue 1 year ago • 5 comments

Is there a way to change things that aren't typically changed dynamically? I have two things in mind:

  • I have a linear phase equaliser that changes the latency it reports dynamically based on various parameters, but the way to report plugin latency in CPLUG seems purely passive. Looking at IPlug2's code for SetLatency() it calls VST3's IComponentHandler's restartComponent().
  • I'm making a host plugin for my WebAssembly modules, it's the same logic as a bridge plugin, the problem is that until the WebAssembly module is loaded the host plugin doesn't know what parameters it's going to have, and unless the host plugin blocks until a module is selected (I'd rather not do that) I'd need a way to dynamically change how many parameters there are and everything about them. Maybe some kind of reset would do it?

Now that I think about it I also can't make CPLUG_NUM_PARAMS a global variable because different instances of the same host plugin would host different modules with different numbers of parameters, so the number of parameters would have to come from a cplug_... callback that provides the instance pointer, for instance we could replace CPLUG_NUM_PARAMS with something like cplug_getParamCount(vst3->userPlugin), which could actually even be done as a macro for each plugin format but that would be unwieldy.

Photosounder avatar Feb 25 '24 10:02 Photosounder

cplug_getParamCount

Good idea. This works well for finding the number of params on the fly.

I'm thinking in order to notify the host of a change in latency, tail time, number of busses, and number of parameters I could pass something like this into createPlugin()

...
enum // property types
{
    CPLUG_CHANGED_LATENCY,
    CPLUG_CHANGED_TAIL_TIME,
    CPLUG_CHANGED_NUM_INPUT_BUSSES,
    CPLUG_CHANGED_NUM_OUTPUT_BUSSES,
    CPLUG_CHANGED_NUM_PARAMS,
};

struct CplugHostContext
{
    void (*propertyChanged)(struct CplugHostContext* ctx, uint32_t changedProperty);
    // ...
    // some other feature?
};

void* createPlugin(struct CplugHostContext*);
...
uint32_t cplug_getParamCount();
...

For the user, they simply save the context struct somewhere in their plugin and call the function with a property type. For the wrapper, this context struct above could be saved within the wrapper struct, and I could use offsetof to shift the pointer back to the start of the struct and recast it.

Something like this should work perfectly well in AUv2 and CLAP (so long as hosts support it)

Thoughts?

Tremus avatar Feb 25 '24 22:02 Tremus

Sounds good. I think you mean that void *cplug_createPlugin() would become void *cplug_createPlugin(struct CplugHostContext *host_context) and we'd be free to store this pointer in our instance structure and then use that pointer to actively call wrapper functions such as propertyChanged(), correct? And this host context would be what is currently the VST3Plugin, AUv2Plugin, and CLAPPlugin, but with a new unified type name, right?

Photosounder avatar Feb 26 '24 10:02 Photosounder

Yep, that's right

Tremus avatar Feb 26 '24 13:02 Tremus

The suggested changes above have been made on a seperate branch https://github.com/Tremus/CPLUG/tree/api_redesign 9dc1c813db42e6d74e65670005179b94e05652c8 See CPLUG_FLAG_RESCAN_LATENCY

Tremus avatar Mar 26 '25 04:03 Tremus

CPLUG_FLAG_RESCAN_PARAM_VALUES is a great addition! And…

In future, this may become a call to a listener for kAudioUnitProperty_PresentPreset

That would be nice! 🙂 iPlug has an InformHostOfPresetChange() method that calls this.

A plugin with internal effects etc. can have hundreds of parameters, and may frequently change all of them at once, if the user browses quickly through presets.

martinfinke avatar Apr 27 '25 02:04 martinfinke