Skip to content

example using p5 #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"postinstall": "simple-git-hooks"
},
"dependencies": {
"p5": "^1.4.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4"
Expand All @@ -23,6 +24,7 @@
"@types/node": "^16.11.46",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/p5": "^1.4.2",
"@vitejs/plugin-react": "^2.0.0",
"eslint": "^8.20.0",
"eslint-config-react-app": "^7.0.1",
Expand Down
61 changes: 61 additions & 0 deletions src/visualizer/visualizers/Optical.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useRef } from "react";
import { useAudioBuffer } from "../../common/useAudioBuffer";
import P5 from "p5";
import ActorSystem from "./optical/ActorSystem";

const FRAME_RATE = 60;
const ACTOR_COUNT = 500;
const ACTOR_SPEED = 3;

export default function Optical() {
const containerRef = useRef<HTMLDivElement>(null);
const bufferRef = useAudioBuffer();

useEffect(() => {
if (!containerRef.current) return;

const Sketch = (p5: P5) => {
let actorSystem: ActorSystem;
p5.setup = () => {
p5.frameRate(FRAME_RATE);
p5.createCanvas(
p5.windowWidth * window.devicePixelRatio,
p5.windowHeight * window.devicePixelRatio
);
actorSystem = new ActorSystem(p5, ACTOR_COUNT, ACTOR_SPEED);
};

p5.windowResized = () => {
p5.resizeCanvas(
p5.windowWidth * window.devicePixelRatio,
p5.windowHeight * window.devicePixelRatio
);
};

p5.draw = () => {
if (bufferRef.current) {
const connectDistance = p5.map(bufferRef.current[2], 0, 175, 10, 70);
const actorSpeed = p5.map(bufferRef.current[5], 0, 175, 0, 10);
const wiggleSpeed = p5.map(bufferRef.current[12], 0, 140, 0, 0.6);
const wiggleAmount = p5.map(bufferRef.current[8], 0, 100, 1.5, 0);
actorSystem.setControls(
connectDistance,
actorSpeed,
wiggleSpeed,
wiggleAmount
);
}
actorSystem.update();
actorSystem.display(p5 as P5.Graphics);
};
};

const sketch = new P5(Sketch, containerRef.current);

return () => {
sketch.remove();
};
}, [bufferRef]);

return <div ref={containerRef} />;
}
62 changes: 62 additions & 0 deletions src/visualizer/visualizers/P5FrequencyBlue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useEffect, useRef } from "react";
import { useTheme } from "../../common/useTheme";
import { useAudioBuffer } from "../../common/useAudioBuffer";
import P5 from "p5";

export default function P5FrequencyBlue() {
const containerRef = useRef<HTMLDivElement>(null);
const bufferRef = useAudioBuffer();
const { background1 } = useTheme();

useEffect(() => {
if (!containerRef.current) return;

const Sketch = (p: P5) => {
p.setup = () => {
p.createCanvas(
p.windowWidth * window.devicePixelRatio,
p.windowHeight * window.devicePixelRatio
);
};

p.windowResized = () => {
p.resizeCanvas(
p.windowWidth * window.devicePixelRatio,
p.windowHeight * window.devicePixelRatio
);
};

p.draw = () => {
p.background(background1);

if (containerRef.current && bufferRef.current) {
const bufferLength = bufferRef.current.length;

p.background(background1);

const barWidth = p.width / bufferLength;
let barHeight;
let canvasBarHeight;
let x = 0;

for (let i = 0; i < bufferLength; i++) {
barHeight = bufferRef.current[i];
canvasBarHeight = p.height * (barHeight / 255);
p.fill(p.color(50, 50, barHeight + 100));
p.rect(x, p.height - canvasBarHeight, barWidth, canvasBarHeight);

x += barWidth + 1;
}
}
};
};

const sketch = new P5(Sketch, containerRef.current);

return () => {
sketch.remove();
};
}, [background1, bufferRef]);

return <div ref={containerRef} />;
}
139 changes: 139 additions & 0 deletions src/visualizer/visualizers/optical/Actor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import P5 from "p5";

const PI = Math.PI;

export default class Actor {
location: P5.Vector;
previousLocation: P5.Vector;
angle: number;
newAngle: number;
type: number;
time: number = 0;
currentWaitTime: number = 30;
wiggleOffset: number = 0;
p5: P5;

actorSpeed: number = 3;
wiggleRate: number = 0.2;
wiggleAmount: number = 0.4;
wiggleOffsetRange: number = 100;
waitTime: number = 80;
angleSpeed: number = 0.2;

constructor(p5: P5, startingLocation: P5.Vector, startingAngle: number) {
this.p5 = p5;
this.location = new P5.Vector(startingLocation.x, startingLocation.y);
this.previousLocation = new P5.Vector(
startingLocation.x,
startingLocation.y
);
this.angle = startingAngle;
this.newAngle = startingAngle;
this.wiggleOffset = this.p5.random(this.wiggleOffsetRange); //CONST WIGGLE_OFFSET_RANGE
this.type = this.p5.floor(this.p5.random(3)); //used to be cast to integer
}

setControls(actorSpeed: number, wiggleRate: number, wiggleAmount: number) {
this.actorSpeed = actorSpeed;
this.wiggleRate = wiggleRate;
this.wiggleAmount = wiggleAmount;
}

update(targetActor: Actor) {
this.time++;
if (this.time >= this.currentWaitTime) {
this.time = 0;
this.currentWaitTime = this.p5.random(this.waitTime, this.waitTime * 5); //CONST WAIT_TIME, WAIT_TIME*5
this.calculateNewAngle(targetActor);
}
this.smoothRotateToNewHeading();
this.updateLocation();
}

calculateNewAngle(targetActor: Actor) {
if (this.type === targetActor.type) {
//if they're friends //fly towards eachother
this.newAngle = P5.Vector.sub(this.location, targetActor.location)
.mult(-1)
.heading();
} else {
//fly one direction if they're not partnered
if (this.type == 1) {
this.newAngle = (2 * PI) / 3 + PI / 2 - 2 * PI;
} else if (this.type == 2) {
this.newAngle = (4 * PI) / 3 + PI / 2 - 2 * PI;
} else if (this.type == 0) {
this.newAngle = (6 * PI) / 3 + PI / 2 - 2 * PI;
}

//normalize the angle to the negative pi to pi range
if (this.newAngle > PI) {
this.newAngle -= 2 * PI;
}
if (this.newAngle < -1 * PI) {
this.newAngle += 2 * PI;
}
}
}

smoothRotateToNewHeading() {
if (Math.abs(this.angle - this.newAngle) > PI) {
if (this.angle < this.newAngle) {
this.angle -= this.p5.random(this.angleSpeed);
} else {
this.angle += this.p5.random(this.angleSpeed);
}
} else {
if (this.angle < this.newAngle) {
this.angle += this.p5.random(this.angleSpeed);
} else {
this.angle -= this.p5.random(this.angleSpeed);
}
}

if (this.angle > PI) {
this.angle = -1 * PI;
} else if (this.angle < -1 * PI) {
this.angle = PI;
}
}

updateLocation() {
this.previousLocation.x = this.location.x;
this.previousLocation.y = this.location.y;

//add some wiggle with sin
this.location.add(
P5.Vector.fromAngle(
this.angle +
this.p5.sin(
(this.p5.frameCount + this.wiggleOffset) * this.wiggleRate
) *
this.wiggleRate
).mult(this.actorSpeed)
);
this.wrapScreenMovement();
}

wrapScreenMovement() {
if (this.location.x > this.p5.width) {
this.previousLocation.x = 0;
this.location.x = P5.Vector.fromAngle(this.angle).mult(this.actorSpeed).x;
}
if (this.location.x < 0) {
this.previousLocation.x = this.p5.width;
this.location.x =
this.p5.width - P5.Vector.fromAngle(this.angle).mult(this.actorSpeed).x;
}
if (this.location.y > this.p5.height) {
this.previousLocation.y = 0;
this.location.y = P5.Vector.fromAngle(this.angle).mult(this.actorSpeed).y;
}
if (this.location.y < 0) {
this.previousLocation.y = this.p5.height;
this.location.y =
this.p5.height -
P5.Vector.fromAngle(this.angle).mult(this.actorSpeed).y;
}
}
}
Loading