Перегруз гитарного усилителя, насыщение ленты и срезанные вершины на мастер-шине получаются одним способом: каждый отсчёт пропускают через функцию, которая меняет выход не пропорционально входу. Ниже разобрано, как такая функция добавляет гармоники, чем мягкая кривая отличается от жёсткого среза, откуда берутся чётные гармоники и постоянная составляющая и где в цепи ставить фильтры. Затем — сатурация в сведении, код на C++23 и JUCE.
Нелинейность без памяти
Фильтр и регулятор громкости линейны: синусоида (sine)синус (sine) — Вертикальная координата точки на единичной окружности под заданным углом от положительного направления горизонтальной оси. Для острого угла прямоугольного треугольника равен отношению противолежащего катета к гипотенузе. проходит через них той же частоты (frequency)частота (frequency) — Число полных колебаний за секунду. Обозначается f и измеряется в герцах; 1 Гц означает одно колебание в секунду., меняются только амплитуда (amplitude)амплитуда (amplitude) — Наибольший модуль отклонения колеблющейся величины от равновесного значения. Для синусоиды обозначается A; единицы совпадают с единицами сигнала. и фаза (phase)фаза (phase) — Положение внутри периода колебания, выраженное углом: полный период соответствует 360°, или 2π радиан. Начальная фаза — её значение в момент t = 0.. У нелинейной системы на выходе появляются составляющие, которых во входе не было, прежде всего на кратных частотах (Zölzer, §10.1). Простейшая нелинейная система не имеет памяти: выходной отсчёт (sample)отсчёт (sample) — Значение сигнала в один момент дискретизации, одно число. В звукозаписи его также называют сэмплом. зависит только от входного отсчёта того же момента, а не от предыдущих.
Такая система задаётся одной функцией . Её график — передаточная кривая (transfer curve, waveshaper)передаточная кривая (transfer curve, waveshaper) — Функция y = f(x), по которой обработка без памяти пересчитывает каждый входной отсчёт в выходной. Прямая y = x ничего не меняет, любой изгиб добавляет гармоники.: по горизонтали значение входа, по вертикали значение выхода (Reiss, McPherson, гл. 8). Прямая ничего не меняет, прямая — только громкость. Любой изгиб меняет форму волны. Эффект, который строят на изгибе намеренно, называют дисторшном (distortion)дисторшн (distortion) — Эффект, который намеренно искажает форму волны передаточной кривой и добавляет гармоники. В узком смысле — сильное искажение, когда сигнал большую часть времени проходит изогнутый участок кривой.. Второе название кривой — waveshaper, «формирователь волны». Её вычисляют по формуле или хранят таблицей значений и читают с интерполяцией; таблица позволяет задать любую форму (Reiss, McPherson, с. 195).
Первый пример уже разобран в статье о лимитере: клиппер (clipper)клиппер (clipper) — Обработчик, который заменяет каждое значение выше границы самой границей, а остальные оставляет. Меняет форму волны внутри периода и добавляет гармоники. оставляет значения внутри и заменяет всё, что за пределами, на . Это кусочная функция из двух горизонталей и отрезка прямой. Синусоида с амплитудой 1,5 теряет вершины и получает третью гармонику на 16,5 дБ ниже основной, пятую — на 35,6 дБ, седьмую — на 32,2 дБ. Тот же излом даёт перегруз цифровой шины, когда сумма выходит за 0 dBFS (decibels relative to full scale)dBFS (decibels relative to full scale) — Уровень цифрового сигнала в децибелах относительно полной шкалы. Для пиковых значений 0 dBFS соответствует её границе; формат с плавающей точкой допускает значения выше неё. Соглашение об опоре RMS указывают отдельно. (статья о микшировании).
Названия эффектов различают по тому, какую часть кривой проходит сигнал. Овердрайв (overdrive) почти линеен на тихом сигнале и искажает громкий. Дисторшн в узком смысле работает в основном на изогнутом участке, фузз (fuzz) — почти целиком в насыщении, его форма волны близка к прямоугольной. Чёткой границы между ними нет, и все три описываются одной передаточной кривой (Reiss, McPherson, с. 184; DAFX, §4.3.2).
Мягкие кривые
Жёсткий срез до предела не искажает ничего, а за пределом сразу ломает вершину. Мягкая кривая загибается постепенно: чем ближе вход к пределу, тем меньше прирост выхода. Такое поведение называют сатурацией (saturation)сатурация (saturation) — Мягкое насыщение: с ростом входа выход растёт всё медленнее и плавно подходит к пределу. Тихий сигнал почти не меняется, громкий получает гармоники и сжатые пики., насыщением. Так ведут себя лампа, магнитная лента и германиевые диоды, а кремниевые диоды и многие транзисторные каскады ближе к жёсткому срезу (Reiss, McPherson, с. 187; DAFX, §4.3.4).
Три распространённые мягкие кривые — гиперболический тангенс (hyperbolic tangent, tanh)гиперболический тангенс (hyperbolic tangent, tanh) — Функция tanh u = (eᵘ − e⁻ᵘ)/(eᵘ + e⁻ᵘ). Около нуля почти совпадает с u, при росте |u| плавно приближается к ±1, не достигая их., кубическая и арктангенс — в формуле (1) записаны так, чтобы их было удобно сравнивать: в нуле наклон 1, тихий сигнал проходит без изменений, а выход не выходит за . Определения и — в математической статье.
- значение на входе кривой, доли полной шкалы;
- знак: при , при .
Кубическая кривая — та же , что в статье о лимитере, растянутая так, чтобы предел 1 достигался при входе 1,5. Сравните на рисунке 1: подходит к пределу быстрее арктангенса, кубическая кривая касается его в точке и дальше идёт горизонтально. В книгах встречается и другая нормировка: доходит до 1 ровно при , но наклон в нуле у неё больше единицы (Pirkle, §19.8).
Входное усиление и уровень на выходе
Перед кривой сигнал умножают на входное усиление , которое на панели плагина называют drive или gain: . Сама кривая не меняется, но тон с большей амплитудой проходит дальше по ней и сильнее загибается. Регулятор входного усиления меняет степень искажения, и именно его в первую очередь крутят при сведении (Reiss, McPherson, с. 187–188; Senior, §12.1).
Таблица 1 показывает это на тоне 220 Гц с амплитудой 0,5 (−6 dBFS). При мягкие кривые уже добавляют третью гармонику на 28–40 дБ ниже основной, а жёсткий срез ещё ничего не меняет: амплитуда 0,5 не доходит до излома. При +6 дБ тон доходит до 0,998 и срез по-прежнему его не трогает. При +12 дБ все кривые дают третью гармонику на 13–16 дБ ниже основной, а при +24 дБ форма волны у всех близка к прямоугольной. У прямоугольника нечётные гармоники убывают как : третья на 9,5 дБ ниже основной, и все четыре кривые подходят к этому пределу (Reiss, McPherson, с. 188).
| Кривая | G = 0 дБ | +6 дБ | +12 дБ | +24 дБ |
|---|---|---|---|---|
| Жёсткая | нет | нет | −12,9 дБ | −9,7 дБ |
| Гиперболический тангенс | −34,1 дБ | −23,5 дБ | −15,5 дБ | −10,0 дБ |
| Кубическая | −40,4 дБ | −27,7 дБ | −14,3 дБ | −9,8 дБ |
| Арктангенс | −28,0 дБ | −20,0 дБ | −15,0 дБ | −10,9 дБ |
Входное усиление поднимает и уровень: при большом выход почти всё время прижат к пределу. Поэтому после кривой ставят выходной регулятор. У линейного эффекта входной и выходной регуляторы взаимозаменяемы, у нелинейного — нет: первый меняет характер звука, второй только громкость (Reiss, McPherson, с. 198–199). Выходное усиление выбирают одним из двух способов. Множитель возвращает тихому сигналу исходный уровень, но громкий после этого тише входа: предел кривой стал . Подбор по RMS (RMS level)среднеквадратичный уровень (RMS level) — Корень из среднего квадрата значений сигнала на выбранном интервале. Имеет те же единицы, что и сигнал; у синусоиды за целое число периодов равен амплитуде, делённой на √2. или по громкости выравнивает варианты для сравнения на слух: иначе более громкий кажется лучше.
Гармоники
Если вход периодичен с периодом , то выход кривой без памяти повторяет его каждые секунд. Периодический сигнал раскладывается на синусоиды с частотами, кратными , поэтому после кривой тон 220 Гц превращается в набор составляющих 0, 220, 440, 660 Гц и так далее: постоянную составляющую, основную частоту и гармоники (Zölzer, §10.1, с. 342).
Откуда они берутся, видно на степенях. Кривую около нуля можно приблизить многочленом . Тождества из математической статьи показывают, что даёт каждая степень синусоиды:
- фаза тона, рад: .
Квадрат добавляет постоянную составляющую и вторую гармонику, куб — третью гармонику и вклад в основную. Многочлен степени даёт гармоники не выше -й (Reiss, McPherson, с. 191–193). Кубическая кривая из формулы (1) поэтому, пока вход не дошёл до излома в 1,5, создаёт ровно одну третью гармонику. Гиперболический тангенс и арктангенс многочленом не записываются, и их гармоники идут до бесконечности, быстро убывая. Жёсткий срез даёт излом, и его гармоники убывают медленнее всего.
Числом степень искажения описывает коэффициент гармоник, или суммарные гармонические искажения (total harmonic distortion, THD): корень из суммарной мощности гармоник, делённый на корень из мощности всего сигнала без постоянной составляющей (формула (3)). Для усилителя или АЦП, которые должны быть линейны, это удобная мера. Для эффекта он почти ничего не говорит о звучании: тембр зависит от того, какие гармоники преобладают, а одно число этого не показывает (Zölzer, §10.1, с. 342).
- амплитуда основной частоты на выходе;
- амплитуда -й гармоники, в тех же единицах.
Симметричная кривая: только нечётные гармоники
Все кривые рисунка 1 симметричны относительно начала координат: . Такие функции называют нечётными (odd function)нечётная функция (odd function) — Функция, для которой f(−u) = −f(u) при любом u. Её график симметричен относительно начала координат; пример — синус. (математическая статья). Через полпериода синусоида меняет знак: . Нечётная кривая сохраняет это свойство и на выходе: вторая половина периода — зеркальная копия первой со сменой знака. Нечётные гармоники при сдвиге на меняют знак, чётные и постоянная составляющая — нет. Чтобы выход сменил знак целиком, чётных составляющих в нём быть не может. У симметричной кривой на выходе только основная, третья, пятая и следующие нечётные гармоники (Zölzer, §10.2, с. 345; Reiss, McPherson, с. 190–193).
Эту картину показывает визуализация 2 в начальном состоянии: столбцы стоят только на нечётных номерах. Смена формы кривой и входного усиления меняет их высоту, но чётные не появляются.
- участок кривой, который проходит тон
- прямая y = x
- вход
- выход
- нечётные гармоники
- чётные гармоники
- постоянная составляющая (DC)
Входное усиление ×3,98 (+12 дБ): тон с амплитудой 0,5 доходит на входе кривой до ±1,99.
Гармоники относительно основной: 2-я нет, 3-я −15,5 дБ, 4-я нет, 5-я −28,4 дБ; чётных нет. THD 17,0 %.
Постоянной составляющей нет: кривая симметрична относительно нуля.
Попробуйте. Выберите «жёсткое ограничение» и уменьшите входное усиление до +6 дБ: гармоники исчезают, тон проходит прямой участок. Верните +12 дБ и сравните на слух с гиперболическим тангенсом: у жёсткого среза выше пятая и седьмая гармоники. Затем сдвиньте рабочую точку и выключите «Убрать постоянную составляющую».
Асимметрия: чётные гармоники и постоянная составляющая
Лампа в усилителе работает не в центре своей характеристики: рабочую точку задаёт напряжение смещения. Триод имеет характеристику, близкую к квадратичной, и, кроме основной частоты, даёт заметную вторую гармонику; у выхода смещается среднее значение (DAFX, §4.3.1, с. 117–118). Цифровую модель такого поведения получают, сдвинув рабочую точку той же кривой на :
- смещение рабочей точки, доли полной шкалы; при кривая симметрична.
Вычитание оставляет тишину тишиной: при выход равен нулю. Но для тона положительная и отрицательная полуволны теперь проходят разные участки кривой. Положительная идёт к пределу и сжимается сильнее, отрицательная — по более пологому участку. Кривая больше не нечётная, и в выходе появляются чётные гармоники и постоянная составляющая (Reiss, McPherson, с. 188–193). Таблица 2 показывает рост второй гармоники со смещением: при она уже сильнее третьей.
| Смещение b | 2-я гармоника | 3-я гармоника | Постоянная составляющая |
|---|---|---|---|
| 0 | нет | −15,5 дБ | 0 |
| 0,1 | −28,8 дБ | −15,6 дБ | −0,064 |
| 0,2 | −22,8 дБ | −15,8 дБ | −0,126 |
| 0,3 | −19,3 дБ | −16,2 дБ | −0,183 |
| 0,5 | −14,9 дБ | −17,7 дБ | −0,281 |
Асимметрию строят и по-другому: умножают положительные и отрицательные значения на разное усиление или пропускают через разные функции. Если две ветви сходятся в нуле с разным наклоном, на кривой появляется излом, а он сам добавляет высокие гармоники, обычно нежелательные; сдвиг рабочей точки гладкой кривой излома не даёт (Pirkle, §19.8.1). Крайний случай асимметрии — выпрямитель: модуль переворачивает отрицательные полуволны, частота основной удваивается, и тон звучит на октаву (octave)октава (octave) — Музыкальный интервал между нотами одного названия в соседних регистрах. Соответствует отношению частот 2:1. выше (Reiss, McPherson, с. 188–189).
Удаление постоянной составляющей
Постоянная составляющая (DC offset)постоянная составляющая (DC offset) — Постоянное смещение сигнала относительно нуля. Ненулевое среднее короткого фрагмента шума само по себе не доказывает такое смещение генератора. не слышна, но мешает. Волна смещается, и пик в одну сторону растёт: при и входном усилении +24 дБ выход идёт от −1,46 до 0,54, а после вычитания постоянной составляющей −0,42 — в пределах ±1,04. Следующая нелинейность получает уже сдвинутую рабочую точку. При включении и выключении эффекта скачок среднего значения звучит щелчком. Поэтому после асимметричной кривой ставят фильтр верхних частот (high-pass filter, HPF)фильтр верхних частот (high-pass filter, HPF) — Фильтр, который пропускает частоты выше частоты среза и ослабляет частоты ниже неё. В сведении убирает гул и низкочастотные помехи. с частотой среза ниже слышимого диапазона, например 20 Гц (DAFX, §4.3.1, с. 117, 122).
Простейший такой фильтр — однополюсный блокиратор постоянной составляющей (DC blocker) из формулы (5): ноль на нулевой частоте и полюс рядом с ним (J. O. Smith, DC Blocker).
- коэффициент обратной связи, безразмерный, чуть меньше 1;
- частота среза, Гц;
- частота дискретизации, Гц.
При частоте дискретизации (sample rate)частота дискретизации (sample rate) — Число отсчётов в каждом канале за одну секунду, то же число кадров аудиоданных в секунду. Измеряется в герцах: 44 100 Гц означает 44 100 отсчётов на канал в секунду. кГц и Гц коэффициент . Расчёт частотной характеристики даёт ослабление 3,0 дБ на 20 Гц, 7,0 дБ на 10 Гц и всего 0,02 дБ на 220 Гц; сдвиг фазы на 220 Гц около 5°. Разность убирает постоянное значение полностью, а обратная связь с возвращает всё, что меняется быстрее примерно . Как устроены полюс и ноль такого фильтра, разобрано в статье о цифровых фильтрах.
Два тона и интермодуляция
Гитарная нота — уже сумма гармоник, и кривая порождает новые гармоники от гармоник: тон остаётся тоном, только ярче. Аккорд из нот с некратными частотами ведёт себя иначе. Квадрат суммы двух синусоид содержит произведение , а оно раскладывается на частоты и . Такие составляющие называют интермодуляционными (intermodulation distortion)интермодуляционные искажения (intermodulation distortion) — Составляющие на суммах и разностях частот входных тонов, |m·f₁ + k·f₂| при ненулевых m и k, которые нелинейная обработка добавляет к сигналу из нескольких тонов. В отличие от гармоник, они обычно не кратны частоте ни одного из тонов.: они не кратны ни одной из нот и звучат как диссонанс (Reiss, McPherson, с. 193–195). Пример расчёта для среза суммы C4 и E4 приведён в статье о микшировании. Поэтому сильный перегруз обычно применяют к отдельным нотам и к квинтам (power chords), где сочетания частот почти совпадают с гармониками (Zölzer, §10.1, с. 343).
Место в цепи
У линейных блоков порядок не важен, у кривой — важен. Цифровые модели аналоговых схем часто раскладывают на линейный фильтр и кривую без памяти: фильтр до кривой задаёт, какие частоты сильнее всего попадают в насыщение, фильтр после — какие гармоники дойдут до выхода (Zölzer, §10.2, с. 344–345). Регулятор тембра дисторшна — чаще всего фильтр нижних частот (low-pass filter, LPF)фильтр нижних частот (low-pass filter, LPF) — Фильтр, который пропускает низкие частоты и ослабляет высокие. Перед дискретизацией помогает ограничить спектр входного сигнала. или полочный фильтр (shelving filter)полочный фильтр (shelving filter) — Фильтр, который поднимает или ослабляет на одинаковую величину все частоты по одну сторону от частоты перехода. Низкая полка действует ниже неё, высокая — выше. до или после кривой (Reiss, McPherson, с. 198–199).
- Фильтр нижних частот до кривой ослабляет высокие частоты входа, и они меньше участвуют в интермодуляции.
- Фильтр верхних частот до кривой убирает низ, который при перегрузе превращается в гул. В учебном примере JUCE по дисторшну он стоит первым, с частотой среза 1 кГц (JUCE, Add distortion through waveshaping and convolution).
- Фильтр нижних частот после кривой срезает верхние гармоники, когда звук получается резким. Педаль вау-вау перед дисторшном звучит иначе, чем после него: в первом случае фильтр выбирает, какие частоты перегрузить, во втором окрашивает уже искажённый звук (Reiss, McPherson, с. 201).
- Фильтр постоянной составляющей после кривой нужен, если кривая асимметрична.
Уровень на входе кривой — часть звучания, а не только громкость. Тихий фрагмент проходит почти линейный участок и остаётся чистым, громкий — уходит в насыщение. Затухающая нота сначала прижата к пределу и только потом опускается в линейную область, поэтому сильный перегруз удлиняет звучание ноты (sustain) (Reiss, McPherson, с. 201–202). Компрессор (dynamic range compressor)компрессор (dynamic range compressor) — Устройство или программа, которая ослабляет сигнал, когда его уровень выше порога, и тем сужает динамический диапазон. перед кривой выравнивает уровень, и количество гармоник меньше зависит от силы удара (Senior, §12.1, с. 194).
Гармоники выше частоты Найквиста
Все расчёты выше сделаны для непрерывной формы волны. В цифровом эффекте гармоники выше частоты Найквиста (Nyquist frequency)частота Найквиста (Nyquist frequency) — Половина частоты дискретизации, fₛ/2. В принятой низкочастотной модели точное восстановление по отсчётам требует, чтобы все частоты исходного сигнала были строго ниже этой границы. отражаются вниз, наложение спектров (aliasing)наложение спектров (aliasing) — Наложение частотных составляющих при дискретизации: разные непрерывные сигналы дают одинаковые отсчёты. Частота выше границы Найквиста может проявиться как более низкая. переносит их на частоты, не кратные тону (Reiss, McPherson, с. 197–198). Гладкая кривая отправляет туда меньше энергии: у тона 220 Гц с усилением +12 дБ при 48 кГц первая отражённая нечётная гармоника — 111-я, 24,42 кГц, она ложится на 23,58 кГц. После жёсткого среза её уровень на 77 дБ ниже основной, после — больше чем на 200 дБ ниже. Чем выше нота и сильнее перегруз, тем больше отражений попадает в слышимую полосу. Основной способ борьбы — передискретизация (oversampling)передискретизация (oversampling) — Работа с частотой дискретизации выше необходимой для полезной полосы. В АЦП уменьшает долю шума квантования в полезной полосе и смягчает требования к входному фильтру, в ЦАПе отодвигает спектральные копии, вокруг нелинейной обработки оставляет место для новых составляющих, чтобы они не отражались в полезную полосу. Новых сведений об исходном звуке не добавляет. вокруг кривой; в JUCE её выполняет juce::dsp::Oversampling.
Сатурация в сведении
Эквалайзер (equalizer)эквалайзер (equalizer) — Обработчик, изменяющий относительные уровни частотных областей сигнала. меняет только то, что уже есть в записи. Если у баса нет верхних гармоник, подъём на 2 кГц ничего не даст: поднимать нечего. Кривая создаёт новые составляющие, кратные нотам, поэтому партия становится плотнее и ярче, но остаётся той же партией (Senior, §12.1, с. 191–192). Слабая сатурация на отдельных дорожках и на общей шине стала обычным приёмом сведения: ей возвращают цифровой записи искажения, которые раньше добавляла аналоговая аппаратура (Izhaki, гл. 24, с. 447).
Плагины сатурации обычно моделируют конкретный прибор, и его поведение сводится к той же передаточной кривой, иногда с фильтрами и памятью. Магнитная лента загибает характеристику постепенно и сжимает пики (DAFX, §4.3.4, с. 132). Триодный каскад даёт вторую гармонику, пентодный — симметричное мягкое насыщение и нечётные гармоники (DAFX, §4.3.1, с. 117–118). Транзисторы и кремниевые диоды ближе к жёсткому срезу (Reiss, McPherson, с. 187). Цифровой перегруз за 0 dBFS — самый грубый вариант: жёсткий срез плюс наложение спектров (Izhaki, гл. 24, с. 450).
Мягкий срез обычно описывают как более гладкий и тёплый, жёсткий — как резкий и жужжащий (Reiss, McPherson, с. 187). Это оценки слушателей, а не измеряемые свойства. Проверяемая часть такова: у мягкой кривой высокие гармоники слабее (таблица 1). Вторая и четвёртая гармоники — октава и две октавы над нотой, их добавление обычно звучит естественно; третья и пятая не октавные и окрашивают звук заметнее (Izhaki, гл. 24, с. 447).
Несколько правил из практики:
- Сравнивать при одинаковой громкости. Сатурация поднимает уровень и плотность, а более громкий вариант кажется лучше. После настройки входного усиления выход убавляют, пока громкость с эффектом и без него не совпадёт, затем переключают bypass (bypass)обход эффекта (bypass) — Режим, в котором эффект не обрабатывает звук и на выход проходит исходный сигнал. Обход выполняет DAW или сам плагин; если плагин вносит задержку, исходный сигнал задерживают на ту же величину. (статья о лимитере).
- Подмешивать параллельно. Сигнал отправляют на отдельный канал, сильно перегружают и подмешивают к исходному заметно тише: в звуковых примерах Izhaki слой перегруза на 6–26 дБ ниже исходного. Так задают отдельно плотность гармоник и их долю в звуке, а канал с эффектом можно обработать эквалайзером (Izhaki, гл. 24, с. 449–450; Senior, §12.1, с. 193–194). Кривая без памяти не задерживает сигнал, поэтому регулятор dry/wet (dry/wet, mix)регулятор dry/wet (dry/wet, mix) — Параметр эффекта, задающий соотношение исходного и обработанного сигнала на выходе: 0 % — только dry, 100 % — только wet. Коэффициенты промежуточных положений зависят от закона смешивания. внутри плагина смешивает отсчёты без гребенчатой фильтрации (comb filtering)гребенчатая фильтрация (comb filtering) — Ряд чередующихся подъёмов и провалов частотной характеристики, возникающий, например, при сложении сигнала с его задержанной копией.; у моделей с фильтрами и у плагинов с передискретизацией задержку и сдвиг фазы надо учитывать (статья о dry/wet).
- Держать сатурацию на шине слабой: искажения отдельных дорожек и шины складываются. Перегруз высоких частот быстро утомляет слух, поэтому результат проверяют после паузы (Senior, §12.1, с. 194).
Код на C++
Сатуратор и фильтр постоянной составляющей
Класс Saturator реализует формулу (4) с кривой . Параметры пользователя хранятся в структуре, производные коэффициенты пересчитываются в setParameters вне цикла отсчётов. Множитель makeup делит на наклон кривой в нуле, : тихий сигнал проходит с усилением 1, поэтому смешивание с исходным по mix не меняет уровень на тихих местах. DcBlocker повторяет формулу (5). Пример использует назначенные инициализаторы (C++20, designated initializers) и std::println (C++23).
// Сатуратор без памяти: входное усиление, смещение рабочей точки, кривая tanh,
// компенсация уровня и смешивание с исходным сигналом. Фильтр после него убирает
// постоянную составляющую, которую даёт асимметричная кривая.
#include <cmath>
#include <numbers>
#include <print>
struct SaturatorParameters
{
float driveDb = 12.0f; // входное усиление
float bias = 0.0f; // смещение рабочей точки; 0 — симметричная кривая
float mix = 1.0f; // доля обработанного сигнала, 0…1
};
class Saturator
{
public:
void setParameters (const SaturatorParameters& parameters) noexcept
{
drive = std::pow (10.0f, parameters.driveDb / 20.0f);
bias = parameters.bias;
offset = std::tanh (bias);
// наклон кривой в нуле: drive · (1 − tanh²(bias)); тихий сигнал проходит с усилением 1
makeup = 1.0f / (drive * (1.0f - offset * offset));
mix = parameters.mix;
}
float processSample (float x) const noexcept
{
const auto wet = (std::tanh (drive * x + bias) - offset) * makeup;
return mix * wet + (1.0f - mix) * x;
}
private:
float drive = 1.0f, bias = 0.0f, offset = 0.0f, makeup = 1.0f, mix = 1.0f;
};
// Фильтр постоянной составляющей: y[n] = x[n] − x[n−1] + R·y[n−1]
class DcBlocker
{
public:
void prepare (double sampleRate, double cutoffHz = 20.0) noexcept
{
r = static_cast<float> (std::exp (-2.0 * std::numbers::pi * cutoffHz / sampleRate));
reset();
}
void reset() noexcept { x1 = y1 = 0.0f; }
float processSample (float x) noexcept
{
const auto y = x - x1 + r * y1;
x1 = x;
y1 = y;
return y;
}
private:
float r = 0.995f, x1 = 0.0f, y1 = 0.0f;
};
int main()
{
constexpr double sampleRate = 48'000.0;
constexpr double toneHz = 220.0;
Saturator saturator;
saturator.setParameters ({ .driveDb = 12.0f, .bias = 0.2f });
DcBlocker dcBlocker;
dcBlocker.prepare (sampleRate);
// 2 с тона −6 dBFS; среднее считаем по последней секунде, когда фильтр успокоился
const auto length = static_cast<int> (2.0 * sampleRate);
double sumBefore = 0.0, sumAfter = 0.0;
for (int n = 0; n < length; ++n)
{
const auto x = 0.5f * static_cast<float> (std::sin (2.0 * std::numbers::pi * toneHz * n / sampleRate));
const auto y = saturator.processSample (x);
const auto z = dcBlocker.processSample (y);
if (n >= length / 2)
{
sumBefore += y;
sumAfter += z;
}
}
const auto count = length - length / 2;
std::println ("Среднее до фильтра: {:.4f}, после: {:.1e}", sumBefore / count, sumAfter / count);
}Программа собрана clang++ -std=c++23 -Wall -Wextra -pedantic -Wconversion без предупреждений и печатает:
Среднее до фильтра: -0.0328, после: -5.2e-08Среднее до фильтра совпадает с таблицей 2: постоянная составляющая −0,126 при , умноженная на makeup . Последняя секунда содержит ровно 220 периодов тона, поэтому основная частота в среднее не попадает, и после фильтра остаётся только погрешность вычислений во float.
В плагине объект Saturator хранят по одному на процессор, а DcBlocker — по одному на канал: у фильтра есть состояние, у кривой нет. Параметры из интерфейса меняют setParameters между блоками; при резком изменении driveDb усиление меняется скачком, поэтому значение регулятора сглаживают, как время задержки в статье о линии задержки.
WaveShaper в JUCE
В модуле juce_dsp кривая без памяти — шаблон juce::dsp::WaveShaper<float>. Он хранит функцию в поле functionToUse и применяет её к каждому отсчёту блока; prepare и reset у него пустые, состояния нет (JUCE 9.0.3, juce_WaveShaper.h). По умолчанию тип функции — указатель float (*) (float), поэтому подходит лямбда без захвата. Входное и выходное усиление дают два juce::dsp::Gain, фильтр постоянной составляющей — IIR::Filter с коэффициентами makeFirstOrderHighPass, размноженный по каналам ProcessorDuplicator.
// Дисторшн на juce::dsp: входное усиление, асимметричная кривая tanh,
// фильтр верхних частот против постоянной составляющей и выходной уровень.
#include <juce_dsp/juce_dsp.h>
class Distortion
{
public:
Distortion()
{
// смещение 0,2 делает кривую асимметричной; вычитание tanh(0,2) оставляет тишину тишиной
chain.get<shaperIndex>().functionToUse = [] (float x)
{
return std::tanh (x + 0.2f) - std::tanh (0.2f);
};
chain.get<driveIndex>().setGainDecibels (12.0f);
chain.get<outputIndex>().setGainDecibels (-12.0f);
}
void prepare (const juce::dsp::ProcessSpec& spec)
{
chain.get<dcFilterIndex>().state =
juce::dsp::IIR::Coefficients<float>::makeFirstOrderHighPass (spec.sampleRate, 20.0f);
chain.prepare (spec);
}
void process (juce::dsp::AudioBlock<float> block) noexcept
{
chain.process (juce::dsp::ProcessContextReplacing<float> (block));
}
private:
using DcFilter = juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<float>,
juce::dsp::IIR::Coefficients<float>>;
enum { driveIndex, shaperIndex, dcFilterIndex, outputIndex };
juce::dsp::ProcessorChain<juce::dsp::Gain<float>,
juce::dsp::WaveShaper<float>,
DcFilter,
juce::dsp::Gain<float>> chain;
};Код собран с JUCE 9.0.3 в консольном приложении с флагами предупреждений JUCE и -Wconversion без предупреждений. На тоне 220 Гц с амплитудой 0,5 среднее выхода за вторую секунду около , RMS 0,199. Фильтр JUCE получен билинейным преобразованием аналогового ФВЧ первого порядка, а не по формуле (5), но на 20 Гц он делает то же самое.
Регулятор mix добавляет juce::dsp::DryWetMixer, как в статье о dry/wet. Для смены кривой во время работы нужна функция с состоянием, например WaveShaper<float, std::function<float (float)>>; присваивать её надо вне аудиопотока (audio thread)аудиопоток (audio thread) — Поток с повышенным приоритетом, который вызывает обработку звука для каждого блока. Каждый вызов должен закончиться до срока блока, поэтому в нём не выделяют память, не берут блокировки и не обращаются к диску., потому что копирование std::function может выделить память (статья об аудиопотоке).
Самопроверка
Тон 1 кГц прошёл через кривую tanh без смещения. Будет ли на выходе составляющая 2 кГц?
Нет. Гиперболический тангенс — нечётная функция, , поэтому выход меняет знак через полпериода вместе со входом. Чётных гармоник, в том числе 2 кГц, и постоянной составляющей у такого выхода нет; есть 3, 5, 7 кГц и далее.
Почему жёсткий срез тона с амплитудой 0,5 при входном усилении +6 дБ не даёт гармоник, а tanh даёт?
Усиление +6 дБ — это множитель около 1,995, и тон доходит до 0,998 — чуть ниже излома в 1. На этом участке жёсткая кривая — прямая . Мягкая кривая изогнута с самого нуля, поэтому tanh даёт третью гармонику на 23,5 дБ ниже основной (таблица 1).
После кривой со смещением рабочей точки среднее выхода −0,03. Чем это плохо и что поставить после кривой?
Волна смещена вниз: отрицательный пик ближе к пределу, следующая нелинейность получает сдвинутую рабочую точку, а при включении и выключении эффекта скачок среднего даёт щелчок. После кривой ставят фильтр верхних частот с частотой среза около 20 Гц, например блокиратор постоянной составляющей из формулы (5).
Плагин на входе прибавляет 12 дБ, на выходе убавляет 12 дБ. Почему звук всё равно изменился?
Входное усиление стоит до нелинейной кривой и меняет, какую её часть проходит сигнал: искажения растут. Выходное усиление умножает уже искажённую волну и меняет только громкость. Компенсация на выходе выравнивает уровень, но не возвращает форму волны.
Источники
- Zölzer U. Digital Audio Signal Processing. §10.1–10.2, с. 341–346; §10.4, с. 350–351. в списке литературы → — нелинейная система без памяти , гармоники периодического выхода, THD и его ограничения, интермодуляция и power chords, разделение модели на линейный фильтр и кривую, симметричная кривая и нечётные гармоники, асимметрия и чётные.
- Reiss J. D., McPherson A. P. Audio Effects: Theory, Implementation and Application. Гл. 8: Distortion, с. 184–203. в списке литературы → — овердрайв, дисторшн и фузз, передаточная кривая без памяти, жёсткий и мягкий срез, входное и выходное усиление, симметрия и выпрямление, доказательство для нечётных и чётных функций, интермодуляция, таблица кривой, наложение спектров и передискретизация, фильтры до и после кривой, регулятор тембра, sustain, сравнение с компрессором.
- Zölzer U. (ред.). DAFX: Digital Audio Effects. §4.3, с. 115–132. в списке литературы → — триод и вторая гармоника, пентод и симметричное насыщение, асимметричная модель лампы с фильтрами постоянной составляющей и тембра, определения овердрайва, дисторшна и фузза, насыщение ленты.
- Pirkle W. C. Designing Audio Effect Plugins in C++: For AAX, AU, and VST3 With DSP Theory. §19.8–19.8.1, с. 547–549. в списке литературы → — сигмоидные кривые, нормировка и , излом при разном усилении двух полуволн, выпрямитель.
- Senior M. Mixing Secrets for the Small Studio. Гл. 12, §12.1, с. 191–194. в списке литературы → — дисторшн как инструмент сведения, главная роль входного усиления, параллельная обработка, компрессор перед кривой, утомление от яркой обработки.
- Izhaki R. Mixing Audio: Concepts, Practices and Tools. Гл. 24: Distortion, с. 447–455. в списке литературы → — гармоники низкого порядка и их созвучие с нотой, THD и интермодуляция, наложение спектров в цифровом дисторшне и передискретизация, параллельный дисторшн, цифровой срез, waveshaper.
- Smith J. O. III. Introduction to Digital Filters with Audio Applications. DC Blocker, DC Blocker Frequency Response. в списке литературы → — разностное уравнение и передаточная функция блокиратора постоянной составляющей, выбор полюса .
- JUCE 9.0.3. juce_WaveShaper.h и WaveShaper — поле
functionToUse, тип функции по умолчанию, обработка отсчёта и блока, пустыеprepareиreset. - JUCE. Add distortion through waveshaping and convolution — цепочка
Gain,WaveShaper,Gain, криваяstd::tanh, фильтр верхних частот 1 кГц перед кривой. - JUCE 9.0.3. juce_ProcessorDuplicator.h и IIR::Coefficients — общий набор коэффициентов для фильтров всех каналов,
makeFirstOrderHighPass.
Связи
Связи списком
Ссылается на
- Алиасинг в нелинейной обработке: интермодуляция и передискретизация
- Дискретизация: отсчёты, период и частота дискретизации
- Линия задержки: кольцевой буфер, эхо и обратная связь
- Математика для аудио
- Микширование сигналов: усиление, фаза и запас уровня
- Первое знакомство с DAW: дорожки, MIDI и звук
- Принцип работы компрессора
- Принцип работы лимитера
- Спектр сигнала: ДПФ и БПФ
- Цифровые фильтры: импульсная характеристика, КИХ и БИХ
- C++ в аудиопотоке: выделение памяти, общие объекты и инструменты JUCE
- Dry/wet и bypass: исходный и обработанный сигнал в плагине