Звук, как и цвет, люди воспринимают по-разному. Например, то, что кажется слишком громким или некачественным одним, может быть нормальным для других.

Для работы над Яндекс.Музыкой нам всегда важно помнить о разных тонкостях, которые таит в себе звук. Что такое громкость, как она меняется и от чего зависит? Как работают звуковые фильтры? Какие бывают шумы? Как меняется звук? Как люди его воспринимают.



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

Поводом для этого поста можете считать то, что мы добавили в приложения Яндекс.Музыки возможность слушать треки в высоком качестве (320kbps). А можете не считать. Итак.

Оцифровка, или Туда и обратно


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


Рис. 1. Осциллограмма звука

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


Рис. 2. Интерактивный пример сложения волн и оцифровки сигнала.
Источник: www.desmos.com/calculator/aojmanpjrl


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

На аппаратном уровне это, разумеется, выглядит значительно сложнее, и в зависимости от аппаратуры сигнал может кодироваться совершенно разными способами. Самым распространённым из них является импульсно-кодовая модуляция, при которой записывается не конкретное значение уровня сигнала в каждый момент времени, а разница между текущим и предыдущим значением. Это позволяет снизить количество бит на каждый отсчёт примерно на 25%. Этот способ кодирования применяется в наиболее распространённых аудио-форматах (WAV, MP3, WMA, OGG, FLAC, APE), которые используют контейнер PCM WAV.

В реальности для создания стерео-эффекта при записи аудио чаще всего записывается не один, а сразу несколько каналов. В зависимости от используемого формата хранения они могут храниться независимо. Также уровни сигнала могут записываться как разница между уровнем основного канала и уровнем текущего.

Обратное преобразование из цифрового сигнала в аналоговый производится с помощью цифро-аналоговых преобразователей, которые могут иметь различное устройство и принципы работы. Я опущу описание этих принципов в данной статье.

Дискретизация


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


Рис. 3. Дискретизация сигнала.
Источник: https://en.wikipedia.org/wiki/Sampling_(signal_processing)


Частота дискретизации указывает на то, с какими интервалами по времени идут данные об уровне сигнала. Существует теорема Котельникова (в западной литературе её упоминают как теорему Найквиста — Шеннона, хотя встречается и название Котельникова — Шеннона), которая утверждает: для возможности точного восстановления аналогового сигнала из дискретного требуется, чтобы частота дискретизации была минимум в два раза выше, чем максимальная частота в аналоговом сигнале. Если брать примерный диапазон воспринимаемых человеком частот звука 20 Гц — 20 кГц, то оптимальная частота дискретизации (частота Найквиста) должна быть в районе 40 кГц. У стандартных аудио-CD она составляет 44.1 кГц


Рис. 4. Квантование сигнала.
Источник: https://ru.wikipedia.org/wiki/Квантование_(обработка сигналов)


Глубина дискретизации по уровню описывает разрядность числа, которым описывается уровень сигнала. Эта характеристика накладывает ограничение на точность записи уровня сигнала и на его минимальное значение. Стоит специально отметить, что данная характеристика не имеет отношения к громкости — она отражает точность записи сигнала. Стандартная глубина дискретизации на audio-CD — 16 бит. При этом, если не использовать специальную студийную аппаратуру, разницу в звучании большинство перестаёт замечать уже в районе 10-12 бит. Однако большая глубина дискретизации позволяет избежать появления шумов при дальнейшей обработке звука.

Шумы


В цифровом звуке можно выделить три основных источника шумов.

Джиттер


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

Шум дробления


Он напрямую связан с глубиной дискретизации. Так как при оцифровке сигнала его реальные значения округляются с определённой точностью, возникают слабые шумы, связанные с её потерей. Эти шумы могут появляться не только на стадии оцифровки, но и в процессе цифровой обработки (например, если сначала уровень сигнала сильно понижается, а затем — снова повышается).

Алиасинг


При оцифровке возможна ситуация, при которой в цифровом сигнале могут появиться частотные составляющие, которых не было в оригинальном сигнале. Данная ошибка получила название Aliasing. Этот эффект напрямую связан с частотой дискретизации, а точнее — с частотой Найквиста. Проще всего понять, как это происходит, рассмотрев вот эту картинку:


Рис. 5. Алиас. Источник: ru.wikipedia.org/wiki/Алиасинг

Зелёным показана частотная составляющая, частота которой выше частоты Найквиста. При оцифровке такой частотной составляющей не удаётся записать достаточно данных для её корректного описания. В результате при воспроизведении получается совершенно другой сигнал — жёлтая кривая.

Уровень сигнала


Для начала стоит сразу понять, что когда речь идёт о цифровом сигнале, то можно говорить только об относительном уровне сигнала. Абсолютный зависит в первую очередь от воспроизводящей аппаратуры и прямо пропорционален относительному. При расчётах относительных уровней сигнала принято использовать децибелы. При этом за точку отсчёта берётся сигнал с максимально возможной амплитудой при заданной глубине дискретизации. Этот уровень указывается как 0 dBFS (dB — децибел, FS = Full Scale — полная шкала). Более низкие уровни сигнала указываются как -1 dBFS, -2 dBFS и т.д. Вполне очевидно, что более высоких уровней просто не бывает (мы изначально берём максимально возможный уровень).

Поначалу бывает тяжело разобраться с тем, как соотносятся децибелы и реальный уровень сигнала. На самом деле всё просто. Каждые ~6 dB (точнее 20 log(2) ~ 6.02 dB) указывают на изменение уровня сигнала в два раза. То есть, когда мы говорим о сигнале с уровнем -12 dBFS, понимаем, что это сигнал, уровень которого в четыре раза меньше максимального, а -18 dBFS — в восемь, и так далее. Если посмотреть на определение децибела, в нём указывается значение 10 log(a/a0) — тогда откуда берётся 20? Всё дело в том, что децибел — это логарифм отношения двух одноимённых энергетических величин, умноженный на 10. Амплитуда же не является энергетической величиной, следовательно её нужно перевести в подходящую величину. Мощность, которую переносят волны с разными амплитудами, пропорциональна квадрату амплитуды. Следовательно для амплитуды (если все прочие условия, кроме амплитуды принять неизменными) формулу можно записать как

N.B. Стоит упомянуть, что логарифм в данном случае берётся десятичный, в то время как большинство библиотек под функцией с названием log подразумевает натуральный логарифм.

При различной глубине дискретизации уровень сигнала по этой шкале изменяться не будет. Сигнал с уровнем -6 dBFS останется сигналом с уровнем -6 dBFS. Но всё же одна характеристика изменится — динамический диапазон. Динамический диапазон сигнала — это разница между его минимальным и максимальным значением. Он рассчитывается по формуле , где n — глубина дискретизации (для грубых оценок можно пользоваться более простой формулой: n * 6). Для 16 бит это ~96.33 dB, для 24 бит ~144.49 dB. Это означает, что самый большой перепад уровня, который можно описать с 24-битной глубиной дискретизации (144.49 dB), на 48.16 dB больше, чем самый большой перепад уровня с 16-битной глубиной (96.33 dB). Плюс к тому — шум дробления при 24 битах на 48 dB тише.

Восприятие


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


Рис. 6. Зависимость воспринимаемой громкости от частоты и амплитуды звука.
Источник: ru.wikipedia.org/wiki/Громкость_звука


Громкость


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

Математика


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

// Минимальное значение громкости - на этом уровне идёт отключение звука
var EPSILON = 0.001;

// Коэффициент для преобразований в dBFS и обратно
var DBFS_COEF = 20 / Math.log(10);

// По положению на шкале вычисляет громкость
var volumeToExponent = function(value) {
	var volume = Math.pow(EPSILON, 1 - value);
	return volume > EPSILON ? volume : 0;
};

// По значению громкости вычисляет положение на шкале
var volumeFromExponent = function(volume) {
	return 1 - Math.log(Math.max(volume, EPSILON)) / Math.log(EPSILON);
};

// Перевод значения громкости в dBFS
var volumeToDBFS = function(volume) {
	return Math.log(volume) * DBFS_COEF;
};

// Перевод значения dBFS в громкость
var volumeFromDBFS = function(dbfs) {
	return Math.exp(dbfs / DBFS_COEF);
}


Цифровая обработка


Теперь вернёмся к тому, что мы имеем цифровой, а не аналоговый сигнал. У цифрового сигнала есть две особенности, которые стоит учитывать при работе с громкостью:
  • точность, с которой указывается уровень сигнала, ограничена (причём достаточно сильно. 16 бит — это в 2 раза меньше, чем используется для стандартного числа с плавающей точкой);
  • у сигнала есть верхняя граница уровня, за которую он не может выйти.


Из того, что уровень сигнала имеет ограничение точности, следует две вещи:
  • уровень шумов дробления возрастает при увеличении громкости. Для малых изменений обычно это не очень критично, так как изначальный уровень шума значительно тише ощутимого, и его можно безопасно поднимать в 4-8 раз (например, применять эквалайзер с ограничением шкалы в ±12dB);
  • не стоит сначала сильно понижать уровень сигнала, а затем сильно его повышать — при этом могут появиться новые шумы дробления, которых изначально не было.


Из того, что сигнал имеет верхнее ограничение уровня, следует, что нельзя безопасно увеличивать громкость выше единицы. При этом пики, которые окажутся выше границы, будут «срезаны» и произойдёт потеря данных.


Рис. 7. Клиппинг.
Источник: https://en.wikipedia.org/wiki/Clipping_(audio)


На практике всё это означает, что стандартные для Audio-CD параметры дискретизации (16 бит, 44,1 кГц) не позволяют производить качественную обработку звука, потому что имеют очень малую избыточность. Для этих целей лучше использовать более избыточные форматы. Однако стоит учитывать, что общий размер файла пропорционален параметрам дискретизации, поэтому выдача таких файлов для он-лайн воспроизведения — не лучшая идея.

Измерение громкости


Для того чтобы сравнивать громкость двух разных сигналов, её для начала нужно как-то измерить. Существует по меньшей мере три метрики для измерения громкости сигналов — максимальное пиковое значение, усреднённое значение уровня сигнала и метрика ReplayGain.

Максимальное пиковое значение достаточно слабая метрика для оценки громкости. Она никак не учитывает общий уровень громкости — например, если записать грозу, то большую часть времени на записи будет тихо шелестеть дождь и лишь пару раз прогремит гром. Максимальное пиковое значение уровня сигнала у такой записи будет довольно высоким, но большая часть записи будет иметь весьма низкий уровень сигнала. Однако эта метрика всё равно является полезной — она позволяет вычислить максимальное усиление, которое можно применить к записи, при котором не будет потерь данных из-за «обрезания» пиков.

Усреднённое значение уровня сигнала — более полезная метрика и легко вычислимая, но всё же имеет существенные недостатки, связанные с тем, как мы воспринимаем звук. Визг циркулярной пилы и рокот водопада, записанные с одинаковым средним уровнем сигнала, будут восприниматься совершенно по-разному.

ReplayGain наиболее точно передает воспринимаемый уровень громкости записи и учитывает физиологические и психические особенности восприятия звука. Для промышленного выпуска записей многие звукозаписывающие студии используют именно её, также она поддерживается большинством популярных медиа-плееров. (Русская статья на WIKI содержит много неточностей и фактически не корректно описывает саму суть технологии)

Нормализация громкости


Если мы можем измерять громкость различных записей, мы можем её нормализовать. Идея нормализации состоит в том, чтобы привести разные звуки к одинаковому уровню воспринимаемой громкости. Для этого используется несколько различных подходов. Как правило, громкость стараются максимизировать, но это не всегда возможно из-за ограничений максимального уровня сигнала. Поэтому обычно берётся некоторое значение немного меньше максимума (например -14 dBFS), к которому пытаются привести все сигналы.

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

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

Фильтрация


Я не стану описывать совсем все аудио-фильтры, ограничусь только стандартными, которые присутствуют в Web Audio API. Самым простым и распространённым из них является биквадратный фильтр (BiquadFilterNode) — это активный фильтр второго порядка с бесконечной импульсной характеристикой, который может воспроизводить достаточно большое количество эффектов. Принцип работы этого фильтра основан на использовании двух буферов, каждый с двумя отсчётами. Один буфер содержит два последних отсчёта во входном сигнале, другой — два последних отсчёта в выходном сигнале. Результирующее значение получается с помощью суммирования пяти значений: текущего отсчёта и отсчётов из обоих буферов перемноженных на заранее вычисленные коэффициенты. Коэффициенты данного фильтра задаются не напрямую, а вычисляются из параметров частоты, добротности (Q) и усиления.

Все графики ниже отображают диапазон частот от 20 Гц до 20000 Гц. Горизонтальная ось отображает частоту, по ней применяется логарифмический масштаб, вертикальная — магнитуду (жёлтый график) от 0 до 2, или фазовый сдвиг (зелёный график) от -Pi до Pi. Частота всех фильтров (632 Гц) отмечена красной чертой на графике.

Lowpass



Рис. 8. Фильтр lowpass

Пропускает только частоты ниже заданной частоты. Фильтр задаётся частотой и добротностью.

Highpass



Рис. 9. Фильтр highpass

Действует аналогично lowpass, за исключением того, что он пропускает частоты выше заданной, а не ниже.

Bandpass



Рис. 10. Фильтр bandpass

Этот фильтр более избирателен — он пропускает только определённую полосу частот.

Notch



Рис. 11. Фильтр notch

Является противоположностью bandpass — пропускает все частоты вне заданной полосы. Стоит, однако, отметить разность в графиках затухания воздействия и в фазовых характеристиках данных фильтров.

Lowshelf



Рис. 12. Фильтр lowshelf

Является более «умной» версией highpass — усиливает или ослабляет частоты ниже заданной, частоты выше пропускает без изменений. Фильтр задаётся частотой и усилением.

Highshelf



Рис. 13. Фильтр highshelf

Более умная версия lowpass — усиливает или ослабляет частоты выше заданной, частоты ниже пропускает без изменений.

Peaking



Рис. 14. Фильтр peaking

Это уже более «умная» версия notch — он усиливает или ослабляет частоты в заданном диапазоне и пропускает остальные частоты без изменений. Фильтр задаётся частотой, усилением и добротностью.

Фильтр allpass



Рис. 15. Фильтр allpass

Allpass отличается ото всех остальных — он не меняет амплитудные характеристики сигнала, вместо чего делает фазовый сдвиг заданных частот. Фильтр задаётся частотой и добротностью.

Фильтр WaveShaperNode


Вейвшейпер (en) применяется для формирования сложных эффектов звуковых искажений, в частности с помощью него можно реализовать эффекты «дисторшна», «овердрайва» и «фузза». Данный фильтр применяет к входному сигналу специальную формирующую функцию. Принципы построения подобных функций довольно сложные и тянут на отдельную статью, поэтому я опущу их описание.

Фильтр ConvolverNode


Фильтр, производящий линейную свёртку входного сигнала с аудио-буфером, задающим некую импульсную характеристику. Импульсная характеристика — это ответ некой системы на единичный импульс. Простым языком это можно назвать «фотографией» звука. Если реальная фотография содержит информацию о световых волнах, о том, насколько они отражаются, поглощаются и взаимодействуют, то импульсная характеристика содержит аналогичную информацию о звуковых волнах. Свёртка аудио-потока с подобной «фотографией» как бы накладывает эффекты окружения, в котором была сняла импульсная характеристика на входной сигнал.

Для работы данного фильтра требуется разложение сигнала на частотные составляющие. Это разложение производится с помощью быстрого преобразования Фурье (к сожалению, в русскоязычной Википедии совершенно несодержательная статья, написанная, судя по всему, для людей, которые и так знают, что такое БПФ и сами могут написать такую же несодержательную статью). Как я уже говорил во вступлении, не стану приводить в данной статье математику БПФ, однако не упомянуть краеугольный алгоритм для цифровой обработки сигналов было бы неправильно.

Данный фильтр реализует эффект реверберации. Существует множество библиотек готовых аудио-буферов для данного фильтра, которые реализуют различные эффекты (1, 2), подобные библиотеки хорошо находятся по запросу [impulse response mp3].

Материалы




Большое спасибо моим коллегам, которые помогали собирать материалы для этой статьи и давали полезные советы.

Отдельное спасибо Тарасу Audiophile Ковриженко за описание алгоритмов нормализации и максимизации громкости и Сергею forgotten Константинову за большое количество пояснений и советов по данной статье.

UPD. Поправил раздел про фильтрацию и добавил ссылки по разным типам фильтров. Спасибо deniskreshikhin и merlin-vrn за то, что обратили внимание.

Комментарии (44)


  1. pehat
    12.11.2015 20:03
    +5

    к сожалению, в русскоязычной Википедии совершенно несодержательная статья, написанная, судя по всему, для людей, которые и так знают, что такое БПФ и сами могут написать такую же несодержательную статью

    geektimes.ru/post/247974/#comment_8432808


  1. icoz
    12.11.2015 22:20
    +2

    Крайне зачётная статья! Спасибо за труд.


  1. deniskreshikhin
    12.11.2015 22:22
    +1

    Есть два существенных замечания.

    Как известно, цифровой сигнал — это набор значений уровня сигнала, записанный через заданные промежутки времени. Процесс преобразования непрерывного аналогового сигнала в дискретный цифровой сигнал называется дискретизацией. Есть две основные характеристики цифрового сигнала — частота дискретизации и глубина дискретизации по уровню.


    Во-первых, тут присутствует путаница в терминологии.

    Дискретный по времени сигнал или кратко просто дискретный (он же импульсный, квантованый по времени) это отдельный вид сигналов. Как раз для него и верна теорема Котельникова.
    Квантованный сигнал, он же квантованный по уровню — другой вид сигналов.
    А квантованный дискретный сигнал уже называется цифровым. Для него теорема Котельникова верна лишь приближенно.

    Т.е. термин «дискретный цифровой сигнал» одновременно и не верен, и тавтологичен.

    Во-вторых, пассивные фильтры, или как вы их назвали «глушащие» не могут иметь коэффициент усиления выше 1. Т.к. они могут только подавлять некоторые частоты, но не усиливать. Глядя же на эти графики можно подумать что происходит усиление:

    image

    Во всяком случае не понятно что означают оси, очевидно не уровень 0dB. Но тогда что?


    1. gheljenor
      12.11.2015 22:42
      +1

      Да, по первому пункту согласен, скорее всего в процессе редактирования напортачил, сейчас поправлю.

      Насчёт второго пункта — серая полоса на графика показывает сигнал с уровнем 1. И я тоже считал, что эти фильтры не должны вызывать усиления сигнала, однако именно такой график получается, если брать информацию из BiquadFilterNode#getFrequencyResponse. Либо это ошибка в реализации данной функции, либо сам фильтр действительно так устроен, тестов пока не проводил. Вообще этот график сильно похож на график групповой задержки для фильтра Баттерворта (https://ru.wikipedia.org/wiki/%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80_%D0%91%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%B2%D0%BE%D1%80%D1%82%D0%B0)


      1. gheljenor
        12.11.2015 23:31

        Используя webaudioplayground.appspot.com (спасибо dtestyk) Воспроизвёл поведение данного фильтра:
        Создаём такую схему: Oscillator node -> Biquad filter (lowpass, Q=15, freq=5000) -> Analyzer -> выход
        Запускаем воспроизведение в oscilator'е и меняем частоту. В районе 5000 Hz отчётливо слышно и видно резкое усиление звука.
        Так что данные графики отображают действительную картину того, как работает фильтр lowpass в web audio api.


        1. deniskreshikhin
          13.11.2015 00:28

          Ага, я тоже уже посмотрел спецификацию и исходники. В общем, эти типы фильтров которые реализованы в Web Audio API с помощью биквадратного фильтра все являются усиливающими, т.к. нормированы к нулевой частоте, а не резонансу как это должно быть в «глушащих фильтрах».

          Строго говоря, в спецификации и нет такого деления на «глушащие» и «усиливающие», типы же фильтров в спецификации просто отражают способ задания исходных параметров.

          Кстати, не обратил внимания, но еще есть одна неточность.

          Принцип работы всех перечисленных фильтров основан на разложении сигнала на различные частотные составляющие — это позволяет производить манипуляции не только над общей громкость, но и над отдельными наборами частот. Разложение сигнала на частотные составляющие производится с помощью быстрого преобразования Фурье


          Это не правда.

          Цифровые фильтры не требуют расчета БПФ, в данном случае биквадратный фильтр использует задержку 2 отсчетов от аргумента и двух отсчетов от функции. Т.е. получается около 5 умножений на каждый отсчет, это намного выгоднее чем БПФ, во первых т.к. N*log(N) это будет больше чем 5*N при достаточно больших N. Во-вторых БПФ создает огромную задержку, а задержка на 2 отсчета вообще не заметная для слуха.

          Можете кстати посмотреть как это реализуется, алгоритм довольно простой:

              while (n--) {
                  // FIXME: this can be optimized by pipelining the multiply adds...
                  float x = *sourceP++;
                  float y = b0*x + b1*x1 + b2*x2 - a1*y1 - a2*y2;
          
                  *destP++ = y;
          
                  // Update state variables
                  x2 = x1;
                  x1 = x;
                  y2 = y1;
                  y1 = y;
              }
          


          А вот задать коэффициенты уже не так просто:

                  // Compute biquad coefficients for lowpass filter
                  resonance = std::max(0.0, resonance); // can't go negative
                  double g = pow(10.0, 0.05 * resonance);
                  double d = sqrt((4 - sqrt(16 - 16 / (g * g))) / 2);
          
                  double theta = piDouble * cutoff;
                  double sn = 0.5 * d * sin(theta);
                  double beta = 0.5 * (1 - sn) / (1 + sn);
                  double gamma = (0.5 + beta) * cos(theta);
                  double alpha = 0.25 * (0.5 + beta - gamma);
          
                  double b0 = 2 * alpha;
                  double b1 = 2 * 2 * alpha;
                  double b2 = 2 * alpha;
                  double a1 = 2 * -gamma;
                  double a2 = 2 * beta;
          


          github.com/WebKit/webkit/blob/20f480a542d431da0d4ffe84347b498bdd614bb8/Source/WebCore/platform/audio/Biquad.cpp


    1. gheljenor
      12.11.2015 22:59
      -1

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


      1. deniskreshikhin
        13.11.2015 01:14

        >> Однако, нижняя граница частоты дискретизации всё равно не меняется.
        Ну это немного не правда) Нижняя частота не меняется при оцифровке способом, который описан в теореме Котельникова. Но есть способы оцифровки как с меньшей частотой (представление Хургина-Яковлева), так и с большей — дельта-модуляци и т.п.

        Т.е. теорема Котельникова не является каким-то универсумом, но тем не менее она применима, с некоторыми оговорками, к тому что мы имеем на практике когда оцифровываем сигнал равными интервалами по уровням, т.н. используя импульсно-кодовую модуляцию (PCM). Т.е. то о чем речь идет в статье.

        А вообще у теоремы Котельникова много недостатков:
        — требуется бесконечное количество отсчетов,
        — требуется бесконечная задержка для восстановления сигнала,
        — требуется бесконечно большое количество уровней квантования,
        — требуется сигналы с бесконечной длительностью (т.к. только такие имеют ограниченную частоту).

        Но все-таки с некоторыми допустимыми ошибками она работает)


        1. forgotten
          13.11.2015 09:52
          +2

          Да, но нет.

          Можно взять конечный по времени сигнал, периодически его продолжить и применить теорему Котельникова. (Правда, придётся работать в обобщённых функциях.) Это снимет все перечисленные недостатки (бесконечное число отсчетов, бесконечная задержка, etc — отсчёты-то повторяются). Но «работать» от этого теорема Котельникова не начнёт, поскольку восстановить по ней сигнал может только математик формулами на бумаге, а реальный ЦАП ничего и близко похожего на процедуру восстановления сигнала по Котельникову выдать не может.

          Подумываю написать статью «Легенды и мифы о теореме Котельникова».


          1. merlin-vrn
            13.11.2015 10:19

            Ну как, «ничего похожего». Ну да, ? x[i] sinc(t) в реальности использовать невозможно. Но используют же «обрезанную половинку sinc» — она похожа до некоторой степени.


            1. forgotten
              13.11.2015 10:53

              В реальности на каждый отсчёт нужно брать по синусоиде, притом с точностью до 6-го знака после запятой. Даже если брать окно 0.05 секунды (исходя из минимальной слышимой человеком частоты 20 Гц), потребуется сложить более 2000 синусоид. Чего-то я не видал таких ЦАП.


          1. schokoro
            13.11.2015 13:11
            +3

            Легенды и мифы о теореме Котельникова уже написаны. Называется «Сигналы, помехи, ошибки...» Автор Лев Финк. Настоятельно рекомендую.


            1. forgotten
              14.11.2015 02:39
              +2

              Чо-т не нахожу его на Хабре. Какой ник?


        1. diakin
          14.11.2015 18:36

          Теорема Котельникова — это математическая теорема ) У нее не может быть «недостатков», поскольку она математически верна (строго доказана). Проблемы применение мат аппарата к решению каких-то прикладных задач — это проблемы самих прикладных задач. Поэтому говорить, что " у теоремы есть определенные недостатки" или «она работает, хотя и плоховато» как-то несколько неправильно ).


          1. deniskreshikhin
            14.11.2015 20:28
            +1

            >> У нее не может быть «недостатков», поскольку она математически верна (строго доказана).

            Математика это довольно практическая наука. Есть теоремы (и теории) которые понятны, многое объясняют и легко применяются. А есть которые непонятны, запутывают и трудны в применении.

            Теорема Котельникова ближе ко вторым, т.к. порождает очень много ошибок и непонимания.

            Грубо говоря, задача дискретизации в обобщенном виде задача звучит так: Если имеется некоторая функция X из пространства L2(пространство квадратично интегрируемых функций), то как построить некоторый оператор A которые бы ставил ей в соответствие вектор Y из l2 (пространство квадратично суммируемых векторов). А то что эти пространства изоморфны доказал еще Гильберт.

            По-сути теорема Котельникова решает эту проблему так: если рассмотреть из всего пространства L2 только подпространство функций с ограниченным спектром (т.н. пространства Пели-Винера), то оператор A представляет собой разложение по дельта-функциям выбранным с некоторым периодом. Этот период и определяет частоту дискретизации, т.н. частота Найквиста.

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

            Поэтому, и говорят про недостатки теоремы.

            Насчет «работает» и «не работает», то в математике это сплошь и рядом. Интеграл Римана не работает со многими функциями, а интеграл Лебега вполне работает. Если вам не нравится слово «работает», замените на слово «применимо».

            Т.е. можно перефразировать так:
            >> Но все-таки с некоторыми допустимыми ошибками она применима)


            1. merlin-vrn
              15.11.2015 09:12

              Но все-таки с некоторыми допустимыми ошибками она применима

              В подобном случае в математике принято оценивать эти самые ошибки.


              1. deniskreshikhin
                15.11.2015 11:55

                Безусловно, но в математике понятие ошибки может подразумевать все что угодно. Оценка ошибок, это то чем должен заниматься инженер при проектировании на основе априорной информации. Без учета ошибок нельзя даже двух чисел корректно сложить в общем случае.


  1. dtestyk
    12.11.2015 23:15
    +1

    может кому будет полезно:
    toxicdump.org/stuff/FourierToy.swf визуализация синусоид
    bfxr.net генерация с множеством параметров

    text programming sound synthesis:
      wavepot.com
      studio.substack.net
      wurstcaptures.untergrund.net/music
    visual block playground:
      webaudioplayground.appspot.com
      app.hya.io

    языки программирования звука:
      pure data графический
      ChucK текстовый


  1. foxyrus
    12.11.2015 23:17
    +10

    Еще бы вы в яндекс радио нормализовали уровень громкости рекламы.


    1. gevak
      13.11.2015 12:01
      +1

      работаем над этим


      1. TimsTims
        13.11.2015 12:27

        Раз пошла такая пьянка про хотелки в Яндекс.музыке, то сделайте пожалуйста кнопку «Избранные» жанры, доступные со стартового.
        Чаще всего слушаю «Энергичное» — оно как-то больше всего подходит, но он постоянно в самом конце длинного списка «Настроение», и очень редко, когда программа предлагает послушать этот жанр с первой страницы… А так — добавил в избранное и всегда где-то в быстром запуске.

        2) Ну и дополню — я забиндил вашу прогу как программу по умолчанию в качестве музыки в Android'е, стоп/пауза и Next работают, а вот «холодный старт» нет. Т.е. нельзя просто с гарнитуры нажать «Play» и начать слушать музыку — приложение Стартует, но просит выбрать жанр. Т.е. просто начать слушать с гарнитуры нельзя.

        3) Очень мало песен в стиле «Русский рэп». Иногда настроение такое, что хочется послушать жесткого гопо-рэпа, а там… всякие сопливые «тимати» и ко)) и почти нет Касты. АК47, Centr итд…


  1. pwl
    13.11.2015 05:00

    Какая куча ошибок…
    Начнем с простого:

    Самым распространённым из них является импульсно-кодовая модуляция,

    ага. PCM.
    при которой записывается не конкретное значение уровня сигнала в каждый момент времени, а разница между текущим и предыдущим значением. Это позволяет снизить количество бит на каждый отсчёт примерно на 25%.

    А вот это уже DPCM.
    Этот способ кодирования применяется в наиболее распространённых аудио-форматах (WAV, MP3, WMA, OGG, FLAC, APE), которые используют контейнер PCM WAV.

    Здесь-же прекрасно почти всё…
    PCM в mp3 ??? Это как?
    WAV, WMA, OGG — это не форматы. Это контейнеры. Тот-же WAV может содержать внутри как PCM, так и mp3
    А вот PCM WAV это уже конкретный формат, а никак не контейнер…


    1. forgotten
      13.11.2015 10:58
      +1

      mp3 и прочие кодеки занимаются тем, что перекодируют PCM WAV во что-то более компактное. Поэтому формулировка «все эти кодеки используют PCM WAV» правильная, хоть и странная. Именно что «используют».


      1. pwl
        13.11.2015 20:52

        Точно так-же они могут использовать какой-нибудь .au в качестве источника, или вообще микрофонный вход…


        1. forgotten
          13.11.2015 21:08

          Обратного никто и не утверждал.


  1. Fanamura
    13.11.2015 10:13
    -1

    А когда в Яндекс.Музыке можно будет ожидать «похожее по исполнеНЕНИЮ». Чтобы можно было начать слушать любой трек и дальше слушать любых исполнителей схожих по звучанию? Даже если слушать радио по определенному жанру, там ну очень все разнообразное и такое ощущение, что просто собираются исполнители у которых тег = жанру, даже если это фактически не так. Искать не по исполнителю, не жанру, а именно звучанию. Или это какой-то космос в плане технологий и «харя треснет»?)


    1. AnimaLocus
      13.11.2015 10:57

      Космос. Лучшее что можно предложить это релейтед с ластфм, ну и у них база самая большая для построения подобного (у айтюнса конечно больше, но они особо не занимаются этим :)).


      1. Certik
        13.11.2015 18:57

        Релейтед с ластфм работает примерно так же хорошо как «с этим товаром часто покупают». То есть чуть лучше, чем никак.
        Теоретически, должно быть вполне возможно машинно проанализировать музыку по каким-то ключевым параметрам. А если к этому добавить тегирование не только по жанру, но и, например, по «составу» (хотя бы на уровне вокал есть/нет, ключевой инструмент, тип состава (соло/дуэт/группа/камерный оркестр/симфонический оркестр)), то можно выдавать действительно похожую музыку. Конечно, тегирование по составу машина сделать вряд ли сможет, но так и жанры пока что «руками» определяются.


    1. dtestyk
      13.11.2015 11:29

      существуют высокоуровневые признаки:

      • energy
      • dancibility
      • hotttnesss
      • duration
      • speechiness
      • acousticness
      • liveness
      • tempo
      • ...


      1. merlin-vrn
        13.11.2015 14:49

        dancibility

        Пожалуй, самый спорный признак. А именно, послушайте музыку (но не смотрите постановку) из танца Монтекки и Капулетти из балета «Ромэо и Джульетта» С. Прокофьева. Знаменитая музыкальная тема, мощная и энергичная. dancibility? Ау, это балет, оно делалось для танца.
        И теперь если вы не видели балет, вы не догадаетесь даже примерно, как выглядит этот танец.


  1. merlin-vrn
    13.11.2015 11:17

    Сумбурная и непоследовательная статья. Как и большинство подобных статей. Вот характерные признаки:

    — пишут про теорему Котельникова: можно восстановить по отсчётам. И всё. Как потом восстановить — ни слова, и далёкие от математики читатели себе выдумывают «лесенку», потом им она не нравится, начинается — линейная интерполяция, квадратичная, кубическая… А потом видим утверждения (было и прямо на Хабре), что при восстановлении из отсчётов -1, 0, +1, 0, -1, 0, +1, 0,… в результате сигнал получается треугольный. Ну или что восстановленный по отсчётам 0, 0, 1, 1, 0, 0, 1, 1,… сигнал окажется меандром. А это совершенно не так, если мы говорим о теореме, потому, что как треугольник, так и меандр заведомо не являются ограниченными по частоте, не удовлетворяют её условию, поэтому не могли быть теми функциями, из которых мы получили отсчёты, и следовательно не могут получиться и в резульате восстановления по этим отсчётам.

    А ведь достаточно было написать формулу для восстановления: и всё, сразу видно: отсчётов нам нужно бесконечное количество, для восстановления почти в каждой точке нужно использовать сразу все отсчёты, а восстановленная функция в любом случае будет гладкой, не будет содержать никаких «острых углов». А если кто не знает, sinc(x)=sin(x)/x. То есть, как обычно, это математическая идеализация, непосредственно не применимая на практике, и для использования нужно строить с её помощью какие-то практически реализуемые конструкции.

    — пишут про преобразование Фурье (даже не упоминая, что имеют ввиду именно дискретное преобразование). А то и сразу про БПФ, вроде как про серебрянную пулю (опять, имея ввижу исключительно алгоритм Cooley–Tukey и его требование, чтобы число отсчётов было степенью 2, хотя это — не единственный алгоритм БПФ, и у других такого жёсткого требования нет). А иногда речь на самом деле идёт про косинусное преобразование (частный случай, применяется в JPEG и т. д.).
    И всё, что говорится про него — «разделяет сигнал на частоты». В чём заключается преобразование, что получается в результате, про оконирование — ни слова. А тут опять дьявол — в деталях. Формулы-то преобразования туда и обратно несложные, казалось бы, почему бы не выписать их? И сразу же станет видно, что результат преобразования — набор комплексных чисел и не всё там так просто.

    — пишут про фильтры. Тут вообще атас, утверждения, что обрезные, шельфовые, полосовые фильтры делаются с помощью преобразования Фурье. Простой же вопрос — откуда тогда там появляется переменнй сдвиг фаз, если мы в образе были вольные его не вносить — не возникает ни у написателя статьи, ни у аудитории.
    Ответ на этот вопрос очень прост: никто не реализует фильтр с помощью преобразования Фурье. Есть такие штуки — фильтры КИХ и фильтры БИХ, у каждого из них свои особенности, вот их-то все и используют. Сдвиг фаз как раз является следствием применения таких фильтров.

    Куда было бы от вашей статьи больше пользы, если бы вы про Web Audio API рассказали подробнее, а не повторяли плохое изложение основ цифрового звука.


    1. gheljenor
      13.11.2015 12:06

      Насчёт «достаточно было написать формулу для восстановления» — совершенно не достаточно. Сколько бы человек её поняло? Для большинства это просто набор математических символов. Я специально исключил практически всю математику из статьи и даже не пытался описывать некоторые детали — это сделало бы статью в разы больше и непонятнее. Плюс к тому я вроде нигде не забыл оставить ссылки на более содержательные и подробные статьи по каждой сложной теме.

      Насчёт «повторения плохого изложения» — если бы было что повторять, этой статьи вообще бы не было. Но чтобы собрать материалы у меня ушло около недели поисков по интернету и вдумчивого чтения далеко не адаптированного для обывателей материала.

      Насчёт фильтров каюсь — сам не разобрался до конца в теме, перепишу этот блок. Спасибо за пояснение про то откуда берётся фазовый сдвиг.

      Про Web Audio API скорее всего будет отдельная статья.


      1. merlin-vrn
        13.11.2015 14:42

        Может, я неправ, но подобных статей даже на хабре было несколько. А уж за пределами хабра…

        Мне казалось, пользователи Хабра способны, видя знак бесконечности в пределе суммы понять, что нужно бесконечное число отсчётов. Конечно, всех деталей сразу не поймут, но это и не нужно — достаточно, чтобы детских заблуждений не появилось.

        Про фильтры — да это не объяснение было, а так, намёк, где его искать. Для понимания лучше всего взять копию сигнала, сдвинуть на 1, 2, и т. д. сэмпла, сложить с оригиналом и посмотреть, что стало со спектром. А второй вариант — взять копию, инвертировать, прибавить и посмотреть, что стало со спектром. А можно взять три сигнала, и не просто сдвинуть и сложить, а ещё умножить часть, сдвинутую на 1 сэмпл, на 1/2, а сдвинутую на два — на -1/2.

        Чтобы было легче смотреть, в качестве исходного сигнала возьмите белый шум — разница в спектре будет хорошо видна и слышна.

        Сдвиг фаз? Вот он и появляется оттого, что мы сдвигаем сигнал на 1, 2,… сэмпла. Разный для разных частот потому, что сдвиг на 1 сэмпл (из 44100 Гц) на частотах 20 Гц и 20 КГц — это разный сдвиг по фазе.

        В целом, вот то, что я тут описал, называется фильтр КИХ — с конечной импульсной характеристикой, он же FIR — finite impulse response. Считается просто, алгоритм реализуется в жёстком реальном времени, математически устойчив — всё хорошо, только вот копий сигнала приходится делать не три, а до нескольких тысяч. Правило простое: хотите, чтобы фильтр влиял на частоты порядка 20 Гц — вам нужно сдвигать сигнал на порядка 1/20 секунды, а при частоте дискретизации 44.1 это будет порядка 2K сэмплов. Может, потребуется в два раза больше, если хотите фильтр поточнее. Существует алгоритм построения FIR, реализующего заданную частотную характеристику с заданной точностью.


        1. gheljenor
          13.11.2015 15:07
          +3

          Статей много, каждая о какой-то части данной статьи пишет гораздо более развёрнуто и зачастую гораздо более научным языком с кучей математики. А вот обзорной статьи, в которой бы на пальцах были объяснены основные принципы и обозначены темы для изучения я так и не нашёл. Самое близкое к этому — статья Тараса Ковриженко про нормализацию громкости.

          Со знаком бесконечности как раз вопросов возникнет больше чем ответов — до этого речь идёт о каком-то конечном сигнале и тут вдруг возникает бесконечность. Откуда, почему? Если требуется бесконечное количество отсчётов, как в таком случае восстанавливать конечный сигнал? Вообще оцифровка сигнала и восстановление сигнала — это темы для двух больших отдельных статей, если не книг.

          В данной конкретной реализации используется биквадратный фильтр. Он как я понял относится к фильтрам БИХ (с бесконечной импульсной характеристикой). Работает примерно также.
          Берётся 2 последних отсчёта входного сигнала, 2 последних отсчёта выходного сигнала и текущий сигнал. Они умножаются на коэффициенты и складываются.


    1. diakin
      14.11.2015 19:02

      С тем же успехом можно сказать, что результат преобразования Фурье — «набор действительных чисел» )


      1. merlin-vrn
        14.11.2015 19:28

        ещё проще берите, набор цифр. Вы же не вычисляете его с бесконечной точностью, верно?


        1. diakin
          14.11.2015 19:39

          Я имею в виду, что результат можно представить или в комплексной или в действительной форме.

          И сразу же станет видно, что результат преобразования — набор комплексных чисел


  1. ESQUELETO
    13.11.2015 15:33
    +1

    А в вебе будет 320?


  1. sci_nov
    13.11.2015 17:07
    +3

    1. dtestyk
      13.11.2015 20:31

      финитный дискретный ограниченный квантованный сигнал :I


  1. ZoomZoomZoom
    16.11.2015 11:16
    +2

    Касательно измерения громкости:
    На данный момент наиболее актуальным является стандарт измерения громкости ITU BS.1770-4 (предыдущая версия 2 используется в Европе как EBU R-128). Это полноценный стандарт, применяемый в аудио-, кино- и телеиндустрии.
    Replaygain версии 1 измеряет воспринимаемую громкость, применяя фильтр обратный кривой Флетчера-Мансона и считающий RMS (вы эту аббревиатуру не упоминаете вообще и зря) 50мс отрезков аудио, плюс статистическая корректировка результата (описано упрощённо!).

    Утверждение, что RG «наиболее точно передает воспринимаемый уровень громкости записи» неверно, чему является подтверждением тот факт, что в предлагаемой версии RG2 планируется использовать способ определения громкости из стандарта ITU BS.1770[1].

    Часть про нормализацию полна неточностей. Нормализация — вполне конкретный термин, означающий увеличение амплитуды сигнала (т.е. повышение громкости) при которой пиковый уровень приводится к заданному значению, чаще всего к 0dBFS. Однако если говорить о нормализации громкости, то это уже комбинация алгоритмов её измерения с ограничением пиков (для предотвращения клиппинга).

    Последний абзац настолько некорректен, что даже не знаю, что там комментировать.

    [1] http://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification


    1. dtestyk
      16.11.2015 11:39

      о нормализации громкости
      А применяется ли фильтр, аналогичный эквилизации гистограммы для изображений?


      1. ZoomZoomZoom
        16.11.2015 12:24

        Нет, так как нормализация аудио подразумевает недеструктивное изменение сигнала.
        Мне вообще не очень легко представить адекватную аналогию такого преобразования. Возможно это могло бы быть расширение динамического диапазона, но толку в этом очень мало*.

        *Можно говорить о расширении динамического диапазона (декомпрессии) как о восстановительном процессе для «убитого» звука, но это обычно контролируемый вручную процесс, применяемый чаще всего на этапе мастеринга записей.


  1. engine9
    18.11.2015 00:41
    -1

    Графики опрятные, статья интересная.