Custom Soundboard

Questions or comments, email joetcochranATgmailDOTcom

One of my all-time favorite video games is MegaMan 2 for the NES. It might be because it's one of the easiest games in the series, but it's also nostalgically fun to blow through the whole game on some lazy afternoon. Mostly though, I enjoy the catchy and highly memorable soundtrack in the game. I thought it would a be fun project to build a soundboard that could play all the different boss themes from the game.

Normal, please.


 

Hardware
A few years ago, in 2009, I won an Arduino Mega from a contest held by Libelium for my sketchduino project. It has been gathering dust ever since, and I thought it might be a good candidate for this project.

The Arduino has no native support for playing MP3's, and I wasn't interested in a shield, so I found the MP3 Trigger board which seems like it hooks into the Arduino pretty easily, but can also stand alone without a microcontroller for some future project.
I found some MP3's of the Megaman 2 soundtrack and loaded them onto a flash drive. Success! The MP3 Trigger has a built-in control to cycle through the tracks loaded onto a Micro SD flash card:

MP3 Trigger

 
The Soundboard
I thought a wood box would look nice with a 9 buttons, each corresponding to a Megaman character. When you push one of the 9 buttons, the Arduino Mega will send a serial command to the MP3 trigger. The MP3 Trigger will read the flash card and play the music for the corresponding Megaman character through the speaker mounted to the side of the box. For Megaman himself, we can play the Intro music.

At Michael's, there are lots of wood boxes available. The trick for me was to find one deep enough to hold all the electronics components. After selecting my box, I used my Dremel router bit to carve out the button holes. I stained it and put a coat of Triple Thick Gloss Glaze on it. Then, I set to work installing the buttons and soldering on my wires. 

Before too long, I realized that I could also add LED's to the wood frame, next to each button to highlight which song is playing. I found some 10mm LED's of various colors and began to drop them into the soundboard and solder the resistors on them.
 
LEDs, Unique Colors
Many of the colors I wanted to use (e.g. Red, Blue, Yellow) are sold specifically, but some colors are a little less common, and will require a RGB LED with a common anode/cathode to get more specific colors. This will also let me use analogWrite commands (an abstraction of PWM), something I've not done before.
Character/LED Color mappings  
Bubbleman  Green
Airman  Yellow 
Quickman Pink?
R=100 G=0 B=100
Heatman  Red 
Megaman  Blue 
Woodman  Light Green?
R=5 G=255 B=5
Metalman Darker Red?
R=250 G=0 B=5
Flashman White 
Crashman Orange 

 

The RGB LEDs arrived in the mail, and I wanted to see if I could produce some custom colors. The holes in my soundboard were not big enough, so I had to drill through to widen them a bit. The adafruit tutorial on RGB LEDs was an immense help to me in figuring out the wiring. For a longer time than I care to admit, I kept wiring the common anode to GND instead of the 5V port.

It seems that there is a much bigger difference at the lower end of the PWM spectrum than the higher end. For example, the difference between a PWM 0 value and PWM 5 value seems much greater than the difference between PWM 250 and PWM 255. For this reason, some of my R/G/B values are quite low, and non-zero (I use 5).

 

YouTube Video


Hardware funs: Arduino, MP3 Trigger, Speaker
Serial Communication
The arduino can communicate with the MP3 trigger via serial commands. The Mega has several serial ports available for use, but the only ones I could get working with the MP3 Trigger were the Serial ports 0 and 1 for some reason.
 
I found that I can hook the {TX on Arduino} to {RX on MP3 Trigger} and the RX on MP3 Trigger to TX on Arduino so that the Arduino can receive some of the Serial notifications which indicate that a track is done playing. We need to know when to turn off the LED's. I tried to hook into the STAT command (via TRIG18) from version 2.53 of the MP3 Trigger firmware, but I had very little success with this. I would have liked a little more documentation on how exactly to wire this, or how to create the MP3TRIGR.INI file to support this.
 
Power
The MP3 Trigger has a power selection option port for "USBVCC" and a onboard jumper to control the power source (USB vs. EXT). Feeding power from the Arduino seems work great. The speaker is a iHome rechargeable speaker, which runs off of its own rechargeable battery. The audio comes from the MP3 trigger via a standard 3.5mm headphone jack (but interfaces into the speaker with a Micro USB for recharging purposes).
 
Soldering 
To interface with the MP3 Trigger, I need to solder some header pins onto the board.
 
Got all my wiring set up. It's not pretty, so I preemptively created a meme.
 
 
Programming the Arduino
Below shows how the wires are connected to the Arduino:

 Boss

Digital

Digital

Analog 

Analog

Analog

  Button  LED Red LED Green LED  Blue LED 
 Bubbleman (UpperLeft) 22  31       
 Airman (UpperCenter) 23 32       
 Quickman (UpperRight) 24   
 Heatman (MiddleLeft) 25 33       
 Megaman (MiddleCenter) 26 34       
 Woodman (MiddleRight) 27   
 Metalman (LowerLeft) 28    10  11 
 Flashman (LowerMiddle) 29  35       
 Crashman (LowerRight) 30  36       
 

The Arduino sketch is below:
int led = 13;
boolean playingnow = false;

const byte BUBBLEMAN = 0x01;
int BUBBLEMAN_BUTTON = 22;
int BUBBLEMAN_LED = 31;
boolean BUBBLEMAN_PUSHED = false;
boolean BUBBLEMAN_PUSHED_NEW = false;

const byte AIRMAN = 0x02;
int AIRMAN_BUTTON = 23;
int AIRMAN_LED = 32;
boolean AIRMAN_PUSHED = false;
boolean AIRMAN_PUSHED_NEW = false;

const byte QUICKMAN = 0x03;
int QUICKMAN_BUTTON = 24;
int QUICKMAN_LED_PWM_RED = 3;
int QUICKMAN_LED_PWM_GREEN = 4;
int QUICKMAN_LED_PWM_BLUE = 5;
boolean QUICKMAN_PUSHED = false;
boolean QUICKMAN_PUSHED_NEW = false;

const byte HEATMAN = 0x04;
int HEATMAN_BUTTON = 25;
int HEATMAN_LED = 33;
boolean HEATMAN_PUSHED = false;
boolean HEATMAN_PUSHED_NEW = false;

const byte MEGAMAN = 0x05;
int MEGAMAN_BUTTON = 26;
int MEGAMAN_LED = 34;
boolean MEGAMAN_PUSHED = false;
boolean MEGAMAN_PUSHED_NEW = false;

const byte WOODMAN = 0x06;
int WOODMAN_BUTTON = 27;
int WOODMAN_LED_PWM_RED = 6;
int WOODMAN_LED_PWM_GREEN = 7;
int WOODMAN_LED_PWM_BLUE = 8;
boolean WOODMAN_PUSHED = false;
boolean WOODMAN_PUSHED_NEW = false;

const byte METALMAN = 0x07;
int METALMAN_BUTTON = 28;
int METALMAN_LED_PWM_RED = 9;
int METALMAN_LED_PWM_GREEN = 10;
int METALMAN_LED_PWM_BLUE = 11;
boolean METALMAN_PUSHED = false;
boolean METALMAN_PUSHED_NEW = false;

const byte FLASHMAN = 0x08;
int FLASHMAN_BUTTON = 29;
int FLASHMAN_LED = 35;
boolean FLASHMAN_PUSHED = false;
boolean FLASHMAN_PUSHED_NEW = false;

const byte CRASHMAN = 0x09;
int CRASHMAN_BUTTON = 30;
int CRASHMAN_LED = 36;
boolean CRASHMAN_PUSHED = false;
boolean CRASHMAN_PUSHED_NEW = false;

byte CurrentBoss = 0x00;

void setup() {
  Serial.begin(38400);
  pinMode(led, OUTPUT); 
  Serial.write('v');
  Serial.write(0x50);

  pinMode(BUBBLEMAN_BUTTON, INPUT);    
  pinMode(AIRMAN_BUTTON, INPUT);    
  pinMode(QUICKMAN_BUTTON, INPUT);    
  pinMode(HEATMAN_BUTTON, INPUT);    
  pinMode(MEGAMAN_BUTTON, INPUT);    
  pinMode(WOODMAN_BUTTON, INPUT);    
  pinMode(METALMAN_BUTTON, INPUT);    
  pinMode(FLASHMAN_BUTTON, INPUT);    
  pinMode(CRASHMAN_BUTTON, INPUT);   

  pinMode(BUBBLEMAN_LED, OUTPUT);    
  pinMode(AIRMAN_LED, OUTPUT);    
  pinMode(QUICKMAN_LED_PWM_RED, OUTPUT);    
  pinMode(QUICKMAN_LED_PWM_GREEN, OUTPUT);    
  pinMode(QUICKMAN_LED_PWM_BLUE, OUTPUT);    
  pinMode(HEATMAN_LED, OUTPUT);    
  pinMode(MEGAMAN_LED, OUTPUT);    
  pinMode(WOODMAN_LED_PWM_RED, OUTPUT);    
  pinMode(WOODMAN_LED_PWM_GREEN, OUTPUT);    
  pinMode(WOODMAN_LED_PWM_BLUE, OUTPUT);    
  pinMode(METALMAN_LED_PWM_RED, OUTPUT);    
  pinMode(METALMAN_LED_PWM_GREEN, OUTPUT);    
  pinMode(METALMAN_LED_PWM_BLUE, OUTPUT);    
  pinMode(FLASHMAN_LED, OUTPUT);    
  pinMode(CRASHMAN_LED, OUTPUT);    
 
  digitalWrite(BUBBLEMAN_BUTTON, HIGH);
  digitalWrite(AIRMAN_BUTTON, HIGH);
  digitalWrite(QUICKMAN_BUTTON, HIGH);
  digitalWrite(HEATMAN_BUTTON, HIGH);
  digitalWrite(MEGAMAN_BUTTON, HIGH);
  digitalWrite(WOODMAN_BUTTON, HIGH);
  digitalWrite(METALMAN_BUTTON, HIGH);
  digitalWrite(FLASHMAN_BUTTON, HIGH);
  digitalWrite(CRASHMAN_BUTTON, HIGH);
}
 
boolean BossButtonPushed(int BossButton)
{   return (digitalRead(BossButton) == LOW); }

void PlayBoss(byte Boss)
{
   Serial.write('p');
   Serial.write(Boss);
   TurnOffLEDs();  
   SetLEDs(Boss); 
   playingnow= true;  
}

void TurnOffLEDs()
{
      digitalWrite(BUBBLEMAN_LED, LOW);
      digitalWrite(AIRMAN_LED, LOW);
      setColor(QUICKMAN_LED_PWM_RED,
                QUICKMAN_LED_PWM_GREEN,
                QUICKMAN_LED_PWM_BLUE,
                0, 0, 0);
      digitalWrite(HEATMAN_LED, LOW);
      digitalWrite(MEGAMAN_LED, LOW);
      setColor(WOODMAN_LED_PWM_RED,
                WOODMAN_LED_PWM_GREEN,
                WOODMAN_LED_PWM_BLUE,
                0, 0, 0);
      setColor(METALMAN_LED_PWM_RED,
                METALMAN_LED_PWM_GREEN,
                METALMAN_LED_PWM_BLUE,
                0, 0, 0);
      digitalWrite(FLASHMAN_LED, LOW);
      digitalWrite(CRASHMAN_LED, LOW);
      digitalWrite(led, HIGH);       
}

void SetLEDs(byte Boss)
{
  switch (Boss)
  {
    case BUBBLEMAN:
      digitalWrite(BUBBLEMAN_LED, HIGH);
      break;
    case AIRMAN:
      digitalWrite(AIRMAN_LED, HIGH);
      break;
    case QUICKMAN:
      setColor(QUICKMAN_LED_PWM_RED,
                QUICKMAN_LED_PWM_GREEN,
                QUICKMAN_LED_PWM_BLUE,
                150, 0, 150);
      break;
    case HEATMAN:
      digitalWrite(HEATMAN_LED, HIGH);
      break;
    case MEGAMAN:
      digitalWrite(MEGAMAN_LED, HIGH);
      break;
    case WOODMAN:
      setColor(WOODMAN_LED_PWM_RED,
                WOODMAN_LED_PWM_GREEN,
                WOODMAN_LED_PWM_BLUE,
                5, 255, 5);
      break;
    case METALMAN:
      setColor(METALMAN_LED_PWM_RED,
                METALMAN_LED_PWM_GREEN,
                METALMAN_LED_PWM_BLUE,
                250, 0, 5);
      break;
    case FLASHMAN:
      digitalWrite(FLASHMAN_LED, HIGH);
      break;
    case CRASHMAN:
      digitalWrite(CRASHMAN_LED, HIGH);
      break;     
  }
 
}

void setColor(int redPin, int greenPin, int bluePin,
                int redValue, int greenValue, int blueValue)
{
  analogWrite(redPin, 255-redValue);
  analogWrite(greenPin, 255-greenValue);
  analogWrite(bluePin, 255-blueValue); 
}

void loop() {
 
    if (Serial.available() > 0) {
      // get incoming byte:
      byte inByte = Serial.read();
      if (inByte == 'X')
      {
        playingnow = false;
        TurnOffLEDs();
      }
    }
  BUBBLEMAN_PUSHED_NEW = BossButtonPushed(BUBBLEMAN_BUTTON);
  AIRMAN_PUSHED_NEW = BossButtonPushed(AIRMAN_BUTTON);
  QUICKMAN_PUSHED_NEW = BossButtonPushed(QUICKMAN_BUTTON);
  HEATMAN_PUSHED_NEW = BossButtonPushed(HEATMAN_BUTTON);
  MEGAMAN_PUSHED_NEW = BossButtonPushed(MEGAMAN_BUTTON);
  WOODMAN_PUSHED_NEW = BossButtonPushed(WOODMAN_BUTTON);
  METALMAN_PUSHED_NEW = BossButtonPushed(METALMAN_BUTTON);
  FLASHMAN_PUSHED_NEW = BossButtonPushed(FLASHMAN_BUTTON);
  CRASHMAN_PUSHED_NEW = BossButtonPushed(CRASHMAN_BUTTON);
   
  //check to see if any buttons just got unpressed.
  if ((BUBBLEMAN_PUSHED) && (!BUBBLEMAN_PUSHED_NEW))  {PlayBoss(BUBBLEMAN);}
  if ((AIRMAN_PUSHED) && (!AIRMAN_PUSHED_NEW))        {PlayBoss(AIRMAN);}
  if ((QUICKMAN_PUSHED) && (!QUICKMAN_PUSHED_NEW))    {PlayBoss(QUICKMAN);}
  if ((HEATMAN_PUSHED) && (!HEATMAN_PUSHED_NEW))      {PlayBoss(HEATMAN);}
  if ((MEGAMAN_PUSHED) && (!MEGAMAN_PUSHED_NEW))      {PlayBoss(MEGAMAN);}
  if ((WOODMAN_PUSHED) && (!WOODMAN_PUSHED_NEW))      {PlayBoss(WOODMAN);}
  if ((METALMAN_PUSHED) && (!METALMAN_PUSHED_NEW))    {PlayBoss(METALMAN);}
  if ((FLASHMAN_PUSHED) && (!FLASHMAN_PUSHED_NEW))    {PlayBoss(FLASHMAN);}
  if ((CRASHMAN_PUSHED) && (!CRASHMAN_PUSHED_NEW))    {PlayBoss(CRASHMAN);}
   
  //persist each button state for the next iteration
  BUBBLEMAN_PUSHED = BUBBLEMAN_PUSHED_NEW;
  AIRMAN_PUSHED = AIRMAN_PUSHED_NEW;
  QUICKMAN_PUSHED = QUICKMAN_PUSHED_NEW;
  HEATMAN_PUSHED = HEATMAN_PUSHED_NEW;
  MEGAMAN_PUSHED = MEGAMAN_PUSHED_NEW;
  WOODMAN_PUSHED = WOODMAN_PUSHED_NEW;
  METALMAN_PUSHED = METALMAN_PUSHED_NEW;
  FLASHMAN_PUSHED = FLASHMAN_PUSHED_NEW;
  CRASHMAN_PUSHED = CRASHMAN_PUSHED_NEW;
 
}


Controllers hooked up
No more technical challenges remain. The only (more cosmetic) challenges involve how to mount the speaker to the side of the box, and how to create some kind of removable (hinged?) panel to the box so
that the controllers are hidden.

Soundboard


Abstraction, Command Modes
Pretty quickly, I realized that I could make the whole thing more interesting and put different collections of tracks if I enabled certain command modes. I refactored the code to allow for entry into 2 Command Modes:
1) "Track Command Mode" by pressing buttons 1 (upperleft), 5 (middle), and 9 (lowerright)
2) "Volume Command Mode" by pressing buttons 3 (upperright), 5 (middle) and 7 (lowerleft)

Track Command Mode lets you select the active group of MP3 tracks (by pressing one of the buttons 1-9). I currently have 5 Track Groups loaded onto my flash card:
1: Megaman boss soundtracks
2: Other Megaman 2 sounds
3: Various Music Tracks, including Rick James' "Superfreak"
4: Napoleon Dynamite Quotes
5: Office Space Quotes
6: (empty)
7: (empty)
8: (empty)
9: (empty)

Volume Command Mode lets you control the volume. Press button 2 (upper middle) to turn volume up and button 8 (lower middle) to turn volume down. Fancy.

Here is the revised sketch:

int TrackCommandModeSequence = 0;
int VolumeCommandModeSequence = 0;

int led = 13;
boolean TrackCommandModeReady = false;
boolean VolumeCommandModeReady = false;
int TrackMode = 1;

const byte TRACK1 = 0x01;
int TRACK1_BUTTON = 22;
int TRACK1_LED = 31;
boolean TRACK1_PUSHED = false;
boolean TRACK1_PUSHED_NEW = false;

const byte TRACK2 = 0x02;
int TRACK2_BUTTON = 23;
int TRACK2_LED = 32;
boolean TRACK2_PUSHED = false;
boolean TRACK2_PUSHED_NEW = false;

const byte TRACK3 = 0x03;
int TRACK3_BUTTON = 24;
int TRACK3_LED_PWM_RED = 3;
int TRACK3_LED_PWM_GREEN = 4;
int TRACK3_LED_PWM_BLUE = 5;
boolean TRACK3_PUSHED = false;
boolean TRACK3_PUSHED_NEW = false;

const byte TRACK4 = 0x04;
int TRACK4_BUTTON = 25;
int TRACK4_LED = 33;
boolean TRACK4_PUSHED = false;
boolean TRACK4_PUSHED_NEW = false;

const byte TRACK5 = 0x05;
int TRACK5_BUTTON = 26;
int TRACK5_LED = 34;
boolean TRACK5_PUSHED = false;
boolean TRACK5_PUSHED_NEW = false;

const byte TRACK6 = 0x06;
int TRACK6_BUTTON = 27;
int TRACK6_LED_PWM_RED = 6;
int TRACK6_LED_PWM_GREEN = 7;
int TRACK6_LED_PWM_BLUE = 8;
boolean TRACK6_PUSHED = false;
boolean TRACK6_PUSHED_NEW = false;

const byte TRACK7 = 0x07;
int TRACK7_BUTTON = 28;
int TRACK7_LED_PWM_RED = 9;
int TRACK7_LED_PWM_GREEN = 10;
int TRACK7_LED_PWM_BLUE = 11;
boolean TRACK7_PUSHED = false;
boolean TRACK7_PUSHED_NEW = false;

const byte TRACK8 = 0x08;
int TRACK8_BUTTON = 29;
int TRACK8_LED = 35;
boolean TRACK8_PUSHED = false;
boolean TRACK8_PUSHED_NEW = false;

const byte TRACK9 = 0x09;
int TRACK9_BUTTON = 30;
int TRACK9_LED = 36;
boolean TRACK9_PUSHED = false;
boolean TRACK9_PUSHED_NEW = false;

byte Volume = 0x40;
void setup() {
  pinMode(led, OUTPUT);    
  FlashAllLEDs(3);

  Serial.begin(38400);
  Serial.write('v');
  Serial.write(Volume);

  pinMode(TRACK1_BUTTON, INPUT);    
  pinMode(TRACK2_BUTTON, INPUT);    
  pinMode(TRACK3_BUTTON, INPUT);    
  pinMode(TRACK4_BUTTON, INPUT);    
  pinMode(TRACK5_BUTTON, INPUT);    
  pinMode(TRACK6_BUTTON, INPUT);    
  pinMode(TRACK7_BUTTON, INPUT);    
  pinMode(TRACK8_BUTTON, INPUT);    
  pinMode(TRACK9_BUTTON, INPUT);   


  pinMode(TRACK1_LED, OUTPUT);    
  pinMode(TRACK2_LED, OUTPUT);    
  pinMode(TRACK3_LED_PWM_RED, OUTPUT);    
  pinMode(TRACK3_LED_PWM_GREEN, OUTPUT);    
  pinMode(TRACK3_LED_PWM_BLUE, OUTPUT);    
  pinMode(TRACK4_LED, OUTPUT);    
  pinMode(TRACK5_LED, OUTPUT);    
  pinMode(TRACK6_LED_PWM_RED, OUTPUT);    
  pinMode(TRACK6_LED_PWM_GREEN, OUTPUT);    
  pinMode(TRACK6_LED_PWM_BLUE, OUTPUT);    
  pinMode(TRACK7_LED_PWM_RED, OUTPUT);    
  pinMode(TRACK7_LED_PWM_GREEN, OUTPUT);    
  pinMode(TRACK7_LED_PWM_BLUE, OUTPUT);    
  pinMode(TRACK8_LED, OUTPUT);    
  pinMode(TRACK9_LED, OUTPUT);    
 

  digitalWrite(TRACK1_BUTTON, HIGH);
  digitalWrite(TRACK2_BUTTON, HIGH);
  digitalWrite(TRACK3_BUTTON, HIGH);
  digitalWrite(TRACK4_BUTTON, HIGH);
  digitalWrite(TRACK5_BUTTON, HIGH);
  digitalWrite(TRACK6_BUTTON, HIGH);
  digitalWrite(TRACK7_BUTTON, HIGH);
  digitalWrite(TRACK8_BUTTON, HIGH);
  digitalWrite(TRACK9_BUTTON, HIGH);

   TurnOffAllLEDs();
}

 
boolean ButtonPushed(int Button)
{
  return (digitalRead(Button) == LOW);
}

void PlayTrack(byte Boss)
{
   Serial.write('p');
   int Track = (int)Boss;
   byte AbsoluteTrack = (byte)(Track + ((TrackMode - 1)  * 9));
   Serial.write(AbsoluteTrack);
   TurnOffAllLEDs();  
   SetLEDs(Boss);    
}
void TurnOffAllLEDs()
{
      digitalWrite(TRACK1_LED, LOW);
      digitalWrite(TRACK2_LED, LOW);
      setColor(TRACK3_LED_PWM_RED, TRACK3_LED_PWM_GREEN, TRACK3_LED_PWM_BLUE, 0, 0, 0);
      digitalWrite(TRACK4_LED, LOW);
      digitalWrite(TRACK5_LED, LOW);
      setColor(TRACK6_LED_PWM_RED, TRACK6_LED_PWM_GREEN, TRACK6_LED_PWM_BLUE, 0, 0, 0);
      setColor(TRACK7_LED_PWM_RED, TRACK7_LED_PWM_GREEN, TRACK7_LED_PWM_BLUE, 0, 0, 0);
      digitalWrite(TRACK8_LED, LOW);
      digitalWrite(TRACK9_LED, LOW);
}

void SetLEDs(byte Boss)
{
  switch (Boss)
  {
    case TRACK1:
      digitalWrite(TRACK1_LED, HIGH);
      break;
    case TRACK2:
      digitalWrite(TRACK2_LED, HIGH);
      break;
    case TRACK3:
      setColor(TRACK3_LED_PWM_RED, TRACK3_LED_PWM_GREEN, TRACK3_LED_PWM_BLUE, 150, 0, 150);
      break;
    case TRACK4:
      digitalWrite(TRACK4_LED, HIGH);
      break;
    case TRACK5:
      digitalWrite(TRACK5_LED, HIGH);
      break;
    case TRACK6:
      setColor(TRACK6_LED_PWM_RED, TRACK6_LED_PWM_GREEN, TRACK6_LED_PWM_BLUE, 5, 255, 5);
      break;
    case TRACK7:
      setColor(TRACK7_LED_PWM_RED, TRACK7_LED_PWM_GREEN, TRACK7_LED_PWM_BLUE, 250, 0, 5);
      break;
    case TRACK8:
      digitalWrite(TRACK8_LED, HIGH);
      break;
    case TRACK9:
      digitalWrite(TRACK9_LED, HIGH);
      break;     
  }
 

}

void setColor(int redPin, int greenPin, int bluePin, int redValue, int greenValue, int blueValue)
{
  analogWrite(redPin, 255-redValue);
  analogWrite(greenPin, 255-greenValue);
  analogWrite(bluePin, 255-blueValue); 
}


void SetVolumeUp()
{
  if (Volume != 0x00)
  {
    Volume = Volume - 0x08;
    Serial.write('v');
    Serial.write(Volume); 
  }
}

void SetVolumeDown()
{
  if (Volume != 0xFF)
  {
    Volume = Volume + 0x08;
    Serial.write('v');
    Serial.write(Volume); 
  }
}

boolean CheckCommandMode(int button)
{
  if ((!TrackCommandModeReady) && (!VolumeCommandModeReady))
  {
    //5=5=5
    if ((button == 1) && (TrackCommandModeSequence == 0))
        TrackCommandModeSequence++;
    else if ((button == 5) && (TrackCommandModeSequence == 1))
        TrackCommandModeSequence++;
    else if ((button == 9) && (TrackCommandModeSequence == 2))
        TrackCommandModeSequence++;
    else if ((button == 3) && (VolumeCommandModeSequence == 0))
        VolumeCommandModeSequence++;
    else if ((button == 5) && (VolumeCommandModeSequence == 1))
        VolumeCommandModeSequence++;
    else if ((button == 7) && (VolumeCommandModeSequence == 2))
        VolumeCommandModeSequence++;
    else
    {
      TrackCommandModeSequence = 0;
      VolumeCommandModeSequence = 0;
    }  
     
    if (TrackCommandModeSequence == 3)
    {
      TrackCommandModeReady = true;
      TrackCommandModeSequence = 0;
      Serial.write('O');
      FlashAllLEDs(3);
      return true;
    }
    else if (VolumeCommandModeSequence == 3)
    {
      VolumeCommandModeReady = true;
      VolumeCommandModeSequence = 0;
      Serial.write('O');
      FlashAllLEDs(2);
      return true;    
    }
    else
    {
      return false;
    }
  }
  else if (TrackCommandModeReady)
  {
    if (button == 1)
      TrackMode = 0x01;
    if (button == 2)
      TrackMode = 0x02;
    if (button == 3)
      TrackMode = 0x03;
    if (button == 4)
      TrackMode = 0x04;
    if (button == 5)
      TrackMode = 0x05;

    FlashAllLEDs(1); 
    TrackCommandModeReady = false;
    return true;
  }
  else if (VolumeCommandModeReady)
  {
    if (button == 2)
      SetVolumeUp();
    if (button == 8)
      SetVolumeDown(); 
    FlashAllLEDs(1);
    VolumeCommandModeReady = false; 
    return true;
  }
}

void TurnOnAllLEDs()
{
  SetLEDs(0x01);
  SetLEDs(0x02);
  SetLEDs(0x03);
  SetLEDs(0x04);
  SetLEDs(0x05);
  SetLEDs(0x06);
  SetLEDs(0x07);
  SetLEDs(0x08);
  SetLEDs(0x09);
}

void FlashAllLEDs(int count)
{
  do
  {
    TurnOnAllLEDs();
    delay(300);
    TurnOffAllLEDs();
    delay(300);
    count--;
  } while (count !=0);
}

void FlashDebugLED(int count)
{
  while (count != 0)
  {
    digitalWrite(led,HIGH);
    delay(300);
    digitalWrite(led,LOW);
    delay(300);
    count--;
  }
  delay(1000);
}

void loop() {
 
    if (Serial.available() > 0) {
      // get incoming byte:
      byte inByte = Serial.read();
      if (inByte == 'X')
      {
        TurnOffAllLEDs();
      }
    }
 
  TRACK1_PUSHED_NEW = ButtonPushed(TRACK1_BUTTON);
  TRACK2_PUSHED_NEW = ButtonPushed(TRACK2_BUTTON);
  TRACK3_PUSHED_NEW = ButtonPushed(TRACK3_BUTTON);
  TRACK4_PUSHED_NEW = ButtonPushed(TRACK4_BUTTON);
  TRACK5_PUSHED_NEW = ButtonPushed(TRACK5_BUTTON);
  TRACK6_PUSHED_NEW = ButtonPushed(TRACK6_BUTTON);
  TRACK7_PUSHED_NEW = ButtonPushed(TRACK7_BUTTON);
  TRACK8_PUSHED_NEW = ButtonPushed(TRACK8_BUTTON);
  TRACK9_PUSHED_NEW = ButtonPushed(TRACK9_BUTTON);
 
 
     
  //check to see if any buttons just got unpressed.
  if ((TRACK1_PUSHED) && (!TRACK1_PUSHED_NEW))  {if (!CheckCommandMode(1)) {PlayTrack(TRACK1);}}
  if ((TRACK2_PUSHED) && (!TRACK2_PUSHED_NEW))        {if (!CheckCommandMode(2)) {PlayTrack(TRACK2);}}
  if ((TRACK3_PUSHED) && (!TRACK3_PUSHED_NEW))    {if (!CheckCommandMode(3)) {PlayTrack(TRACK3);}}
  if ((TRACK4_PUSHED) && (!TRACK4_PUSHED_NEW))      {if (!CheckCommandMode(4)) {PlayTrack(TRACK4);}}
  if ((TRACK5_PUSHED) && (!TRACK5_PUSHED_NEW))      {if (!CheckCommandMode(5)) {PlayTrack(TRACK5);}}
  if ((TRACK6_PUSHED) && (!TRACK6_PUSHED_NEW))      {if (!CheckCommandMode(6)) {PlayTrack(TRACK6);}}
  if ((TRACK7_PUSHED) && (!TRACK7_PUSHED_NEW))    {if (!CheckCommandMode(7)) {PlayTrack(TRACK7);}}
  if ((TRACK8_PUSHED) && (!TRACK8_PUSHED_NEW))    {if (!CheckCommandMode(8)) {PlayTrack(TRACK8);}}
  if ((TRACK9_PUSHED) && (!TRACK9_PUSHED_NEW))    {if (!CheckCommandMode(9)) {PlayTrack(TRACK9);}}
   
  //persist each button state for the next iteration
  TRACK1_PUSHED = TRACK1_PUSHED_NEW;
  TRACK2_PUSHED = TRACK2_PUSHED_NEW;
  TRACK3_PUSHED = TRACK3_PUSHED_NEW;
  TRACK4_PUSHED = TRACK4_PUSHED_NEW;
  TRACK5_PUSHED = TRACK5_PUSHED_NEW;
  TRACK6_PUSHED = TRACK6_PUSHED_NEW;
  TRACK7_PUSHED = TRACK7_PUSHED_NEW;
  TRACK8_PUSHED = TRACK8_PUSHED_NEW;
  TRACK9_PUSHED = TRACK9_PUSHED_NEW;
 
}




Demo of Command Modes below:

Command Modes



Cross-Stitch Supplemental

Separately from the sound board, I wanted some kind of interesting display of each boss, but each piece should be able to stand alone as its own finished product. I had recently finished a cross-stitching project (Disco Stu, right), a challenging piece that I decided to tackle after discovered the website pic2pat.com. The Disco Stu cross-stitch project was tough mostly because of the number of colors involved (about 50). As the project got closer to completion, I found it increasingly difficult to match up the canvas location with the stitch instructions generated by the website. For example, trying to visually discern the difference between Ultra Very Light Beige Brown and Light Mocha Brown was rather difficult.

 
 
Despite my subject's strict aversion 
to advertisement..

It occurred to me that video game sprites lend themselves very well to cross-stitching patterns. They also have much fewer distinct colors to worry about. I found some Megaman 2 sprites online, and laid out the 100x100 stitch pattern using Paint.NET.



Future Enhancements
Power: I'd also like to run the Arduino off of a 9V battery and put a power toggle on the side of the soundboard. I have some spare 9V battery snap-connectors I can put to use.
Reduce electronic footprint: I get the sense I've gone overboard with the controllers on this project. I suspect there's a way I could liberate the Arduino from this whole configuration if I were more clever about using the MP3 Trigger the way it was designed.
MP3 Trigger cuts out: The MP3 Trigger sometimes cuts out in the middle of a track. I haven't been able to fix this yet.
White LED: The White LED seems really bright, leading me to think I used the wrong type of resistor on it. Might need to rewire that before it burns out.

Questions or comments, email joetcochranATgmailDOTcom

Comments