Определение частот в JS AudioContext.analyserNode

ОБЩАЯ ИНФОРМАЦИЯ

Моя цель — создать веб-приложение на основе JavaScript для анализа и отображения информации о частоте в источниках звука, как в источниках на странице (тег <audio>), так и в сигналах, передаваемых с микрофона клиента. я уже в пути :)

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

Доступ и отображение информации о частоте — это довольно тривиальная задача с использованием JS AudioContext.analyserNode, который я использую в сочетании с элементом HTML5 Canvas для создания карты частот или «гистограммы в стиле winamp», похожей на найденную 'Визуализации с API веб-аудио' @ MDN.

ПРОБЛЕМА

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

// example...
var APP = function() {
    // ...select source and initialise etc..

    var aCTX = new AudioContext(),
        ANAL = aCTX.createAnalyser(),
        rANF = requestAnimationFrame,
        ucID = null;

    ANAL.fftSize = 2048;

    function audioSourceStream(stream) {

        var source = aCTX.createMediaStreamSource(stream);
        source.connect(ANAL);

        var fData = new Uint8Array(ANAL.frequencyBinCount);

        (function updateCanvas() {
            ANAL.getByteFrequencyData(fData);

            // using 'fData' to paint HTML5 Canvas

            ucID = rANF(updateCanvas);
        }());
    }
};

ПРОБЛЕМЫ

Хотя я могу легко представить fData в виде гистограммы или линейного графика и т. д. с помощью <canvas> API, чтобы основные и верхние части источника звука были четко видны, до сих пор я не смог определить...

  • Диапазон частот fData (мин-макс Гц)
  • Частота каждого значения в fData (Гц)

Без этого я не могу приступить к определению доминирующей частоты источника (чтобы сравнить вариации в настройке с традиционными названиями музыкальных тонов) и/или выделить или исключить области представленного спектра (увеличение или уменьшение масштаба и т. д.) для более подробного изучения.

Мое намерение состоит в том, чтобы на видном месте отображать доминирующую частоту по высоте тона (название ноты) и частоте (Гц), а также отображать частоту любого отдельного столбца на графике при наведении курсора мыши. Н.Б. У меня уже есть объект данных, в котором хранятся все частоты (Гц) хроматических тонов между C0-B8.

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

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

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

БП


person Brian Peacock    schedule 12.06.2017    source источник
comment
Привет, Брайан, я только что увидел это и задался вопросом, закончил ли ты когда-нибудь этот проект?   -  person Katie.Sun    schedule 16.11.2018
comment
@Katie.Sun Hiya. Мне удалось заставить что-то работать, но, в конце концов, то, что я хотел от приложения, было выше возможностей JS AudioContext API. Сейчас я разрабатываю отдельное настольное приложение для Linux — работа идет медленно, но когда-нибудь я смогу это сделать. :D   -  person Brian Peacock    schedule 22.11.2018


Ответы (1)


Итак, во-первых, поймите, что выходные данные БПФ дадут вам массив относительной мощности в частотных ДИАПАЗОНАХ, а не точные частоты.

Эти диапазоны рассредоточены в спектре [0, частота Найквиста]. Частота Найквиста составляет половину частоты дискретизации. Поэтому, если ваш AudioContext.sampleRate равен 48000 (Герц), ваши частотные интервалы будут варьироваться в пределах [0,24000] (также в Гц).

Если вы используете значение по умолчанию 2048 для fftSize в вашем AnalyserNode, тогда FrequencyBinCount будет 1024 (это всегда половина размера FFT). Это означает, что каждый частотный бин будет представлять (24000/1024 = 23,4) примерно 23,4 Гц диапазона, поэтому бины будут выглядеть примерно так (экспромтом, здесь могут возникнуть ошибки округления):

fData[0] is the strength of frequencies from 0 to 23.4Hz.
fData[1] is the strength of frequencies from 23.4Hz to 46.8Hz.
fData[2] is the strength of frequencies from 46.8Hz to 70.2Hz.
fData[3] is the strength of frequencies from 70.2Hz to 93.6Hz.
...
fData[511] is the strength of frequencies from 11976.6Hz to 12000Hz.
fData[512] is the strength of frequencies from 12000Hz to 12023.4Hz.
...
fData[1023] is the strength of frequencies from 23976.6Hz to 24000Hz.

Пока есть смысл?

Следующий комментарий, который обычно появляется, звучит так: «Подождите секунду, с музыкальной точки зрения это менее точно в басовых регистрах (где 23,4 Гц могут охватывать целую ОКТАВУ), чем в высоких регистрах (где между нотами сотни герц). " На это я говорю: да, да, это так. Именно так работают БПФ. В верхних регистрах легче увидеть разницу в настройке.

СЛЕДУЮЩИЙ следующий комментарий обычно звучит так: «Вау, мне нужен МАССИВНЫЙ fftSize, чтобы быть точным в басовых регистрах». Обычно ответ таков: «Нет, вам, вероятно, не следует делать это таким образом» — в какой-то момент автокорреляция оказывается более эффективной, чем БПФ, и намного более точной.

Надеюсь, это поможет указать вам правильное направление, добавьте комментарий, если есть продолжение.

person cwilso    schedule 12.06.2017
comment
Эта единственная информация о взаимосвязи между размером буфера и частотой дискретизации — это как раз то, что мне нужно, хотя она предполагает, что мне, возможно, придется использовать другой подход по указанным причинам. :( Думаю, мне нужен способ проанализировать анализатор!! :D Есть какие-нибудь ссылки для "автокорреляции", которые могут быть полезны? Спасибо в любом случае. - person Brian Peacock; 12.06.2017
comment
en.wikipedia.org/wiki/Autocorrelation содержит довольно хорошее резюме. А также упоминает, что часто самый быстрый способ вычислить автокорреляцию — использовать БПФ. Другой альтернативой для получения значений басового регистра является использование банка полосовых фильтров для получения энергии в каждой полосе. Разработка фильтров может быть немного сложной, поскольку полосы пропускания будут небольшими, и, по-видимому, вы хотите, чтобы полосы были достаточно изолированы друг от друга. - person Raymond Toy; 13.06.2017