jjzjj

javascript - 从流式音频 Node js 中删除高频声音

coder 2025-01-04 原文

我有一个小应用程序可以接受来自互联网的传入音频流,我正在尝试找出音调或连续蜂鸣声的频率。在发出提示音/哔哔声时,它是唯一会播放的东西。音频的其余部分要么是沉默,要么是说话。我正在使用 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/

有关javascript - 从流式音频 Node js 中删除高频声音的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  3. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  4. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  5. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  6. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  7. ruby-on-rails - 为什么在 Rails 5.1.1 中删除了 session 存储初始化程序 - 2

    我去了这个website查看Rails5.0.0和Rails5.1.1之间的区别为什么5.1.1不再包含:config/initializers/session_store.rb?谢谢 最佳答案 这是删除它的提交:Setupdefaultsessionstoreinternally,nolongerthroughanapplicationinitializer总而言之,新应用没有该初始化器,session存储默认设置为cookie存储。即与在该初始值设定项的生成版本中指定的值相同。 关于

  8. ruby - 如果它是标点符号,我怎么能从字符串中删除最后一个字符,在 ruby​​ 中? - 2

    啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组

  9. 键删除后 ruby​​ 哈希内存泄漏 - 2

    你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p

  10. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

随机推荐