Оригинальный ответ:
Я не могу предоставить вам решение, но (надеюсь) дать вам достаточно советов для решения проблемы.
Я бы порекомендовал вамсохраните часть потока, который вы хотите проанализировать, в файл, а затем посмотрите на файл с помощью анализатора спектра (например, с помощью Audacity ).Это позволяет вам определить, присутствует ли сигнал 17 кГц в аудиопотоке.
Если сигнал 17 кГц присутствует в аудиопотоке, то вы можете отфильтровать аудиопоток с помощью фильтра нижних частот (например, аудио-биквад с типом lowpass
и частотой где-то выше 2 кГц).
Если в аудиосигнале отсутствует сигнал 17 кГц, вы можете попытаться увеличить размер буфера BUFSIZE
(в настоящее время в вашем коде установлено значение 500).В примере на странице GitHub node-pitchfinder
они используют полный аудиофайл для определения высоты звука.В зависимости от того, как реализован алгоритм обнаружения основного тона, результат может отличаться для больших фрагментов аудиоданных (т.е. нескольких секунд) по сравнению с очень короткими фрагментами (500 выборок - это около 11 мс при частоте дискретизации 44100).Начните с большого значения для BUFSIZE
(например, 44100 -> 1 секунда) и посмотрите, имеет ли это значение.
Объяснение кода Python: код использует FFT (быстрое преобразование Фурье) , чтобы узнать, какие частоты присутствуют в аудиосигнале, а затем ищет частоту с наибольшим значением.Это обычно хорошо работает для простых сигналов, таких как синусоида 2 кГц.Вы можете использовать dsp.js , который обеспечивает реализацию FFT, если вы хотите реализовать ее в javascript.Тем не менее, сделать это правильно, не зная теории цифровой обработки сигналов.
В качестве примечания: алгоритм YIN не использует БПФ, он основан на автокорреляция .
Обновление
Следующий скрипт использует данные fft audio-analyser
и ищет максимальную частоту.Этот подход очень простой и хорошо работает только для сигналов, где доминирует только одна частота.Алгоритм YIN
гораздо лучше подходит для обнаружения основного тона, чем этот пример.
const fs = require('fs');
const Lame = require('lame');
const Analyser = require('audio-analyser')
const Chunker = require('stream-chunker');
var analyser;
var fftSize = 4096;
var decoder = new Lame.Decoder();
decoder.on('format', format => {
analyser = createAnalyser(format);
decoder.pipe(analyser);
analyser.on('data', processSamples);
console.log(format);
});
var chunker = Chunker(fftSize);
var audio_stream = fs.createReadStream('./sine.mp3');
audio_stream.pipe(chunker);
chunker.pipe(decoder);
function createAnalyser(format) {
return new Analyser({
fftSize: fftSize,
frequencyBinCount: fftSize / 2,
sampleRate: format.sampleRate,
channels: format.channels,
bitDepth: format.bitDepth
});
}
function processSamples() {
if (analyser) {
var fftData = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fftData);
var maxBin = fftData.indexOf(Math.max(...fftData));
var thefreq = maxBin * analyser.sampleRate / analyser.fftSize;
console.log(maxBin + " " + thefreq);
}
}