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

в 21:17, , рубрики: c++, dsp, GUI, Martin Finke, Reaper, Visual Studio, VST, xcode, интерфейсы, перевод, Работа со звуком, метки: , , , , , , , , ,

Все посты серии:
Часть 1. Введение и настройка
Часть 2. Изучение кода
Часть 3. VST и AU
Часть 4. Цифровой дисторшн
Часть 5. Пресеты и GUI
______________________________________________________________

Давайте добавим несколько предустановок для плагина и создадим [относительно] симпатичный интерфейс.

Пресеты

Пресет — это настройки, позволяющие хранить конкретные значения параметров. На данный момент в нашем коде пресеты состоят из названия и значений для всех параметров, но, как мы увидим позже, тут можно хранить и другие данные. Пресеты еще иногда называют программами (programs).

Для начала давайте сделаем окно GUI пошире. Поменяйте соответствующую константу в resource.h:

// GUI default dimensions
#define GUI_WIDTH 400

В DigitalDistortion.h объявим private функцию-член класса:

private:
  double mThreshold;
  void CreatePresets();

А в DigitalDistortion.cpp добавим

void DigitalDistortion::CreatePresets() {
  MakePreset("clean", 100.0);
  MakePreset("slightly distorted", 80.0);
  MakePreset("woooo", 40.0);
  MakePreset("waaaa", 20.0);
  MakePreset("buzzz!!!", 0.01);
}

MakePreset в качестве аргументов берет имя пресета и значения для всех параметров. Порядок следования аргументов определен в enum EParams вверху файла.
Обратите внимание, что значения параметров меняются от 0 до 100, а не от 0 до 1. Эти значения относятся к параметру kThreshold, а не к переменной mThreshold.

Вместо вызова функции MakeDefaultPreset в конце конструктора напишите вызов CreatePresets:

DigitalDistortion::DigitalDistortion(IPlugInstanceInfo instanceInfo)
  : IPLUG_CTOR(kNumParams, kNumPrograms, instanceInfo), mThreshold(1.)
{
  // ...

  CreatePresets();
}

Наконец, нам надо изменить константу, которая передается при вызове конструктора базового класса (это где-то в окрестностях 13-й строки):

const int kNumPrograms = 5;

Если значение этой константы больше, чем реальное количество пресетов, остальные просто будут называться «Empty».

Запустите сборку VST2. Возможно придется удалить плагин с дорожки и подгрузить его повторно, чтобы появились свеженаписанные пресеты. Их можно менять, используя выпадающий список, который находится прямо над GUI плагина. Попробуйте разные — ручка поворачивается в соответствии со значением в пресете.
Напомню, что OnParamChange вызывается при изменении каждого параметра.
Справа от выпадающего меню есть кнопка, открывающая меню пресетов:

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

Попробуйте переименовать пресет и покрутить ручку. Ее положение не запомнится, если удалить плагин с дорожки и загрузить снова. Чтобы сохранить эти данные, щелкните “Export VST patch/bank file (.fxp/.fxb)…” и сохраните файл test.fxb на рабочий стол. Теперь удалите плагин, снова добавьте его и подгрузите этот файл с настройками.
Плагины VST для хранения отдельного пресета используют формат FXP, а для хранения банка пресетов — FXB.

Запустите таргет AU (возможно сначала придется зайти в Edit Scheme, чтобы он запускался вместе с хостом). REAPER по умолчанию пишет «No preset», но в выпадающем списке все пресеты на месте и все работает как надо. Сохранение пресетов в плагине работает иначе — мы не можем импортировать и экспортировать банки пресетов. Процессы сохранениязагрузки описаны Оли Ларкиным более детально в этом посте.

Пора, наконец, приступать к созданию красивого интерфейса!

GUI

Такого результата мы хотим добиться:

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

Это конечно не офигительно круто, но мы узнаем как можно добавлять графику и, что еще интереснее, как можно сделать вращающуюся ручку.
Скачайте этот TIFF с дизайном. Откройте в Фотошопе (или в чем вам больше нравится) и взгляните на разные слои и группы.
Как видим, единственное, что меняется — это ручка. Так что остальное можно просто сохранить в одном png:

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

Добавление фона для сборок на Mac

Сохраните картинку выше себе на рабочий стол. В Xcode в Project Navigator раскройте папку Resources и перетяните туда фоновую картинку:

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

Надо поставить галочку напротив Copy items into folder и добавить наше изображение для всех таргетов:

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

Добавление фона для сборок на Windows

В Visual Studio добавление ресурсов (типа графики) немного отличается. Добавление для всех таргетов на Маке означает, что картинка будет включена в файлы .app, .vst и .component, которые вы предоставляете своим пользователям. В Visual Studio для этого надо сначала кинуть нашу картинку в подпапку проекта resourcesimg, а затем отредактировать файл .rc в проекте. В данном случае, DigitalDistortion.rc. Его шапка выглядит так:

#include "resource.h"
KNOB_ID       PNG KNOB_FN

Сначала подключается resource.h, так что все #define из него доступны и в этом файле. Следующая строка объявляет, что будет добавлена ручка. Чтобы добавить фон, допишите это строку:

BACKGROUND_ID       PNG BACKGROUND_FN

Через минутку добавим BACKGROUND_ID и BACKGROUND_FN в resource.h.
Каждый раз при добавлении изображения к проекту нам нужно добавлять подобную строчку.

Фоновое изображение

Давайте подцепим нашу картинку в плагин. Где-то в районе 60-й строки в файле resource.h нужно изменить размер окна:

// GUI default dimensions
#define GUI_WIDTH 280
#define GUI_HEIGHT 230

и добавить уникальный ID и имя файла изображения:

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

// Image resource locations for this plug.
#define KNOB_FN "resources/img/knob.png"
#define BACKGROUND_FN "resources/img/background.png"

В DigitalDistortion.cpp надо изменить конструктор, чтобы использовать наш файл вместо красного цвета:

// pGraphics->AttachPanelBackground(&COLOR_RED);
pGraphics->AttachBackground(BACKGROUND_ID, BACKGROUND_FN);

Это было несложно. Давайте соберем APP и полюбуемся на картинку:

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

Ручка

Ручка немного сложнее. У нее есть текстура и отражения, она состоит из нескольких слоев. Когда крутишь ручку, металл вращается, а лампа на потолке — нет (будем надеяться). Так что какие-то составляющие должны вращаться, а какие-то, имеющие отношение к освещению, не должны. Поэтому мы не сможем сохранить ручку как одну картинку и крутить ее в процессе.
Я сделал так: у ручки есть основа, которая не вращается; поверх нее металлическая текстура, которая вращается; и сверху всего этого — отражения, которые не вращаются. Все три части представлены по отдельности (тут я добавил черный фон, просто чтобы было видно границы и светлые части):

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

Для нашей задачи есть очень хороший инструмент: KnobMan. Это бесплатная программа, специально для создания ручек. Скачайте, запустите, и откройте в ней файл, который я подготовил:

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

Все, что я тут сделал — добавил три слоя и немного поменял некоторые координаты, чтобы металлическая текстура вращалась правильно. Если хотите разобраться с программой получше, прочитайте руководство.
Экспортируйте эту ручку (Cmd+E на Mac, Ctrl+E на Windows) и назовите файл knob.png (или скачайте мой). В этом png есть 128 кадров для разных положений ручки, и вращаются только металл со стрелкой. То, что надо.

В Xcode удалите существующий knob.png (правый клик, Delete). В появивщемся диалоге выберите Move to Trash. Теперь перетяните новый knob.png в папку img и проделайте все то же самое, что мы делали с фоновым изображением.
Так как имя файла не поменялось, нам нет необходимости менять resource.h. Переключайтесь сразу на DigitalDistortion.cpp изменяйте enum ELayout:

enum ELayout
{
  kWidth = GUI_WIDTH,
  kHeight = GUI_HEIGHT,

  kThresholdX = 79,
  kThresholdY = 62,
  kKnobFrames = 128
};

Как видно, нам даже не приходится указывать для WDL, что новая ручка больше. Нам нужно только указать количество кадров и задать координаты.
Запускайте VST2 и посмотрите, как при вращении ручки меняются кадры. Однако меня смущает то, что плагин называется дисторшн, а при ручке, выкрученной на 100%, у нас чистый звук.

Направление ручки

Где-то около 90-й строки надо внести изменения:

mThreshold = 1 - (GetParam(kThreshold)->Value() / 100.);

Чтобы предотвратить деление на ноль, о котором мы говорили ранее, надо изменить значение по умолчанию на 0, и максимальное значение на 99.99 (примерно 30-я строка):

GetParam(kThreshold)->InitDouble("Threshold", 0.0, 0.0, 99.99, 0.01, "%");

Теперь все должно работать как надо. С семантической точки зрения хорошо бы еще переименовать переменную Threshold во что-то типа DistortionAmount, так как единственное, что представляет пороговое значение, это переменная mThreshold.

Промежуточные результаты

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

Файлы со всеми результатами работы можно скачать.

Дополнительные материалы

Существует много бесплатных примеров для KnobMan тут и тут.

При создании GUI я пользовался вот этим уроком по Фотошопу. Спасибо автору!
И спасибо g200kg за KnobMan!

Автор: 1eqinfinity

Источник

Поделиться

* - обязательные к заполнению поля