xxxxxxxxxx
90
// inspiration: https://iv.nboeck.de/watch?v=4GaGnU8Ij2Y
let balls = [];
function setup() {
createCanvas(800, 400);
noFill();
strokeWeight(8);
const numberOfArcs = 20;
const startY = height * 0.95;
let baseSpeed = TWO_PI / 60;
// Initialize balls for each arc
for (let i = 0; i < numberOfArcs; i++) {
let radius = startY - i * 20;
let speed = baseSpeed / (i + 1);
let osc = new p5.Oscillator("sine");
osc.start();
osc.amp(0);
balls.push({
radius: radius,
angle: PI,
speed: speed,
direction: -1,
oscillator: osc,
});
}
}
function draw() {
background(0);
const startY = height * 0.95;
// Draw the arcs and update the balls
for (let i = 0; i < balls.length; i++) {
let ball = balls[i];
// Draw arc
let hueValue = (i * 360) / balls.length;
stroke(color(`hsl(${Math.floor(hueValue)}, 100%, 50%)`));
arc(width / 2, startY, ball.radius * 2, ball.radius * 2, PI, TWO_PI);
// Update ball position
ball.angle += ball.direction * ball.speed;
if (ball.angle <= 0) {
ball.direction = 1;
playPianoNote(ball, i);
}
if ((ball.angle >= PI) & (ball.direction == 1)) {
ball.direction = -1;
playPianoNote(ball, i);
}
// Draw ball
fill(255);
noStroke();
let x = width / 2 + cos(ball.angle) * ball.radius;
let y = startY - sin(ball.angle) * ball.radius;
ellipse(x, y, 10, 10);
noFill();
}
}
// Function to play a piano note with ADSR envelope
function playPianoNote(ball, index) {
let freq = midiToFreq(60 + index); // Convert MIDI note to frequency
ball.oscillator.freq(freq);
// Define ADSR parameters
let attackTime = 0.01; // Attack time in seconds
let decayTime = 0.2; // Decay time in seconds
let susPercent = 0.3; // Sustain percentage
let releaseTime = 0.5; // Release time in seconds
// Set amplitude to 0 to ensure a clean start
ball.oscillator.amp(0);
// Attack and Decay
ball.oscillator.amp(0.5, attackTime);
ball.oscillator.amp(0.5 * susPercent, decayTime + attackTime);
// Release
setTimeout(() => {
ball.oscillator.amp(0, releaseTime);
}, 100); // Note duration before release
}