#include <MIDI.h>
#include <SPI.h>       
#include <DAC_MCP49xx.h>
// https://github.com/FortySevenEffects/arduino_midi_library
// https://github.com/exscape/electronics/tree/master/Arduino/Libraries/DAC_MCP49xx

// This work is licensed by Paul Cooper of Soundtronics Ltd under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
MIDI_CREATE_DEFAULT_INSTANCE();

//Assign Pins with user name
const byte Gate=3;
const byte HexA=4;
const byte HexB=5;
const byte HexC=6;
const byte HexD=7;
const byte Vel=8;
const byte Bend=9;
const byte SS_PIN = 10; // The Arduino pin used for the slave select / chip select

byte MidiCh=1; //Set default Midi channel to channel 1
byte Mode = 0; // 0 = Mod, 1 = Velocity, 2 = Bend
byte LastNote;

// Set up the DAC. 
    // First argument: DAC model (MCP4902, MCP4912, MCP4922)
    // Second argument: SS pin (10 is preferred)
    // (The third argument, the LDAC pin, can be left out if not used)
    DAC_MCP49xx dac(DAC_MCP49xx::MCP4922, SS_PIN);


void setup()
{
    //Configure Pins
    pinMode(HexA, INPUT_PULLUP);
    pinMode(HexB, INPUT_PULLUP);
    pinMode(HexC, INPUT_PULLUP);
    pinMode(HexD, INPUT_PULLUP);
    pinMode(Vel, INPUT_PULLUP);
    pinMode(Bend, INPUT_PULLUP);
    pinMode(Gate, OUTPUT); 
    
    //Set-up MIDI function calls
    MIDI.setHandleNoteOn(handleNoteOn); 
    MIDI.setHandleNoteOff(handleNoteOff);
    MIDI.setHandlePitchBend(pitchbend);
    MIDI.setHandleControlChange(control);
    // Initiate MIDI communications on channel 0
    MIDI.begin(1);
    
    digitalWrite (Gate, HIGH); //Set gate output high, this gets inverted by the voltage level shifter transistor
}

void loop()
{
    MidiCh = CalcMidiCh(); //Function call to calculate Midi Channel selected
    Mode = ModeSwitch(); // Function call to detect mode switch position
    MIDI.setInputChannel(MidiCh); //Set Midi channel to that selected by channel hex switch    
    MIDI.read();
  
}

//This function calculates the selected Midi channel from the hex switch type Lorlin BCK1002 in the range 1-16
    int CalcMidiCh(){
    int result;
    bool A;
    bool B;
    bool C;
    bool D;
    A = !digitalRead (HexA);
    B = !digitalRead (HexB);
    C = !digitalRead (HexC);
    D = !digitalRead (HexD);
    result = A | (B << 1) | (C << 2) | (D << 3);
    if (result == 0){
      result = 16;
    }
    return result;  
}

int ModeSwitch(){
    int result;
    int A;
    int B;
    A = !digitalRead (Vel);
    B = !digitalRead (Bend);
    result = A | (B << 1);
    return result;
}

void handleNoteOn(byte channel, byte pitch, byte velocity)
{
  //Do the following when a note is pressed - Note priority is 
  digitalWrite(Gate, HIGH);
  LastNote = pitch;
  delay(10);
  dac.outputA(pitch*32);//128 MIDI notes which when multiplied by 32 gives a dac range of 0 - 4064 in 32 bit steps 
  if (Mode == 1){   //Velocity mode
    dac.outputB(velocity*32);
  }
  digitalWrite(Gate, LOW);  
}

void handleNoteOff(byte channel, byte pitch, byte velocity)
{
  if (pitch == LastNote){
    digitalWrite(Gate, HIGH);//Turn off gate only when the last key pressed is released
  }
}

void pitchbend(byte channel, int bend)
{ 
  delayMicroseconds(1);
  bend=((bend/16)-3500);
  if (Mode == 2){
    dac.outputB(bend);
  }
}

void control(byte channel, byte number, byte value)
{
  if ((number == 1) & (Mode == 0)){ // Modulation wheel
  delayMicroseconds(1);
  dac.outputB(value*31);
  }
}



