
// include libraries
#include <Adafruit_MCP23X17.h>
#include <MIDI.h>

// Instantiate libraries
Adafruit_MCP23X17 mcp1; // First MCP23017
Adafruit_MCP23X17 mcp2; // Second MCP23017
// Default hardware MIDI. SoftwareSerial is too slow...
MIDI_CREATE_DEFAULT_INSTANCE();
//                        A7 A6 A5 A4 A3 A2 A1 A0  <-- GPIO A
// MCP pins               28 27 26 25 24 23 22 21 20 19 18 17 16 15    
// 8 = pin 1             ╔══════════════════════════════════════════╗ 
// 9 = pin 2             ╠                 MCP23017                 ║
// 10 = pin 3            ╚══════════════════════════════════════════╝
//                        01 02 03 04 05 06 07 08  9 10 11 12 13 14
//                        B0 B1 B2 B3 B4 B5 B6 B7  <-- GPIO B

// Default MIDI channel
byte currentMidiChannel = 8; // Default MIDI channel

// Struct for 2 MCP chips. 
struct MCPOutput {
  uint8_t chip;    // 0 = mcp1, 1 = mcp2
  uint8_t pin;     // 0–15
};

// LED shows MIDI activity
unsigned long ledOnTime = 0;
bool ledActive = false;
const unsigned long ledDuration = 50; // flash for 50ms

// Note to pin mapping. {chip, pin}
// One would be able to add up to 8 MCPs, but 2 is plenty for a Meowsic.
MCPOutput noteToMCP[32] = {
  // MCP1 – MIDI 57 to 72
  {0,  0}, // 57 A3
  {0,  1}, // 58 A#3
  {0,  2}, // 59 B3
  {0,  3}, // 60 C4
  {0,  4}, // 61 C#4
  {0,  5}, // 62 D4
  {0,  6}, // 63 D#4
  {0,  7}, // 64 E4
  {0,  8}, // 65 F4
  {0,  9}, // 66 F#4
  {0, 10}, // 67 G4
  {0, 11}, // 68 G#4
  {0, 12}, // 69 A4
  {0, 13}, // 70 A#4
  {0, 14}, // 71 B4
  {0, 15}, // 72 C5

  // MCP2 – MIDI 73 to 88
  {1,  0}, // 73 C#5
  {1,  1}, // 74 D5
  {1,  2}, // 75 D#5
  {1,  3}, // 76 E5
  {1,  4}, // 77 F5
  {1,  5}, // 78 F#5
  {1,  6}, // 79 G5
  {1,  7}, // 80 G#5
  {1,  8}, // 81 A5
  {1,  9}, // 82 A#5
  {1, 10}, // 83 B5
  {1, 11}, // 84 C6
  {1, 12}, // 85 C#6
  {1, 13}, // 86 D6
  {1, 14}, // 87 D#6
  {1, 15}  // 88 E6
};


void setup() {
  // LED debug
  pinMode(LED_BUILTIN, OUTPUT);

  // Initialize MCP23017s
  mcp1.begin_I2C(0x20);
  mcp2.begin_I2C(0x21);
  // Initialize MIDI
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleNoteOn(handleNoteOn);
  MIDI.setHandleNoteOff(handleNoteOff);

  for (int i = 0; i < 16; i++) {
    mcp1.pinMode(i, OUTPUT);
    mcp1.digitalWrite(i, LOW);

    mcp2.pinMode(i, OUTPUT);
    mcp2.digitalWrite(i, LOW);
  }
}

void loop() {
  MIDI.read();

  // LED feedback
  if (ledActive && millis() - ledOnTime >= ledDuration) {
    digitalWrite(LED_BUILTIN, LOW);
    ledActive = false;
  }
  // if (MIDI.read()) {
  //   digitalWrite(LED_BUILTIN, HIGH);
  //   delay(50);
  //   digitalWrite(LED_BUILTIN, LOW);
  
  // }
}

void handleNoteOn(byte channel, byte pitch, byte velocity) {
  if (channel == currentMidiChannel) {

    if (pitch >= 57 && pitch <= 88) {
      MCPOutput out = noteToMCP[pitch - 57];
      if (out.chip == 0) {
        mcp1.digitalWrite(out.pin, HIGH);
      } else if (out.chip == 1) {
        mcp2.digitalWrite(out.pin, HIGH);
      }
   }
  }

  // Flash LED on any valid Note On
  digitalWrite(LED_BUILTIN, HIGH);
  ledOnTime = millis();
  ledActive = true;
}

void handleNoteOff(byte channel, byte pitch, byte velocity) {
  if (channel == currentMidiChannel) {
    if (pitch >= 57 && pitch <= 88) {
      MCPOutput out = noteToMCP[pitch - 57];
      if (out.chip == 0) {
        mcp1.digitalWrite(out.pin, LOW);
      } else if (out.chip == 1) {
        mcp2.digitalWrite(out.pin, LOW);
      }
   }
  }
}