我正在尝试从一个简单的主机应用程序创建一个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的作用是什么?如何获得它来创建插件类的实例?

我从任何类(IPluginFactory,IComponent等)中获取的每个iid都得到了无法解析的外部符号。

createInstance函数通过以下方式返回 Steinberg::kNoInterface ,因此当我尝试插入空的iid时找不到任何类。

有人对斯坦伯格(Steinberg)的Vst3有所了解吗?
任何代码示例或文档如何将Vst3用于插件托管?

谢谢/// Alex。

最佳答案

关于模块初始化。

* .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(); }

为此,您也可以使用在VST3::Hosting::Module中定义的public.sdk/source/vst/hosting/module.h类。

关于ID。

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

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

IID是用于指定接口(interface)类的interface-id。
在插件加载上下文中,IID代表您要获取所创建插件的接口(interface)类的类型,通常为Vst::IComponent。

VST3 SDK基于VST模块体系结构(VST-MA),与Microsoft的组件对象模型(COM)非常相似。
学习COM将帮助您理解VST-MA。

此外,*。vst3模块文件中的每个插件通常都包含两个组件:Processor组件和EditController组件。
  • Processor组件提供基本的插件API和DSP API。
  • Processor组件派生两个接口(interface)类:Vst::IComponent类和Vst::IAudioProcessor类。
  • EditController组件提供参数管理API和UI API。



  • 插件由两个组件组成,因此您将调用createInstance()两次。
    这是从* .vst3模块文件加载插件的步骤:
  • 从模块文件中创建插件的Processor组件,作为Vst::IComponent类。
  • 初始化处理器组件。
  • 获取与Processor组件相对应的EditController组件的CID。
  • 使用具有CID的模块文件创建EditController组件。
  • 也初始化EditController组件。
  • 连接并设置它们。
  •     // 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版本。但这可能对您有所帮助。

    谢谢。

    09-30 09:05