Если сыграть пилу высоко на дешёвом софт-синте, поверх ноты появляется тонкий посторонний свист, который не попадает в тон. Это алиасинг. В этой статье разберу, как я убирал его из ядра плагинов D-module, во сколько раз стало тише и что неожиданно поменялось в звуке заодно.
Все цифры ниже я снял измерительным стендом, а не на слух. Правило у меня в проекте такое: утверждение о звуке без замера - только гипотеза.
Откуда берётся свист
Цифровой звук хранится отсчётами, и на частоте 48 кГц он честно передаёт только частоты до 24 кГц. Это половина частоты дискретизации, её называют частотой Найквиста. Всё, что выше, не исчезает, а отражается вниз, как от зеркала. Гармоника на 30 кГц превращается в 18 кГц, гармоника на 50 кГц ещё во что-то, и все эти отражения не кратны основному тону. Поэтому алиасинг слышен как негармоничный призвук, который ещё и «едет» в обратную сторону, когда нота скользит вверх.
У пилы и меандра гармоник бесконечно много: резкий перепад формы и есть бесконечный спектр. Значит, нарисовать идеальную пилу в цифре нельзя, будет зеркало. Второй источник - нелинейности: клиппер, сатуратор, вейвфолдер. Они рождают новые гармоники из любого сигнала, даже из синуса, и эти гармоники тоже улетают за Найквиста.
polyBLEP: стандартное решение и его цена
Чаще всего для этого берут polyBLEP. Осциллятор рисует пилу с резким перепадом, а в точке перепада подмешивает маленькую поправку, которая сглаживает ступеньку. Это дёшево и в целом работает, поэтому так делают очень многие.
У меня пила на polyBLEP на ноте 220 Гц давала алиасинг на уровне −47.7 дБ, меандр −50.9 дБ, узкий импульс со скважностью 0.10 −40.7 дБ. Минус сорок с небольшим децибел от основного звука - это слышно, особенно на высоких нотах и в тихих местах.
Была и вторая проблема, о которой обычно не говорят: polyBLEP заметно приглушает верх. По замеру он теряет 1.6 дБ в полосе 8…16 кГц. Эта потеря звучит не как алиасинг, а как лёгкая «замыленность» пилы.
Мип-таблицы
Я перевёл пилу и меандр на мип-таблицы. Идея старая и простая: при запуске плагин заранее строит одну и ту же волну в нескольких вариантах, с разным числом гармоник. Для низких нот гармоник много, для каждой следующей октавы меньше - ровно столько, чтобы ни одна не перелезла за Найквиста. Во время игры осциллятор читает таблицу, подходящую по высоте ноты. Зеркалить нечего, потому что лишних гармоник в волне просто нет.
Результат на той же ноте 220 Гц:
| Форма | polyBLEP | Мип-таблицы |
|---|---|---|
| Пила | −47.7 дБ | −108.2 дБ |
| Меандр | −50.9 дБ | −111.1 дБ |
| Импульс 0.10 | −40.7 дБ | −101.1 дБ |
| Треугольник | −85.2 дБ | −120.9 дБ |
Шестьдесят децибел - это в тысячу раз по амплитуде. Треугольник у меня получается интегрированием меандра, поэтому он стал чище сам, без собственного набора таблиц.
По процессору замена ничего не стоит: три пары прогонов подряд дали одинаковые доли процента ядра до и после. Таблицы занимают 237 КБ памяти на процесс и строятся один раз за 52 мс.
Что изменилось в звуке, кроме свиста
Звук стал светлее. Те 1.6 дБ на верхах, которые съедал polyBLEP, вернулись. Это не побочный эффект: просто верх перестал теряться. Но разницу слышно, так что после такой правки обязательно нужна прослушка.
Пик вырос на 18 % при той же громкости. RMS пилы не изменился, а пиковое значение подросло. Это звон Гиббса: когда спектр волны честно обрезан, у перепада появляется маленький выброс. Это свойство любой волны без лишних гармоник, а не ошибка. Но у меня уровень заводских драм-патчей выставлен по пику одиночного удара, поэтому четыре патча из тридцати трёх пришлось перевыставить. Остальные не сдвинулись даже на 0.05 дБ.
Узкий импульс заработал на высоких нотах. С polyBLEP узкую скважность приходилось ограничивать снизу, иначе две поправки (на переднем и заднем фронте) накладывались друг на друга, и на верху клавиатуры импульс схлопывался в меандр. Импульс на мип-таблицах считается как разность двух табличных пил, и накладываться там нечему. Ограничение я снял, а тест развернул: теперь он требует, чтобы формы на высоких нотах различались.
Ошибка, которую пропустила бы проверка «на одной ноте»
Первая версия таблиц строила все уровни по одной сетке длиной 8192 отсчёта с целым шагом. На мелких уровнях шаг округлялся до единицы, и уровни мельче четвёртого содержали не ту форму: −36.6 дБ вместо −112.6.
Коварство в том, что первые три ноты, на которых я проверял, были идеальны. Если бы проверка гоняла одну ноту, дефект прошёл бы целиком. Поэтому измерения у меня идут по всему диапазону, а не по одной точке.
Чего мип-таблицы не лечат
Частотной модуляции. Если пилой модулировать частоту другого осциллятора с индексом 0.25, мгновенная частота уходит выше Найквиста, и никакая таблица этого не спасёт: −12.5 дБ (было −15.0). Синусный FM, который стоит по умолчанию, чист: −123.7 дБ. Я прямо записал это в документацию ядра, чтобы никто не думал, что проблема FM решена.
Нелинейности: ADAA
С фолдером и клиппером таблицы не помогут: гармоники рождаются из входного сигнала, а он заранее неизвестен. Для них я взял ADAA - антиалиасинг через первообразную. Вместо значения функции в точке считается её среднее между соседними отсчётами через первообразную, и высокие гармоники гасятся сами.
| Узел | До | После |
|---|---|---|
| Жёсткий клиппер | −39.4 дБ | −58.8 дБ |
| Синусный фолд | −41.1 дБ | −64.9 дБ |
| Треугольный фолд | −14.8 дБ | −54.6 дБ |
И тут нашлись четыре места, где легко ошибиться.
Только double. Во float ADAA второго порядка не «чуть менее точна», она разваливается. На синусе 220 Гц пик фолдера достиг 82.9 при форме, ограниченной ±1: формула делит разность почти равных чисел на маленькую разность, и точности float на это не хватает. Мой собственный прототип был во float и занижал качество метода на 12…15 дБ. Я чуть не записал в выводы недостаток float, приняв его за недостаток метода. С тех пор стенд считает в том же типе, что и ядро.
Кэш первообразных. Без кэша ADAA-2 считает первообразную четыре раза на отсчёт, и драм-кит на фолдере стал бы вдвое дороже по процессору. С кэшем дёшево, но кэш обязан сбрасываться при каждом изменении параметра. Иначе складываются первообразные двух разных функций, и на модуляции drive слышен щелчок.
ADAA немного режет верх даже там, где искажать нечего. В линейной области метод вырождается в усреднение по двум или трём отсчётам: −1.25 и −3.52 дБ на 16 кГц. Я пробовал это компенсировать, но замер показал, что в нелинейной области компенсация ломает тембр, и от неё я отказался.
Оверсэмплинг остался. ADAA работает поверх двукратного оверсэмплинга, который там уже был, а не вместо него.
D-Fold. Фолдер внутри работает с антиалиасингом ADAA второго порядка.
Где это живёт
Мип-осцилляторы стоят в графовом движке, на котором работает генеративная драм-машина D-drum. ADAA-фолдер работает в модульном синтезаторе D-SP и в D-Fold, клиппер в D-Drive (оба из FX-пака).
После выступления 26 сентября 2026 года, где весь сет был сыгран только на плагинах D-module, в заметках осталась строка: «алиасинга на слух не было». Ради таких строк всё это и делалось.