[FINAL PROJECT] Smash It!/Smash Your Memory! (A Music Memory Game)

IDEA:

Setup: Five Pads on the floor and an interface.

Operations: The note pads correspond to the pentatonic C scale: C, D, E, G, A. As shown on the pads, they represent all the things I hate, I assume you too, the most throughout this semester. To win the game, you must recreate a melody by smashing the pads.

Symbols: The things I hate the most this semester

  • C note: COVID
  • D note: Deadlines
  • E note: course Enrollment
  • G note: GPA
  • A note: Anxiety

IMPLEMENTATION:

  1. Title Page
  2. Rules
  3. Practice: plays demo melody
  4. Test
  5. Win or Lose

video of im showcase:

Most people got it correct after 2-3 tries, around 3-5 succeeded on the first try (talk about music talents), and 3 people just gave up. People enjoyed it a lot more than I thought they would!

CODES:

//Processing Codes

/*
 name: Chi-Ting Tsai
 assignment: final project
 date: 12/07/2021
 "Smash It!" is a music memory game where player would be instructed to memorize a melody 
 and recreate it by stepping on the pads corresponding to notes on the pentatonic C scale.
 */

import processing.sound.*;
SoundFile demoMelody;
SoundFile recC;
SoundFile recD;
SoundFile recE;
SoundFile recG;
SoundFile recA;
SoundFile winning;
SoundFile losing;

int size = 200;
color frame = color(237, 168, 17);

int stage;
int noteC = 1;
int noteD = 2;
int noteE = 3;
int noteG = 5;
int noteA = 6;
int[] correctMelody = {noteD, noteC, noteE, noteG, noteA, noteG, noteD, noteC};

void setup() {
  size (displayWidth, displayHeight);
  background(color(99, 144, 130));
  String portname=Serial.list()[3];
  println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  demoMelody = new SoundFile (this, "/Users/chi-tingtsai/Downloads/5-seconds-of-silence_gcP1Vako.wav");
  recC = new SoundFile (this, "/Users/chi-tingtsai/Downloads/C.wav");
  recD = new SoundFile (this, "/Users/chi-tingtsai/Downloads/D.wav");
  recE = new SoundFile (this, "/Users/chi-tingtsai/Downloads/E.wav");
  recG = new SoundFile (this, "/Users/chi-tingtsai/Downloads/G.wav");
  recA = new SoundFile (this, "/Users/chi-tingtsai/Downloads/A.wav");
  winning = new SoundFile (this, "/Users/chi-tingtsai/Downloads/Winning Sound Effect.wav");
  losing = new SoundFile (this, "/Users/chi-tingtsai/Downloads/The Price is Right Losing Horn - Gaming Sound Effect (HD).wav");
}

void draw() {
  //scene change
  if (stage == 0) {
    rank();
  } else if (stage == 1) {
    rules();
  } else if (stage == 2) {
    practice();
  } else if (stage == 3) {
    game();
  } else if (stage == 4) {
    lose();
  } else if (stage == 5) {
    win();
  }
}
//Processing codes 

void rank() {
background(color(99, 144, 130));
PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
noStroke();
fill(255);
textAlign(CENTER);

textFont(F, 50);
text("Smash Your Memory!\nA Music Memory Game", width/2, height/2-50);
text("Smash C note(COVID) to Begin", width/2, height*3/4);

//frame
noStroke();
rectMode(CENTER);
fill(frame);
rect(width/2, 10, width, 20);
rect(width/2, height-60, width, 20);
rect(10, height/2, 20, height);
rect(width-10, height/2, 20, height);
}
//Processing 

void rules() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  //explain how to play
  textFont(F, 50);
  text("RULES: Memory Game", width/2, height/4);
  textFont(F, 30);
  text("INSTRUCTIONS:\n The note pads correspond to the pentatonic C scale: C,D,E,G,A.\n As shown on the pads, they represent all the things I hate,\nI assume you too, the most throughout this semester.\n To win the game, you must recreate a melody by smashing the pads.", width/2, height/2-120);
  textFont(F, 30);
  text("Smash Deadlines to play the melody ONCE(AND ONLY ONCE!) and practice!", width/2, height-200);
  
  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
//Processing Codes 

int i = 0;
char[] refMelody = {' ', ' ', ' ', 'D', 'C', 'E', 'G', 'A', 'G', 'D', 'C'};


void practice() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  //text
  textFont(F, 50);
  text("LISTEN CAREFULLY & PRACTICE (8 NOTES)", width/2, height/4);
  textFont(F, 30);
  text("Practice to familiarize with how the notes sound!\nRememer: your job is to smash the pads to recreate the melody!\n", width/2, height/2-120);
  textFont(F, 50);
  textFont(F, 50);
  text("Smash Space Bar to begin smashing!", width/2, height-170);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);

  //telling player which note it is
  if (frameCount%118 == 0 && i < 10) {
    i++;
  }
  text("Now playing: \n" + refMelody[i], width/2, height/2+75);
}
//Processing Codes

import processing.serial.*;
Serial myPort;

int aSignal = 0;
int prevASignal = 0;
int val = 0;

void game() {
  if (i == 10) {
    i = 0;
  }
  
  //background
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  textFont(F, 50);
  text("Listen Carefully and Recreate!", width/2, height/4);
  textFont(F, 30);
  text("The things I hate the most this semester\nC note: COVID\nD note: Deadlines\nE note: course Enrollment\nG note: GPA\nA note: Anxiety\n", width/2, height/2-80);
  fill(frame);
  textFont(F, 50);
  text(val + "/8" + " Notes Correct! Keep smashing!", width/2, height-170);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}

void serialEvent(Serial myPort) {
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!= null) {
    aSignal = parseInt(s);
    //scene transition
    if (stage == 0 && aSignal == noteC) {
      stage = 1;
      recC.play();
      val = 0;
    }
    if (stage == 1 && aSignal == noteD) {
      stage = 2;
      demoMelody.amp(0.8);
      demoMelody.play();
    }
    if ((stage == 4 || stage == 5) && aSignal == noteG) {
      stage = 0;
      recG.play();
    }

    //note playing and verification
    if ((stage == 2 || stage == 3) && prevASignal!= aSignal) {
      if (aSignal == noteC) {
        recC.play();
      } else if (aSignal == noteD) {
        recD.play();
      } else if (aSignal == noteE) {
        recE.play();
      } else if (aSignal == noteG) {
        recG.play();
      } else if (aSignal == noteA) {
        recA.play();
      }
      //verify note in array
      if (stage == 3 && aSignal != 0) {
        if (correctMelody[val] == aSignal) {
          val++;
          prevASignal = aSignal;
          if (val == 8) {
            delay(2000);
            stage = 5;
            winning.play();
          }
        } else {
          delay(2000);
          stage = 4;
          losing.amp(0.3);
          losing.play();
        }
      }
      prevASignal = aSignal;
    }
  }
  myPort.write('\n');
}

void keyReleased() {
  if (key == ' ' && stage == 2) {
    stage = 3;
    game();
  }
}
//Processing Codes

void lose() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);
  
  textFont(F, 50);
  text("Awwww... Smash GPA to play again.", width/2, height*3/4);
  text("Not the right note!\nYou've reached the " + (val) + "th note in the melody!", width/2, height/2-80);
  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
//Processing 

void win() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  textFont(F, 50);
  text("Congratulations! You have recreated the entire melody!", width/2, height/2);
  textFont(F, 50);
  text("Smash GPA to play again!", width/2, height/2+50);
  textFont(F, 30);
  fill(frame);
  text("Have you found your peace by smashing those that give off negative energy?", width/2, height/2-50);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
//Arduino codes 

//variable declaration
const int C = 1;
const int D = 2;
const int E = 3;
const int G = 5;
const int A = 6;
const int in_C = 2;
const int in_D = 3;
const int in_E = 4;
const int in_G = 5;
const int in_A = 6;

const int led_C = 9;
const int led_D = 10;
const int led_E = 11;
const int led_G = 12;
const int led_A = 13;

int switch_C, switch_D, switch_E, switch_G, switch_A = 0;

int smash = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(in_C, INPUT);
  pinMode(in_D, INPUT);
  pinMode(in_E, INPUT);
  pinMode(in_G, INPUT);
  pinMode(in_A, INPUT);

  Serial.begin(9600);
  Serial.println("0");
}

void loop() {
  // put your main code here, to run repeatedly:
  switch_C = digitalRead(in_C);
  switch_D = digitalRead(in_D);
  switch_E = digitalRead(in_E);
  switch_G = digitalRead(in_G);
  switch_A = digitalRead(in_A);

  while (Serial.available()) {
    smash = 0;
    if (Serial.read() == '\n') {
      //Note C
      if (switch_C == 1) {                //released, if the two aluminum foils touch
        smash = C;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note D
      if (switch_D == 1) {                //released, if the two aluminum foils touch
        smash = D;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note E
      if (switch_E == 1) {                //released, if the two aluminum foils touch
        smash = E;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note G
      if (switch_G == 1) {                //released, if the two aluminum foils touch
        smash = G;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note A
      if (switch_A == 1) {                //released, if the two aluminum foils touch
        smash = A;
      }
      Serial.println(smash);
    }
  }
} 

CHALLENGES:

After receiving feedback from classmates, I have made several improvements:

  1. Adding visual cues with the demo melody
  2. Informing players how many notes they have recreated correctly

At the beginning of the showcase, someone flagged out a few bugs in the interface but nothing major. They were removed swiftly and the rest of the show went by smoothly in back-to-back user testing!

last note

Thank you so much for the semester. Happy Christmas holidays and have a joyful New Year. Have a restful winter break as well.

Warms regards,

Chi-Ting

Leave a Reply