Average
This commit is contained in:
parent
5389f22ff2
commit
add2c28363
1083
package-lock.json
generated
1083
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -11,9 +11,15 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"p5": "^0.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.4.4",
|
||||
"@babel/plugin-transform-runtime": "^7.4.4",
|
||||
"@babel/preset-env": "^7.4.5",
|
||||
"babel-loader": "^8.0.6",
|
||||
"css-loader": "^2.1.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"node-sass": "^4.12.0",
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import Worker from './sound.worker.js';
|
||||
import { getRMS, getPitch } from './util.js';
|
||||
import { getSpectrumData } from './util.js';
|
||||
|
||||
export default class HorizontalLines {
|
||||
export default class HorizontalLinesAnimation {
|
||||
VOLUME_THRESHOLD = 20;
|
||||
LINE_MARGIN = 20;
|
||||
MAX_LINES = window.innerWidth / LINE_MARGIN;
|
||||
FFT_SIZE = 256;
|
||||
BASE_WIDTH = 2;
|
||||
BASE_WIDTH = 4;
|
||||
|
||||
spectrumPointHeight = 20;
|
||||
maxLines = 10;
|
||||
|
||||
line;
|
||||
fresh;
|
||||
maxPitch;
|
||||
minPitch;
|
||||
fresh = false;
|
||||
|
||||
averageSpectrum;
|
||||
|
||||
worker;
|
||||
analyser;
|
||||
|
@ -22,20 +22,28 @@ export default class HorizontalLines {
|
|||
constructor(audioCtx) {
|
||||
this.worker = new Worker();
|
||||
this.analyser = new AnalyserNode(audioCtx);
|
||||
this.analyser.fftSize = FFT_SIZE;
|
||||
this.analyser.fftSize = this.FFT_SIZE;
|
||||
this.audioProcessor = audioCtx.createScriptProcessor(this.FFT_SIZE * 2, 1, 1);
|
||||
audioProcessor.onaudioprocess = this.audioProcess;
|
||||
this.audioProcessor.onaudioprocess = () => this.audioProcess();
|
||||
this.analyser.connect(this.audioProcessor);
|
||||
this.worker.onmessage = e => this.getAverageData(e.data);
|
||||
}
|
||||
|
||||
setup(sketch) {
|
||||
sketch.colorMode(sketch.HSL, 255);
|
||||
sketch.colorMode(sketch.RGB, 255);
|
||||
sketch.background(0);
|
||||
this.resize();
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.spectrumPointHeight = window.innerHeight / this.analyser.frequencyBinCount;
|
||||
this.maxLines = window.innerWidth / this.LINE_MARGIN;
|
||||
}
|
||||
|
||||
getAverageData(data) {
|
||||
this.averageSpectrum = data.averageSpectrum;
|
||||
console.log('got average');
|
||||
console.log(this.averageSpectrum);
|
||||
}
|
||||
|
||||
audioProcess() {
|
||||
|
@ -44,21 +52,9 @@ export default class HorizontalLines {
|
|||
|
||||
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;
|
||||
}
|
||||
const data = getSpectrumData(spectrum);
|
||||
this.worker.postMessage(data);
|
||||
this.line = data;
|
||||
|
||||
this.fresh = true;
|
||||
}
|
||||
|
@ -76,21 +72,26 @@ export default class HorizontalLines {
|
|||
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.stroke(255, 255, 255);
|
||||
sketch.strokeWeight(1);
|
||||
sketch.beginShape();
|
||||
sketch.curveVertex(lineBaseWidth, -10);
|
||||
sketch.curveVertex(lineBaseWidth, -10);
|
||||
sketch.curveVertex(lineBaseWidth, 0);
|
||||
sketch.curveVertex(this.BASE_WIDTH, -10);
|
||||
sketch.curveVertex(this.BASE_WIDTH, -10);
|
||||
sketch.curveVertex(this.BASE_WIDTH, 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);
|
||||
let point;
|
||||
if (this.averageSpectrum) {
|
||||
point = Math.max(this.line.spectrum[i] - (this.averageSpectrum[i] * 0.8), 0);
|
||||
// point = 5 * (this.line.spectrum[i] / this.averageSpectrum[i]);
|
||||
} else {
|
||||
point = this.line.spectrum[i];
|
||||
}
|
||||
sketch.curveVertex(this.BASE_WIDTH + point, i * this.spectrumPointHeight);
|
||||
}
|
||||
sketch.curveVertex(lineBaseWidth, window.innerHeight);
|
||||
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
|
||||
sketch.curveVertex(lineBaseWidth, window.innerHeight + 10);
|
||||
sketch.curveVertex(this.BASE_WIDTH, window.innerHeight);
|
||||
sketch.curveVertex(this.BASE_WIDTH, window.innerHeight + 10);
|
||||
sketch.curveVertex(this.BASE_WIDTH, window.innerHeight + 10);
|
||||
sketch.endShape();
|
||||
}
|
||||
}
|
||||
|
|
26
src/index.js
26
src/index.js
|
@ -1,22 +1,34 @@
|
|||
import p5 from 'p5';
|
||||
import './index.scss';
|
||||
|
||||
import HorizontalLines from './horizontal-lines.js';
|
||||
import HorizontalLinesAnimation from './horizontal-lines.js';
|
||||
import SquaresAnimation from './squares.js';
|
||||
|
||||
async function main() {
|
||||
const audioCtx = new AudioContext();
|
||||
const microphone = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
const input = audioCtx.createMediaStreamSource(microphone);
|
||||
|
||||
let activeAnimation;
|
||||
|
||||
const instance = new p5(( sketch ) => {
|
||||
let activeAnimation;
|
||||
|
||||
window.onresize = () => {
|
||||
sketch.resizeCanvas(window.innerWidth, window.innerHeight);
|
||||
activeAnimation.resize();
|
||||
};
|
||||
|
||||
function activate(animation) {
|
||||
activeAnimation = animation;
|
||||
input.connect(animation.analyser);
|
||||
animation.setup(sketch);
|
||||
}
|
||||
|
||||
sketch.setup = () => {
|
||||
sketch.createCanvas(window.innerWidth, window.innerHeight);
|
||||
|
||||
const horizontalLines = new HorizontalLines(analyser, sketch);
|
||||
activeAnimation = horizontalLines;
|
||||
input.connect(activeAnimation.analyser);
|
||||
const horizontalLines = new HorizontalLinesAnimation(audioCtx);
|
||||
const squares = new SquaresAnimation(audioCtx);
|
||||
activate(horizontalLines);
|
||||
};
|
||||
|
||||
sketch.draw = () => {
|
||||
|
@ -24,7 +36,7 @@ async function main() {
|
|||
};
|
||||
|
||||
setTimeout(() => {
|
||||
activactiveAnimation =
|
||||
// activactiveAnimation =
|
||||
}, 1 * 60 * 1000);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,26 +1,33 @@
|
|||
const PERIOD = 60 * 1000;
|
||||
const PERIOD = 20 * 1000;
|
||||
const data = [];
|
||||
let firstRun = true;
|
||||
|
||||
function onDataPoint(event) {
|
||||
console.log(event);
|
||||
if (!firstRun) {
|
||||
data.shift();
|
||||
}
|
||||
data.push(event.data);
|
||||
}
|
||||
|
||||
self.addEventListener('message', onDataPoint);
|
||||
self.onmessage = onDataPoint;
|
||||
|
||||
function calculateAndSend() {
|
||||
firstRun = false;
|
||||
|
||||
if (!data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let averagePitch = 0;
|
||||
let averageVolume = 0;
|
||||
let averageSpectrum = [];
|
||||
let averageSpectrum = (new Array(data[0].spectrum.length)).fill(0);
|
||||
|
||||
let minPitch = data[0].spectrum.length;
|
||||
let maxPitch = 0;
|
||||
let minPitch = spectrum.length;
|
||||
let maxVolume = 0;
|
||||
let minVolume = 500;
|
||||
let maxVolume = 0;
|
||||
|
||||
for (const { volume, pitch, spectrum } in data) {
|
||||
for (const { volume, pitch, spectrum } of data) {
|
||||
if (pitch > maxPitch) {
|
||||
maxPitch = pitch;
|
||||
} else if (pitch < minPitch) {
|
||||
|
@ -43,7 +50,7 @@ function calculateAndSend() {
|
|||
|
||||
averageVolume /= data.length;
|
||||
averagePitch /= data.length;
|
||||
averageSpectrum = averageSpectrum.map(p => p / spectrum.length);
|
||||
averageSpectrum = averageSpectrum.map(p => p / data.length);
|
||||
|
||||
self.postMessage({
|
||||
minVolume,
|
||||
|
|
124
src/squares.js
124
src/squares.js
|
@ -1,37 +1,101 @@
|
|||
const VOLUME_THRESHOLD = 20;
|
||||
const GRID_SIZE = 20;
|
||||
const MAX_WIDTH = 5;
|
||||
const MAX_HEIGHT = 8;
|
||||
const FFT_SIZE = 1024;
|
||||
import Worker from './sound.worker.js';
|
||||
import { getSpectrumData, getRandomBetween } from './util.js';
|
||||
|
||||
export function setup(sketch, analyser) {
|
||||
sketch.background('rgb(20, 30, 30)');
|
||||
sketch.colorMode(sketch.HSB);
|
||||
analyser.fftSize = FFT_SIZE;
|
||||
}
|
||||
export default class SquaresAnimation {
|
||||
VOLUME_THRESHOLD = 20;
|
||||
GRID_SIZE = 20;
|
||||
MAX_WIDTH = 5;
|
||||
MAX_HEIGHT = 8;
|
||||
FFT_SIZE = 1024;
|
||||
|
||||
export function draw(sketch) {
|
||||
sketch.background('rgba(20, 30, 30, 0.01)');
|
||||
if (!circle) {
|
||||
return;
|
||||
worker;
|
||||
analyser;
|
||||
audioProcessor;
|
||||
|
||||
minVolume = 360;
|
||||
maxVolume = 0;
|
||||
minPitch = 360;
|
||||
maxPitch = 0;
|
||||
|
||||
circle;
|
||||
fresh = false;
|
||||
|
||||
constructor(audioCtx) {
|
||||
this.worker = new Worker();
|
||||
this.analyser = new AnalyserNode(audioCtx);
|
||||
this.analyser.fftSize = this.FFT_SIZE;
|
||||
this.audioProcessor = audioCtx.createScriptProcessor(this.FFT_SIZE * 2, 1, 1);
|
||||
this.audioProcessor.onaudioprocess = () => this.audioProcess();
|
||||
this.analyser.connect(this.audioProcessor);
|
||||
this.worker.onmessage = e => this.getAverageData(e.data);
|
||||
}
|
||||
|
||||
const color = ((circle.pitch - minPitch) / (maxPitch - minPitch)) * 360;
|
||||
const brightness = ((circle.volume - minVolume) / (maxVolume - minVolume));
|
||||
sketch.stroke(color, 100, 100, brightness);
|
||||
for (let i = 0; i < circle.spectrum.length + 2; i++) {
|
||||
const p = circle.spectrum[i - 2] * i * i * i * i / 2;
|
||||
const x = getRandomBetween(0, Math.floor(window.innerWidth / GRID_SIZE)) * GRID_SIZE;
|
||||
const y = getRandomBetween(0, Math.floor(window.innerHeight / GRID_SIZE)) * GRID_SIZE;
|
||||
// const width = getRandomBetween(1, MAX_WIDTH) * GRID_SIZE;
|
||||
// const height = getRandomBetween(1, MAX_HEIGHT) * GRID_SIZE;
|
||||
setup(sketch) {
|
||||
sketch.background('rgb(20, 30, 30)');
|
||||
sketch.colorMode(sketch.HSB);
|
||||
this.resize();
|
||||
}
|
||||
|
||||
resize() {}
|
||||
|
||||
getAverageData(data) {
|
||||
this.minVolume = data.minVolume;
|
||||
this.maxVolume = data.maxVolume;
|
||||
|
||||
this.minPitch = data.minPitch;
|
||||
this.maxPitch = data.maxPitch;
|
||||
}
|
||||
|
||||
audioProcess() {
|
||||
const spectrum = new Uint8Array(this.analyser.frequencyBinCount);
|
||||
this.analyser.getByteFrequencyData(spectrum);
|
||||
|
||||
spectrum.reverse();
|
||||
|
||||
const data = getSpectrumData(spectrum);
|
||||
const { volume, pitch } = data;
|
||||
this.worker.postMessage(data);
|
||||
|
||||
if (volume > this.maxVolume) {
|
||||
this.maxVolume = volume;
|
||||
}
|
||||
|
||||
if (volume !== 0 && volume < this.minVolume) {
|
||||
this.minVolume = volume;
|
||||
}
|
||||
|
||||
if (pitch > this.maxPitch) {
|
||||
this.maxPitch = pitch;
|
||||
}
|
||||
|
||||
if (pitch < this.minPitch) {
|
||||
this.minPitch = pitch;
|
||||
}
|
||||
|
||||
this.circle = data;
|
||||
this.fresh = true;
|
||||
}
|
||||
|
||||
draw(sketch) {
|
||||
sketch.background('rgba(20, 30, 30, 0.01)');
|
||||
if (!this.fresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
const color = ((this.circle.pitch - this.minPitch) / (this.maxPitch - this.minPitch)) * 360;
|
||||
const brightness = ((this.circle.volume - this.minVolume) / (this.maxVolume - this.minVolume));
|
||||
sketch.stroke(color, 100, 100, brightness);
|
||||
for (let i = 0; i < spectrum.length + 2; i++) {
|
||||
const x = getRandomBetween(0, Math.floor(window.innerWidth / this.GRID_SIZE)) * this.GRID_SIZE;
|
||||
const y = getRandomBetween(0, Math.floor(window.innerHeight / this.GRID_SIZE)) * this.GRID_SIZE;
|
||||
sketch.fill(color, 100, 100, brightness * 0.5);
|
||||
sketch.beginShape();
|
||||
sketch.vertex(x, y);
|
||||
sketch.vertex(x, y + GRID_SIZE);
|
||||
sketch.vertex(x + GRID_SIZE, y + GRID_SIZE);
|
||||
sketch.vertex(x + GRID_SIZE, y);
|
||||
sketch.vertex(x, y);
|
||||
sketch.endShape();
|
||||
sketch.beginShape();
|
||||
sketch.vertex(x, y);
|
||||
sketch.vertex(x, y + this.GRID_SIZE);
|
||||
sketch.vertex(x + this.GRID_SIZE, y + this.GRID_SIZE);
|
||||
sketch.vertex(x + this.GRID_SIZE, y);
|
||||
sketch.vertex(x, y);
|
||||
sketch.endShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
29
src/util.js
29
src/util.js
|
@ -1,24 +1,29 @@
|
|||
export function getRMS(spectrum) {
|
||||
export function getSpectrumData(spectrum) {
|
||||
let highestPitch = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
export function getPitch(spectrum) {
|
||||
let cg = 0;
|
||||
let weight = 0;
|
||||
for (let i = 0; i < spectrum.length; i++) {
|
||||
rms += spectrum[i] * spectrum[i];
|
||||
cg += spectrum[i] * i;
|
||||
weight += spectrum[i];
|
||||
if (spectrum[i] > highestPitch) {
|
||||
highestPitch = spectrum[i];
|
||||
}
|
||||
}
|
||||
return Math.floor(cg / weight);
|
||||
rms /= spectrum.length;
|
||||
rms = Math.sqrt(rms);
|
||||
const pitch = Math.floor(cg / weight);
|
||||
return {
|
||||
spectrum,
|
||||
volume: rms,
|
||||
pitch,
|
||||
highestPitch,
|
||||
};
|
||||
}
|
||||
|
||||
function getRandomBetween(min, max) {
|
||||
|
||||
export function getRandomBetween(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ module.exports = {
|
|||
entry: './src/index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bundle.js'
|
||||
filename: 'bundle.js',
|
||||
globalObject: `typeof self !== 'undefined' ? self : this`,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
|
@ -17,6 +18,23 @@ module.exports = {
|
|||
{ loader: "sass-loader" },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env'],
|
||||
plugins: [
|
||||
'@babel/plugin-transform-runtime',
|
||||
[
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
{ loose: true },
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.worker\.js$/,
|
||||
use: { loader: 'worker-loader' },
|
||||
|
|
Loading…
Reference in a new issue