109 lines
2.7 KiB
JavaScript
109 lines
2.7 KiB
JavaScript
import p5 from 'p5';
|
|
import './index.scss';
|
|
|
|
const FFT_SIZE = 256;
|
|
|
|
function getRMS(spectrum) {
|
|
let rms = 0;
|
|
for (let i = 0; i < spectrum.length; i++) {
|
|
rms += spectrum[i] * spectrum[i];
|
|
}
|
|
rms /= spectrum.length;
|
|
rms = Math.sqrt(rms);
|
|
return rms;
|
|
}
|
|
|
|
function getPitch(spectrum) {
|
|
let cg = 0;
|
|
let weight = 0;
|
|
for (let i = 0; i < spectrum.length; i++) {
|
|
cg += spectrum[i] * i;
|
|
weight += spectrum[i];
|
|
}
|
|
return Math.floor(cg / weight);
|
|
}
|
|
|
|
function getRandomX() {
|
|
return Math.floor(Math.random() * window.innerWidth);
|
|
}
|
|
|
|
function getRandomY() {
|
|
return Math.floor(Math.random() * window.innerHeight);
|
|
}
|
|
|
|
|
|
async function main() {
|
|
const audioCtx = new AudioContext();
|
|
const microphone = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
const analyser = new AnalyserNode(audioCtx);
|
|
analyser.smoothingTimeConstant = 0.2;
|
|
analyser.fftSize = FFT_SIZE;
|
|
|
|
let fresh = false;
|
|
let spectrum = [];
|
|
let pitch = 0;
|
|
let volume = 0;
|
|
let volumeThreshold = 0;
|
|
let bars = [];
|
|
|
|
const audioProcessor = audioCtx.createScriptProcessor(FFT_SIZE * 2, 1, 1);
|
|
audioProcessor.onaudioprocess = () => {
|
|
fresh = true;
|
|
// bitcount returns array which is half the FFT_SIZE
|
|
spectrum = new Uint8Array(analyser.frequencyBinCount);
|
|
|
|
// getByteFrequencyData returns amplitude for each bin
|
|
analyser.getByteFrequencyData(spectrum);
|
|
// getByteTimeDomainData gets volumes over the sample time
|
|
// analyser.getByteTimeDomainData(self.spectrum);
|
|
|
|
spectrum.reverse();
|
|
|
|
const currentVolume = getRMS(spectrum);
|
|
// get peak - a hack when our volumes are low
|
|
if (currentVolume > volumeThreshold) volumeThreshold = currentVolume;
|
|
volume = currentVolume;
|
|
pitch = getPitch(spectrum, volume, volumeThreshold);
|
|
}
|
|
|
|
const input = audioCtx.createMediaStreamSource(microphone);
|
|
input.connect(analyser);
|
|
analyser.connect(audioProcessor);
|
|
// audioProcessor.connect(audioCtx.destination);
|
|
|
|
const instance = new p5(( sketch ) => {
|
|
sketch.setup = () => {
|
|
sketch.createCanvas(window.innerWidth, window.innerHeight);
|
|
sketch.colorMode(sketch.HSL, 255);
|
|
};
|
|
|
|
sketch.draw = () => {
|
|
if (!fresh) {
|
|
return;
|
|
}
|
|
|
|
fresh = false;
|
|
sketch.background(sketch.color(0, 0, 0));
|
|
|
|
bars.push({
|
|
x: getRandomX(),
|
|
volume,
|
|
pitch,
|
|
age: 1,
|
|
});
|
|
const newBars = [];
|
|
for (const bar of bars) {
|
|
sketch.fill(sketch.color(0, (bar.volume / volumeThreshold) * 255, 255));
|
|
sketch.rect(bar.x, 0, bar.age * bar.volume * 2, window.innerHeight);
|
|
bar.age /= 2;
|
|
if (bar.age > 0.1) {
|
|
newBars.push(bar);
|
|
}
|
|
}
|
|
|
|
bars = newBars;
|
|
};
|
|
});
|
|
}
|
|
|
|
main();
|