Files
purrChestrion/purrChestrion-arduino/purrChestrion-arduino.ino
T
2025-06-14 00:05:03 +02:00

187 lines
4.8 KiB
Arduino
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define FW_VER 1.0
#define USE_OLED true // LEDC68 (Gotek alphanumeric displays)
#define USE_ENCODER false
// include libraries
#include <Adafruit_MCP23X17.h>
#include <MIDI.h>
#if USE_OLED
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "font.h"
#include "gfx.h"
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
Adafruit_SSD1306 oled(SCREEN_WIDTH,SCREEN_HEIGHT,&Wire,-1);
#endif
#if USE_ENCODER
#endif
// 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 = MIDI_CHANNEL_OMNI; //8; // Default MIDI channel
// Struct for 2 MCP chips.
struct MCPOutput {
uint8_t chip; // 0 = mcp1, 1 = mcp2
uint8_t pin; // 015
};
// 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 updateOLED() {
#if USE_OLED
oled.clearDisplay();
oled.drawBitmap(0, 0, midich, MIDICH_WIDTH, MIDICH_HEIGHT, 1);
oled.setCursor(88, 18);
oled.setTextColor(SSD1306_WHITE);
oled.setTextSize(1);
if (currentMidiChannel == MIDI_CHANNEL_OMNI) {
oled.print("ALL");
} else {
oled.print(currentMidiChannel);
}
oled.display();
#endif
}
void setup() {
#if USE_OLED
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // I2C addr 0x3C
// Don't halt if missing, just skip display
} else {
oled.clearDisplay();
oled.drawBitmap(0, 0, bootuplogo, BOOTLOGO_WIDTH, BOOTLOGO_HEIGHT, 1);
oled.setCursor(62, 18);
oled.setTextColor(SSD1306_WHITE);
oled.print("FW ver. " + String(FW_VER));
oled.display();
delay(2500);
oled.setFont(&UiFont);
}
#endif
// Midi Activity LED on Pin 13 (aka LED_BUILTIN)
pinMode(LED_BUILTIN, OUTPUT);
// Initialize MCP23017s
mcp1.begin_I2C(0x20);
mcp2.begin_I2C(0x21);
// Initialize MIDI
MIDI.begin(currentMidiChannel);
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);
}
updateOLED();
}
void loop() {
MIDI.read();
// LED feedback
if (ledActive && millis() - ledOnTime >= ledDuration) {
digitalWrite(LED_BUILTIN, LOW);
ledActive = false;
}
}
void handleNoteOn(byte channel, byte pitch, byte velocity) {
if (currentMidiChannel == MIDI_CHANNEL_OMNI || 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 Note On
digitalWrite(LED_BUILTIN, HIGH);
ledOnTime = millis();
ledActive = true;
}
void handleNoteOff(byte channel, byte pitch, byte velocity) {
if (currentMidiChannel == MIDI_CHANNEL_OMNI || 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);
}
}
}
}