До сих пор мы рассматривали методы отладки при взаимодействии с API веб-аудио. Если вы еще не проверяли его, эта статья, вероятно, избавит вас от пары головной боли: https://medium.com/@alexanderleon/working-with-the-web-audio-api-debugging-tips-45de8b493ee7

Кривые искажения

Под проектированием эффектов искажения я имею в виду, что мы будем создавать кривые искажения. Искажение - это процесс, в котором мы берем образцы звука в форме чисел и накладываем их на внешнюю функцию. Эти функции - наши кривые искажения. Различные кривые дадут разные результаты. Некоторые кривые создадут более тяжелые тона овердрайва; некоторые из них дадут тот классический звук лампового клапана; другие могут дать вам простой богатый звук; и другие, которых вы не знаете, как описать. Создание этих кривых - это больше искусство, чем наука, но всегда полезно иметь немного науки.

Сигмовидные функции

Все кривые искажения, которые я когда-либо видел или писал, были сигмовидными функциями. Эти функции обладают особыми свойствами, без которых трудно жить. Возможности включают:

  1. переменный наклон, поэтому результат будет нелинейным.
  2. ограниченный выход, поэтому результат не становится настолько шумным, что исходный звук становится неразличимым.
  3. Плавная S-образная форма, так что получаемый звук снова не выходит из-под контроля.

Подожди ... переменная крутизна?

Взгляните на эту сигмовидную функцию, которую я только что взял из Интернета без ссылки (рисунок 1).

Обратите внимание, как наклон, крутизна кривой постоянно меняется от -6 до -6? Вот что я имею в виду под переменным наклоном.

Что вы имеете в виду под нелинейным?

Я подойду к этому через минуту.

Давайте посмотрим на сигмовидную функцию. Перейдите на https://www.desmos.com/calculator. Вы должны увидеть чистую декартову плоскость с множеством кнопок и областью для ввода функций. Скопируйте этот текст и вставьте его в один из слотов ввода функции:

(3+20)\cdot x\cdot57\cdot(3/180)/(3+20\cdot\left|x\right|)

Надеюсь, вы увидите на странице рендеринг функции. Если вы исследуете кривые искажения в Интернете, скорее всего, вы столкнетесь с этой функцией. У него много замечательных свойств. Во-первых, он имеет S-образную форму. Когда мы добавляем кривую к звуку, мы накладываем исходные звуковые образцы (в форме чисел) на значения из кривой искажения. S-образная форма функции поможет создать более плавный и естественный звук.

Кого заботят плавные, естественные звуки? Я думал, что суть в том, чтобы создавать эпические электрические звуки! —Человек, читающий эту статью прямо сейчас

Нелинейность

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

Засучи рукава

Давайте создадим узел искажения в API веб-аудио и применим его к узлу генератора. Подготовим простой HTML-файл:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Test</title>
  </head>
  <body>
    <script src="test.js"></script>
  </body>
</html>

Скопируйте и вставьте следующее в соответствующий файл javascript:

// test.js
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();

var oscillatorNode = audioCtx.createOscillator();
var oscillatorGainNode = audioCtx.createGain();
var finish = audioCtx.destination;

var distortionGainNode = audioCtx.createGain();
var distortionNode = audioCtx.createWaveShaper();

function makeDistortionCurve(amount) {
    var k = amount,
        n_samples = typeof sampleRate === 'number' ? sampleRate : 44100,
        curve = new Float32Array(n_samples),
        deg = Math.PI / 180,
        i = 0,
        x;
    for ( ; i < n_samples; ++i ) {
        x = i * 2 / n_samples - 1;
        curve[i] = (3 + k)*Math.atan(Math.sinh(x*0.25)*5) / (Math.PI + k * Math.abs(x));
    }
    return curve;
}

distortionNode.curve = makeDistortionCurve(400);

oscillatorNode.connect(oscillatorGainNode);
oscillatorGainNode.connect(distortionGainNode);
distortionGainNode.connect(distortionNode);
distortionNode.connect(finish);

oscillatorNode.start(0);

Не слишком увлекательно?

Я знаю, что использование узла осциллятора для проверки искажений не особо грандиозно, но, по крайней мере, это работает! Если вы хотите создать лучший интерфейс, опробовать его и услышать эффекты искажения с реальными звуковыми образцами, подумайте о том, чтобы проверить эту библиотеку звуковых эффектов с открытым исходным кодом, в которую я сейчас работаю: https://github.com/alien35 / Ревун-Плюс

ПОДСКАЗКА: вы тоже можете внести свой вклад!

Мой подход

Помимо простого тестирования случайных функций и надежды на то, что они окажутся сигмовидными функциями, ограниченными границами -1≤x≤1 и -1≤y≤1, я проверяю сигмовидные функции из канона математики и пробую их. Например, в приведенном выше примере гудерманова сигмоидальная функция сочетается с первой сигмоидной функцией, которую мы рассмотрели.

Удачного кодирования!