Bil*_*ill 6 javascript audio pcm audio-streaming node.js
我有一个小应用程序接受来自互联网的传入音频流,我试图找到音调或连续发出哔哔声的频率.在音调/哔哔声时,它是唯一可以播放的东西.其余的音频是沉默或说话.我正在使用node-pitchfinder npm模块来查找音调,当我使用由2,000Hz制作的样本音频剪辑时,app会打印出一到两赫兹的频率.当我在线提取音频流时,我会得到17,000 Hz的结果.我的猜测是音频信号中存在一些"噪音",这就是节点 - 音调探测器模块正在拾取的东西.
有没有什么方法可以实时滤除噪音以获得准确的频率?
流音频文件是: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)
}
}
Run Code Online (Sandbox Code Playgroud)
我的目标是在一大块数据中找到最主要的音频,这样我就可以找出音调.
我发现一些代码可以用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)
Run Code Online (Sandbox Code Playgroud)
原答案:
我无法为您提供解决方案,但(希望)为您提供足够的建议来解决问题。
我建议您将要分析的流的一部分保存到文件中,然后使用频谱分析仪(例如使用Audacity )查看该文件。这使您可以确定音频流中是否存在 17kHz 信号。
如果音频流中存在 17 kHz 信号,那么您可以使用低通滤波器(例如,类型和频率高于 2 kHz 的音频双二阶)来过滤音频流。lowpass
如果音频中不存在 17 kHz 信号,那么您可以尝试增加缓冲区大小BUFSIZE(当前在代码中设置为 500)。node-pitchfinder在GitHub 页面的示例中,他们使用完整的音频文件进行音调检测。根据音高检测算法的实现方式,较大的音频数据块(即几秒)与非常短的音频数据块(500 个样本在采样率 44100 下约为 11 毫秒)相比,结果可能会有所不同。从一个较大的值BUFSIZE(例如 44100 -> 1 秒)开始,看看它是否会产生影响。
python代码说明:该代码使用FFT(快速傅里叶变换)来找出音频信号中存在哪些频率,然后搜索具有最高值的频率。这通常适用于 2 kHz 正弦波等简单信号。如果您想在 JavaScript 中实现 FFT,您可以使用dsp.js,它提供了 FFT 实现。然而,如果没有一定的数字信号处理理论知识,要做到这一点是一个相当大的挑战。
更新
以下脚本使用 的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
426 次 |
| 最近记录: |