JSFiddle - React, Tailwind, and code Playground

by szimek

HTML

<div>
    <div>Input frequency: <strong id="input_frequency"></strong></div>
    <div>Output frequency: <strong id="output_frequency"></strong></div>
</div>

<h2>Input signal</h2>
<canvas id="input"></canvas>

<h2>Autocorrelated signal</h2>
<canvas id="xcorr"></canvas>

CSS

canvas {
    background-color: #111;
}

JavaScript

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
window.AudioContext = window.AudioContext || window.webkitAudioContext;

FREQUENCY = 120;

var PitchAnalyser = function () {
    this.context  = new AudioContext();
    this.analyser = this.context.createAnalyser();
    
    this.analyser.fftSize = 2048;
    this.analyser.smoothingTimeConstant = 0.0;
    
    // Buffer for time domain data
    this.buffer = new Uint8Array(this.analyser.fftSize);

    // Generate sine wave with custom frequency
    this.source = this.context.createOscillator();
    this.source.frequency.value = FREQUENCY;
    this.source.start(0);
    
    this.source.connect(this.analyser);
};

PitchAnalyser.prototype.getPitch = function () {
    console.time("Get pitch");

    var corr = new Float32Array(this.buffer.length),
        locations, diffs, freq;

    this.analyser.getByteTimeDomainData(this.buffer);

    // Perform autocorrelation on input signal
    xcorr(this.buffer, corr);
    
    // Find peaks
    locations = findpeaks(corr);

    // Calculate frequency from mean value of distances between peaks
    diffs = diff(locations);
    freq = this.context.sampleRate / mean(diffs);

    console.timeEnd("Get pitch");

    display("input", this.buffer);
    display("xcorr", corr);
    document.getElementById("input_frequency").innerText =      this.source.frequency.value;
+ "Hz";
    document.getElementById("output_frequency").innerText = freq + "Hz";

    
    return {
        frequency: freq,
        volume: 0
    };
};

/// Lame MATLAB/Octave-like functions
function xcorr(input, output) {
    var n = input.length,
        norm, sum,  i, j;
    
    for (i = 0; i < n; i++) {
        sum = 0;
        for (j = 0; j < n; j++) {
            sum += (input[j] * (input[j+i] || 0)); // Pad input with zeroes
        }
        if (i === 0) norm = sum;
        output[i] = sum / norm;
    }
}

function findpeaks(data) {
    var locations = [0];

    for (var i = 1; i <...