В этом документе описывается встроенный собственный интерфейс аудиоплагина Unity 5.0. Мы сделаем это, рассмотрев некоторые конкретные примеры плагинов, сложность которых возрастает по мере продвижения вперед. Таким образом, мы начинаем с самых основных понятий и представляем более сложные варианты использования ближе к концу документа.
Скачать
Первое, что вам нужно сделать, это загрузить новейший пакет SDK аудиоплагина.
Обзор
Нативная система аудиоплагинов состоит из двух частей:
Собственный подключаемый модуль DSP (цифровая обработка сигналов), который должен быть реализован в виде .dll (Windows) или .dylib (OSX) на языке C или C++. В отличие от скриптовфрагмент кода, позволяющий создавать собственные компоненты, запускать игровые события, изменять свойства компонентов с течением времени и реагировать на пользовательский ввод любым удобным для вас способом. Подробнее
См. в Словарь, и из-за высоких требований к производительности его необходимо скомпилировать для любой платформы, которую вы хотите поддерживать, возможно, с оптимизацией для конкретной платформы.Графический интерфейс, разработанный на C#. Обратите внимание, что графический интерфейс является необязательным, поэтому вы всегда начинаете разработку плагина с создания базового нативного плагина DSP и позволяете Unity показывать класс UI(Пользовательский интерфейс) Позволяет пользователю взаимодействовать с вашим приложением. Подробнее
См. в Словарь описания параметров, предоставляемые собственным подключаемым модулем. Мы рекомендуем этот подход для запуска любого проекта.
Обратите внимание, что изначально можно создать прототип графического интерфейса C# в виде файла .cs, который нужно просто поместить в папку Assets/Editor (как и любой другой скрипт редактора). Позже вы можете переместить это в соответствующий проект Visual Studio, поскольку ваш код начнет расти и ему потребуется лучшая модульность и лучшая поддержка IDE. Это позволяет скомпилировать его в .dll, упрощая пользователю вход в проект, а также защищая ваш код.
Также обратите внимание, что библиотеки DSP и GUI могут содержать несколько подключаемых модулей и что привязка происходит только через имена эффектов в подключаемых модулях, независимо от того, как называется файл DLL.
Что это за файлы?
Нативная часть SDK подключаемого модуля на самом деле состоит только из одного файла (AudioPluginInterface.h), но для упрощения работы с несколькими подключаемыми эффектами в одной библиотеке DLL мы добавили вспомогательный код для обработки определения эффекта и регистрации параметров в простой унифицированный способ (AudioPluginUtil.h и AudioPluginUtil.cpp). Обратите внимание, что проект NativePluginDemo содержит несколько примеров подключаемых модулей, которые помогут вам начать работу и демонстрируют множество различных типов подключаемых модулей, полезных в контексте игры. Мы размещаем этот код в открытом доступе, поэтому не стесняйтесь использовать его в качестве отправной точки для своих собственных творений.
Разработка подключаемого модуля начинается с определения параметров, которые должен иметь ваш подключаемый модуль. Вам не нужно иметь подробный генеральный план всех параметров, которые плагин выложит перед тем, как вы начнете, но это помогает примерно иметь представление о том, каким вы хотите, чтобы был пользовательский опыт, и какие компоненты вам понадобятся.
Примеры подключаемых модулей, которые мы предоставляем, содержат множество полезных функций, упрощающих Давайте посмотрим на пример плагина «Ring Modulator». Этот простой плагин умножает входящий сигнал на синусоиду, что дает хороший эффект радиошума/обрыва приема, особенно если несколько эффектов кольцевой модуляции с разными частотами объединены в цепочку.
Базовая схема работы с параметрами в примерах подключаемых модулей состоит в том, чтобы определить их как значения перечисления, которые мы используем в качестве индексов в массиве с плавающей запятой для удобства и краткости.
enum Param
{
P_FREQ,
P_MIX,
P_NUM
};
int InternalRegisterEffectDefinition(UnityAudioEffectDefinition& definition)
{
int numparams = P_NUM;
definition.paramdefs = new UnityAudioParameterDefinition [numparams];
RegisterParameter(definition, "Frequency", "Hz",
0.0f, kMaxSampleRate, 1000.0f,
1.0f, 3.0f,
P_FREQ);
RegisterParameter(definition, "Mix amount", "%",
0.0f, 1.0f, 0.5f,
100.0f, 1.0f,
P_MIX);
return numparams;
}
Числа в вызовах RegisterParameter представляют собой минимальное, максимальное значение и значение по умолчанию, за которыми следует коэффициент масштабирования, используемый только для отображения, т. е. в случае процентного значения фактическое значение изменяется от 0 до 1 и масштабируется на 100, когда отображается. Для этого не существует пользовательского кода графического интерфейса, но, как упоминалось ранее, Unity сгенерирует графический интерфейс по умолчанию из этих основных определений параметров. Обратите внимание, что для неопределенных параметров проверки не выполняются, поэтому система AudioPluginUtil ожидает, что все объявленные значения перечисления (кроме P_NUM
) совпадают с соответствующим определением параметра.
За сценамиСцена содержит окружение и меню вашей игры. Думайте о каждом уникальном файле сцены как об уникальном уровне. В каждой сцене вы размещаете свое окружение, препятствия и декорации, по сути проектируя и создавая свою игру по частям. Подробнее
См. в Словарь функция RegisterParameter заполняет запись в массиве UnityAudioParameterDefinition Структура UnityAudioEffectDefinition, связанная с этим подключаемым модулем (см. «AudioEffectPluginInterface.h»). Остальное, что необходимо настроить в UnityAudioEffectDefinition, — это обратные вызовы функций, которые обрабатывают создание экземпляра подключаемого модуля (CreateCallback), настройку/получение параметров (SetFloatParameterCallback/UnityAudioEffect_GetFloatParameterCallback
), выполнение фактического обработка (UnityAudioEffect_ProcessCallback
) и, в конечном итоге, уничтожение экземпляра подключаемого модуля по завершении (UnityAudioEffect_ReleaseCallback
).
Чтобы упростить использование нескольких подключаемых модулей в одной библиотеке DLL, каждый подключаемый модуль находится в своем собственном пространстве имен, а для функций обратного вызова используется особое соглашение об именах, так что DEFINE_EFFECT
и макросы DECLARE_EFFECT
могут заполнять структуру UnityAudioEffectDefinition. Под капотом все определения эффектов хранятся в массиве, указатель на который возвращается единственной точкой входа библиотеки UnityGetAudioEffectDefinitions.
Это полезно знать, если вы хотите разработать подключаемые модули, которые сопоставляются с другими форматами подключаемых модулей, такими как VST или AudioUnits, в интерфейс аудиоплагина Unity или из него, и в этом случае вам необходимо разработать более динамичный способ настройки. описания параметров во время загрузки.
Создание экземпляра плагина
Следующее — это данные для экземпляра подключаемого модуля. В примерах плагинов мы помещаем все это в структуру EffectData. Распределение этого должно происходить в соответствующем CreateCallback, который вызывается для каждого экземпляра плагина в микшере. В этом простом примере есть только одна синусоида, которая умножается на все каналы, другим более продвинутым плагинам нужно выделять дополнительные данные для каждого входного канала.
struct EffectData
{
struct Data
{
float p[P_NUM]; // Parameters
float s; // Sine output of oscillator
float c; // Cosine output of oscillator
};
union
{
Data data;
unsigned char pad[(sizeof(Data) + 15) & ~15];
};
};
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK CreateCallback(
UnityAudioEffectState* state)
{
EffectData* effectdata = new EffectData;
memset(effectdata, 0, sizeof(EffectData));
effectdata->data.c = 1.0f;
state->effectdata = effectdata;
InitParametersFromDefinitions(
InternalRegisterEffectDefinition, effectdata->data.p);
return UNITY_AUDIODSP_OK;
}
UnityAudioEffectState содержит различные данные от хоста, такие как частота дискретизации, общее количество обработанных семплов (для синхронизации), а также сведения о том, обходится ли подключаемый модуль и передается ли он всем функциям обратного вызова.
И, очевидно, для освобождения экземпляра плагина также есть соответствующая функция:
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ReleaseCallback(
UnityAudioEffectState* state)
{
EffectData::Data* data = &state->GetEffectData()->data;
delete data;
return UNITY_AUDIODSP_OK;
}
Основная обработка звука происходит в ProcessCallback:
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ProcessCallback(
UnityAudioEffectState* state,
float* inbuffer, float* outbuffer,
unsigned int length,
int inchannels, int outchannels)
{
EffectData::Data* data = &state->GetEffectData()->data;
float w = 2.0f * sinf(kPI * data->p[P_FREQ] / state->samplerate);
for(unsigned int n = 0; n < length; n++)
{
for(int i = 0; i < outchannels; i++)
{
outbuffer[n * outchannels + i] =
inbuffer[n * outchannels + i] *
(1.0f - data->p[P_MIX] + data->p[P_MIX] * data->s);
}
data->s += data->c * w; // cheap way to calculate a sine-wave
data->c -= data->s * w;
}
return UNITY_AUDIODSP_OK;
}
Функция GetEffectData в верхней части — это просто вспомогательная функция, преобразующая поле effectdata переменной состояния в EffectData::Data в структуре, которую мы объявили выше.
Другие простые подключаемые модули включают в себя подключаемый модуль NoiseBox, который добавляет и умножает входной сигнал на белый шум с переменной частотой, или подключаемый модуль Lofinator, который выполняет простое понижение частоты дискретизации и квантование сигнала. Все это можно использовать в сочетании с анимированными параметрами, управляемыми игрой, для имитации чего угодно, от мобильных телефонов до плохого радиоприема на рациях, сломанных громкоговорителей и т. д.
StereoWidener, который разлагает входной стереосигнал на монофонические и побочные компоненты с переменной задержкой, а затем рекомбинирует их для усиления воспринимаемого стереоэффекта.
Какой плагин загружать на какой платформе?
Нативные аудиоплагины используют ту же схему, что и другие нативные или управляемые плагины, в том смысле, что они должны быть связаны с соответствующими платформами с помощью модуля импорта плагинов инспекцииОкно Unity, в котором отображается информация о текущем выбранном игровом объекте, активе или настройках проекта, что позволяет просматривать и редактировать значения. Дополнительная информация
См. в Словарь. Вы можете узнать больше о подпапках, в которые следует помещать плагины здесь. Ассоциация с платформой необходима, чтобы система знала, какие плагины включать в каждую цель сборки в автономных сборках, а с введением поддержки 64-разрядных систем это даже необходимо указывать внутри платформы. Плагины для OS X в этом отношении особенные, поскольку универсальный двоичный формат позволяет им содержать как 32-, так и 64-битные варианты в одном комплекте.
Нативные подключаемые модули в Unity, вызываемые из управляемого кода, загружаются через атрибут [DllImport], ссылающийся на функцию, которая будет импортирована из собственной библиотеки DLL. Однако в случае с нативными аудиоплагинами все обстоит иначе. Особая проблема, возникающая здесь, заключается в том, что звуковые плагины должны быть загружены до того, как Unity начнет создавать какие-либо активы микшера, для которых могут потребоваться эффекты от плагинов. В редакторе это не проблема, потому что мы можем просто перезагрузить и пересобрать микшеры, которые зависят от плагинов, но в автономных сборках плагины должны быть загружены до того, как мы создадим активы микшера. Чтобы решить эту проблему, текущее соглашение состоит в том, чтобы префикс DLL плагина «аудиоплагин» (без учета регистра), чтобы система могла обнаружить это и добавить его в список плагинов, которые будут автоматически загружаться при запуске. Помните, что только определения внутри плагина определяют имена эффектов, которые отображаются в микшере Unity, поэтому DLL может называться как угодно, но она должна начинаться со строки «аудиоплагин», чтобы быть обнаруженной как таковая. р>
Для таких платформ, как IOSмобильная операционная система Apple. Подробнее
См. в Словарь, код плагина должен быть статически связан в двоичный файл Unity, созданный сгенерированным проектом XCode, и там - так же, как плагин рендерингпроцесс вывода графики на экран (или к текстуре рендера). По умолчанию основная камера в Unity отображает изображение на экране. Подробнее
См. в устройствах Словарь — регистрация плагина должна быть явно добавлена в автозагрузку код приложения.
В OSX один пакет может содержать как 32-битную, так и 64-битную версию плагина. Вы также можете разделить их, чтобы сохранить размер.
Плагины с пользовательским графическим интерфейсом
Теперь давайте рассмотрим кое-что более сложное: эффекты для выравнивания и многополосного сжатияметода хранения данных, который уменьшает количество места для хранения, которое ему требуется. См. Сжатие текстур, Сжатие анимации, Сжатие звука, Сжатие компоновки.
См. в Словарь. Такие плагины имеют гораздо большее количество параметров, чем простые плагины, представленные в предыдущем разделе, а также существует некоторая физическая связь между параметрами, которая требует лучшего способа визуализации параметров, чем просто набор простых ползунков. Рассмотрим, например, эквалайзер: каждая полоса имеет 3 разных фильтра, которые в совокупности вносят вклад в окончательную кривую выравнивания, и каждый из этих фильтров имеет 3 параметра частоты, добротности и усиления, которые физически связаны и определяют форму каждого фильтра. Таким образом, это очень помогает пользователю, если плагин эквалайзера имеет хороший большой дисплей, показывающий результирующую кривую, вклад отдельных фильтров, и может работать таким образом, что несколько параметров могут быть установлены одновременно простым перетаскиванием на элементе управления, а не изменение ползунков по одному.
Пользовательский графический интерфейс подключаемого модуля эквалайзера. Перетащите три полосы, чтобы изменить усиление и частоты кривой фильтра. Удерживайте клавишу Shift при перетаскивании, чтобы изменить форму каждой полосы.
Итак, еще раз, определение, инициализация, деинициализация и обработка параметров следуют точно такому же основанному на перечислении методу, который используют простые плагины, и даже код ProcessCallback довольно короткий. Что ж, пора перестать смотреть на нативный код и открыть проект AudioPluginDemoGUI.sln в Visual Studio. Здесь вы найдете связанные классы C# для кода GUI. Это работает очень просто: как только Unity загрузит собственные DLL-плагины и зарегистрирует содержащиеся в них аудио-плагины, она начнет искать соответствующие графические интерфейсы, которые соответствуют именам зарегистрированных плагинов. Это происходит через свойство Name класса EqualizerCustomGUI, который, как и все настраиваемые графические интерфейсы подключаемых модулей, должен наследоваться от IAudioEffectPluginGUI. В этом классе есть только одна важная функция — функция bool OnGUI (плагин IAudioEffectPlugin). С помощью аргумента подключаемого модуля IAudioEffectPlugin эта функция получает дескриптор собственного подключаемого модуля, который она может использовать для чтения и записи параметров, определенных собственным подключаемым модулем. Итак, чтобы прочитать параметр, который он вызывает:
plugin.GetFloatParameter("MasterGain", out masterGain);
который возвращает true, если параметр найден, и для его установки вызывает:
plugin.SetFloatParameter("MasterGain", masterGain);
который также возвращает true, если параметр существует. И это, по сути, самая важная связь между графическим интерфейсом и нативным кодом. Вы также можете использовать функцию
plugin.GetFloatParameterInfo("NAME", out minVal, out maxVal, out defVal);
для запроса минимального, максимального значения и значения по умолчанию для параметра "ИМЯ" во избежание дублирования их определений в нативном коде и коде пользовательского интерфейса. Обратите внимание, что если ваша функция OnGUI возвращает значение true, Инспектор покажет ползунки пользовательского интерфейса по умолчанию под пользовательским графическим интерфейсом. Это снова полезно для запуска разработки вашего графического интерфейса, поскольку у вас есть все параметры, доступные при разработке пользовательского графического интерфейса, и есть простой способ проверить, что правильные действия, выполненные над ним, приводят к ожидаемым изменениям параметров.
Мы не будем обсуждать здесь подробности об обработке DSP, которая происходит в плагинах Equalizer и Multiband. Для тех, кто заинтересован, фильтры взяты из превосходной книги Audio EQ Cookbook Роберта Бристоу Джонсона, а для построения кривых Unity предоставляет некоторые внутренние функции API для построения сглаженных кривых частотной характеристики.
Еще один момент, о котором следует упомянуть, заключается в том, что подключаемые модули Equalizer и Multiband также предоставляют код для наложения входных и выходных спектров для визуализации эффекта подключаемых модулей. частота обновления (частота кадров), чем обработка звука, и не имеет доступа к аудиопотокам, так как же мы читаем эти данные? Для этого в нативном коде есть специальная функция для этого:
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK GetFloatParameterCallback(
UnityAudioEffectState* state,
int index,
float* value,
char *valuestr)
{
EffectData::Data* data = &state->GetEffectData()->data;
if(index >= P_NUM)
return UNITY_AUDIODSP_ERR_UNSUPPORTED;
if(value != NULL)
*value = data->p[index];
if(valuestr != NULL)
valuestr[0] = 0;
return UNITY_AUDIODSP_OK;
}
Он просто позволяет считывать массив данных с плавающей запятой из собственного подключаемого модуля. Какими бы ни были эти данные, системе плагинов все равно, пока запрос не сильно замедляет пользовательский интерфейс или нативный код. Для эквалайзера и многополосного кода существует служебный класс под названием FFTanalyzer, который позволяет легко вводить входные и выходные данные из плагина и получать обратно спектр. Затем эти данные спектра передискретизируются с помощью GetFloatBufferCallback и передаются коду пользовательского интерфейса C#. Причина необходимости повторной выборки данных заключается в том, что FFTAnalyzer выполняет анализ с фиксированным частотным разрешением, в то время как GetFloatBufferCallback просто возвращает количество запрошенных выборок, которое определяется шириной представления, отображающего данные. Для очень простого плагина с минимальным количеством кода DSP вы также можете взглянуть на плагин CorrelationMeter, который просто отображает амплитуду левого канала в зависимости от амплитуды правого канала, чтобы показать «насколько стереофонический» сигнал. есть.
Слева: Пользовательский графический интерфейс плагина CorrelationMeter.
Справа: графический интерфейс эквалайзера с наложенным спектральным анализом (зеленая кривая — исходная, красная — обработанная).
На этом этапе мы также хотели бы отметить, что эффекты эквалайзера и многополосности намеренно сохранены простыми и неоптимизированными, но мы думаем, что они служат хорошими примерами более сложных пользовательских интерфейсов, поддерживаемых системой плагинов. Очевидно, предстоит еще много работы по соответствующей платформенно-зависимой оптимизации, тонны настроек параметров, чтобы сделать их действительно правильными и реагировать наиболее музыкальным образом и т. д. и т. д. Мы также можем реализовать некоторые из этих эффектов в виде встроенных плагинов. в Unity в какой-то момент просто для удобства расширения стандартного репертуара плагинов Unity, но мы искренне надеемся, что читатель также возьмет на себя задачу создать несколько действительно потрясающих плагинов — и кто знает, может быть, в какой-то момент они закончатся как построенные -в плагинах. ;-)
Пример плагина реверберации свертки. Импульсная характеристика представляет собой затухающий случайный шум, определяется параметрами. Это только для демонстрационных целей, как производственный плагин должен позволять пользователю загружать произвольные записанные импульсы, лежащий в основе алгоритм свертки тем не менее остается прежним.
Пример инструмента мониторинга громкости, измеряющего уровни в 3 разных временных масштабах. Также только в демонстрационных целях, но это хорошее место для начала создания инструмента мониторинга, который соответствует современным стандартам громкости. Код рендеринга кривых встроен в Unity.
Синхронизация с часами DSP
Пришло время для веселых упражнений. Почему бы не использовать систему плагинов для генерации звука, а не просто для его обработки? Давайте попробуем сделать несколько простых басовых и барабанных синтезаторов, которые должны быть знакомы людям, слушающим эйсид-транс — простые клоны некоторых основных синтезаторов, которые определили этот жанр. Взгляните на Plugin_TeeBee.cpp и Plugin_TeeDee.cpp. Эти простые синтезаторы просто генерируют паттерны со случайными нотами и имеют некоторые параметры для настройки фильтров, огибающих и т. д. в механизме синтеза. Опять же, мы не будем обсуждать здесь эти детали, а просто укажем, что параметр state->dsptick считывается в ProcessCallback, чтобы определить позицию в «песни». Этот счетчик является глобальной позицией сэмпла, поэтому мы просто делим его на длину каждой ноты, указанной в сэмплах, и запускаем событие ноты в механизм синтеза всякий раз, когда это деление имеет нулевой остаток. Таким образом, все эффекты плагинов остаются синхронизированными с одними и теми же часами на основе семпла, и если вы, например, воспроизведете предварительно записанную музыкальную пьесу с известным темпом через такой эффект, вы можете использовать информацию о времени для применения синхронизированного с темпом фильтра. эффекты или задержки в музыке.
Пространственность
Собственный SDK подключаемого модуля аудио является основой SDK Spatialization, который позволяет разрабатывать собственные эффекты пространственной обработки, которые создаются для каждого источника звука Компонент, который воспроизводит аудиоклип в сцене для аудиослушателя или через аудиомикшер. Подробнее
См. в Словарь.
Дополнительную информацию об этом можно найти здесь.
Перспективы
Это только начало усилий по открытию частей звуковой системы для высокопроизводительного нативного кода. У нас есть планы интегрировать это в другие части Unity, а также сделать эффекты пригодными для использования вне микшера, а также расширить SDK для поддержки других типов параметров, кроме float, с поддержкой улучшенных графических интерфейсов по умолчанию, а также для хранения двоичных данных.
Получите массу удовольствия, создавая свои собственные плагины. Надеемся увидеть их в магазине ресурсоврастущей библиотеке бесплатных и коммерческих ресурсов, созданных Unity и членами сообщества. Предлагает широкий спектр ресурсов, от текстур, моделей и анимации до целых примеров проектов, руководств и расширений редактора. Подробнее
См. в Словарь. ;-)
Отказ от ответственности
Несмотря на то, что в дизайне есть много общего, собственный звуковой SDK Unity не создан поверх других подключаемых SDK, таких как Steinberg VST или Apple AudioUnits. Следует отметить, что заинтересованному читателю было бы легко реализовать базовые оболочки для них с помощью этого SDK, которые позволяют использовать такие плагины для использования в Unity. Это не то, чем планирует заниматься команда разработчиков Unity. Надлежащее размещение любого подключаемого модуля быстро становится очень сложным, и работа со всеми тонкостями ожидаемых порядков вызова и обработки пользовательских окон графического интерфейса, основанных на собственном коде, быстро растет как на дрожжах, что делает его менее полезным в качестве примера кода.
Хотя мы понимаем, что потенциально может быть весьма полезно загрузить ваш плагин VST или AU или даже эффекты только для макета / тестирования звукового дизайна, имейте в виду, что использование VST/AU также ограничивает вас несколькими конкретными платформами. Потенциал написания аудиоплагинов на основе Unity SDK заключается в том, что он распространяется на все платформы, которые поддерживают микширование программного обеспечения и динамически загружаемый собственный код. Тем не менее, есть веские варианты использования для макетирования раннего звукового дизайна с вашими любимыми инструментами, прежде чем вы решите посвятить время разработке пользовательских плагинов (или просто иметь возможность использовать плагины измерения в редакторе, которые никак не изменяют звук). ), поэтому, если кто-то хочет сделать хорошее решение для этого, сделайте это.
MonoDevelop заменен Visual Studio с 2018.1