For my final project, I created a simple step sequencer with 4 sounds and background music! You can add sounds at different points by toggling the squares and circles (the squares indicate a note switched off, and a circle indicates a note switched on), and change the speed the music player loops through the sequencer on the bpm toggle.
I really enjoyed making this because it became about the curation of the sounds and music, letting anyone generate a soothing atmosphere.
//Jenny Hu
//Section E
//jjh1@andrew.cmu.edu
//Final Project
//This final project is a simple step sequencer.
//Sounds are loaded into each row,
//as the music player passes each note (switched on), it plays the sound
//squares indicate switched off notes, and circles indicate the ones switched on.
var playing = false;
var notesArray = []; //all notes are pushed into this array
//sizing variables
var totalC = 15;
var canvasWidth = window.innerWidth; //sizing of everything should overall be parametric to this width.
var margin = 0.02 * canvasWidth; //space between notes and everything else
var noteW = (canvasWidth - (totalC + 1) * margin)/ totalC; //calculated width of each square/circle
var canvasHeight = 5 * margin + 4 * noteW + (noteW*4);
//variables key to moving and playing components
var playButtonW = margin ; //big play/pause button
var baseLineX = margin;
var baseLineY = (canvasHeight / 5) * 3.5;
var movingPlayBar = 20;
var movingPlayBarW = 10;
var playX; //moving x tracked against the array's x's.
//variables to make bpm changeable
var bpmEdit = 2;
var bpm;
var bpmX;
var bpmToggleX;
var bpmToggleLength;
var backgroundMusicToggle = false;
var interval;
var volume = 1;
function preload() {
// load sound files
bird = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/182507__swiftoid__bird-chirp.wav");
bird.setVolume(volume);
bell = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/173000__keykrusher__bicycle-bell-2.wav");
bell.setVolume(volume / 3 * 2);
cello = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/398494__anthousai__wind-chimes-single-01.wav");
cello.setVolume(volume);
shaker = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/368607__samsterbirdies__shake.wav");
shaker.setVolume(volume);
backgroundMusic = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/203099__lemoncreme__groove-music.wav");
backgroundMusic.setVolume(volume);
}
function setup(){
createCanvas(canvasWidth, canvasHeight);
frameRate(1000);
angleMode(DEGREES);
bpmToggleLength = width / 8 * 5;
bpmX = bpmToggleLength + margin;
//setting up rows with different sounds
for (var c = 0; c < totalC; c++){
for (var r = 0; r < 4; r++){
var x = c * (noteW + margin) + margin;
var y = r * (noteW + margin) + margin;
if ( r == 0){
snd = bird;
} else if (r == 1){
snd = bell;
} else if (r == 2){
snd = cello;
} else {
snd = shaker;
}
var n = Note(x , y, snd, noteW);
notesArray.push(n);
}
}
}
function draw(){
background(250, 230, 10);
var wiggleRoom = 2;
//intro text
stroke(0, 0, 250);
strokeWeight(1);
fill(0, 0, 250);
textSize(margin);
textFont('Courier');
text('press play to begin!', width / 2 - bpmToggleLength / 1.75, canvasHeight / 8 * 7);
//static line
strokeWeight(5);
line( baseLineX, baseLineY, canvasWidth - baseLineX, baseLineY);//playbar baseline
//for loop rendering the array into notes
for (var i = 0; i < notesArray.length; i++){
notesArray[i].render();
//play music when the play x and array of on notes collide
if (playX >= notesArray[i].x - wiggleRoom
& playX <= notesArray[i].x + wiggleRoom
&& notesArray[i].on == true){
notesArray[i].snd.play();
}
}
bpmToggle();
playBackground();
playButton();
movePlayStream();
}
//function to move the bpm visual ui
function bpmToggle(){
//shadow
noStroke();
fill(250, 250, 250, 150);
rect( bpmToggleLength + margin, baseLineY + (margin * 2.5), width/5, noteW/5, 80);
//bpm text
stroke(0, 0, 250, 250);
fill(0, 0, 250);
strokeWeight(1);
text('bpm', bpmToggleLength + margin, canvasHeight / 8 * 7 + margin);
//toggle
fill(0, 0, 250);
ellipse(bpmX, baseLineY + (margin * 2) + noteW / 3, noteW / 3, noteW / 3);
}
//function to play background music
function playBackground(){
if (backgroundMusicToggle == true){ //counter will be 1, or 2 (on rare occasion), immediate at play
interval = 1250;
if (counter > 0 & counter < 3){
backgroundMusic.play();
playing = true;
} else if ( counter % interval > 0 & counter % interval <= 2){ //interval is based on the timing of the background song
playing = false;
counter = 0; //reset counter if you've paused the music
}
}
}
//play/pause functionality + visuals
//playing is toggled in mousePressed
function playButton(){
fill(0, 0, 250);
if (playing == true) {
//pause button
rect(width/2 - playButtonW, baseLineY + (margin * 2) ,
playButtonW, playButtonW * 3);
rect(width/2 + playButtonW, baseLineY + (margin * 2),
playButtonW, playButtonW * 3);
//mapping of the bpm toggle to the speed of playX
bpmEdit = map(bpmX,
bpmToggleLength + noteW / 2, bpmToggleLength - noteW / 2 + width/5,
2, 4);
bpm = bpmEdit; // the set BPM by the user
backgroundMusicToggle = ! backgroundMusicToggle; //turning on the background music
counter += 1;
} else {
//play button
triangle ( width/2 - playButtonW, baseLineY + (margin * 2),
width/2 - playButtonW, baseLineY + (margin * 2) + noteW * .75 * 2,
width/2 - playButtonW + noteW * .75 * 2, baseLineY + (margin * 2) + noteW * .75 )
bpm = 0; //stop the player if we've paused the switch
counter = 0;
backgroundMusic.stop();
}
}
//draws the animated line
function movePlayStream(){
playX = baseLineX + movingPlayBar - 20;
stroke(0, 0, 250);
fill(250);
strokeWeight(4);
//loops the line if the play button moves off the line
if (playX > canvasWidth - baseLineX) {
movingPlayBar = baseLineX;
} else {
//the visual parts
rect(playX, margin / 2, movingPlayBarW, canvasHeight / 5 * 3.5);
ellipse( playX + movingPlayBarW / 2 , baseLineY, movingPlayBarW*2, movingPlayBarW*2);
}
//add whatever the bpm has been toggled to be
movingPlayBar += bpm;
}
function mousePressed(){
//turning on and off the individual notes by checking your mouse position
for (var i = 0; i < notesArray.length; i++){
if (mouseX > notesArray[i].x
& mouseX < notesArray[i].x + noteW
&& mouseY > notesArray[i].y
&& mouseY < notesArray[i].y + noteW){
var currentToggle = !notesArray[i].on;
notesArray[i].on = currentToggle;
}
}
//switch play/pause mode by clicking on the play/pause button
if (mouseX > width / 2 - playButtonW
& mouseX < width / 2 + margin + playButtonW
&& mouseY > baseLineY + (margin * 2)
&& mouseY < baseLineY + (margin * 2) + playButtonW * 3){
playing = ! playing;
}
}
function mouseDragged(){
//dragging the bpm toggle
if (mouseX > bpmToggleLength + margin
& mouseX < bpmToggleLength + width/5 + margin
&& mouseY > baseLineY + (margin * 2.5)
&& mouseY < baseLineY + (margin * 2.5) + noteW){
bpmX = mouseX;
}
}
//make the note real
function render(){
fill(250);
stroke(0, 0, 250);
strokeWeight(5);
//rendering cirlces if the note is on
if (this.on){
fill(250, 130, 180);
noStroke();
ellipse(this.x + noteW/2, this.y + noteW/2, this.w, this.w);
} else {
//rendering squares if the notes is off
rect(this.x, this.y, noteW, noteW);
}
if(this.snd.isPlaying() & playX < this.x + noteW*1.5 && playX > this.x){
var t = frameCount;
this.w = noteW * sin(t*5);
}else{
this.w = noteW;
}
}
//my note object maker function
function Note(x, y, snd, wide){
var objNote = { //object literal format
x : x,
y : y,
w: wide,
snd : snd,
on : false,
playing: false
}
objNote.render = render;
return objNote;
}