/*
  Merge MIDI Input keyboard data with 3 Analog controllers
  Send MIDI OUT
 
 Adrian S. Bruce 2014
 http://www.artandtechnology.com.au/arduino/arduino.html
 
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int sensorValue0 = 0;
int sensorValue1 = 0;
int sensorValue2 = 0;

int ctrl0 = 0; // keep state of last values
int ctrl1 = 0;
int ctrl2 = 0;


// midi globals
byte inByte = 0;
byte cmd =0;
byte midiByte1 =0;
byte midiByte2 =0;
byte lastCmd =0; // for running status, do'y send command if same as last  time
byte channel = 0;
byte messageCnt = 0;
byte triggerState = HIGH ;
byte ctrlSend = 0 ;

//
// the setup routine runs once when you press reset:
//
void setup() {
  // initialize serial communication at 38400 bits per second:
  Serial.begin(38400);
  // initialize MIDI port UART2 in Mega 2560
  Serial2.begin(31250);
 
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);  

}
//
// the loop routine runs over and over again forever:
//
void loop() 
{
  // read from MIDI port  
  while(Serial2.available()  ) 
  {
    inByte = Serial2.read();
    if ( inByte != 0xFE   )  // dump active sensing
    {
      if( (inByte & 0x80) == 0x80 )  //a midi command?
      {      
          cmd = inByte; // current cmd including midi channel
          channel = inByte & 0x0f ; // save the midi channel to use for controllers
          messageCnt = 1;
          sendMidi(inByte);
          ctrlSend = 0 ; //don't send ctrl now
      }
      else
      {  
        if (messageCnt == 1)
        {
            messageCnt = 2;
            sendMidi(inByte);
        }
        else if(messageCnt == 2)
        {
            messageCnt = 3;
            sendMidi(inByte);
            ctrlSend = 1 ; //can send ctrl now
        }   
        else if(messageCnt == 3) // running status command
        {
            messageCnt = 2;
             sendMidi(cmd);           
            sendMidi(inByte);
          ctrlSend = 0 ; //don't send ctrl now            
        }     
        
      }
    }  
   
  }

//
// read the input on analog pin 0, 1, 2, average with last value make 0 - 127
//
  sensorValue0 = (sensorValue0 + analogRead(A0))/9;
  sensorValue1 = (sensorValue1 + analogRead(A1))/9;
  sensorValue2 = (sensorValue2 + analogRead(A2))/9;
//
//  Only senda controller message when complete midi in messages
//  have been collected and sent
//
  
   if (ctrlSend == 1) // safe to send control message 
   { 
     if (sensorValue0 != ctrl0) {
       ctrl0 = sensorValue0 ;
       ctrlMessage(0xb0  + channel, 1, ctrl0);  // send 1, modulation
       //ctrlMessage(0xb0  + channel, 91, ctrl0) ; // send 91
      }
 
      if (sensorValue1 != ctrl1) {
       ctrl1 = sensorValue1 ;
       ctrlMessage(0xb0 + channel, 17, ctrl1) ; // send 17
      }
 
       if (sensorValue2 != ctrl2) {
       ctrl2 = sensorValue2 ;
        ctrlMessage(0xb0  + channel, 92, ctrl2) ; // send 92
      }
      
     
      // read the state of the pushbutton value:
      buttonState = digitalRead(buttonPin);    
    
      // check if the pushbutton is pressed.
      // if it is, the buttonState is LOW:
      if ((buttonState == LOW)    ) {     
        // turn LED off:    
        digitalWrite(ledPin, HIGH);  
       //  ctrlMessage(0xb0 + channel, 100, 127) ; // send 100       ON 

      } 
      else {
        // turn LED on:
        digitalWrite(ledPin, LOW); 
       //  ctrlMessage(0xb0 + channel, 100, 0) ; // send 100 OFF

      }         
       
   }
       
}

//
//  send a 3 byte midi message  
//
void midiMessage(int noteCmd, int data1, int data2) {
  sendMidi(noteCmd);
  sendMidi(data1);
  sendMidi(data2);
}

//  send controller message:
void ctrlMessage(int ccCmd, int ctrl, int value) {
  sendMidi(ccCmd);
  sendMidi(ctrl);
  sendMidi(value);
}
//
//  send midi bytes and maintain running ststus
//  don't send un required midi commands
//
void sendMidi(int midiByte ) 
{
       
  if( (midiByte & 0x80) == 0x80 )  //a command?
  {
    if ((midiByte != lastCmd)  ) // enable running status
//    if ((midiByte != 0xff)  ) // dissable running status
    {
      lastCmd = midiByte ; // update new command running status
      Serial2.write(midiByte); //  send command data byte
      textMidi(midiByte) ;   // print midi to console   
    }
  }
  else
  {
       Serial2.write(midiByte); // just send data byte 
       textMidi(midiByte) ;   // print midi to console   
  }

}

//
//  text dump midi to console to work out what is happening   
//
void textMidi(int midiByte)
{
  
//  return; // uncomment to print to console window
   char	textString[16];
      // print midi 
      if( (midiByte & 0x80) == 0x80 )  //a command byte?
      {
          Serial.write(0x0d);  // CR LF to console so commands start on new line
          Serial.write(0x0a);
      }
      sprintf(textString, "%02X ", midiByte);
      Serial.print(textString);
    
} 
