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 <...