Pattr

Distortion (Waveshaping) Эффекты в Max/MSP

Дисторшены используются для добавления гармоник к исходному звуку. В большинстве случаев для этого используются вэйвшэйперы, Я говорю «в большинствe», потому что гармоники можно добавлять еще с помощью, например, кольцевой модуляции (ring modulation). Итак, суть waveshaping-а заключается в преобразовании сигнала с помощью специально подобранной передаточной функции. Звучит сложно? Вовсе нет. По сути, возведение сигнала в квадрат – это тоже передаточная функция. Это вся теория, которую нам нужно знать. Приступим к патчингу!

Откуда будем брать функции?

Не будем изобретать велосипед и возьмем функции с сайта musicdsp.org – это сообщество dsp программистов, на котором можно найти множество готовых алгоритмов, правда, большинство из них приведены в C++ коде.

Первый

Начнем с самого простого примера, доступного по ссылке:

z = M_PI * a;
s = 1/sin(z)
b = 1/a

if (x > b)
  f(x) = 1
else
  f(x) = sin(z*x)*s


Здесь переменная а – управляет степенью искажения сигнала, а входящий сигнал представлен в виде переменной x. Теперь реализуем это в максе:

Первый патч

Здесь роль if выполняет конструкция из объектов >~, +~ и [selector~ 2]. Объект >~ сравнивает входящий сигнал (из cycle~) с переменной b и выводит единицу, если значение сигнала больше переменной b, и ноль, если меньше. Единица и ноль управляют объектом selector~, который подает на выход сигналы только одного из инлетов. Соответственно, когда условие x > b выполняется, на выход подается 1, в ином случае, выход рассчитывается по формуле cos(z * x) * s. Можно заметить, что у нас используется функция косинуса, в то время как в оригинальной формуле синус. Дело в том, что в максе нет объекта для вычисления синуса, вот и приходится заменять его косинусом, разницы нет, потому что различаются они только начальной фазой.

Второй

Его можно посмотреть по ссылке.

x = input in [-1..1]
k = 2*amount/(1-amount);

f(x) = (1+k)*x/(1+k*abs(x))


Автор кода отмечает, что значение amount должно быть в диапазоне -1…1. Разумеется, не надо ставить amount равным 1, в этом случае будет деление на ноль. Здесь у нас входящий сигнал – x.

Второй патч

Здесь ничего сложного нет, внимательно изучив патч и сопоставив его с формулой, можно легко разобраться, как все работает.

Третий

Ссылка на оригинал. Код:

f(x,a) = x*(abs(x) + a)/(x^2 + (a-1)*abs(x) + 1)

Он же в максе:

Третий патч

Сигнал искажается при параметре amount  > 1. Я же заметил странный эффект (по крайней мере, на синусоиде) когда amount находится в диапазоне -1…0. Пробуйте, экспериментируйте и будет счастье! :)

Полиномы

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

Они обладают очень важным свойством: при подаче через них гармонического сигнала с единичной амплитудой (например, синусоиды), мы получим тот же сигнал, только в несколько раз выше. Множитель частоты будет зависеть от порядка полинома.

Все полиномы имеют примерно следующий вид:

y = f(x) = d0 + d1x + d2x2 + d3x3 + ... + dNxN;

То есть это, по сути, многочлен. N-ый элемент определяет порядок полинома. В нашем случае каждый элемент генерирует определенную гармонику, после чего они все складываются. Вид каждого члена определяется по следующему рекуррентному соотношению:

Tk+1(x) = 2xTk(x) – Tk–1(x);

В нем каждый член определяется на основе предыдущего, начинается все с нулевого, в нашем случае он равен единице, и первого, который равен x:

T0(x) = 1;

T1(x) = x;

Зная их, можно определить третий член:

T2(x) = 2x * x – 1 = 2 x2 – 1;

И четвертый:

T3(x) = 2 x (2x2 – 1) – x = 4x3 – 3x;

Как нетрудно догадаться, второй член – первая гармоника, третий – вторая и так далее.

Еще особенность полиномов Чебышева: когда через них подаешь сигнал, с амплитудой, меньше единичной, на выходе получается звук с меньшей насыщенностью гармоник. Это позволяет создать параметр drive для дисторшена.

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

Рекурсия

В первый инлет подается предыдущая гармоник, во второй – стоящая перед предыдущей, а в третий – не измененный входящий сигнал. Как видно, этот субпатч просто реализует рекуррентное соотношение Tk+1(x) = 2xTk(x) – Tk – 1(x), ничего сложного нет.

Теперь из этих блоков создадим патч, позволяющий добавлять вплоть до восьмой гармоники (высокочастотный фильтр в конце цепочки убирает DC offset):

Готовый полином восьмой степени

Этот патч позволяет регулировать амплитуду добавляемых гармоник, это можно использовать для эмуляции аналоговых устройств. Так, многие ламповые дисторшены, в основном добавляют четные гармоники, нечетные в них появляются только при высоком входящем сигнале. Многие низкокачественные усилители могут создвать третью гармонику. Твердотельные “Fuzz-Face” дисторшены искажают сигнал несимметрично, в них явно присутствуют вторая и третья гармоники, а также немного четвертой и пятой гармоник. Electro-Harmonix Big-Muff PI искажает симметрично и производит  в основном пятую и седьмую гармоники.

Заключение

Любые амплитудные преобразования влекут за собой неприятное последствие – алиасинг. Он появляется тогда, когда генерируемые гармоники превышают максимальную частоту сигнала (Niquist frequency), которая равна половине частоты дискретизации. Для борьбы с ним используют оверсемплинг – выполнение внутреннего алгоритма на увеличенной в несколько раз частоте дискретизации, с последующим ее понижением при выходе сигнала из устройства. При использовании полиномов Чебышева можно точно узнать, во сколько раз требуется повысить частоту дискретизации, чтобы полностью убрать алиасинг – это определяется по самой высокой генерируемой гармоники. Когда же алгоритм основан на других передаточных функциях, исключить его полностью не удастся, так как обычно эти алгоритмы генерируют бесконечное количество гармоник, однако оверсемплинг позволяет значительно уменьшить эффект алиасинга.

Большинство вэйвшейперных vst в работе не используют формулы для преобразования сигнала, их роль выполняют таблицы значений. В нее заносятся значения формул в диапазоне -1…1. Это позволяет не проводить ресурсоемкие вычисления в реальном времени, а также дает возможность «рисовать» передаточные функции.

Думаю, в одной из следующих статей напишу о том, как сделать оверсемплинг и табличный вэйвшэйпинг в максе, так что stay tuned.

P.S. В архиве с патчами также находится патч all_in_one.maxpat, в котором представлены все алгоритмы с возможностью выбора алгоритма и исходного звука.

12 Aug 2011  OSCII