Как создать плагин Vst3 в коде?Для хост-приложения vst3 - PullRequest
0 голосов
/ 11 апреля 2019

Я пытаюсь создать плагин 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);
    }

Вопрос: для чего нужны эти идентификаторы? Я могу догадаться, что cid означает идентификатор класса. Но для чего нужен iid и как я могу получить его для создания экземпляра класса плагина?

Каждый iid, взятый из любых классов, IPluginFactory, IComponent и т. Д., Я получаю неразрешенный внешний символ.

Функция createInstance, кстати, возвращает Steinberg :: kNoInterface , поэтому при попытке вставить пустой iid классы не найдены.

Кто-нибудь, кто знает что-нибудь о Vst3 от Steinberg? Любой пример кода или документация, как использовать Vst3 для размещения плагинов?

Спасибо // Алекс.

1 Ответ

1 голос
/ 12 апреля 2019

Об инициализации модуля.

Модуль * .vst3 может потребовать дополнительной инициализации.

Если модуль экспортирует некоторые предопределенные функции, вы должны вызвать его до получения IPluginFactory.

Имена экспортируемых функций - «InitDll» и «ExitDll» для платформы Windows.

    // 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 для этой цели.

Об идентификаторах.

CID - это идентификатор класса (a.k.a. component-id), который используется для идентификации фактического класса компонента плагина в файле модуля vst3.

Файл модуля * .vst3 может содержать несколько плагинов, однако хост-приложение не может идентифицировать плагин по его фактическому имени класса C ++ (потому что хост никогда не знает его). Вот почему VST3 SDK позволяет идентифицировать фактический класс компонентов плагина с помощью CID.

IID - это идентификатор интерфейса, который используется для указания класса интерфейса. В контексте загрузки плагина IID представляет, какой тип интерфейса интерфейса вы хотите получить созданный плагин, как правило, это будет Vst :: IComponent.

VST3 SDK основан на модульной архитектуре VST (VST-MA), которая очень похожа на объектную модель компонентов (COM) от Microsoft. Изучение COM поможет вам понять VST-MA.

Кроме того, каждый плагин в файле модуля * .vst3 обычно состоит из двух компонентов: компонента Processor и компонента EditController.

  • Компонент Processor предоставляет базовые API плагинов и DSP API.
    • Компонент Processor выводит два интерфейсных класса: класс Vst :: IComponent и класс Vst :: IAudioProcessor.
  • Компонент EditController предоставляет API-интерфейсы управления параметрами и пользовательский интерфейс.

Основная концепция Аудиоэффект или инструмент VST 3 в основном состоит из двух частей: части обработки и части контроллера редактирования. Соответствующие интерфейсы:

Процессор: Steinberg :: Vst :: IAudioProcessor + Steinberg :: Vst :: IComponent Контроллер: Steinberg :: Vst :: IEditController Конструкция VST 3 предполагает полное разделение процессора и контроллера редактирования путем реализации двух компонентов. Разбиение эффекта на эти две части требует, конечно, дополнительных усилий для реализации. Но это разделение позволяет хосту запускать каждый компонент в другом контексте. Он даже может запускать их на разных компьютерах. Еще одним преимуществом является то, что изменения параметров могут быть разделены, когда дело доходит до автоматизации. В то время как для обработки эти изменения должны быть переданы точным способом выборки, часть GUI может быть обновлена ​​с гораздо более низкой частотой, и она может быть смещена на величину, которая является результатом любой компенсации задержки или другого смещения обработки.

Подключаемый модуль, поддерживающий это разделение, должен установить флаг Steinberg :: Vst :: kDistributable в информации о классе компонента процессора (Steinberg :: PClassInfo2 :: classFlags). Конечно, не каждый плагин может поддерживать это, например, если он сильно зависит от ресурсов, которые нельзя легко перенести на другой компьютер. Поэтому, если этот флаг не установлен, хост не должен пытаться разделить компоненты каким-либо образом. Хотя это и не рекомендуется, в одном классе компонентов можно реализовать как часть обработки, так и часть контроллера. Хост пытается запросить интерфейс Steinberg :: Vst :: IEditController после создания Steinberg :: Vst :: IAudioProcessor и в случае успеха использует его в качестве контроллера.

- Документация по API VST3 (VST_SDK 3.6.13)

Плагин состоит из двух компонентов, поэтому вы будете вызывать createInstance () дважды. Это шаг для загрузки плагина из файла модуля * .vst3:

  1. Создайте компонент Processor плагина из файла модуля в виде класса Vst :: IComponent.
  2. Инициализировать компонент Процессор.
  3. Получите CID компонента EditController, соответствующего компоненту Processor.
  4. Создайте компонент EditController из файла модуля с 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();
    }

К вашему сведению, я разрабатываю VST3-приложение с открытым исходным кодом, которое называется Terra.

https://github.com/hotwatermorning/Terra

Это все еще альфа-версия.Но это может быть полезно для вас.

Спасибо.

...