Создание аудиоплагинов, часть 2

Предыдущие посты из серии: Часть 1. Введение и настройка______________________________________________________________Изучение кодаДавайте получше рассмотрим наш тестовый проект. Самые важные файлы — resource.h, MyFirstPlugin.h и MyFirstPlugin.cpp. На данный момент плагин представляет собой простой регулятор громкости звука.

Константы, флаги и источники изображений Откройте в навигаторе resource.h. Этот файл содержит такие константы, как название плагина, его версию, уникальный ID и ссылки на источники изображений для GUI. В строках 23–26 можно прописать уникальный ID:

// 4 chars, single quotes. At least one capital letter #define PLUG_UNIQUE_ID 'Ipef' // make sure this is not the same as BUNDLE_MFR #define PLUG_MFR_ID 'Acme' ID важен для общей каталогизации плагинов. Можете зарегистрировать его здесь. Строки 56 и далее определяют ID и путь к изображению для той ручки громкости, которую вы видите при запуске плагина:

// Unique IDs for each image resource. #define KNOB_ID 101

// Image resource locations for this plug. #define KNOB_FN «resources/img/knob.png» Найдите в навигаторе и откройте Resources → img → knob.png. Это спрайт с шестьюдесятью различными положениями ручки, каждое размером 48 на 48 пикселей. Когда вы запускаете плагин и крутите ручку, изображение ручки не вращается. Программа только показывает соответствующую часть этого спрайта.Почему оно не вращается? Представьте себе, что ручка имеет какие-нибудь насечки и отбрасывает тень. Тогда при вращении тень тоже будет крутиться. Такого в действительности не бывает, как вы (надеюсь) знаете.

Ниже в resource.h можно установить размеры окна плагина:

#define GUI_WIDTH 300 #define GUI_HEIGHT 300 Поиграйтесь со значениями и запустите плагин.

Интерфейс класса плагина Откройте MyFirstPlugin.h. В нем содержится интерфейс для класса плагина. Часть public включает конструктор, деструктор и три функции-члена класса:

Reset вызывается, когда изменяется частота дискретизации. OnParamChange вызывается при изменении параметров плагина, например, когда мы крутим ручку. ProcessDoubleReplacing это самое ядро плагина. Именно в ней осуществляется обработка входящего аудио. В части private находится только переменная типа double, хранящая текущее значение громкости.

Реализация Переходим к интересной части! Откройте MyFirstPlugin.cpp. Сразу видим интересный приемчик с типом enum:

enum EParams { kGain = 0, kNumParams }; Устанавливая kGain = 0 и ставя kNumParams после него, kNumParams становится количеством параметров плагина (в данном случае 1).Следующий enum использует константы, описанные в resource.h и устанавливает координаты ручки в окне плагина:

enum ELayout { kWidth = GUI_WIDTH, kHeight = GUI_HEIGHT,

kGainX = 100, kGainY = 100, kKnobFrames = 60 }; Он также определяет количества кадров в knob.png равным 60.Далее начинается имплементация конструктора. Устанавливаются атрибуты плагина:

//arguments are: name, defaultVal, minVal, maxVal, step, label GetParam (kGain)→InitDouble («Gain», 50., 0., 100.0, 0.01,»%»); В GUI пока что не видно ни значения, ни значка процента, но значение может меняться от 0 до 100. Значение по умолчанию равно 50. Можно заметить, что градация значений не равномерна на окружности. Это из-за SetShape (2.). Если заменить это на SetShape (1.), то распределение значений будет линейным. Именно SetShape задает нелинейное поведение.Далее конструктор создает графический контекст нужного размена и задает фоновый красный цвет:

IGraphics* pGraphics = MakeGraphics (this, kWidth, kHeight); pGraphics→AttachPanelBackground (&COLOR_RED); После этого загружается knob.png, создается новый IKnobMultiControl с изображением и привязывается к GUI. IKnobMultiControl — это класс для ручек интерфейса.Обратите внимание, как передается параметр kKnobFrames для обозначения количества кадров в спрайте:

IBitmap knob = pGraphics→LoadIBitmap (KNOB_ID, KNOB_FN, kKnobFrames); pGraphics→AttachControl (new IKnobMultiControl (this, kGainX, kGainY, kGain, &knob)); Наконец, конструктор привязывает графический контекст и создает для плагина пресет по умолчанию:

MakeDefaultPreset ((char *) »-», kNumPrograms); Взглянем на OnParamChange (в конце файла). IMutexLock обеспечивает потоковую безопасность — концепт, который мы разберем попозже. Все остальное — это просто набор вариантов действий в зависимости от того, какой параметр изменяется:

case kGain: mGain = GetParam (kGain)→Value () / 100.; break; Как мы помним, kGain изменяется от 0 до 100. Так что после деления значения на 100 мы назначаем величину от 0 до 1 private члену класса mGain.

Итак, мы немного разобрали процесс создания GUI и привязку к нему таких параметров, как mGain. Давайте теперь взглянем на то, как плагин обрабатывает входящее аудио. В нашем случае аудио поток — это последовательность семплов, представленная типом данных double, каждый из которых содержит значение амплитуды сигнала в заданный момент времени.Первый параметр, передаваемый функции ProcessDoubleReplacing, это double** inputs. Последовательность значений типа double можно передать, используя double*. Но плагин обрабатывает два канала (стерео) или даже больше, так что нам нужны несколько последовательностей семплов, и мы сообщаем это при помощи double**. Первые две строки в функции иллюстрируют это:

double* in1 = inputs[0]; double* in2 = inputs[1]; in1 указывает на первую последовательность семплов (левый канал), in2 — на семплы правого канала. После выполнения аналогичных действий для выходного буфера мы можем итерировать над элементами входного и выходного буферов:

for (int s = 0; s < nFrames; ++s, ++in1, ++in2, ++out1, ++out2) { *out1 = *in1 * mGain; *out2 = *in2 * mGain; } Для каждого семпла мы берем входное значение, умножаем его на mGain и записываем его в выходной буфер. nFrames сообщает нам, сколько семплов на канал имеется, чтобы мы знали длину буферов.Вы могли заметить, что когда запускаете плагин как самостоятельное приложение, можно слышать себя из динамиков, если в компьютере есть встроенный микрофон. Это из-за того, что по умолчанию приложение использует этот микрофон как источник входного сигнала. Чтобы изменить это (и кое-что еще), зайдите в preferences:

32f724b1254c4862bf9651b6766348a5.jpg

747d4887490d4617b71cac37eea8af69.jpg

Установите брэйкпоинт в функции Reset. Измените Sampling Rate справа и примените изменения. Отладчик прервет исполнение кода в функции Reset. Внизу справа, где работает lldb, Введите print GetSampleRate ().

f7f7b6ed6bb44122a39d03a6bca8114a.jpg

Обратите внимание, что так же можно вызвать любую функцию из отладчика и посмотреть правильные значения. Нажмите Stop вверху слева, когда налюбуетесь и решите продолжить.Теперь пора создать из кода плагин и загрузить его в хост. Это и будет темой следующего поста.А пока что

Дополнительное чтение Чтобы заполнить некоторые пробелы, настоятельно рекомендую прочесть эти слайды авторства изобретательного г-на Оли Ларкина. В них найдутся некоторые из ключевых разъяснений о WDL-OL.

© Habrahabr.ru