Jenny Hu — Final Project

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’s sketch

//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;
}


Leave a Reply