Schedule‎ > ‎

Lab 12: Music Player

Objectives

  • Use CStrings (char arrays) and arrays
  • Understand how different frequencies are used to make music
  • Write functions to get user input
  • Make use of reference parameters

^ top

Academic Honesty

Read the Scholastic Honesty Policy and Assignment Integrity policies of the syllabus. Here are some clarifications for this particular assignment:

  • You are expected to work either by yourself.
  • You may NOT give a copy of your code to any other student nor post it online.
  • You must breadboard the circuits yourself.
  • You may NOT look at another student's code until you complete and submit this assignment.
  • You may get help from people if you get stuck, but only if they show you like examples and not show or tell you the exact code to type.

^ top

Project A: Simple Music Player

Setup

This lab uses a simple circuit pictured below.


You can place the positive speaker wire on any pin, so long as it is PWM capable (i.e. it has a tilde (~) next to it). 

Background

Today, computers are capable of playing audio that was directly recorded from a real world source. This wasn't always the case. Classic gaming systems like the Atari 2600 and the original Nintendo Entertainment System contained microchips that worked like a keyboard synthesizer. Those chips could only play pre-defined notes just like a piano can only play the notes corresponding to its keys. Despite their limitations people created catchy chiptunes that went along with games. 

Here's an example chiptune from Super Locomotive (source: Wikipedia):

Here's another chiptune by 8 bit Betty

In this project you'll implement a simplified version of an audio chip. 

^ top

Part A1: Making Sense of Notes - remember to provide function headers

Your project, named sound.ino, will read a simplified music notation and play it. Each note is a specific frequency that you send to the speaker using Arduino's tone() function. The table below lists the notes your program should understand with their frequencies and the letter that will be used to play the tone: 

 Note  Code Letter  Action 
 Middle C  c  261 Hz
 C#   C  277 Hz
 D  d  294 Hz
 D#  D  311 Hz
 E  e  330 Hz
 F  f  349 Hz
 F#  F  370 Hz
 G  g  392 Hz
 G#  G  415 Hz
 A  a  440 Hz
 A#  A  466 Hz
 B  b  494 Hz
   -  Stretch last note
   (space)  Rest (no sound)

There are two special characters. They are used to "stretch" a note when a longer sound is needed and to make a musical "rest" when a gap in the sound is needed. Make a function in your program that translates letters into frequencies, ignoring for now the two special characters. The function should look something like this: 

/* getNote()
 *  char note: The letter that represents the note 
 *  returns: The note's frequency
 */
int getNote(char note) {
    ...
}

Once you have that working be sure you can play a scale: 

void setup() {
  String scale = "cdefgabagfedc";
  for (int i=0; i<scale.length(); i++) {
    tone(speakerPin, getNote(scale[i]));
    delay(200);         
  }
  noTone(speakerPin);
}

^ top

Part A2: Playing a Melody - use the same sound.ino file

Now that you can play a scale it's time to play a melody. The first thing you must do is read the serial input for the melody. A melody will be input all at once like this: 

agfgaaa

The melody ends with the newline ('\n') character. When you read the newline character you should stop reading input and play the melody.When you're ready you can test your program using this melody: 

Mary Had a Little Lamb: 
agfgaaagggaaaagfgaaaaggagf 


Your code should read characters from the serial port with the Serial.read() function and place them into an array. The array should be big enough to hold 128 characters.  Here is some code to get you started:

void loop() {
  const int NUM_NOTES = 128;
  char noteArray[NUM_NOTES];
  int currIndex = 0;
  bool done = false;
  if (Serial.available())  {
    while (done == false)  {
      int got = Serial.read();
      if (got == -1)  {
        cout << "-1 back from Serial.read" << endl;
      }  else if (got == '\n')  {
        done = true;
        noteArray[currIndex] = '\n';
        cout << "newline found" << endl;
      } else {
        cout << "(char) got is " << (char) got << endl;
        //  ADD YOUR CODE TO FILL IN THE ARRAY HERE 
      }
    }  //end while
    cout << "you entered: ";
    for (int i = 0; i < currIndex; i++)  {
      // ADD YOUR CODE TO PRINT OUT THE ARRAY HERE
    }
    cout << endl;
    for (int i = 0; i < currIndex; i++) {
      tone(speakerPin, getNote(noteArray[i]));
      delay(200);
    }
    noTone(speakerPin);
  }  //end if Serial.available
}

If you carefully read the Arduino manual you may notice that the Serial.readUntil() function basically does this for you. Do not use that function for this assignment. You must use arrays to store the melody.

^ top

^ top

Style Requirements

Remember to follow all the style rules from previous assignments, as well as the new rules we recently covered, including:

  1. Function naming conventions (See: Function Names)
  2. Indentation in functions and placement of curly braces (See: Indentation)
  3. Function comment blocks See: Function Comment Block)
  4. Use named constants instead of magic numbers (see: Limit Magic Numbers)
  5. Proper use of spaces around operators (see: Spacing Around Operators

^ top

EXTRA CREDIT (3pts):  Here is the Super Mario Theme song played on the Piezo speaker.

Get it to work on your Arduino with the serial console printing out the current melody and modify it in some way of your choice.  Call your file mario.ino

^ top

Grading Criteria (20 pts) + 3 pts Extra Credit

Note that function headers must have the @param and @return comments filled in.

2 Parts:  submit only one file sound.ino for Part 1 & 2

Each Part:  10 points  (Header 1pt, Function Headers 1pt, Compiles 1 pts, Proper Formatting 1 pt,  Works as Specified 6 pts)

Part 1:  10 pts total

Part 2:  10 pts total

Extra Credit:  3 pts.