//Lydia Jin
//jialuj@andrew.cmu.edu
//Section D
//Final Project
//define necessary variables
var piano = [];
var alphabet = ['a', 's', 'd', 'f', 'g', 'h', 'j'];
var alphabet2 = ['A', 'S', 'D', 'F', 'G', 'H', 'J'];
var ASSETS_DIR = "assets/";
var POSTFIX = "-piano.wav"
var amp;
var hz;
var rec = [];
var w;
var buffer;
var button1, button2, button3, button4, button5, button6, button7;
var colorNum = 0;
var bgm1, bgm2, bgm3; //BGM stands for background metronome
var mic, recorder, soundFile;
var state = 0;
var soundLinks = ["https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/0-piano.wav",
"https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/1-piano.wav",
"https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/2-piano.wav",
"https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/3-piano.wav",
"https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/4-piano.wav",
"https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/5-piano.wav",
"https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/6-piano.wav"];
for (var i = 0; i < 7; i++){
//push keys into the array
piano[i] = new KeyStroke(alphabet[i], alphabet2[i]);
}
function setup() {
createCanvas(600, 200);
amp = new p5.Amplitude();
hz = new p5.FFT(0, 256);
w = width/256;
colorMode(HSB);
angleMode(DEGREES);
//create button for BGM 40
button1 = createButton('40 BPM');
button1.position(543,40);
button1.mousePressed(PlayBGM1);
//create button for BGM 50
button2 = createButton('50 BPM');
button2.position(543,64);
button2.mousePressed(PlayBGM2);
//create button for BGM 60
button3 = createButton('60 BPM');
button3.position(543,88);
button3.mousePressed(PlayBGM3);
//create button for no background metronome
button4 = createButton('No BGM');
button4.position(541,112);
button4.mousePressed(ResetBGM);
//create button for recording
button5 = createButton('Record');
button5.position(545,136);
button5.mousePressed(RecordAudio);
//create button for playing recording
button6 = createButton('Play');
button6.position(562,160);
button6.mousePressed(PlayAduio);
button6.hide();
//create button for saving recording
button7 = createButton('Save');
button7.position(557,184);
button7.mousePressed(SaveRecord);
button7.hide();
//create recorded soundfile
recorder = new p5.SoundRecorder();
recorder.setInput();
soundFile = new p5.SoundFile();
}
//helper function for playing BGM1
function PlayBGM1(){
bgm2.stop();
bgm3.stop();
bgm1.loop();
}
//helper function for playing BGM2
function PlayBGM2(){
bgm1.stop();
bgm3.stop();
bgm2.loop();
}
//helper function for playing BMG3
function PlayBGM3(){
bgm1.stop();
bgm2.stop();
bgm3.loop();
}
//helper function for no BGM
function ResetBGM(){
bgm1.stop();
bgm2.stop();
bgm3.stop();
}
//helper function to record audio
function RecordAudio(){
if (state == 0 ){
recorder.record(soundFile);
state ++;
}
else if (state = 1){
recorder.stop();
state++;
}
}
//helper function to play recording
function PlayAduio(){
soundFile.play();
}
//helper function to download recording
function SaveRecord(){
saveSound(soundFile, 'mySound.wav');
}
function draw() {
noStroke();
background('black');
//draw buttons
fill('white');
textSize(13);
noStroke();
text('Metronome', 535, 15);
text('Rhythms', 543, 27);
//hide buttons
if (state === 0) {
button6.hide();
button7.hide();
//state++;
}
else if (state === 1) {
//display instructing text
text('Recording! Click Record Again to stop.', 150, 20);
}
else if (state === 2) {
if (soundFile.isPlaying() == true){
button6.hide();
bgm1.stop();
bgm2.stop();
bgm3.stop();
//display text
text('Playing...', 250, 20);
}
else{
button5.hide();
//show buttons after recording is done
button6.show();
button7.show();
text('Recording stopped! Chose to play or save. Refresh the page to start a new recording.', 20, 20);
}
}
//draw keyboard letters
for (var i = 0; i < 7; i++){
push();
textSize(25);
stroke('white');
fill('white');
text(alphabet2[i], i* (width - 70)/7 + (width - 70)/14, 195);
pop();
}
//draw displays
if (state != 0){
push();
var level = amp.getLevel();
rec.push(level);
stroke('white');
noFill();
var cy = map(level, 0 , 1, height, 0);
translate(0, height/2 - cy);
beginShape();
colorNum++;
if (colorNum > 255){
colorNum = 0;
}
for (var i = 0; i < rec.length; i++){
var y = map(rec[i], 0 , 1, height, 0);
stroke(colorNum, 255, 255);
vertex(i, y);
}
endShape();
if (rec.length > width - 70){
rec.splice(0, 1);
}
pop();
push();
stroke('red');
line(rec.length, 0, rec.length, height);
pop();
}
//display amplitude with rectangles
var spectrum = hz.analyze();
noStroke();
for (var i = 0; i < spectrum.length; i++){
var amp1 = spectrum[i];
var y = map(amp1, 0, 256, height, 0);
fill(i, 255, 255);
if (soundFile.isPlaying() == true){
rect(i + (width - 90)/2, y , w - 2, height - y);
}
else{
rect(i + buffer, y , w - 2, height - y);
}
}
}
function preload(){
//preload sound files
for (var i = 0; i < piano.length; i++){
piano[i].sound = loadSound(soundLinks[i]);
}
//store sound files to variables
bgm1 = loadSound("https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/40-BPM.wav");
bgm2 = loadSound("https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/50-BPM.wav");
bgm3 = loadSound("https://courses.ideate.cmu.edu/15-104/f2016/wp-content/uploads/2016/12/60-BPM.wav");
}
function KeyStroke(LKey, CKey){
var sound;
//lower case keys
this.LKey = LKey;
//upper case keys
this.CKey = CKey;
}
function keyPressed(){
if (state === 0 & key === 'space') {
state++;
}
for (var i = 0; i < piano.length; i++){
if ((key === piano[i].LKey) || (key === piano[i].CKey)){
piano[i].sound.play();
buffer = i*80;
fill('orange');
rect(i*width/7, 170, width/7, 30);
}
}
}
My program is designed for kids or beginners who don’t have any musical background in the goal of getting them to know the 7 basic keys in piano with the aid of a metronome. This program is simple to use and should build interest in users because they get to record what they played and replay or download the recordings. Users can follow instructions that are displayed in the program to know exactly how to use this program.
Instructions for use:
1. 4 background metronome options: 40 BPM, 50 BPM, 60 BPM or no BPM at all. Press the button to access each. (The buttons are named BGM, which stands for background metronome)
2. Keys A,S,D,F,G,H,J when pressed, will play piano keys A,B,C,D,E,F,G respectively. The code is written in a way that both capital and lower case keyboard keys will work.
3. Record your performance by hitting the record button, once done, hit the record button again to stop recording.
4. After you are finished recording, you have the option to either play your recording or save it. By pressing the save button, your audio recording file will be downloaded to your computer.
5. Refresh the page to start new recording.
Additional features displayed:
1. The line in the middle shows you the amplitude of the sound. The lines changes color for more fun 🙂
2. The rectangles that pop up when sound is played shows you the frequency of the sound.
* These are made possible by using P5js built in sound functions
Notes to be taken into consideration when grading:
1. This is modified from the final proposal. The reason I decided to change this is because I think this program is more practical for users and also has cool features. (Already talked to the professor about the change)
2. The sounds are downloaded from freesound.org
3. The buttons’ scales are off when sketch is embedded on WordPress. The original file did not have overlapping buttons.
4. When running locally, the program only runs when Firefox is used.