如何在代码中实例化 Vst3 插件?对于 vst3 主机应用

How to Instantiate a Vst3 plugin in code? For a vst3 host app

本文关键字:对于 vst3 主机 应用 插件 Vst3 代码 实例化      更新时间:2023-10-16

我正在尝试从一个简单的主机应用程序创建一个 Vst3 插件。

在这里,我有一个简单的代码,只是为了从 *.vst3 文件创建 Vst3 插件的实例。

auto proc = (GetFactoryProc)GetFunction(hmodule, "GetPluginFactory");
Steinberg::IPluginFactory* rawFactory = proc();
// Get factory info.
Steinberg::PFactoryInfo factoryInfo;
rawFactory->getFactoryInfo(&factoryInfo);
// Get classes.
for (size_t i = 0; i < rawFactory->countClasses(); i++)
{
Steinberg::PClassInfo info;
rawFactory->getClassInfo(i, &info);
// ------------------------------------
// ----------HOW TO USE THIS IDs-------
// ------------------------------------
Steinberg::FIDString cid = info.cid; // Is this correct?
Steinberg::FIDString iid = Steinberg::Vst::IComponent::iid; // I dont know what I am doing...
// ------------------------------------
// HOW TO USE THE createInstance FUNCTION?
// ------------------------------------
void* instance(nullptr);
Steinberg::tresult result = rawFactory->createInstance(cid, iid, &instance);
}

问题是:这个 ID 有什么用?我可以猜到cid代表class-id。但是 iid 有什么用,我怎样才能让它创建一个插件类的实例?

我从任何类中获取的每一个 IID,IPluginFactory,IComponent 等等,我都会得到未解析的外部符号。

顺便说一下,createInstance 函数返回Steinberg::kNoInterface,因此当我尝试插入空 iid 时找不到任何类。

有人从斯坦伯格那里知道Vst3吗? 任何代码示例或文档如何使用 Vst3 进行插件托管?

谢谢//亚历克斯。

关于模块初始化。

*.vst3 模块可能需要其他初始化。

如果模块导出了一些预定义的函数,则应在获取 IPluginFactory 之前调用它。

导出的函数名称是Windows平台的"InitDll"和"ExitDll"。

// after the module is loaded.
auto initDll = (bool(*)())GetFunction(hmodule, "InitDll");
if(initDll) { initDll(); }
auto proc = (GetFactoryProc)GetFunction(hmodule, "GetPluginFactory");
Steinberg::IPluginFactory* rawFactory = proc();
// before the module is unloaded.
auto exitDll = (bool(*)())GetFunction(hmodule, "ExitDll");
if(exitDll) { exitDll(); }

您还可以使用public.sdk/source/vst/hosting/module.h中定义的类VST3::Hosting::Module来实现此目的。

关于身份证件。

CID 是类 ID(又名组件 ID),用于标识 vst3 模块文件中的实际插件组件类。

*.vst3 模块文件可以包含多个插件,但是主机应用程序无法通过其实际的C++类名来识别插件(因为主机永远不知道它)。 这就是为什么 VST3 SDK 提供了使用 CID 识别实际插件组件类的方法。

IID 是用于指定接口类的接口 ID。 在插件加载上下文中,IID 表示您希望获取创建的插件的接口类类型,通常它将是 Vst::IComponent。

VST3 SDK基于VST模块架构(VST-MA),非常类似于Microsoft的组件对象模型(COM)。 学习COM将帮助您了解VST-MA。

此外,*.vst3 模块文件中的每个插件通常由两个组件组成:处理器组件和编辑控制器组件。

  • 处理器组件提供基本的插件 API 和 DSP API。
    • 处理器组件派生了两个接口类:Vst::IComponent 类和 Vst::IAudioProcessor 类。
  • EditController 组件提供参数管理 API 和 UI API。

基本概念 VST 3 音频效果或乐器基本上由两部分组成:处理部分和编辑控制器部分。 相应的接口是:

处理器 : Steinberg::Vst::IAudioProcessor + Steinberg::Vst::IComponent 控制器 : 斯坦伯格::Vst::IEdit控制器 VST 3 的设计建议通过实现两个组件来完全分离处理器和编辑控制器。当然,将效果拆分为这两个部分需要一些额外的努力来实现。 但这种分离使主机能够在不同的上下文中运行每个组件。它甚至可以在不同的计算机上运行它们。另一个好处是,在自动化方面,参数更改可以分开。虽然为了处理这些变化需要以样本精确的方式传输,但GUI部分可以以低得多的频率进行更新,并且可以根据任何延迟补偿或其他处理偏移产生的量进行偏移。

支持这种分离的插件必须在处理器组件的类信息中设置 Steinberg::Vst::kDistributable 标志(Steinberg::P ClassInfo2::classFlags)。当然,并非每个插件都可以支持此功能,例如,如果它严重依赖于无法轻松移动到另一台计算机的资源。因此,如果未设置此标志,主机不得尝试以任何方式分离组件。 尽管不建议这样做,但可以在一个组件类中同时实现处理部分和控制器部分。主机在创建 Steinberg::Vst::IAudioProcessor 后尝试查询 Steinberg::Vst::IEditController 接口,并在成功时将其用作控制器。

-- VST3 API 文档 (VST_SDK 3.6.13)

插件由两个组件组成,因此您将调用 createInstance() 两次。 这是从 *.vst3 模块文件加载插件的步骤:

  1. 从模块文件创建插件的处理器组件,作为 Vst::IComponent 类。
  2. 初始化处理器组件。
  3. 获取与处理器组件对应的编辑控制器组件的 CID。
  4. 使用 CID 从模块文件创建编辑控制器组件。
  5. 也初始化 EditController 组件。
  6. 连接并设置它们。
// Get classes.
for (size_t i = 0; i < rawFactory->countClasses(); i++)
{
Steinberg::PClassInfo info;
rawFactory->getClassInfo(i, &info);
// info.category will be kVstAudioEffectClass for Processor component.
// skip this component if not.
if(info.category != kVstAudioEffectClass) {
continue;
}
Vst::IComponent *comp(nullptr);
Steinberg::tresult result
= rawFactory->createInstance(info.cid, // tell factory which plugin to be created.
Vst::IComponent::iid, // tell factory which type of interface you want.
(void **)&comp // get the pointer to `comp`, and pass it as (void **)
);
if(result != kResultTrue) {
// TODO: error handling
return;
}
// now `comp` shall be valid pointer of Vst::IComponent.
// initialize comp
comp->setIoMode(Vst::IoModes::kAdvanced);
// you should define host context object before and pass it here as `FUnknown *`.
// the host context object is the class which normally derives Vst::IHostApplication,
// Vst::IComponentHandler, Vst::IPluginInterfaceSupport, etc.
comp->initialize(host_context);
TUID edit_cid;
comp->getControllerClassId(edit_cid);
// (in detail, IEditController interface may be obtained from IComponent directly if the plugin
//  derives SingleComponentEffect.
//  For such plugins, do not use this method and obtain IEditController with `comp->queryInstance()`
// )
Vst::IEditController *edit(nullptr);        
result = rawFactory->createInstance(edit_cid,
Vst::IEditController::iid,
(void **)&edit);
if(result != kResultTrue) {
// TODO: error handling
return;
}
// initialize the EditController component too.
edit->initialize(host_context);
//...
// now the two components are created.
// connect and setup them.
// use the plugin.
// ...
// don't forget destruction after using it.
edit->terminate();
comp->terminate();
edit->release();
comp->release();
}

仅供参考,我开发了一个名为Terra的开源 VST3 主机应用程序。

https://github.com/hotwatermorning/Terra

它现在仍然是alpha版本。但它可能对您有所帮助。

谢谢。

相关文章: