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" "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",

View file

@ -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"
} }
} }

View file

@ -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;
export function draw(sketch) { spectrumPointHeight = 20;
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; line;
sketch.fill(`rgba(255, 255, 255, 0.2)`); fresh;
sketch.stroke(((line.pitch - minPitch) / (maxPitch - minPitch)) * 255); maxPitch;
sketch.strokeWeight(1); minPitch;
sketch.beginShape();
sketch.curveVertex(lineBaseWidth, -10); worker;
sketch.curveVertex(lineBaseWidth, -10); analyser;
sketch.curveVertex(lineBaseWidth, 0); audioProcessor;
for (let i = 1; i < line.spectrum.length - 1; i++) {
const point = line.spectrum[i]; constructor(audioCtx) {
sketch.curveVertex(lineBaseWidth + point, i * spectrumPointHeight); 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 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
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" }, { loader: "sass-loader" },
], ],
}, },
{
test: /\.worker\.js$/,
use: { loader: 'worker-loader' },
},
], ],
}, },
plugins: [ plugins: [