/*
NAME:                 MIDI Program Change Filter
 WRITTEN BY:           TOM SCARFF
 DATE:                 8/5/2009
 FILE SAVED AS:        program_change_filter.pde
 FOR:                  Miduino ATmega168
 CLOCK:                16.00 MHz CRYSTAL                                        
 PROGRAMME FUNCTION:  Detect midi Program Change inputs and allow out, block other midi data.
 
 
 IMPORTANT:
 The Miduino might not start if it receives data directly after a reset,
 because the bootloader thinks you want to upload a new progam.You might 
 need to unplug the MIDI IN cable until the board is running your program. 
 Also when programming the Miduino disconnect the MIDI IN cable.
 
 HARDWARE NOTE:
 The Midi IN Socket is connected to the Miduino RX through an 6N139 opto-isolator
 *
 * To send MIDI, attach a MIDI out Female 180 Degree 5-Pin DIN socket to Arduino.
 * Socket is seen from solder tags at rear.
 * DIN-5 pinout is:                                         _______ 
 *    pin 2 - Gnd                                          /       \
 *    pin 4 - 220 ohm resistor to +5V                     | 1     3 |  MIDI jack
 *    pin 5 - Arduino Pin 1 (TX) via a 220 ohm resistor   |  4   5  |
 *    all other pins - unconnected                         \___2___/
 *
 *
 ***************************************************************************** 
 *
 */



//variables setup

byte midiByte;
byte MIDIchannel=0x0F;
byte channel;

byte status=0;
byte statusType;
byte statusTest;
byte volume_now=0;
byte volume_past=0;
byte x;
byte startTest=0;
byte runningStatus;
byte Flag;
byte LedPin = 13;   // select the pin for the LED
byte runStatusFlag=0;
byte realTimeTest;
byte count;
byte note;
byte startNoteFlag=0;


int startNote=60;
int channelTest=0;


void setup() {


  pinMode(LedPin,OUTPUT);   // declare the LED's pin as output

  for (x=1; x<=4; x++){
    digitalWrite( LedPin, HIGH );
    delay(300);
    digitalWrite( LedPin, LOW );
    delay(300);
  }


  // Serial.begin(38400);  //start serial with midi baudrate 38400 Roland MIDI

  Serial.begin(31250);  //start serial with midi baudrate 31250

    Serial.flush();


}


void loop() {




  // Midi in to out
  midiThru();



}
//_____________________________________________________________________________________________________

// Functions:


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 


void midiThru(){

  if (Serial.available() > 0){      //If MIDI available read the incoming MIDI byte and transmit Program Change thru
    midiByte = Serial.read();
    digitalWrite(LedPin, HIGH);   // sets the LED on

    statusType= midiByte&0xF0;
    statusTest=midiByte&0x80;
    channel=midiByte&0x0F;

    if(statusTest==0x80){        // if midi status and NOT data

      if(midiByte>=0x80 && midiByte<=0xEF){ //if midi channel command
        runningStatus=midiByte;
      }
      status=midiByte;
      if(statusType==0xC0){
        Serial.print(status,BYTE); // transmit midi status byte
        txMidi();                   // transmit following data bytes
      }
    }


    if(statusTest!=0x80&&status!=0){      // if running status and NOT starting data byte

      status=runningStatus;    // insert status byte
      channel=status&0x0F;
      statusType= status&0xF0;
      if(statusType==0xC0){
        Serial.print(status,BYTE); // transmit midi running status byte
        txMidi2(status);                   // transmit following data bytes
      }
    }

  }
  digitalWrite(LedPin, LOW);    // sets the LED off//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


void readMidi(){

  while (Flag==0){
    if (Serial.available() > 0) {  
      midiByte = Serial.read();         
      Flag=1;
    }
  }
  Flag=0;

}

////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void txMidi(){



  if(statusType==0xF0){

    getStatus1(status);  // complete status byte

  }

  else if(statusType!=0xF0){

    getStatus2(status); // status with channel removed
  }

}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void getStatus1(byte val){


  switch (val) {


  default:
    break;
  }
}

//___________________________________________________

void getStatus2(byte val){

  val = val & 0xF0;          //remove channel info

  switch (val) {


  case 0xC0:                //Program Change           1100bbbb (CX)

    mididata1Tx(); 
    break;


  default:
    break;
  }
}


////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void txMidi2(byte val){      // running status mode data 1 available already in midiByte


  val = val & 0xF0;          //remove channel info

  switch (val) {


  case 0xC0:                //Program Change           1100bbbb (CX)

    Serial.print(midiByte,BYTE); // transmit midi program change data  
    break;

  default:
    break;
  }
}

//---------------------------------------------------------------------------------

void mididata2Tx()

{
  count=2;
  while (count!=0){
    readMidi();             // get midi 
    realTimeTest=midiByte&0x80;   // if Real Time dont decrement count
    if (realTimeTest==0){
      count=count-1;
    }            // data byte
    Serial.print(midiByte,BYTE); // transmit midi 
  }

}    

//------------------------------------------------------------------------------

void mididata1Tx()

{
  count=1;
  while (count!=0){
    readMidi();             // get midi 
    realTimeTest=midiByte&0x80;   // if Real Time dont decrement count
    if (realTimeTest==0){
      count=count-1;
    }            // data byte
    Serial.print(midiByte,BYTE); // transmit midi 
  }

}

////++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++