Go Down

Topic: Guitar Hero Midi Controller (Read 1 time) previous topic - next topic


May 17, 2008, 03:11 am Last Edit: May 17, 2008, 03:14 am by SlapYak Reason: 1
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/

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

#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


[code]void setup(){
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, 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.println("MIDI GUI                                TAR HERO"); // spaces are to put us onto line 2 for the second half of the message
//lcd.println("TAR HERO");
//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.
 digitalWrite(13,HIGH);  // useful for telling when we get to this point.

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

void loop(){
 guitar_refresh();                        // get new info from the guitar to arduino
 buttonstatus = guitar_buttons();

 setMode();                              // guitar mode or drum 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                              
             oldButtonStatus = buttonstatus;
        case 1:                        // drum mode
                        // 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
                 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
                 midi.noteOffAll();                              // stop all notes


//////////////////////////////  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

     case B10010001:            // key change down
           key -= 5;                                          // moves back in the circle of 5ths
           if (key >= 240 ){                                    
                 key += 12;                                    
     case B01011011:            // mode change up
           scale++;                                    // change tonal mode
           if (scale>6 && scale<250){                              
           scale -7;                                    // we want them to circle around though.

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

     ////////////////////////////////////  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

     case B10010010:            // chord selection - single note, root-3-5, root-4, power chord

////////////////////////////////////  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
           case 1:                                                // root & fifth
                 statusLed(2);                        // lights LEDS as
           case 2:                                                // root, third & fifth
                 statusLed(7);                        // lights LEDS as
           case 3:                                                // power chord
                 statusLed(11);                        // lights LEDS

//////////////////////////////  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
    if(guitar_whammy()<=2 && wham==true){              // this only runs once after the pitch was bent, then just skips both midi. send statements
          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);
         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);
       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()){
                 if(octave>7&&octave<100){octave=8;}      // (ocatave, 2, 7) may be more normal sounding
                 delay(2*commandDelay);                  // full octave range is 0-9, but a piano is 2-7
                 getDips();                        // resets dip settings without a full reset.
     if (guitar_minus()){
           if(octave>=100 || octave<1){octave=1;}      // (ocatave, 2, 7) may be more normal sounding



////////////////////////////////////  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
           break;                  // exit case loop
     case B00010000:                  // buttons: X _ _ _ _
     case B00011000:                  // buttons: X X _ _ _
     case B00001000:                  // buttons: _ X _ _ _
     case B00001100:                  // buttons: _ X X _ _
     case B00010100:                  // buttons: X _ X _ _
     case B00011100:                  // buttons: X X X _ _
     case B00000100:                  // buttons: _ _ X _ _
     case B00000110:                  // buttons: _ _ X X _
     case B00001010:                  // buttons: _ X _ X _
     case B00001110:                  // buttons: _ X X X _
     case B00000010:                  // buttons: _ _ _ X _
     case B00000011:                  // buttons: _ _ _ X X
     case B00000101:                  // buttons: _ _ X _ X
     case B00000111:                  // buttons: _ _ X X X
     case B00000001:                  // buttons: _ _ _ _ X

////////////////////////////////////  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;                        
           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.
                         note += scale_chart[scale][chord_chart[chord]];      // these will sound different based on the mode/key
           midi.noteOn(note, velocity);                  // send the midi command
     }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.
     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.
     drumOn -= _position;
 }else {
   if (guitar_minus())
   if (guitar_plus())

///////////////////////////  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.

Go Up

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131