add shapes animation
This commit is contained in:
parent
4b38f48f37
commit
db822f35c0
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/node_modules/
|
||||
tags
|
||||
|
|
8
shell.nix
Normal file
8
shell.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.python3
|
||||
pkgs.nodejs
|
||||
];
|
||||
}
|
61
src/birds.js
Normal file
61
src/birds.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { getSpectrumData, getRandomBetween } from './util.js';
|
||||
|
||||
const BIRD_NUM = 300;
|
||||
|
||||
export default class BirdsAnimation {
|
||||
maxX;
|
||||
maxY;
|
||||
|
||||
birds = [];
|
||||
|
||||
constructor() { }
|
||||
|
||||
start(sketch) {
|
||||
this.resize();
|
||||
|
||||
this.worker = new Worker();
|
||||
this.worker.onmessage = e => this.onBirdPositions(e.data);
|
||||
this.worker.postMessage({
|
||||
maxX: this.maxX,
|
||||
maxY: this.maxY,
|
||||
});
|
||||
|
||||
sketch.background(0);
|
||||
sketch.colorMode(sketch.HSB);
|
||||
}
|
||||
|
||||
onBirdPositions(data) {
|
||||
this.birds = data.birds;
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.maxX = window.innerWidth;
|
||||
this.maxY = window.innerHeight;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.worker.terminate();
|
||||
}
|
||||
|
||||
draw(sketch) {
|
||||
sketch.background('rgba(0, 0, 0, 0.20)');
|
||||
|
||||
const brightness = ((this.data.volume - this.minVolume) / (this.maxVolume - this.minVolume)) * 80;
|
||||
const color = ((this.data.pitch - this.minPitch) / (this.maxPitch - this.minPitch)) * 360;
|
||||
for (let i = 0; i < brightness; i++) {
|
||||
const p = this.data.spectrum[i];
|
||||
sketch.stroke(color, 100, 100);
|
||||
|
||||
sketch.fill(color, 100, brightness);
|
||||
const x = getRandomBetween(0, this.maxX) * this.GRID_SIZE;
|
||||
const y = getRandomBetween(0, this.maxY) * this.GRID_SIZE;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
47
src/birds.worker.js
Normal file
47
src/birds.worker.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import Worker from './birds.worker.js';
|
||||
|
||||
const STEP_TIME = 10;
|
||||
const
|
||||
const data = {};
|
||||
|
||||
function onInitialData(event) {
|
||||
data.maxX = event.maxX;
|
||||
data.maxY = event.maxY;
|
||||
|
||||
for (let i = 0; i < BIRD_NUM; i += 1) {
|
||||
data.birds.push({
|
||||
x: getRandomBetween(0, data.maxX),
|
||||
y: getRandomBetween(0, data.maxY),
|
||||
r: getRandomBetween(0, 360),
|
||||
v: getRandomBetween(1, 10),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.onmessage = onInitialData;
|
||||
|
||||
function calculateAndSend() {
|
||||
const {
|
||||
birds,
|
||||
maxX,
|
||||
maxY,
|
||||
} = data;
|
||||
|
||||
for (const bird of birds) {
|
||||
|
||||
}
|
||||
|
||||
self.postMessage({
|
||||
minVolume,
|
||||
averageVolume,
|
||||
maxVolume,
|
||||
|
||||
minPitch,
|
||||
averagePitch,
|
||||
maxPitch,
|
||||
|
||||
averageSpectrum,
|
||||
});
|
||||
}
|
||||
|
||||
setInterval(calculateAndSend, STEP_TIME);
|
|
@ -3,10 +3,10 @@ import { getSpectrumData } from './util.js';
|
|||
|
||||
export default class CirclesAnimation {
|
||||
VOLUME_THRESHOLD = 20;
|
||||
CIRCLE_RADIUS = 100;
|
||||
CIRCLE_RADIUS = 30;
|
||||
CIRCLE_POINTS = 256;
|
||||
FFT_SIZE = 256;
|
||||
MAX_CIRCLES = 20;
|
||||
MAX_CIRCLES = 50;
|
||||
|
||||
baseHeight;
|
||||
baseWidth;
|
||||
|
@ -15,7 +15,7 @@ export default class CirclesAnimation {
|
|||
minPitch = 0;
|
||||
circles = [];
|
||||
|
||||
averageSpectrum;
|
||||
averageSpectrum = [];
|
||||
|
||||
constructor(audioCtx) {
|
||||
this.analyser = new AnalyserNode(audioCtx);
|
||||
|
@ -83,11 +83,11 @@ export default class CirclesAnimation {
|
|||
sketch.background(30);
|
||||
sketch.noFill();
|
||||
sketch.strokeWeight(2);
|
||||
sketch.stroke(230);
|
||||
|
||||
for (let c = 0; c < this.circles.length; c++) {
|
||||
const circle = this.circles[c];
|
||||
sketch.beginShape();
|
||||
sketch.stroke((c / this.circles.length) * 200 + 50);
|
||||
for (let i = 0; i < circle.spectrum.length; i++) {
|
||||
const p = Math.max(circle.spectrum[i] - (this.averageSpectrum[i] * 0.6), 0);
|
||||
sketch.curveVertex(
|
||||
|
|
14
src/index.js
14
src/index.js
|
@ -4,6 +4,8 @@ import './index.scss';
|
|||
import HorizontalLinesAnimation from './horizontal-lines.js';
|
||||
import SquaresAnimation from './squares.js';
|
||||
import CirclesAnimation from './circles.js';
|
||||
import BirdsAnimation from './birds.js';
|
||||
import ShapesAnimation from './shapes.js';
|
||||
|
||||
// const ANIMATION_TIME = 10 * 60 * 1000;
|
||||
const ANIMATION_TIME = 20 * 1000;
|
||||
|
@ -16,11 +18,15 @@ async function main() {
|
|||
const horizontalLines = new HorizontalLinesAnimation(audioCtx);
|
||||
const squares = new SquaresAnimation(audioCtx);
|
||||
const circles = new CirclesAnimation(audioCtx);
|
||||
const birds = new BirdsAnimation(audioCtx);
|
||||
const shapes = new ShapesAnimation(audioCtx);
|
||||
|
||||
const animations = [
|
||||
squares,
|
||||
horizontalLines,
|
||||
circles,
|
||||
// birds,
|
||||
shapes,
|
||||
// circles,
|
||||
// squares,
|
||||
// horizontalLines,
|
||||
];
|
||||
|
||||
let animationNum = 0;
|
||||
|
@ -39,7 +45,9 @@ async function main() {
|
|||
}
|
||||
activeAnimation = animation;
|
||||
input.disconnect();
|
||||
if (activeAnimation.analyser) {
|
||||
input.connect(activeAnimation.analyser);
|
||||
}
|
||||
animation.start(sketch);
|
||||
}
|
||||
|
||||
|
|
121
src/shapes.js
Normal file
121
src/shapes.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
import p5 from 'p5';
|
||||
import { getSpectrumData, getRandomBetween } from './util.js';
|
||||
|
||||
const MIN_SIDES = 3;
|
||||
const MAX_SIDES = 6;
|
||||
const SHAPE_NUM = 12;
|
||||
|
||||
export default class ShapesAnimation {
|
||||
FFT_SIZE = 1024;
|
||||
|
||||
maxX;
|
||||
maxY;
|
||||
|
||||
minVolume = 360;
|
||||
maxVolume = 0;
|
||||
|
||||
shapes = [];
|
||||
|
||||
data;
|
||||
fresh = false;
|
||||
|
||||
analyser;
|
||||
audioProcessor
|
||||
|
||||
constructor(audioCtx) {
|
||||
this.analyser = new AnalyserNode(audioCtx);
|
||||
this.analyser.fftSize = this.FFT_SIZE;
|
||||
this.analyser.timeSmoothingConstant = 0.2;
|
||||
this.audioProcessor = audioCtx.createScriptProcessor(this.FFT_SIZE * 2, 1, 1);
|
||||
this.audioProcessor.onaudioprocess = () => this.audioProcess();
|
||||
}
|
||||
|
||||
start(sketch) {
|
||||
this.resize();
|
||||
this.analyser.connect(this.audioProcessor);
|
||||
|
||||
this.shapes = (new Array(SHAPE_NUM))
|
||||
.fill(null)
|
||||
.map(() => {
|
||||
const baseX = getRandomBetween(0, this.maxX);
|
||||
const baseY = getRandomBetween(0, this.maxY);
|
||||
const baseV = sketch.createVector(
|
||||
getRandomBetween(-5, 5),
|
||||
getRandomBetween(-5, 5),
|
||||
getRandomBetween(-5, 5),
|
||||
);
|
||||
return (new Array(getRandomBetween(MIN_SIDES, MAX_SIDES)))
|
||||
.fill(null)
|
||||
.map(() => ({
|
||||
x: getRandomBetween(baseX - 50, baseX + 50),
|
||||
y: getRandomBetween(baseY - 50, baseY + 50),
|
||||
v: sketch.createVector(
|
||||
getRandomBetween(-10, 10) / 3,
|
||||
getRandomBetween(-10, 10) / 3,
|
||||
getRandomBetween(-10, 10) / 3,
|
||||
).add(baseV),
|
||||
}));
|
||||
});
|
||||
|
||||
sketch.background(0);
|
||||
sketch.colorMode(sketch.HSB);
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.analyser.disconnect();
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.maxX = window.innerWidth;
|
||||
this.maxY = window.innerHeight;
|
||||
}
|
||||
|
||||
getAverageData(data) {
|
||||
this.minVolume = data.minVolume;
|
||||
this.maxVolume = data.maxVolume;
|
||||
|
||||
this.minPitch = data.minPitch;
|
||||
this.maxPitch = data.maxPitch;
|
||||
|
||||
this.averageSpectrum = data.averageSpectrum;
|
||||
}
|
||||
|
||||
audioProcess() {
|
||||
const spectrum = new Uint8Array(this.analyser.frequencyBinCount);
|
||||
this.analyser.getByteFrequencyData(spectrum);
|
||||
|
||||
spectrum.reverse();
|
||||
|
||||
const data = getSpectrumData(spectrum);
|
||||
const { volume, pitch } = data;
|
||||
|
||||
if (volume > this.maxVolume) {
|
||||
this.maxVolume = volume;
|
||||
}
|
||||
|
||||
if (volume !== 0 && volume < this.minVolume) {
|
||||
this.minVolume = volume;
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
this.fresh = true;
|
||||
}
|
||||
|
||||
draw(sketch) {
|
||||
sketch.background(0, 0, 10);
|
||||
|
||||
sketch.stroke(0, 0, 255);
|
||||
sketch.fill(0, 0, 255);
|
||||
|
||||
for (const shape of this.shapes) {
|
||||
sketch.beginShape();
|
||||
for (const point of shape) {
|
||||
sketch.vertex(point.x, point.y);
|
||||
point.x = point.x + point.v.x;
|
||||
point.y = point.y + point.v.y;
|
||||
point.z = point.z + point.v.z;
|
||||
}
|
||||
sketch.endShape();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -96,7 +96,7 @@ export default class SquaresAnimation {
|
|||
}
|
||||
|
||||
draw(sketch) {
|
||||
sketch.background('rgba(0, 0, 0, 0.02)');
|
||||
sketch.background('rgba(0, 0, 0, 0.20)');
|
||||
if (!this.fresh) {
|
||||
return;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ export default class SquaresAnimation {
|
|||
const p = this.data.spectrum[i];
|
||||
sketch.stroke(color, 100, 100);
|
||||
|
||||
sketch.fill(color, 100, brightness);
|
||||
sketch.fill(color, 100, 100);
|
||||
const x = getRandomBetween(0, this.maxX) * this.GRID_SIZE;
|
||||
const y = getRandomBetween(0, this.maxY) * this.GRID_SIZE;
|
||||
sketch.beginShape();
|
||||
|
|
Loading…
Reference in a new issue