More work on combined state
This commit is contained in:
parent
b9483fbcf0
commit
5389f22ff2
22
package-lock.json
generated
22
package-lock.json
generated
|
@ -6996,6 +6996,28 @@
|
||||||
"errno": "~0.1.7"
|
"errno": "~0.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"worker-loader": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "http://localhost:4873/worker-loader/-/worker-loader-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"loader-utils": "^1.0.0",
|
||||||
|
"schema-utils": "^0.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"schema-utils": {
|
||||||
|
"version": "0.4.7",
|
||||||
|
"resolved": "http://localhost:4873/schema-utils/-/schema-utils-0.4.7.tgz",
|
||||||
|
"integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ajv": "^6.1.0",
|
||||||
|
"ajv-keywords": "^3.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "http://localhost:4873/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
"resolved": "http://localhost:4873/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"webpack": "^4.33.0",
|
"webpack": "^4.33.0",
|
||||||
"webpack-cli": "^3.3.3",
|
"webpack-cli": "^3.3.3",
|
||||||
"webpack-dev-server": "^3.7.1"
|
"webpack-dev-server": "^3.7.1",
|
||||||
|
"worker-loader": "^2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,96 @@
|
||||||
const VOLUME_THRESHOLD = 20;
|
import Worker from './sound.worker.js';
|
||||||
const LINE_MARGIN = 20;
|
import { getRMS, getPitch } from './util.js';
|
||||||
const MAX_LINES = window.innerWidth / LINE_MARGIN;
|
|
||||||
const FFT_SIZE = 256;
|
|
||||||
|
|
||||||
export function setup(sketch, analyser) {
|
export default class HorizontalLines {
|
||||||
sketch.colorMode(sketch.HSL, 255);
|
VOLUME_THRESHOLD = 20;
|
||||||
sketch.background(0);
|
LINE_MARGIN = 20;
|
||||||
analyser.fftSize = FFT_SIZE;
|
MAX_LINES = window.innerWidth / LINE_MARGIN;
|
||||||
|
FFT_SIZE = 256;
|
||||||
|
BASE_WIDTH = 2;
|
||||||
|
|
||||||
|
spectrumPointHeight = 20;
|
||||||
|
|
||||||
|
line;
|
||||||
|
fresh;
|
||||||
|
maxPitch;
|
||||||
|
minPitch;
|
||||||
|
|
||||||
|
worker;
|
||||||
|
analyser;
|
||||||
|
audioProcessor;
|
||||||
|
|
||||||
|
constructor(audioCtx) {
|
||||||
|
this.worker = new Worker();
|
||||||
|
this.analyser = new AnalyserNode(audioCtx);
|
||||||
|
this.analyser.fftSize = FFT_SIZE;
|
||||||
|
this.audioProcessor = audioCtx.createScriptProcessor(this.FFT_SIZE * 2, 1, 1);
|
||||||
|
audioProcessor.onaudioprocess = this.audioProcess;
|
||||||
|
this.analyser.connect(this.audioProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function draw(sketch) {
|
setup(sketch) {
|
||||||
const image = sketch.drawingContext.getImageData(0, 0, (window.innerWidth - LINE_MARGIN) * 2, window.innerHeight * 2);
|
sketch.colorMode(sketch.HSL, 255);
|
||||||
sketch.drawingContext.putImageData(image, LINE_MARGIN * 2, 0);
|
sketch.background(0);
|
||||||
|
this.resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
resize() {
|
||||||
|
this.spectrumPointHeight = window.innerHeight / this.analyser.frequencyBinCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioProcess() {
|
||||||
|
const spectrum = new Uint8Array(this.analyser.frequencyBinCount);
|
||||||
|
this.analyser.getByteFrequencyData(spectrum);
|
||||||
|
|
||||||
|
spectrum.reverse();
|
||||||
|
|
||||||
|
const volume = getRMS(spectrum);
|
||||||
|
const pitch = getPitch(spectrum, volume);
|
||||||
|
this.line = {
|
||||||
|
spectrum,
|
||||||
|
volume,
|
||||||
|
pitch,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pitch > this.maxPitch) {
|
||||||
|
this.maxPitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pitch < this.minPitch) {
|
||||||
|
this.minPitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw(sketch) {
|
||||||
|
if (!this.fresh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fresh = false;
|
||||||
|
|
||||||
|
const image = sketch.drawingContext.getImageData(0, 0, (window.innerWidth - this.LINE_MARGIN) * 2, window.innerHeight * 2);
|
||||||
|
sketch.drawingContext.putImageData(image, this.LINE_MARGIN * 2, 0);
|
||||||
sketch.noStroke();
|
sketch.noStroke();
|
||||||
sketch.fill(0);
|
sketch.fill(0);
|
||||||
sketch.rect(0, 0, LINE_MARGIN, window.innerHeight);
|
sketch.rect(0, 0, this.LINE_MARGIN, window.innerHeight);
|
||||||
|
|
||||||
const lineBaseWidth = baseWidth;
|
const lineBaseWidth = this.BASE_WIDTH;
|
||||||
sketch.fill(`rgba(255, 255, 255, 0.2)`);
|
sketch.fill(`rgba(255, 255, 255, 0.2)`);
|
||||||
sketch.stroke(((line.pitch - minPitch) / (maxPitch - minPitch)) * 255);
|
sketch.stroke(((this.line.pitch - this.minPitch) / (this.maxPitch - this.minPitch)) * 255);
|
||||||
sketch.strokeWeight(1);
|
sketch.strokeWeight(1);
|
||||||
sketch.beginShape();
|
sketch.beginShape();
|
||||||
sketch.curveVertex(lineBaseWidth, -10);
|
sketch.curveVertex(lineBaseWidth, -10);
|
||||||
sketch.curveVertex(lineBaseWidth, -10);
|
sketch.curveVertex(lineBaseWidth, -10);
|
||||||
sketch.curveVertex(lineBaseWidth, 0);
|
sketch.curveVertex(lineBaseWidth, 0);
|
||||||
for (let i = 1; i < line.spectrum.length - 1; i++) {
|
for (let i = 1; i < this.line.spectrum.length - 1; i++) {
|
||||||
const point = line.spectrum[i];
|
const point = this.line.spectrum[i];
|
||||||
sketch.curveVertex(lineBaseWidth + point, i * spectrumPointHeight);
|
sketch.curveVertex(lineBaseWidth + point, i * this.spectrumPointHeight);
|
||||||
}
|
}
|
||||||
sketch.curveVertex(lineBaseWidth, window.innerHeight);
|
sketch.curveVertex(lineBaseWidth, window.innerHeight);
|
||||||
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
|
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
|
||||||
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
|
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
|
||||||
sketch.endShape();
|
sketch.endShape();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
63
src/index.js
63
src/index.js
|
@ -1,68 +1,31 @@
|
||||||
import p5 from 'p5';
|
import p5 from 'p5';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
|
import HorizontalLines from './horizontal-lines.js';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const audioCtx = new AudioContext();
|
const audioCtx = new AudioContext();
|
||||||
const microphone = await navigator.mediaDevices.getUserMedia({ audio: true });
|
const microphone = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||||
const analyser = new AnalyserNode(audioCtx);
|
|
||||||
analyser.smoothingTimeConstant = 0.2;
|
|
||||||
|
|
||||||
let line;
|
|
||||||
let fresh = false;
|
|
||||||
let maxPitch = 0;
|
|
||||||
let minPitch = 0;
|
|
||||||
|
|
||||||
const audioProcessor = audioCtx.createScriptProcessor(FFT_SIZE * 2, 1, 1);
|
|
||||||
audioProcessor.onaudioprocess = () => {
|
|
||||||
// bitcount returns array which is half the FFT_SIZE
|
|
||||||
const 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 volume = getRMS(spectrum);
|
|
||||||
const pitch = getPitch(spectrum, volume);
|
|
||||||
line = {
|
|
||||||
spectrum,
|
|
||||||
volume,
|
|
||||||
pitch,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (pitch > maxPitch) {
|
|
||||||
maxPitch = pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pitch < minPitch) {
|
|
||||||
minPitch = pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
fresh = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const input = audioCtx.createMediaStreamSource(microphone);
|
const input = audioCtx.createMediaStreamSource(microphone);
|
||||||
input.connect(analyser);
|
|
||||||
analyser.connect(audioProcessor);
|
let activeAnimation;
|
||||||
// audioProcessor.connect(audioCtx.destination);
|
|
||||||
const baseWidth = 2;
|
|
||||||
const spectrumPointHeight = window.innerHeight / analyser.frequencyBinCount;
|
|
||||||
|
|
||||||
const instance = new p5(( sketch ) => {
|
const instance = new p5(( sketch ) => {
|
||||||
sketch.setup = () => {
|
sketch.setup = () => {
|
||||||
sketch.createCanvas(window.innerWidth, window.innerHeight);
|
sketch.createCanvas(window.innerWidth, window.innerHeight);
|
||||||
|
|
||||||
|
const horizontalLines = new HorizontalLines(analyser, sketch);
|
||||||
|
activeAnimation = horizontalLines;
|
||||||
|
input.connect(activeAnimation.analyser);
|
||||||
};
|
};
|
||||||
|
|
||||||
sketch.draw = () => {
|
sketch.draw = () => {
|
||||||
if (!fresh) {
|
activeAnimation.draw(sketch);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fresh = false;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
activactiveAnimation =
|
||||||
|
}, 1 * 60 * 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
61
src/sound.worker.js
Normal file
61
src/sound.worker.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
const PERIOD = 60 * 1000;
|
||||||
|
const data = [];
|
||||||
|
let firstRun = true;
|
||||||
|
|
||||||
|
function onDataPoint(event) {
|
||||||
|
console.log(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addEventListener('message', onDataPoint);
|
||||||
|
|
||||||
|
function calculateAndSend() {
|
||||||
|
firstRun = false;
|
||||||
|
|
||||||
|
let averagePitch = 0;
|
||||||
|
let averageVolume = 0;
|
||||||
|
let averageSpectrum = [];
|
||||||
|
|
||||||
|
let maxPitch = 0;
|
||||||
|
let minPitch = spectrum.length;
|
||||||
|
let maxVolume = 0;
|
||||||
|
let minVolume = 500;
|
||||||
|
|
||||||
|
for (const { volume, pitch, spectrum } in data) {
|
||||||
|
if (pitch > maxPitch) {
|
||||||
|
maxPitch = pitch;
|
||||||
|
} else if (pitch < minPitch) {
|
||||||
|
minPitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (volume > maxVolume) {
|
||||||
|
maxVolume = volume;
|
||||||
|
} else if (volume < minVolume) {
|
||||||
|
minVolume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
averageVolume += volume;
|
||||||
|
averagePitch += pitch;
|
||||||
|
|
||||||
|
for (let i = 0; i < spectrum.length; i++) {
|
||||||
|
averageSpectrum[i] += spectrum[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
averageVolume /= data.length;
|
||||||
|
averagePitch /= data.length;
|
||||||
|
averageSpectrum = averageSpectrum.map(p => p / spectrum.length);
|
||||||
|
|
||||||
|
self.postMessage({
|
||||||
|
minVolume,
|
||||||
|
averageVolume,
|
||||||
|
maxVolume,
|
||||||
|
|
||||||
|
minPitch,
|
||||||
|
averagePitch,
|
||||||
|
maxPitch,
|
||||||
|
|
||||||
|
averageSpectrum,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(calculateAndSend, PERIOD);
|
|
@ -17,6 +17,10 @@ module.exports = {
|
||||||
{ loader: "sass-loader" },
|
{ loader: "sass-loader" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.worker\.js$/,
|
||||||
|
use: { loader: 'worker-loader' },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|
Loading…
Reference in a new issue