Skip to content

Instantly share code, notes, and snippets.

@lean8086
Last active April 21, 2024 03:30
Show Gist options
  • Save lean8086/7de896c3b8f29d15e092e17ad177d055 to your computer and use it in GitHub Desktop.
Save lean8086/7de896c3b8f29d15e092e17ad177d055 to your computer and use it in GitHub Desktop.
#include "MIDIUSB.h"
const byte TOTAL_BUTTONS = 16;
// All the Arduino pins used for buttons, in order.
const byte BUTTONS_PIN[TOTAL_BUTTONS] = {2,3,4,5,6,7,8,9,10,11,12,A0,A1,A2,A3,A4};
// Every pitch corresponding to every Arduino pin. Each note has an associated numeric pitch (frequency scale).
// See https://github.com/arduino/tutorials/blob/master/ArduinoZeroMidi/PitchToNote.h
const byte BUTTONS_PITCH[TOTAL_BUTTONS] = {36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
// Current state of the pressed buttons.
byte currentRead[TOTAL_BUTTONS];
// Temporary input reads to check against current state.
byte tempRead;
// The setup function runs once when you press reset or power the board
void setup() {
// Initialize all the pins as a pull-up input.
for (byte i = 0; i < TOTAL_BUTTONS; i++) {
pinMode(BUTTONS_PIN[i], INPUT_PULLUP);
}
}
// The loop function runs over and over again forever
void loop() {
for (byte i = 0; i < TOTAL_BUTTONS; i++) {
// Get the digital state from the button pin.
// In pull-up inputs the button logic is inverted (HIGH is not pressed, LOW is pressed).
byte buttonState = digitalRead(BUTTONS_PIN[i]);
// Temporarily store the digital state.
tempRead = buttonState;
// Continue only if the last state is different to the current state.
if (currentRead[i] != tempRead) {
// See https://docs.arduino.cc/built-in-examples/digital/Debounce/
delay(2);
// Get the pitch mapped to the pressed button.
byte pitch = BUTTONS_PITCH[i];
// Save the new input state.
currentRead[i] = tempRead;
// Execute note on or noted off depending on the button state.
if (buttonState == LOW) {
noteOn(pitch);
} else {
noteOff(pitch);
}
}
}
}
void noteOn(byte pitch) {
MidiUSB.sendMIDI({0x09, 0x90, pitch, 127});
MidiUSB.flush();
}
void noteOff(byte pitch) {
MidiUSB.sendMIDI({0x08, 0x80, pitch, 0});
MidiUSB.flush();
}
@DRCRecoveryData
Copy link

To use a matrix button, you need to add a diode and utilize the matrix button method to enable simultaneous pressing of all buttons at the same time:

#include <MIDIUSB.h>

// The note numbers corresponding to the buttons in the matrix
const int addresses[4][4] = {
  {36, 37, 38, 39},
  {40, 41, 42, 43},
  {44, 45, 46, 47},
  {48, 49, 50, 51}
};

// Pins for the rows and columns of the button matrix
const int rowPins[4] = {2, 3, 4, 5};
const int colPins[4] = {6, 7, 8, 9};

void setup() {
  MidiUSB.flush(); // Initialize the MIDIUSB library
  setupButtonMatrix();
}

void loop() {
  checkButtonMatrix();
}

// Function to set up the button matrix
void setupButtonMatrix() {
  for (int i = 0; i < 4; i++) {
    pinMode(rowPins[i], INPUT_PULLUP); // Set row pins as input with pull-up resistors
    pinMode(colPins[i], OUTPUT); // Set column pins as output
    digitalWrite(colPins[i], HIGH); // Set column pins to high
  }
}

// Function to check the state of the buttons in the matrix
void checkButtonMatrix() {
  for (int i = 0; i < 4; i++) {
    digitalWrite(colPins[i], LOW); // Set current column pin to low
    for (int j = 0; j < 4; j++) {
      if (digitalRead(rowPins[j]) == LOW) { // If button is pressed
        midiEventPacket_t noteOn = {0x09, 0x90 | 0, addresses[j][i], 127}; // MIDI note-on message
        MidiUSB.sendMIDI(noteOn); // Send MIDI message
        delay(50); // Debouncing delay
        while (digitalRead(rowPins[j]) == LOW) {} // Wait until button is released
        midiEventPacket_t noteOff = {0x08, 0x80 | 0, addresses[j][i], 0}; // MIDI note-off message
        MidiUSB.sendMIDI(noteOff); // Send MIDI message
      }
    }
    digitalWrite(colPins[i], HIGH); // Set current column pin back to high
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment