我有一个小应用程序可以接受来自互联网的传入音频流,我正在尝试找出音调或连续蜂鸣声的频率。在发出提示音/哔哔声时,它是唯一会播放的东西。音频的其余部分要么是沉默,要么是说话。我正在使用 node-pitchfinder npm 模块来查找音调,当我使用由 2,000Hz 制作的示例音频剪辑时,应用程序会打印出一到两赫兹内的频率。当我在线拉取音频流时,我不断得到 17,000 Hz 之类的结果。我的猜测是音频信号中有一些“噪音”,这就是 node-pitchfinder 模块正在拾取的。
有什么方法可以实时滤除噪音以获得准确的频率?
流式音频文件是:http://relay.broadcastify.com/fq85hty701gnm4z.mp3
代码如下:
const fs = require('fs');
const fsa = require('fs-extra');
const Lame = require('lame');
const Speaker = require('speaker');
const Volume = require('pcm-volume');
const Analyser = require('audio-analyser')
const request = require('request')
const Chunker = require('stream-chunker');
const { YIN } = require('node-pitchfinder')
const detectPitch = YIN({ sampleRate: 44100})
//const BUFSIZE = 64;
const BUFSIZE = 500;
var decoder = new Lame.Decoder();
decoder.on('format', function(format){onFormat(format)});
var chunker = Chunker(BUFSIZE);
chunker.pipe(decoder);
var options = {
url: 'http://relay.broadcastify.com/fq85hty701gnm4z.mp3',
headers: {
"Upgrade-Insecure-Requests": 1,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15"
}
}
var audio_stream = request(options);
//var audio_stream = fs.createReadStream('./2000.mp3');
audio_stream.pipe(chunker);
function onFormat(format)
{
//if (volume == "undefined")
volume = 1.0;
vol = new Volume(volume);
speaker = new Speaker(format);
analyser = createAnalyser(format);
analyser.on('data', sample);
console.log(format);
vol.pipe(speaker);
vol.pipe(analyser);
decoder.pipe(vol);
vol.setVolume(volume);
}
function createAnalyser(format)
{
return new Analyser({
fftSize: 8,
bufferSize: BUFSIZE,
'pcm-stream': {
channels: format.channels,
sampleRate: format.sampleRate,
bitDepth: format.bitDepth
}
});
}
var logFile = 'log.txt';
var logOptions = {flag: 'a'};
function sample()
{
if (analyser) {
const frequency = detectPitch(analyser._data)
console.log(frequency)
}
}
我的目标是在一大块数据中找到最主要的音频频率,以便找出音调。
我发现了一些据说用 python 做的代码
def getFreq( pkt ):
#Use FFT to determine the peak frequency of the last chunk
thefreq = 0
if len(pkt) == bufferSize*swidth:
indata = np.array(wave.struct.unpack("%dh"%(len(pkt)/swidth), pkt))*window
# filter out everything outside of our bandpass Hz
bp = np.fft.rfft(indata)
minFilterBin = (bandPass[0]/(sampleRate/bufferSize)) + 1
maxFilterBin = (bandPass[1]/(sampleRate/bufferSize)) - 1
for i in range(len(bp)):
if i < minFilterBin:
bp[i] = 0
if i > maxFilterBin:
bp[i] = 0
# Take the fft and square each value
fftData = abs(bp)**2
# find the maximum
which = fftData[1:].argmax() + 1
# Compute the magnitude of the sample we found
dB = 10*np.log10(1e-20+abs(bp[which]))
#avgdB = 10*np.log10(1e-20+abs(bp[which - 10:which + 10].mean()))
if dB >= minDbLevel:
# use quadratic interpolation around the max
if which != len(fftData)-1:
warnings.simplefilter("error")
try:
y0, y1, y2 = np.log(fftData[which-1:which+2:])
x1 = (y2 - y0) * .5 / (2 * y1 - y2 - y0)
except RuntimeWarning:
return(-1)
# find the frequency and output it
warnings.simplefilter("always")
thefreq = (which + x1) * sampleRate/bufferSize
else:
thefreq = which * sampleRate/bufferSize
else:
thefreq = -1
return(thefreq)
最佳答案
原答案:
我无法为您提供解决方案,但(希望)能给您足够的建议来解决问题。
我建议您将要分析的流的一部分保存到一个文件中,然后使用频谱分析仪(例如 Audacity)查看该文件。这使您可以确定音频流中是否存在 17kHz 信号。
如果音频流中存在 17 kHz 信号,则您可以使用低通滤波器过滤音频流(例如 audio-biquad 类型为 lowpass
且频率高于 2 kHz)。
如果音频中不存在 17 kHz 信号,那么您可以尝试增加缓冲区大小 BUFSIZE
(当前在您的代码中设置为 500)。在 node-pitchfinder
's GitHub page 上的示例中他们使用完整的音频文件进行音调检测。根据音高检测算法的实现方式,较大的音频数据 block (即几秒钟)与非常短的 block (500 个样本在采样率 44100 时大约 11 毫秒)相比,结果可能会有所不同。从 BUFSIZE
的较大值开始(例如 44100 -> 1 秒),看看它是否有所作为。
python代码解释:代码使用FFT (fast fourier transform)找出音频信号中存在哪些频率,然后搜索具有最高值的频率。这通常适用于像 2 kHz 正弦波这样的简单信号。你可以使用 dsp.js如果你想在 javascript 中实现它,它提供了一个 FFT 实现。然而,如果不了解数字信号处理理论,要做到这一点是一项相当大的挑战。
作为旁注:YIN algorithm不使用 FFT,它基于 autocorrelation .
更新
以下脚本使用audio-analyser
的fft 数据并搜索最大频率。这种方法非常基础,仅适用于只有一个频率占主导地位的信号。 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);
}
}
关于javascript - 从流式音频 Node js 中删除高频声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53696891/