Однажды я столкнулся с ситуацией, когда, если у меня была основная звуковая карта с собственным драйвером ASIO, мне нужно было подключить к DAW USB-микрофон с собственным драйвером ASIO. И DAW не поддерживает одновременное подключение двух драйверов ASIO. Во время поиска я наткнулся на VST-плагин «VST-интерфейс ASIO-Host», написанный на Delphi. К сожалению, хотя плагин и был виден через jBridge, он никогда не работал должным образом.
Таким образом, мне пришлось написать аналогичный плагин самому.
В результате плагин ASIOInput с открытым исходным кодом был написан за 10 дней.
В этой статье я расскажу о некоторых особенностях его разработки и архитектуры.
Сам плагин VST технически представляет собой .
dll, который экспортирует одну функцию.
SVSTPlugin* VSTPluginMain(void*)
Эта функция вызывается DAW и получает указатель на структуру данных, в которой хранится вся информация о загруженном плагине.
Для работы плагина необходимо заполнить как минимум следующие поля.
- InputCount и OutputCount — количество входных и выходных каналов.
Количество каналов — это строго заданная величина на этапе загрузки плагина, и ее нельзя изменить в дальнейшем.
Итак, здесь я указываю 0 входных каналов и 2 выходных канала.
Если требуется 1 реальный канал, он будет продублирован на обоих выходах плагина.
- PluginProperties — флаги свойств плагина.
Здесь мы устанавливаем 3 флага: наличие собственного интерфейса, поддержку обратного вызова UpdateBufferData() и то, что плагин является инструментом — в некоторых DAW для инструментов в микшере создаются отдельные дорожки, что удобно.
- Обратный вызов RequestFromHost() — эта функция будет вызываться DAW для информирования плагина об определенных событиях.
Минимальный набор событий, реализованный в плагине, следующий: инициализация и деинициализация плагина, приостановка и возобновление работы плагина, изменение частоты дискретизации, изменение размера буфера выборки, а также события для графического интерфейса плагина: показать и скрыть окно редактора, получить размер окна редактора и событие простоя - для перерисовки элементов интерфейса окна редактора.
- Обратный вызов UpdateBufferData() — DAW вызывает эту функцию, когда ей необходимо получить значения следующего набора аудиосэмплов.
Здесь в параметрах вы указываете, сколько именно сэмплов DAW хочет получать каждый раз при вызове этой функции.
Более того, при вызове функции создания буферов выборки также необходимо передавать указатели на обратные вызовы для обновления данных в буфере и запросы от ASIO-драйвера к хосту.
Таким образом, получается, что у плагина есть две функции, вызываемые извне: DAW вызывает функцию, в которой плагин должен заполнить выходные данные выборки из плагина в DAW — VSTPluginCallUpdateBufferData(), а дочерний ASIO-драйвер вызывает функцию, где он передает плагину следующую порцию выборочных данных с карт аудиовхода - ASIOHostCallUpdateBufferDataEx().
Причем эти функции вызываются независимо друг от друга.
А если размеры буферов выборки DAW и дочернего ASIO-драйвера разные, то и количество раз в секунду тоже разное.
Нам необходимо передать данные из дочернего ASIO-драйвера в DAW, причем сделать это с минимальной задержкой.
В случае одинакового размера буфера выборки я синхронизировал два вызова.
Таким образом, когда DAW запрашивает семплы у плагина, вызов функции приостанавливается до следующего вызова от дочернего ASIO-драйвера, при котором буфер DAW обновляется напрямую, только после этого запрос DAW на сэмплы из плагина освобождается и завершается.
.
Технически синхронизация обеспечивается ожиданием событий ОС Windows (функции CreateEvent(), SetEvent() и WaitForSingleObject()).
Если размер буферов драйвера DAW и дочернего ASIO различен, то используется кольцевой буфер.
Обратный вызов дочернего драйвера ASIO записывает данные в кольцевой буфер, а обратный вызов DAW считывает данные.
Чтобы чтение не происходило во время записи, используется мьютекс ОС Windows. Размер кольцевого буфера выбирается как максимальный размер буфера DAW и дочернего драйвера ASIO и может быть настроен пользователем x2, x3 и x4.
Подводные камни при разработке плагина.
- Для COM-объекта драйвера ASIO все функции возвращают 0 в случае успеха.
Все, кроме функции инициализации.
В случае успеха возвращается 1. Минус один вечер отладки.
- DAW передает дескриптор родительского окна плагину.
Если после события скрытия окна редактора не отвязать окно редактора с этим дескриптором, то окно редактора плагина продолжает отображаться, но, в случае с DAW Cubase 9.5, поверх системного меню DAW - т. е.
поверх «Файл, Редактировать» и т. д.
- Если вы укажете неправильное значение драйверу ASIO при создании буферов выборки, то буферы будут созданы с правильными размерами, требуемыми драйвером ASIO, но частота обратного вызова будет рассчитана неправильно, и обратный вызов будет вызывать неправильное количество раз в секунду.
В этом случае функция создания буфера вернет 0. Ещё минус один вечер отладки.
- Не следует деинициализировать COM-объект дочернего драйвера ASIO из обратного вызова самого драйвера ASIO.
Загрузите последнюю версию плагина (VST2, x86 и x64): тыц .
Источники на GitHub: тыц .
Теги: #Звук #программирование #прошивка #asio #DAW #синхронизация потока
-
Важность Держателей Карт
19 Oct, 24 -
Электронный Мультитул Проекта Quark
19 Oct, 24 -
Делаем «Самое Бесполезное Устройство» Сами
19 Oct, 24 -
Ответ На Сообщение «Презумпция Ума»
19 Oct, 24 -
Временные Темы
19 Oct, 24 -
Что Такое Когортный Анализ?
19 Oct, 24