spotify / pedalboard

🎛 🔊 A Python library for audio.
https://spotify.github.io/pedalboard
GNU General Public License v3.0
5.25k stars 261 forks source link

VST plugin Program presets not accessible #257

Open petrikaj opened 1 year ago

petrikaj commented 1 year ago

I have tried to access and change iZotope's VST plugins' Program presets but it seems they are not exposed.

Parameters work ok.

Here's what MrsWatson prints out from plugin —display-info

mrswatson

Notice it's not part of the parameters.

Using plugin.show_editor() allows to access those presets and changing them will change the parameters accordingly after quitting the showeditor(/).

MrsWatson allows to change it while loading the plugin: "mrswatson64 --plugin 'plugin_name,preset_name’ -i input.wav -o output.wav"

0xdevalias commented 1 year ago

Looking at the MrsWatson source code, this seems to be where the 'Programs' is being printed:

It reads from:

Googling for effGetProgramNameIndexed, it seems to be part of the VST2 SDK or similar.

Eg. Here's a go package that implements bindings for it:

Pedalboard doesn't seem to support VST2, but not sure if there is an equivalent function in VST3. We can start by looking at the VST3 SDK:

Searching for effGetProgramNameIndexed doesn't seem to turn up any results there (neither does GetProgramName / ProgramName)

Clicking through from that repo lead me to:

And searching that repo for GetProgramName lead me to this definition:

IUnitInfo describes the internal structure of the plug-in.
- The root unit is the component itself, so getUnitCount must return 1 at least.
- The root unit id has to be 0 (kRootUnitId).
- Each unit can reference one program list - this reference must not change.
- Each unit, using a program list, references one program of the list.
    /** Component intern program structure. */
    /** Gets the count of Program List. */
    virtual int32 PLUGIN_API getProgramListCount () = 0;

    /** Gets for a given index the Program List Info. */
    virtual tresult PLUGIN_API getProgramListInfo (int32 listIndex, ProgramListInfo& info /*out*/) = 0;

    /** Gets for a given program list ID and program index its program name. */
    virtual tresult PLUGIN_API getProgramName (ProgramListID listId, int32 programIndex, String128 name /*out*/) = 0;

    /** Gets for a given program list ID, program index and attributeId the associated attribute value. */
    virtual tresult PLUGIN_API getProgramInfo (ProgramListID listId, int32 programIndex,
        CString attributeId /*in*/, String128 attributeValue /*out*/) = 0;
/** Basic Program List Description.
\see IUnitInfo
*/
struct ProgramListInfo
{
    ProgramListID id;               ///< program list identifier
    String128 name;                 ///< name of program list
    int32 programCount;             ///< number of programs in this list
};

Then we can find the definition for ProgramListID in the following:

typedef int32 ProgramListID;    ///< program list identifier

So it definitely seems like the concept of 'programs' still exists in the VST3 SDK.


Looking at an example CLI app for using the vst-rs Rust bindings for VST2, they don't seem to print the 'programs' details either; but they do have a section called 'presets':

    // Get the plugin information
    let info = instance.get_info();

    println!(
        "Loaded '{}':\n\t\
         Vendor: {}\n\t\
         Presets: {}\n\t\
         Parameters: {}\n\t\
         VST ID: {}\n\t\
         Version: {}\n\t\
         Initial Delay: {} samples",
        info.name, info.vendor, info.presets, info.parameters, info.unique_id, info.version, info.initial_delay
    );

Tracing through the code a bit, I found the definition for Info, which again doesn't mention 'program', but does mention 'presets':

Tracing through the code a bit more I found this implementation of PluginInstance, which seems to equate presets with programs:

plug.info = Info {
  // ..snip..
  presets: effect.numPrograms,
  // ..snip..
  preset_chunks: flags.intersects(PluginFlags::PROGRAM_CHUNKS),
}

Looking at the vst3-sys Rust bindings for VST3:

petrikaj commented 1 year ago

Here's less technical explanation on the github docs:

https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Presets+Program+Lists/Index.html

0xdevalias commented 6 months ago

Just wanted to note that #297 just got merged, which may provide one potential angle of a solution here:

Apologies that this took so long - I've just made a couple changes and merged this, and it should be available as of v0.9.6 (released later today).

I did rename this property to raw_state instead of just state, as the state data is often (but not always) encoded in a format that I hope we can parse and expose as a .state parameter later. (i.e.: if the state of a VST3 is valid XML, Pedalboard could unwrap and parse that XML directly to make the client code simpler.)

Originally posted by @psobot in https://github.com/spotify/pedalboard/issues/297#issuecomment-2119315514

Docs: