12

I'm trying to create a project that pulls in a live stream audio file from the internet and continuously samples the audio looking for the most dominant frequency for a given time period. The idea is that if it detects a frequency of let's say 440Hz over a period of time (a few seconds) that means that a particular tone was played on the live stream. Once it detects a particular tone I'll have it do some other stuff in the program. The live stream is either talking, a single tone, or silence.

I was able to do this and got a proof of concept working reading a file I generated from an online tone generator. When I pass in that file it correctly identifies the frequency (it's off by only 1 or 2 Hz). When I pull in the live stream I get frequency data that's something like: 17704Hz. My guess is that it's from the "noise" of the live stream.

I'm using the npm modules node-pitchfinder and audio-analyer to do most of the processing

Any ideas on how to get a single tone?

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)
    }
}
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Bill
  • 5,478
  • 17
  • 62
  • 95
  • You may have to put a filter in front of the pitch detection module to filter out all of the frequencies except the one of interest. Your frequency of interest isn't necessarily the dominant one unless it is very loud. – Robert Harvey Dec 08 '18 at 16:19
  • Thanks for the suggestion. The problem is I don't know which frequency I want until i hear it. What i'm basically "listening" for is a tone or beep that lasts about 3 seconds – Bill Dec 08 '18 at 17:07
  • You may find [cepstral analysis](https://en.wikipedia.org/wiki/Cepstrum) worth looking into. – Sami Hult Dec 08 '18 at 19:17
  • You might want to change your sample rate to a higher one. Your detected frequency might result from aliasing. – yunzen Dec 20 '18 at 07:44

1 Answers1

1

You may need to:

  • Apply a Noise Reduction effect to filter out the noise from the audio source (take a look at noise-gate package)

  • Use compressor and/or limiter to optimize your sound before treatment (take a look at audio-object

Before audio signal treatment.

A. STEFANI
  • 6,707
  • 1
  • 23
  • 48