Saturday, 15 December 2018

Remove high frequency sound from streaming audio node js

I have a small app that accepts incoming audio stream from the internet and I'm trying to find the frequency of a tone or continuous beep. At the time of the tone / beep it is the only thing that would be playing. The rest of the audio is either silence or talking. I'm using the node-pitchfinder npm module to find the tone and when I use a sample audio clip I made of 2,000Hz the app prints out the frequency within one or two Hz. When I pull the audio stream online I keep getting results like 17,000 Hz. My guess is that there is some "noise" in the audio signal and that's what the node-pitchfinder module is picking up.

Is there any way I can filter out that noise in real time to get an accurate frequency?

The streaming audio file is: http://relay.broadcastify.com/fq85hty701gnm4z.mp3

Code below:

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)
        }
}

My goal is to find the most dominant audio frequency in a chunk of data so I can figure out the tone.

I found some code that supposedly does this with 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)


from Remove high frequency sound from streaming audio node js

No comments:

Post a Comment