More work on combined state

This commit is contained in:
Benjamin Bädorf 2019-06-14 12:45:35 +02:00
parent b9483fbcf0
commit 5389f22ff2
6 changed files with 194 additions and 82 deletions

22
package-lock.json generated
View file

@ -6996,6 +6996,28 @@
"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": {
"version": "2.1.0",
"resolved": "http://localhost:4873/wrap-ansi/-/wrap-ansi-2.1.0.tgz",

View file

@ -21,6 +21,7 @@
"style-loader": "^0.23.1",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.3",
"webpack-dev-server": "^3.7.1"
"webpack-dev-server": "^3.7.1",
"worker-loader": "^2.0.0"
}
}

View file

@ -1,35 +1,96 @@
const VOLUME_THRESHOLD = 20;
const LINE_MARGIN = 20;
const MAX_LINES = window.innerWidth / LINE_MARGIN;
const FFT_SIZE = 256;
import Worker from './sound.worker.js';
import { getRMS, getPitch } from './util.js';
export function setup(sketch, analyser) {
sketch.colorMode(sketch.HSL, 255);
sketch.background(0);
analyser.fftSize = FFT_SIZE;
}
export default class HorizontalLines {
VOLUME_THRESHOLD = 20;
LINE_MARGIN = 20;
MAX_LINES = window.innerWidth / LINE_MARGIN;
FFT_SIZE = 256;
BASE_WIDTH = 2;
export function draw(sketch) {
const image = sketch.drawingContext.getImageData(0, 0, (window.innerWidth - LINE_MARGIN) * 2, window.innerHeight * 2);
sketch.drawingContext.putImageData(image, LINE_MARGIN * 2, 0);
sketch.noStroke();
sketch.fill(0);
sketch.rect(0, 0, LINE_MARGIN, window.innerHeight);
const lineBaseWidth = baseWidth;
sketch.fill(`rgba(255, 255, 255, 0.2)`);
sketch.stroke(((line.pitch - minPitch) / (maxPitch - minPitch)) * 255);
sketch.strokeWeight(1);
sketch.beginShape();
sketch.curveVertex(lineBaseWidth, -10);
sketch.curveVertex(lineBaseWidth, -10);
sketch.curveVertex(lineBaseWidth, 0);
for (let i = 1; i < line.spectrum.length - 1; i++) {
const point = line.spectrum[i];
sketch.curveVertex(lineBaseWidth + point, i * spectrumPointHeight);
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);
}
setup(sketch) {
sketch.colorMode(sketch.HSL, 255);
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.fill(0);
sketch.rect(0, 0, this.LINE_MARGIN, window.innerHeight);
const lineBaseWidth = this.BASE_WIDTH;
sketch.fill(`rgba(255, 255, 255, 0.2)`);
sketch.stroke(((this.line.pitch - this.minPitch) / (this.maxPitch - this.minPitch)) * 255);
sketch.strokeWeight(1);
sketch.beginShape();
sketch.curveVertex(lineBaseWidth, -10);
sketch.curveVertex(lineBaseWidth, -10);
sketch.curveVertex(lineBaseWidth, 0);
for (let i = 1; i < this.line.spectrum.length - 1; i++) {
const point = this.line.spectrum[i];
sketch.curveVertex(lineBaseWidth + point, i * this.spectrumPointHeight);
}
sketch.curveVertex(lineBaseWidth, window.innerHeight);
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
sketch.endShape();
}
sketch.curveVertex(lineBaseWidth, window.innerHeight);
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
sketch.endShape();
}

View file

@ -1,68 +1,31 @@
import p5 from 'p5';
import './index.scss';
import HorizontalLines from './horizontal-lines.js';
async function main() {
const audioCtx = new AudioContext();
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);
input.connect(analyser);
analyser.connect(audioProcessor);
// audioProcessor.connect(audioCtx.destination);
const baseWidth = 2;
const spectrumPointHeight = window.innerHeight / analyser.frequencyBinCount;
let activeAnimation;
const instance = new p5(( sketch ) => {
sketch.setup = () => {
sketch.createCanvas(window.innerWidth, window.innerHeight);
const horizontalLines = new HorizontalLines(analyser, sketch);
activeAnimation = horizontalLines;
input.connect(activeAnimation.analyser);
};
sketch.draw = () => {
if (!fresh) {
return;
}
fresh = false;
activeAnimation.draw(sketch);
};
setTimeout(() => {
activactiveAnimation =
}, 1 * 60 * 1000);
});
}

61
src/sound.worker.js Normal file
View 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);

View file

@ -17,6 +17,10 @@ module.exports = {
{ loader: "sass-loader" },
],
},
{
test: /\.worker\.js$/,
use: { loader: 'worker-loader' },
},
],
},
plugins: [