Electronic Drums Midi Mapper for Rock Band

This is my first post, so please forgive any oversights!
I wanted to hook my Yamaha DTXplorer drum kit to our Guitar Hero drum kit's midi input, and play the songs in the game using some "real drums".

More expensive drum kits can assign midi note numbers to the drum pads and cymbals, but the relatively inexpensive DTXplorer's brain requires some external remapping of the (standard) drum midi notes to those expected by the (Guitar Hero or Rock Band) video game. I'd been using my laptop plus the $10 eDrum MIDI Mapper software to do this, but it was time to put the laptop back to work doing it's "regular" job.

Thanks to some forum topics on how to interface to Midi (see MIDI under Communications in the Reference) and the sketch included below, I was able to get my Arduino to "echo" my e-drum hits over to the game controller's midi input. Strangely, though, I was limited to only about two drum hits per second. This was going to be totally impractical, not to mention that it was impossible for me to believe the AtMega368 couldn't process more than one note per 500 milliseconds! Turns out there is a poorly-documented catch in the Midi specs.

The sketch I've included is (as far as I can tell) different from most any applications I've been able to find using Google, in that it can handle the Midi Note-On mode. Basically, the midi note-on mode gets enabled with the first Note-On command, and although the Midi Note-On message is three bytes (command, note #, velocity) in length, subsequent notes may be sent without the command (the first of the three bytes). At least, that is, until some other command comes along which will terminate the Note-On mode. (The exception to this are the Midi Real-Time commands.)

Anyway, if anyone is interested I can put some detailed construction info up here on how I did it all "on the cheap". ($5 for Midi cables, $15 for Guitar Hero wireless drum brain, $8 for the enclosure and battery wires, $2 for resistors, $5 for a breadboard, and the cost of the Arduino itself). By simply adding a switch to Arduino you can easily change the mapping to best suit which game you're using at the moment (Guitar Hero or Rock Band) and preferred drum pad layout.
:slight_smile:

// Midi Drum Note Re-mapping utility
// All commands and data are assumed to be on channel 10.

// Global Variables: 
byte note = 0;        // The MIDI note value received and to be played
byte velocity = 0;    // Midi note velocity
byte stat = 0;        // Midi command/status byte
int ledPin =  13;     // LED connected to digital pin 13
boolean noteMode = false;    // Keep track of whether we have multiple notes going or not.

void setup() 
{
  //  Set MIDI baud rate:
  Serial.begin(31250);  // bit rate for Midi = (31250)
  // Initialize the digital pin as an output:
  pinMode(ledPin, OUTPUT);    
}

void loop() 
{
        digitalWrite(ledPin, LOW);    // set the LED on
        noteMode = false;
        stat = getCmd();  // wait for actual Midi Status byte
            switch (stat) // Now we'll take action based on the midi command.
            {

            case 248:  // if we received a Timing Clock, echo it
              Serial.print(stat, BYTE);
            break;

            case 254:  // if we received an "Active Sense", echo it and turn LED On
              digitalWrite(ledPin, HIGH);
              Serial.print(stat, BYTE);
            break;

            case 153:  // if we received a midi Note ON, turn on LED and enter the "note on" mode.
              noteMode = true;  // from now on just echo note & velocity received until we exit "Note ON" mode
                                // when we receive some (non-data or Real Time) command.
              digitalWrite(ledPin, HIGH);
              do {
              note = getData();
              velocity = getData();
                  switch (note)    // re-map note as necessary (this map is for Rock Band)
                  {
                  case 31:  // rx snare
                    note = 38;  // red
                    break;
                  case 33:  // rx kick
                    note = 36;  // purple
                    break;
                  case 34:  // rx snare open rim
                    note = 38;  // red
                    break;
                  case 37:  // rx snare close rim
                    note = 38;  // red
                    break;
                  case 42:  // rx hi hat close
                    note = 46;  // yellow
                    break;
                  case 46:  // rx hi hat open
                    note = 46;  // yellow
                    break;
                  case 47:  // rx mid tom
                    note = 48;  // blue
                    break;
                  case 48:  // rx hi tom
                    note = 46;  // yellow
                    break;
                  case 43:  // rx low tom
                    note = 45;  // green
                    break;
                  case 49:  // rx crash
                    note = 46;  // yellow
                    break;
                  case 51:  // rx ride
                    note = 49;  // orange
                    break;
                  case 52:  // rx ride edge
                    note = 49;  // orange
                    break;
                  case 57:  // rx crash edge
                    note = 46;  // yellow
                    break;
                  default:   // if no re-map matches, leave note as-is.
                    break;
                  }  // end note remapping switch
              noteOn(stat, note, velocity);
              note = 0;
              velocity = 0;
              }
              while (noteMode = true);
              stat = 0;
              break;

            case 240:  // received System Exclusive GM System ON (includes four bytes data + EOX)
              stat = getCmd();  // wait for EOX command (value = 247)
            break;

            case 247:  // received EOX; no need to do anything
            break;

            case 250:  // received Start
            break;

            case 251:  // received Continue
            break;

            case 252:  // received Stop
            break;

            case 255:  // received System Reset
            break;

            case 185:  // received Note OFF cmd: (grab two bytes data)
              note = getData();
              velocity = getData();
              noteOn(stat, note, velocity);
              note = 0;
              velocity = 0;
              stat = 0;
              break;

            default:  // if we have no command match, discard it for this version.
            break;

            stat = 0;
            } // end command switch
         //  digitalWrite(ledPin, LOW);    // set the LED off
}  // end loop

//////////////////////////////////////////////////////////////////////////////////////////////////
//  verify that an expected incoming data byte is < 127;
//  if not, assume a System Realtime msg and get the next byte
byte getData() {
byte value;
    value = 255;  // Begin assuming "non-data" value received to ensure that only 
    //               an incoming value <= 127 breaks out of the loop.
    do
    {
      if (Serial.available() > 0) 
      {  
      value = Serial.read();
      if (value > 127) {noteMode = false;}
      }
    }
    while (value > 127);  // waiting for data byte only (reject any commands)
    return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Wait for and verify that an expected incoming command byte is > or = 128
byte getCmd() {
byte value;
    value = 0;  // ensure that only an incoming value > 127 breaks out of the loop.
    do
    {
      if (Serial.available() > 0) 
      {  
      value = Serial.read();
      }
    }
    while (value < 128);  // waiting for Command byte
    noteMode = false;  // received command byte, so by default we're out of Note ON mode.
    return value;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  plays a three byte MIDI note.
void noteOn(byte midistat, byte midi1, byte midi2) 
{
  Serial.print(midistat, BYTE); // send midi note ON/OFF command, channel 10
  Serial.print(midi1, BYTE);  // send out note #
  Serial.print(midi2, BYTE);  // send out velocity
}

Hey I know it's been a while, but if you still have any schematics or construction notes, I'd love to see them. I'm about to do a very similar project to use my DTXplorer with Rock Band on the Wii.

Yikes, yes it's been a while, and right now I'm a long way from home and any notes I kept. I'd bought an inexpensive MIDI cable, cut off the connector, soldered wires onto the input of the Arduino, connected the output to the RockBand drum kit's wireless controller (there are tutorials out there on how to do this), and buttoned it all back up running the midi note translator sketch. I learned too much in the process about stuff I'll never need again.
Now that there's a ready-made adapter available for a reasonable price, I'd go with the RockBand3 Midi Adapter (Xbox 360 or Wii), which as I recall, works with our DTXplorer kits right out of the box, and/or a midi keyboard to boot! $40 from Amazon...

Your idea of using real drums is Great!

That's awesome, I didn't know there was an actual adapter out yet! And it does work with the DTXplorer, accrding to the manual [http://www.madcatz.com/UsersGuides/RockBand/RB3_98071_MUG.pdf ]. So I guess that puts an end to that. Although I'll prob make one also, since I already have a RB1 drum brain. Thanks for the help.