Bouncing Ball Piano

Our assignment this week was to create a p5 sketch that incorporates an algorithmic design and an interface device. Max Horwich, my partner, and I decided to make a kind of musical instrument.

Max kickstarted the process by sharing a sketch of a bouncing ball that made an interesting sound each time it bounced. I saw this and began thinking of ways that we might be able to add interactivity.

The original sketch that we moved from. Click through to launch it.

I figured, adding more balls could be an interaction of the user. Then, I realized we could create a kind of sequencer that could play specific tones based off of the mouse location and the sketch could become melodic. We put it together with Max focusing on the sound portion and me on the interactivity and came up with this:

Depending on which column the mouse is hovering over, a ball will appear in that column and begin bouncing up and down, playing different tones. Each column can have a single ball at a time, but one can reset the entire sequence by pressing the reset button at the bottom.

There were some challenges that we had to work through, like how to prevent the mouse from rapid firing balls into each column. We fixed that by assigning a boolean to each column that gets flipped once the mouse button gets pressed. The only way to unflip it is to press the reset button.

Overall, it creates a pretty pleasant sound and can be used to throw together some basic melodies! Not bad.

let k = 8;
let zone = 0;
let x = [];
let toneX = [];
let toneY = [];
let bounce = [];
let color = [];
let ballno = 0;
let speed = 3;
let rad = 0;
let noteFreq = [261.6, 293.7, 329.7, 349.2, 392, 440, 493, 523.3, 587.4]; //this is a standard c major scale
let pitch = [];
let oneNote = []; //this is a boolean that gets flipped once the first click is pressed. Only note can exist in each column now.
let buttonwidth = 40;

var attackLevel = 1.0;
var releaseLevel = 0;

var attackTime = 0.001
var decayTime = 0.2;
var susPercent = 0.2;
var releaseTime = 0.5;

var env, triOsc;



function setup() {
 createCanvas(400, 400);

for (let i = 0; i < k; i++) {
 x[i] = i * width / k + (width / k) / 2;
 oneNote[i] = true;
 }

env = new p5.Env();
 env.setADSR(attackTime, decayTime, susPercent, releaseTime);
 env.setRange(attackLevel, releaseLevel);

triOsc = new p5.Oscillator('triangle');
 triOsc.amp(env);
 triOsc.start();
 triOsc.freq(220);

for (let i = 0; i < k; i++) {
 print(i, ":", noteFreq[i]);
 }
}

function playEnv() {
 env.play();
}

function draw() {
 background(0);
 stroke(255);
 for (let i = 1; i < k; i++) {
 line(i * width / k, 0, i * width / k, (height - buttonwidth))
 }

for (let i = 0; i < k; i++) {
 if (mouseX > i * width / k) {
 if (mouseX < (i + 1) * width / k) {
 noStroke();
 fill(255, 100);
 rect(i * width / k, 0, width / k, height - buttonwidth);
 if (mouseIsPressed) {
 if (oneNote[i] == true) {
 zone = i;
 ballno++;

pitch[ballno] = noteFreq[zone];
 toneX[ballno] = x[zone];
 toneY[ballno] = height - buttonwidth - speed;
 bounce[ballno] = false;
 color[ballno] = (mouseX / width) * 255;
 oneNote[i] = false;
 }
 }
 }
 }
 }

for (let i = 1; i <= ballno; i++) {
 noStroke();
 fill(255, color[i], 255 - color[i], 150);
 ellipse(toneX[i], toneY[i], width / (k + 1), width / (k + 1));
 if (bounce[i] == false) {
 toneY[i] += speed;
 }
 if (bounce[i] == true) {
 toneY[i] -= speed;
 }

if (toneY[i] > height - buttonwidth) {
 bounce[i] = true;
 triOsc.freq(pitch[i]);
 playEnv()
 }
 if (toneY[i] < 0) {
 bounce[i] = false;
 triOsc.freq(pitch[i] / 2);
 playEnv()
 }
 }

//reset button stuff
 noStroke();
 fill(0);
 rect(0, height - buttonwidth, width, buttonwidth);
 stroke(255);
 line(0, height - buttonwidth, width, height - buttonwidth);
 noStroke();
 fill(255);
 textAlign(CENTER);
 textSize(buttonwidth / 2);
 text("RESET", width / 2, height - (buttonwidth / 2 / 2));

if (mouseY > height - buttonwidth) {
 fill(255, 100);
 rect(0, height - buttonwidth, width, buttonwidth);
 if (mouseIsPressed) {
 ballno = 0;
 for (let i = 0; i < k; i++) {
 oneNote[i] = true;
 }
 }
 }
}

Leave a Reply

Your email address will not be published. Required fields are marked *