Assignment 5: Musical Instrument (SuperMario + Tik Tok)

Concept: (Lucy and Chun Xiao)

Buttons that play notes in an octave. When certain notes are played in a melody correctly, the next melody corresponding to the previous melody plays automatically until a red switch is pressed to terminate it. The instrument has two melodies stored inside- SuperMario Theme Song and Kesha’s Tik Tok. Two Servo Motors act as drums that add the tempo to the songs. 

 

Behavior:

There are 8 buttons in a row which are 8 notes in an octave. The user can play any melodies using the ‘keyboard’ but to initiate either of the melodies that are stored in the program, the user has to hit certain notes correctly. While the melody plays, the user can click the red switch on the right to terminate the song and go back to playing whatever they want. The melody that plays after the correct notes are hit is then accompanied by the tempo by two servo motors. 

 

 

Schematic: 

 

Code:

#include "pitches.h"
int buzzer = 12;
int switch1 = 2;
int switch2 = 3;
int switch3 = 4;
int switch4 = 5;
int switch5 = 6;
int switch6 = 7;
int switch7 = 8;
int switch8 = 11;

int index1 = 0;
int index2 = 0;
int current_key = 0; // a variable recording the last pressed but not checked 
int reading = false; // a boolean keeping track if a botton is being pressed
int key1[] = {3, 3, 3, 1, 3, 5};
int key2[] = {5, 4, 4, 4, 4};
int notes[] = {
  NOTE_C7, NOTE_D7, NOTE_E7, NOTE_F7,
  NOTE_G7, NOTE_A7, NOTE_B7, NOTE_C8
};
// melody and tempo for the Mario theme song
int melody1[] = {
  NOTE_G6, 0,
  NOTE_C7, 0, 0, NOTE_G6,
  0, 0, NOTE_E6, 0,
  0, NOTE_A6, 0, NOTE_B6,
  0, NOTE_AS6, NOTE_A6, 0,

  NOTE_G6, NOTE_E7, NOTE_G7,
  NOTE_A7, 0, NOTE_F7, NOTE_G7,
  0, NOTE_E7, 0, NOTE_C7,
  NOTE_D7, NOTE_B6, 0, 0,

};

int tempo1[] = {
  12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

};
// Melody and Tempo for Tik Tok
//E, D, E, F, G, F, E, E, E, E, D, E, B
int melody2[] = {
  NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, 0,
  NOTE_G7, NOTE_F7, 0,
  NOTE_F7, NOTE_F7, NOTE_F7, 0,
  NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_E7, 0, NOTE_D7, 0,
  NOTE_G7, NOTE_F7, 0,
  NOTE_F7, NOTE_F7, NOTE_F7, 0,
  NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_F7, NOTE_D7,
  NOTE_D7, NOTE_D7, NOTE_D7, NOTE_A7,

};

int tempo2[] = {

  125, 125, 125, 125, 125, 125, 125, 125,
  250, 125, 125,
  125, 125, 125, 125,
  125, 125, 125, 125, 125, 125, 125, 125, 125,
  375, 125, 125,
  125, 125, 125, 125,
  125, 125, 125, 125, 250, 250, 250,
  250, 250, 250, 500
};


#include 

Servo Rservo;  // create servo object to control a servo
Servo Lservo;
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

void setup() {
  // put your setup code here, to run once:
  Serial.begin(1200);
  Lservo.attach(9);
  Rservo.attach(10);

  pinMode(switch1, INPUT);
  pinMode(switch2, INPUT);
  pinMode(switch3, INPUT);
  pinMode(switch4, INPUT);
  Lservo.write(0);
  Rservo.write(150);
}

void play_tone(int note) {
  tone(buzzer, notes[note - 1]);
}

void loop() {
  // put your main code here, to run repeatedly:
  int switch1State = digitalRead(switch1);
  int switch2State = digitalRead(switch2);
  int switch3State = digitalRead(switch3);
  int switch4State = digitalRead(switch4);
  int switch5State = digitalRead(switch5);
  int switch6State = digitalRead(switch6);
  int switch7State = digitalRead(switch7);
  int switch8State = digitalRead(switch8);
  Lservo.write(30);
  Rservo.write(120);
  if (switch1State == 1) {

    play_tone(1);
    current_key = 1;
    reading = true;


  } else if (switch2State == 1) {

    play_tone(2);
    current_key = 2;
    reading = true;


  } else if (switch3State == 1) {

    play_tone(3);
    current_key = 3;
    reading = true;


  } else if (switch4State == 1) {

    play_tone(4);
    current_key = 4;
    reading = true;



  } else if (switch5State == 1) {

    play_tone(5);
    current_key = 5;
    reading = true;



  } else if (switch6State == 1) {

    play_tone(6);
    current_key = 6;
    reading = true;



  } else if (switch7State == 1) {

    play_tone(7);
    current_key = 7;
    reading = true;



  } else if (switch8State == 1) {

    play_tone(8);
    current_key = 8;
    reading = true;



  } else {
    noTone(buzzer);
    delay(1);
    reading = false;

  }

  if (!reading && current_key != 0) {
    if (current_key == key1[index1]) {
      index1++;

    }
    else {
      index1 = 0;
    }
    if (current_key == key2[index2]) {
      index2++;
    }
    else {
      index2 = 0;
    }
    current_key = 0; //important resetting!
    reading = true;
  }


// if the first 5 keys matches the ones of Mario theme song, the instrument will play the song
  if (index1 > 5) {
    delay(500);
    int side = 0;
    for (int thisNote = 0 ; thisNote < 33; thisNote++) {
      switch1State = digitalRead(switch1);
      switch2State = digitalRead(switch2);
      switch3State = digitalRead(switch3);
      switch4State = digitalRead(switch4);
      switch5State = digitalRead(switch5);
      switch6State = digitalRead(switch6);
      switch7State = digitalRead(switch7);
      switch8State = digitalRead(switch8);

      if (!switch1State && !switch2State && !switch3State && !switch4State && !switch5State && !switch6State && !switch7State && !switch8State) {
        int noteDuration = 1000 / tempo1[thisNote];
        tone(buzzer, melody1[thisNote], noteDuration);
        if (side % 2 == 0) {
//loops for the left servo to “hit” the can
          for (pos = 30; pos <= 50; pos += 1) { Lservo.write(pos); delay(3); } for (pos = 50; pos >= 30; pos -= 1) {
            Lservo.write(pos);
            delay(3);
          }
        }
        else {
//loops for the right servo to “hit” the can
          for (pos = 30; pos <= 50; pos += 1) { Rservo.write(150 - pos); delay(3); } for (pos = 50; pos >= 30; pos -= 1) {
            Rservo.write(150 - pos);
            delay(3);
          }
        }
        side++;


        int pause = noteDuration * 1.8;
        //delay(pause);
      }
      else {
        break;
      }
    }
    index1 = 0;

  }
// Similar for Tik Tok
  if (index2 > 4) {
    delay(500);
    int side = 0;
    for (int thisNote = 0 ; thisNote < 41; thisNote++) {
      switch1State = digitalRead(switch1);
      switch2State = digitalRead(switch2);
      switch3State = digitalRead(switch3);
      switch4State = digitalRead(switch4);
      switch5State = digitalRead(switch5);
      switch6State = digitalRead(switch6);
      switch7State = digitalRead(switch7);
      switch8State = digitalRead(switch8);
      if ((!switch1State && !switch2State && !switch3State && !switch4State && !switch5State && !switch6State && !switch7State && !switch8State)) {
        tone(buzzer, melody2[thisNote], tempo2[thisNote]);
        if (side % 2 == 0) {
          for (pos = 30; pos <= 50; pos += 1) { Lservo.write(pos); delay(3); } for (pos = 50; pos >= 30; pos -= 1) {
            Lservo.write(pos);
            delay(3);
          }
        }
        else {
          for (pos = 30; pos <= 50; pos += 1) { Rservo.write(150 - pos); delay(3); } for (pos = 50; pos >= 30; pos -= 1) {
            Rservo.write(150 - pos);
            delay(3);
          }
        }
        side++;
        int pause = tempo2[thisNote] * 1.2;
        delay(pause);
      }
      else {
        break;
      }
    }
    index2 = 0;

  }

}


Problems:

  1. At first the code didn’t work with Lucy’s laptop and we couldn’t find any error in the code. After switching to Chunxiao’s, the code worked without modifying.
  2. Whenever the push buttons were pressed, multiple signals were sent to the Arduino and it was hard to keep track of which buttons were pressed in a sequence. To solve this, we used boolean variable “reading” to indicate a block of signals initialized by the pressing of a button. We also used a variable “current_key” to store the key last pressed. We made a comparison of the key pressed to the first part of the two music pieces only after “reading” was false ( no longer getting signal from the previous pressing).
  3. At first we forget to set current_key & reading back to default stage. We also didn’t specify that comparison should be made when current_key is not default. These stopped our code to operate as intended.
  4. When implementing the “servo drum”, we thought of using threads which were not supported on Arduino. Instead of that, we added the commands to operate the servos along with the commands to play the tone inside the same loops.

 

Mario Theme song was taken from:

https://www.hackster.io/jrance/super-mario-theme-song-w-piezo-buzzer-and-arduino-1cc2e4

One thought on “Assignment 5: Musical Instrument (SuperMario + Tik Tok)

  1. Michael Shiloh

    Very clever project, and very nicely executed. It was satisfying and pleasant to play with.
    The schematic has an error: the connection from each switch to the input is from the wrong end of the switch. In this case, the digitalRead() would always return HIGH, because it’s permanently connected to 5V.
    In the code, the variables index1 and index2 could use comments explaining what they are for, and the variable names should reflect that as well. (A well-chosen name makes a comment unnecessary.)
    The arrays key1 and key2 also need comments, and perhaps better names.
    Instead of melody1 and tempo1, why not call them marioMelody, marioTemp, tikTokMelody and tikTokTempo?
    Delete the comment that says “// put your main code here, to run repeatedly:”
    The sections starting with “if (!reading && current_key != 0) {” need commenting.
    You said this didn’t work on Lucy’s laptop. Be more specific: what didn’t work? Did it fail to upload? Did the tone not play? Did the servo not move? “didn’t work” is vague.
    Great job indicating the problems that you had and how you solved them!

    Reply

Leave a Reply

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