Play Mario Bros theme song on Arduino and 2 piezo buzzer / speakers in Stereo Harmonies

Here is the code! Go get it, Luigi! Orignal work by John Harrison that the following code was based on: http://cratel.wichita.edu/blogs/engr101fall2010/2010/11/29/2-voices-simultaneously-on-1-arduino/

// 2 voices on 1 Arduino
// demo by John Harrison
// Nov 28, 2011
// public domain
// Modified by Dipto Pratyaksa
// Added Mario tunes by Dipto Pratyaksa
// Apr 3, 2013
// v 1.1

// for the demo to work unmodified, hook up a 1Kish resistor to pin 11 and a 1Kish resistor to pin 12.
// tie the other ends of the resistors together and hook those up to an amp and speaker.
// or you could skip the resistors and hook up pin 11 to one side of a stereo amp and pin 12 to the other side

// You have to include pitches.h in the same folder as your .ino or .pde skecth file
#include "pitches.h"

// as stated above,
// connect amp/speaker to FIRST_TONE_PIN and subsequent.
// for example, if FIRST_TONE_PIN is 8 and NUM_OF_VOICE is 2,
// connect amp/speaker to arduino  pin 8 and pin 9.
// if using the same amp/speaker for both pins, have each
// pin go through a 1Kish resistor before being summed together
#define FIRST_TONE_PIN 8
#define NUM_OF_VOICES 2
#define LED_PIN 13

// a future version will support more than 2 simultaneous voices

// notes in the melody:
int melody1[] = {
  NOTE_E7, NOTE_E7,0,NOTE_E7, 
  0, NOTE_C7, NOTE_E7,0,
  NOTE_G7,0,0,0,
  NOTE_G6,0,0,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_G7, NOTE_E7, NOTE_G7, 
  NOTE_A7, 0, NOTE_F7, NOTE_G7, 
  0, NOTE_E7, 0,NOTE_C7, 
  NOTE_D7, NOTE_B6, 0,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_G7, NOTE_E7, NOTE_G7, 
  NOTE_A7, 0, NOTE_F7, NOTE_G7, 
  0, NOTE_E7, 0,NOTE_C7, 
  NOTE_D7, NOTE_B6, 0,0,
};

int harmony1[] = {
  NOTE_FS6, NOTE_FS6,0,NOTE_FS6, 
  0, NOTE_FS6, NOTE_FS6,0,
  NOTE_B6,0,0,0,
  NOTE_G6,0,0,0,

  NOTE_E6, 0, 0,NOTE_C6, 
  0, 0,NOTE_G5,0,
  0, NOTE_C6, 0, NOTE_D6, 
  0, NOTE_CS6, NOTE_C6, 0,

  NOTE_C6, NOTE_G6, NOTE_B6, 
  NOTE_C7, 0, NOTE_A6, NOTE_B6, 
  0, NOTE_A6, 0,NOTE_E6, 
  NOTE_F6, NOTE_D6, 0,0,

  NOTE_E6, 0, 0,NOTE_C6, 
  0, 0,NOTE_G5,0,
  0, NOTE_C6, 0, NOTE_D6, 
  0, NOTE_CS6, NOTE_C6, 0, 

  NOTE_C6, NOTE_G6, NOTE_B6, 
  NOTE_C7, 0, NOTE_A6, NOTE_B6, 
  0, NOTE_A6, 0,NOTE_E6, 
  NOTE_F6, NOTE_D6, 0,0,
};

int underworld_melody[] = {
  NOTE_C5, NOTE_C6, NOTE_A4, NOTE_A5, 
  NOTE_AS4, NOTE_AS5, 0,
  0,
  NOTE_C5, NOTE_C6, NOTE_A4, NOTE_A5, 
  NOTE_AS4, NOTE_AS5, 0,
  0,
  NOTE_F4, NOTE_F5, NOTE_D4, NOTE_D5,
  NOTE_DS4, NOTE_DS5, 0,
  0,
  NOTE_F4, NOTE_F5, NOTE_D4, NOTE_D5,
  NOTE_DS4, NOTE_DS5, 0,
  0, NOTE_DS5, NOTE_D5, NOTE_CS5,
  NOTE_C5, NOTE_DS5, 
  NOTE_DS5, NOTE_GS4,
  NOTE_G4, NOTE_CS5,
  NOTE_C5, NOTE_FS5,NOTE_F5, NOTE_E4, NOTE_AS5, NOTE_A5,
  NOTE_GS5, NOTE_DS5, NOTE_B4,
  NOTE_AS4, NOTE_A4, NOTE_GS4,
  0, 0, 0
};

int underworld_melody1[] = {
  NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4, 
  NOTE_AS3, NOTE_AS4, 0,
  0,
  NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4, 
  NOTE_AS3, NOTE_AS4, 0,
  0,
  NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
  NOTE_DS3, NOTE_DS4, 0,
  0,
  NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
  NOTE_DS3, NOTE_DS4, 0,
  0, NOTE_DS4, NOTE_D4, NOTE_CS4,
  NOTE_C4, NOTE_DS4, 
  NOTE_DS4, NOTE_GS3,
  NOTE_G3, NOTE_CS4,
  NOTE_C4, NOTE_FS4,NOTE_F4, NOTE_E3, NOTE_AS4, NOTE_A4,
  NOTE_GS4, NOTE_DS4, NOTE_B3,
  NOTE_AS3, NOTE_A3, NOTE_GS3,
  0, 0, 0
};
//melody notes in miliseconds
int underworld_tempo[] = {
  200, 200, 200, 200, 
  200, 200, 400,
  800,
  200, 200, 200, 200, 
  200, 200, 400,
  800,
  200, 200, 200, 200, 
  200, 200, 400,
  800,
  200, 200, 200, 200, 
  200, 200, 400,
  400, 133, 133, 133,
  400, 400,
  400, 400,
  400, 400,
  133, 133, 133,133, 133, 133,
  267, 267, 267,
  267, 267, 267,
  800, 800, 800
};

int mel1Durations[] = {
  150, 150, 150,150, 
  150, 150, 150,150,
  150, 150,150,150,
  150, 150,150,150,

  150, 150,150,150,
  150, 150,150,150,
  150, 150, 150,150, 
  150, 150, 150,150, 

  200, 200, 200,
  150, 150,150,150,
  150, 150, 150,150, 
  150, 150, 150,150,

  150, 150, 150,150, 
  150, 150, 150,150,   
  150, 150, 150,150, 
  150, 150, 150,150, 

  200, 200, 200, 
  150, 150, 150,150,   
  150, 150, 150,150, 
  150, 150, 150,150,
};

int harm1Durations[] = {
  150, 150, 150,150, 
  150, 150, 150,150,
    150, 150, 150,150, 
  150, 150, 150,150, 

  150, 150, 150,150, 
  150, 150, 150,150,   
  150, 150, 150,150, 
  150, 150, 150,150, 

  150, 150, 150,150, 
  150, 150, 150,150,   
  150, 150, 150,150, 
  150, 150, 150,150,

  150, 150, 150,150, 
  150, 150, 150,150,   
  150, 150, 150,150, 
  150, 150, 150,150, 

  150, 150, 150,150, 
  150, 150, 150,150,   
  150, 150, 150,150, 
  150, 150, 150,150,
};

void setup() {
  Serial.println("play");
  Serial.begin(9600);
  for (unsigned char i = 0; i < NUM_OF_VOICES; i++) {
    pinMode(i+FIRST_TONE_PIN,OUTPUT);
    Serial.println(i);
  }

  //led indicator
  pinMode(LED_PIN,OUTPUT);

  Serial.println("play");

}

void loop() {
  // if we get here, we played the melody
  // all we can do is pee in corner of circular room

  // OPTIONAL. in this test example, the harmony and the melody are initially the same
  // so we raise the harmony up an octave and slow it down to 1/2 speed
  //for (int j = 0; j < (sizeof(harmony1) / sizeof(int)); j++) {
  //  harmony1[j] = harmony1[j] *2;
  //  harm1Durations[j] = harm1Durations[j] * 2;
  //  Serial.println(harmony1[j]);
  //}
  //for (int j = 0; j < (sizeof(melody1) / sizeof(int)); j++) {
  //  melody1[j] = melody1[j] *2;
  //  mel1Durations[j] = mel1Durations[j] * 2;
  //  Serial.println(melody1[j]);
  //}

  // call magic function to play both voices
  playTune(melody1, sizeof(melody1)/sizeof(int), mel1Durations, harmony1, sizeof(harmony1)/sizeof(int), mel1Durations);
  playTune(underworld_melody, sizeof(underworld_melody)/sizeof(int), underworld_tempo, underworld_melody1, sizeof(underworld_melody1)/sizeof(int), underworld_tempo);
}

// no need to modify anything below for basic use
void playTune(int melody[], int melLength, int melDurations[], int harmony[], int harmLength, int harmDurations[])
{
  unsigned int Counts[] = { 0, 0};
  unsigned int Periods[] = { 0, 0};
  unsigned char States[] = { 0, 0};

  unsigned long stopTimeNote1 = 0;
  unsigned long stopTimeNote2 = 0;
  unsigned char TimedPin = 0;
  unsigned int CurrentCount = 0;
  unsigned char i;
  unsigned char indexMel = 0, indexHarm = 0;

  while (1) {
    CurrentCount = Counts[0];
    TimedPin = 0;
    for (i=1;i<NUM_OF_VOICES;i++) {
      if (Counts[i] < CurrentCount) {
        TimedPin = i;
        CurrentCount = Counts[i];
      } // for
    }
    if (CurrentCount > 3)
      delayMicroseconds(CurrentCount);
    if (Periods[TimedPin] < 65535)
      States[TimedPin] = !States[TimedPin];

    digitalWrite(LED_PIN, HIGH);
    digitalWrite(FIRST_TONE_PIN+TimedPin,States[TimedPin]);
    digitalWrite(LED_PIN, LOW);

    if (millis() >= stopTimeNote1) {
      if (indexMel >= melLength)
        break;
      stopTimeNote1 = millis() + melDurations[indexMel];
      Periods[0] = 1000000 / melody[indexMel++];

    }
    if (millis() >= stopTimeNote2) {
      if (indexHarm >= harmLength)
        break;
      stopTimeNote2 = millis() + harmDurations[indexHarm];
      Periods[1] = 1000000 / harmony[indexHarm++];
    }

    for (i = 0; i < NUM_OF_VOICES; i++) {
      Counts[i] = Counts[i] - CurrentCount;
    }
    Counts[TimedPin] = Periods[TimedPin];
  }
}
(Visited 3,474 times, 4 visits today)
  • Andre

    this is bad ass ! wonderful demonstration.

    • Dipto Pratyaksa

      Thank you Andre!
      Have you tried programming any other theme songs that you can share with us in LinuxCircle?

  • Andre

    yes. I did make a little gamebox, with 4 games, I used yours for one and I made “Impossible Mission” myself. I also did it with one speaker using two digital outs plus I changed the play tone function to work while other code is executed. I would like to contribute and share, where should I put the source ?

    • Dipto Pratyaksa

      Hi Andre,
      I have created a contributor account for you, so you can write and publish the article here. Please check your email for your username and password.
      Thanks for sharing!

      • Andre

        Hy Dipto,
        It may take a few days till I will contribute a working / compiling stand alone version, as it is part of my “game engine”. But I´m looking forward to make it as fast as possible. Thanks for the account.

  • Anegan2015

    Hi Am new to Arduino Uno..can you please share the pin diagram with components.?