VST plugin Program presets not accessible
petrikaj opened this issue · comments
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
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"
Looking at the MrsWatson source code, this seems to be where the 'Programs' is being printed:
It reads from:
data->pluginHandle->numPrograms
data->pluginHandle effGetProgramNameIndexed
nameBuffer->data
data->pluginHandle effGetProgramName
nameBuffer->data
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:
- https://github.com/pipelined/vst2
-
Build vst2 plugins and hosts with Go
-
vst2 implements VST2 SDK API. It provides capabilities to build both VST2 hosts and plugins.
- https://pkg.go.dev/github.com/pipelined/vst2
-
// EffGetProgramNameIndexed passed to get program name by index. // Index: program index. // Ptr: *[maxProgNameLen]uint8 buffer for program name. // Return: true for success. EffGetProgramNameIndexed
-
-
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:
- https://github.com/steinbergmedia/vst3sdk
-
VST 3 Plug-In 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:
- https://github.com/RustAudio/vst3-sys/blob/f3e8f01c3de6d5df2f503c920c9f2bf8166a771b/src/vst/vsttypes.rs#L11
-
pub type ProgramListID = i32;
-
- https://github.com/RustAudio/vst3-sys/blob/f3e8f01c3de6d5df2f503c920c9f2bf8166a771b/src/vst/ivstunits.rs#L23-L27
-
#[repr(C)] #[derive(Copy, Clone)] pub struct ProgramListInfo { pub id: i32, pub name: [u16; 128], pub program_count: i32, }
-
- https://github.com/RustAudio/vst3-sys/blob/f3e8f01c3de6d5df2f503c920c9f2bf8166a771b/src/vst/ivstunits.rs#L43-L63
-
#[com_interface("3D4BD6B5-913A-4FD2-A886-E768A5EB92C1")] pub trait IUnitInfo: IUnknown { // ..snip.. unsafe fn get_program_list_count(&self) -> i32; unsafe fn get_program_list_info(&self, list_index: i32, info: *mut ProgramListInfo) -> tresult; unsafe fn get_program_name(&self, list_id: i32, program_index: i32, name: *mut u16) -> tresult; unsafe fn get_program_info( &self, list_id: i32, program_index: i32, attribute_id: *const u8, attribute_value: *mut u16, ) -> tresult; unsafe fn has_program_pitch_names(&self, id: i32, index: i32) -> tresult; unsafe fn get_program_pitch_name( &self, id: i32, index: i32, pitch: i16, name: *mut u16, ) -> tresult; // ..snip..
-
- https://github.com/RustAudio/vst3-sys/blob/f3e8f01c3de6d5df2f503c920c9f2bf8166a771b/src/vst/ivstunits.rs#L82-L97
-
#[com_interface("8683B01F-7B35-4F70-A265-1DEC353AF4FF")] pub trait IProgramListData: IUnknown { unsafe fn program_data_supported(&self, list_id: i32) -> tresult; unsafe fn get_program_data( &self, list_id: i32, program_idx: i32, stream: SharedVstPtr<dyn IBStream>, ) -> tresult; unsafe fn set_program_data( &self, id: i32, idx: i32, stream: SharedVstPtr<dyn IBStream>, ) -> tresult; }
-
Here's less technical explanation on the github docs: