Guitar Hero Midi Controller

Hi everyone. I’ve been tinkering with the arduino/boarduino/freeduino and put together a pretty cool project i’d like to share. I’d love some pointers on the code as well. I’m sure it can be smaller or better formed, but have no formal training in such things. heres the code for the main program. I also wrote a library for some basic MIDI commands as well as a library for the guitar commands they can be found at…
main program - http://www.dwdesignlabs.com/GuitarHeroMidi.zip
midi library - http://www.dwdesignlabs.com/Midi.zip
wii guitar library - http://www.dwdesignlabs.com/guitar_funcs.zip
& the blog and main page are at http://slapyak.wordpress.com/guitar-hero-midi-controller/

the GuitarHeroMidi gets unzipped to the projects folder, the other 2 go into your libraries folder.

/*

This is a program for Arduino written for the purpose of using a Wii Guitar Hero Controller
as a MIDI input device. As with most arduino projects, this is released under the GNU
understanding. The use of and modification of the software for personal use is granted. 
however rights of sale of completed Guitar Hero Midi Controllers, or kits for the same is 
reserved. any commercialization of this kit may only be with the express written consent of
the original author.

The use of the MIDI library from http://slapyak.wordpress.com/ is required.
 author: Dave Wernli (slapyak)
 created: April 2008
 website: http://slapyak.wordpress.com/ 

resources:
 Midi Guide:      http://www.indiana.edu/~emusic/etext/MIDI/chapter3_MIDI.shtml
 I2C (wire) library: included with new arduino environment disrtibutions
 Wii adaptor/code: Tod Kurt -  http://www.todbot.com
      Windmeadow labs - http://www.windmeadow.com/node/42
 Wii guitar mapping, function basics: Jason Leyrer - http://www.jleyrer.net/
 LCD4Bit library: http://www.arduino.cc/playground/Code/LCD4BitLibrary
 Arduino Playground: Serial, test library, countless tidbits from the forum posts
*/


/***********************************************************************************************
*          guitar Hero Midi Controller.
*          By: Dave Wernli (SlapYak)
*          http://www.dwdesignlabs.com/projects/
*          April 2008
************************************************************************************************/

//includes
#include <Wire.h>
//#include <LCD4Bit.h>      // for output to lcd. hooked into pins 4,5,6,7
#include <Midi.h>
#include "guitar_funcs.h" // available at http://googlepages.slapyak.com & http://slapyak.wordpress.com
      
Midi midi=Midi();
//LCD4Bit lcd = LCD4Bit(2);


#define latchPin 16      // setting up our shift registers  
#define dataPin 14            // the input and output registers are connected serially
#define clockPin 15      // we'll only be accessing the input register at startup 
#define commandDelay 150      // a variable for experimenting with the loop
                        // to avoid duplicate commands cancelling each other out.
#define mCC_1 71                // the controller for resonance, changes with joystick X
#define mCC_2 74                // the controller for frequency, chages with joystick Y

uint8_t mode=0;            // holds byte indicating mode selection - 
      // scale is the tonal mode - 
      // Ionian, Mixolydian, Lydian, Dorian, Aeolian, Phrygian, Locrian, Petatonic(not really a mode, and not in use...)
uint8_t scale=0;
uint8_t scale_chart[8][7]={{0,2,4,5,7,9,11},{0,2,3,5,7,9,10},{0,1,3,5,7,8,10},{0,2,4,6,7,9,11},{0,2,4,5,7,9,10},{0,2,3,5,7,8,10},{0,1,3,5,6,8,10},{0,4,7,9,12,16,19}};
//char scale_name[24] = {"Ion", "Dor", "Phy", "Lyd", "Mix", "Aeo", "Loc", "PET"};
uint8_t octave= 4;
uint8_t key = 0;
      // chord will hold our chord patterns and position in the pattern
uint8_t chord = 0;
uint8_t chord_chart[4][4]={{0,0,0,0},{0,4,0,0},{0,3,5,0},{0,7,12,16}};
uint8_t buttonstatus;                  // button/strum info - referenced in binary (a bit for each button)
uint8_t oldButtonStatus=0;            // to compare to avoid duplicate commands from a single action
byte mCC_1val = 64;                        // controller 1 value xJoy, controlls timbre
byte mCC_2val = 64;                        // controller 2 value yJoy, controlls resonance
byte wham = 0;                  // a boolean value to control how often we enter the pitchbend funtion.
uint8_t dipSwitch = 0;          // to hold our dipswitch information
uint8_t drumOn = 0;            // keeps track of drums that are playing, so we dont just re-trigger the drums over and over
  uint8_t drumUp = 0x2E;      // sets up strum to open hi-hat
  uint8_t drumDn = 0x2A;      // sets down strum to closed hi-hat      
  uint8_t drumGr = 0x24;      // sets green button to kick      
  uint8_t drumRe = 0x26;      // sets red button to snare
  uint8_t drumYe = 0x30;      // sets yellow to high tom
  uint8_t drumBl = 0x2D;      // sets blue to low tom
  uint8_t drumOr = 0x33;      // sets orange to ride      
  uint8_t drumPlus = 0x31;      // sets plus to crash one
  uint8_t drumMinus = 0x39;      // sets minus to crash two
void setup(){
 pinMode(13,OUTPUT);
 pinMode(latchPin, OUTPUT);
 pinMode(clockPin, OUTPUT);
 pinMode(dataPin, OUTPUT);
 pinMode(9,OUTPUT);
 pinMode(10,OUTPUT);
 pinMode(11,OUTPUT);
 pinMode(12,OUTPUT);
 delay(100); // wait for things to stabilize 
 midi.startMidi();            // initialize out midi connection, pin 1, serial tx is data pin
 guitar_initialize();            // initialize wii i2c connection to guitar
 //lcd.init();            // initialize 4Bit lcd connection. I modified the library to allow an
                   // set shift register pins to input
 delay(100);            // let all that soak in.
 dipSwitch = getDips();
 mode = (dipSwitch>>7 & 1);            // and read data in from dipswitches
                              // mode, note hold/release, open, open, key(4 switches)
 key = (dipSwitch & 15);            //  
 if (key >11){key=0;}            // key 0 is C, 1 is C#, etc...
 delay(100);                  // short delay to allow everything to catch up.
                  // set shift register to output
                  // and light up appropriate leds for mode indication.
//lcd.clear();
//delay(50);
//lcd.println("MIDI GUI                                TAR HERO"); // spaces are to put us onto line 2 for the second half of the message
//lcd.cursorTo(1,40);
//lcd.println("TAR HERO");
//lcd.leftScroll(9,50);
//Serial.begin(38400);//debugging to serial. value is close to midi output so we can see if the communication speed is causgin a an issue.
  if(dipSwitch>127){digitalWrite(13,HIGH);delay(1000);digitalWrite(13,LOW);delay(10000);delay(10000);delay(1000);}
  delay(200);
  digitalWrite(13,HIGH);  // useful for telling when we get to this point.
  chordLights();
}


/****************************************************************************************
//////////////////////////////////// MAIN PROGRAM LOOP///////////////////////////////////
****************************************************************************************/

void loop(){
  digitalWrite(13,HIGH);  
  guitar_refresh();                        // get new info from the guitar to arduino
  buttonstatus = guitar_buttons();
  digitalWrite(13,LOW);

  setMode();                              // guitar mode or drum mode?
       switch(mode){
         case 0:                        // guitar mode                
               if ((buttonstatus<<2) != (oldButtonStatus<<2)){ // if our buttons have changed
                      if(dipSwitch & 64 || chord > 0){        // if dipswitch 2 is down or chords are on  
                    midi.noteOffAll();       // this will stop notes every time a new note is played
                      }
                      if (buttonstatus > 32){      // if the strum bar is up or down we'll be greater than this
                           setKey();               // checks for chord type changes
                  guitarMode();            // plays the notes                        
              }else{                  // if strum bar is at rest                              
                         midi.noteOffAll();                   
              }
              oldButtonStatus = buttonstatus;
              }
             setWhammy();
             break;
         case 1:                        // drum mode
            drumMode();
            break;
                         // reset our comparison variable
      }
}

////////////////////////////////////  Mode selection  ///////////////////////////////////
// this checks the recent input from the guitar and if it was buttons 1-4 and a strum
// will change the mode to whatever is next. Only modes 0&1 are currently active.
// the status leds and chord mode are alse set within this block. 
/////////////////////////////////////////////////////////////////////////////////////////
void setMode(){
      if(buttonstatus==B01011110){                        // if buttons 1-4 are down w/ down strum
                  mode++;                                                // go to the next mode up
                  if(mode>=1&&mode<100){mode=1;}                  // here you'd change the max mode #            
                  statusLed(12);                                    // sets LEDs to proper illumination
                  midi.noteOffAll();                              // stop all notes before switching modes
                  delay(commandDelay);
                  midi.setChannel(0);
                  if (mode==1){
                    midi.setChannel(10);            //drum channel
                    }
      }
      if(buttonstatus==B10011110){                        // if buttons 1-4 are down w/ up strum
                  mode--;                                                // go to the next mode down
                  if(mode>=100){mode=0;}
                  delay(commandDelay);                        
                  midi.noteOffAll();                              // stop all notes
                  chordLights();
                  midi.setChannel(0);
      }      
}

////////////////////////////// Key and Scale selection ////////////////////////////////
// this controls the octave, key, and tonal mode called “tonal” in variables
// up and down control key up and down
// left and right change the tonal mode - check out some musical theory for detail on this
////////////////////////////////////////////////////////////////////////////////////////
void setKey(){
switch (buttonstatus){
case B01010001: // key change up
key += 5; // moves up the circle of 5ths (more theory stuff)
if (key>11){ // this is to keep the root note in the octave
key -= 12; // selected - so we can still get the full range
}
delay(commandDelay);
break;

case B10010001: // key change down
key -= 5; // moves back in the circle of 5ths
if (key >= 240 ){
key += 12;
}
delay(commandDelay);
break;

case B01011011: // mode change up
scale++; // change tonal mode
if (scale>6 && scale<250){
scale -7; // we want them to circle around though.
}
delay(commandDelay);
break;

case B10011011: // mode change down
scale++; // change tonal mode
if (scale >= 250){
scale += 6; // we want them to circle around though.
}
delay(commandDelay);
break;

//////////////////////////////////// Chord Select /////////////////////////////////////
// changes chord mode:
// 0 = root note only
// 1 = root + fifth
// 2 = root + third + fifth
// 3 = power chord (root + fifth + octave + 2nd third
/////////////////////////////////////////////////////////////////////////////////////////
case B01010010: // chord selection - single note, root-3-5, root-4, power chord
chord++;
if(chord>=3&&chord<100){chord=3;}
chordLights();
delay(commandDelay);
break;

case B10010010: // chord selection - single note, root-3-5, root-4, power chord
chord–;
if(chord>=100){chord=0;}
chordLights();
delay(commandDelay);
break;
}
}

//////////////////////////////////// Chord Lights ///////////////////////////////////
// turns on the 8 lights that indicate which chord mode you’re in
/////////////////////////////////////////////////////////////////////////////////////////
void chordLights(){
switch (chord){ // different lights indicate different
case 0: // chord patterns - defined by chord_chart
statusLed(1); // lights LEDS
break;
case 1: // root & fifth
statusLed(2); // lights LEDS as
break;
case 2: // root, third & fifth
statusLed(7); // lights LEDS as
break;
case 3: // power chord
statusLed(11); // lights LEDS
break;
}
}

////////////////////////////// Whammy & effects ////////////////////////////////
// checks the joystick and whammy bar for movement
// whammy bar will pitchbend up about a half step at full on
// the joystick controls 2 continuous controllers, could be just about anything…
////////////////////////////////////////////////////////////////////////////////////////

void setWhammy(){
if (guitar_whammy()>2){ // the whammy moves a little at rest…
midi.pitchBend((guitar_whammy()-2)*600); //whammy returns a value between 1 & 10, 4000 bend value is roughly a half tone
wham = true; //sets a control variable so we arent running extra commands when the bar is at rest
}else{
if(guitar_whammy()<=2 && wham==true){ // this only runs once after the pitch was bent, then just skips both midi. send statements
midi.pitchReset();
wham = false;
}
}

// then we check the joystick and set the continuous controllers
if (guitar_joyX()>35) { //the joystick goes from 0 - 60 with 30 being the center
mCC_1val += ((guitar_joyX() -35)/3); // moves the CC around based on how far the joystick is pressed
mCC_1val = constrain(mCC_1val, 0, 127);
midi.controllerCmd(mCC_1, mCC_1val);
}else{
if (guitar_joyX()<25) { //the joystick goes from 0 - 60 with 30 being the center
mCC_1val -= ((25-guitar_joyX())/3); // moves the CC around based on how far the joystick is pressed
mCC_1val = constrain(mCC_1val, 0, 127);
midi.controllerCmd(mCC_1, mCC_1val);
}
}
if (guitar_joyY()>35) { //the joystick goes from 0 - 60 with 30 being the center
mCC_2val += ((guitar_joyY() -35)/3); // moves the CC around based on how far the joystick is pressed
mCC_2val = constrain(mCC_2val, 0, 127);
midi.controllerCmd(mCC_2, mCC_2val);
}else{
if (guitar_joyY()<25) { //the joystick goes from 0 - 60 with 30 being the center
mCC_2val -= ((25-guitar_joyY())/3); // moves the CC around based on how far the joystick is pressed
mCC_2val = constrain(mCC_2val, 0, 127);
midi.controllerCmd(mCC_2, mCC_2val);
}
}
if (guitar_plus()){
octave++;
if(octave>7&&octave<100){octave=8;} // (ocatave, 2, 7) may be more normal sounding
delay(2commandDelay); // full octave range is 0-9, but a piano is 2-7
getDips(); // resets dip settings without a full reset.
}
if (guitar_minus()){
octave–;
if(octave>=100 || octave<1){octave=1;} // (ocatave, 2, 7) may be more normal sounding
delay(2
commandDelay);
getDips();
}

}

//////////////////////////////////// guitar Mode //////////////////////////////////////
// this function is the heart of the Guitar Hero Midi Controller.
// based on the current key, octave, button press and strum stroke, the proper note
// will be played via midi.
/////////////////////////////////////////////////////////////////////////////////////////
void guitarMode(){

uint8_t buttons = buttonstatus << 2; // bitshift to get rid of strum info
buttons = buttons >> 2; // bitshift back to original position

byte note = 0;

switch (buttons)
{
case B00000000: // no buttons pressed - ROOT
play_note(0,0);
break; // exit case loop
case B00010000: // buttons: X _ _ _ _
play_note(1,0);
break;
case B00011000: // buttons: X X _ _ _
play_note(2,0);
break;
case B00001000: // buttons: _ X _ _ _
play_note(3,0);
break;
case B00001100: // buttons: _ X X _ _
play_note(4,0);
break;
case B00010100: // buttons: X _ X _ _
play_note(5,0);
break;
case B00011100: // buttons: X X X _ _
play_note(6,0);
break;
case B00000100: // buttons: _ _ X _ _
play_note(0,1);
break;
case B00000110: // buttons: _ _ X X _
play_note(1,1);
break;
case B00001010: // buttons: _ X _ X _
play_note(2,1);
break;
case B00001110: // buttons: _ X X X _
play_note(3,1);
break;
case B00000010: // buttons: _ _ _ X _
play_note(4,1);
break;
case B00000011: // buttons: _ _ _ X X
play_note(5,1);
break;
case B00000101: // buttons: _ _ X _ X
play_note(6,1);
break;
case B00000111: // buttons: _ _ X X X
play_note(0,2);
break;
case B00000001: // buttons: _ _ _ _ X
play_note(0,2);
break;
default:
break;
}
}

//////////////////////////////////// Play Note ///////////////////////////////////////////
// the switch-case satement in guitar mode calls this function and passes two numbers,
// the first is the note as a number of the scale (0-6)
// then the octave of the scale as the second variable.
///////////////////////////////////////////////////////////////////////////////////////////
void play_note(uint8_t scalePos, uint8_t _octa){
byte velocity = 70 + guitar_strumUp()15 + guitar_strumDn()40; // not the most elegant way,
uint8_t note = 0; // but allows for up, down, (and hammer ons in the future)
uint8_t root = key + (octave
12); // root is the root note of the possible chords we’d play
int i = 0;
do{
note = root + (_octa
12) + scale_chart[scale][scalePos]; // root + our place in the chord
if(chord==3){ //allows for powerchords to work differently from normal chords
note += chord_chart[chord]; // power chords are always the same.

  • }else{*
    note += scale_chart[scale][chord_chart[chord]]; // these will sound different based on the mode/key
    * }*
    * midi.noteOn(note, velocity); // send the midi command*
    * i++;*
    }while (chord_chart[chord]>0&&i<4);
    }
    //////////////////////////////////// Drum Mode //////////////////////////////////////
    // similar to guitar mode, only the buttons all react in a preset manner.
    // strumming is not necessary (but has its own sounds)
    // programming mode is a future addition that will allow the user to change the note
    // sent by each button. I just have not worked out the control scheme for it.
    /////////////////////////////////////////////////////////////////////////////////////////
    void drumMode(){
    * playDrums(7, drumUp);*
    * playDrums(6, drumDn);*
    * playDrums(4, drumGr);*
    * playDrums(3, drumRe);*
    * playDrums(2, drumYe);*
    * playDrums(1, drumBl);*
    * playDrums(0, drumOr);*
    * playDrums(10, drumPlus);*
    * playDrums(11, drumMinus);*

* if ((buttonstatus & 128) && (drumOn ^ 128)) // if the strum bar is up and we are not already playing this*
* {*
* midi.noteOn(0x2E, 100); // sends a open high hat note on.*
* drumOn += 128;*
* }else if ((buttonstatus^128) && (drumOn & 128)) // if the strum bar is released and we were playing a note.*
* midi.noteOff(0x2E);*
* drumOn -= 128;*
* {*
* }*
}
//////////////////////////////////// Play Drums ///////////////////////////////////////
// as of this writing - channel 10 is found to not be the drum channel and the
// note repeats until you release the button. The intended operation would have the
// note play once, ring out and be ready to play again.
/////////////////////////////////////////////////////////////////////////////////////////
void playDrums(uint8_t _position, uint8_t _but){
if (_position <8)
{
* position = pow(2,position);
if ((buttonstatus & position) && (drumOn ^ position)) // if the button is on and the note is not yet playing*
* {*

* midi.noteOn(but, 100); // sends a open high hat note on.
drumOn += position;
}else if ((buttonstatus^ position) && (drumOn & position)) // if the button is up and we’re playing a note.
midi.noteOff(but);
drumOn -= position;*
* }else {*

* if (guitar_minus())*
* {midi.noteOn(drumMinus);*

* delay(20);*

* }*

* if (guitar_plus())
_ {midi.noteOn(drumPlus);
delay(20);
}
}
}
/////////////////////////// Checks our DIPswitch settings /////////////////////////////
// uses the shift register to pull the info only a few times in the whole program*
/////////////////////////////////////////////////////////////////////////////////////////_

uint8_t getDips(){

Hi... I could not download your code anyway. could you please send me the code through email. I develop a virtual guitar too for my bachelor thesis. therefore i need your code for my references.

thank you.