Pages: [1]   Go Down
Author Topic: Guitar Hero Midi Controller  (Read 1434 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
[code]/*

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
« Last Edit: May 16, 2008, 08:14:49 pm by SlapYak » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

[code]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);
      }      
}


Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

//////////////////////////////  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(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()){
            octave--;
            if(octave>=100 || octave<1){octave=1;}      // (ocatave, 2, 7) may be more normal sounding
            delay(2*commandDelay);
            getDips();
      }

}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

////////////////////////////////////  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 <smiley-cool
{
  _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(){
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Pages: [1]   Go Up
Jump to: