I am having problems with my Arduino Mega midi controller sending proper midi pitch bend commands. Everything else on the controller works fine. It has 37 keys, 12 pots and 8 program select buttons. There is a Spark Fun joystick which outputs 0 to 5 volts in both the X and Y axis. The center points are not exactly 2.5V. I compensated for that on the Y but not yet on the X. Y axis + outputs 0 to 127 cc1 data while Y axis – outputs cc 74 based on the reading of potentiometer 1 also assigned to that value. X is assigned to pitch bend. I need an inverse output compared to the voltage so that 5V = midi value 0 and 0V = 16383.
The center detent of the joystick gives a midi value of oX0132 ( I can compensate for this later). When I move the joystick towards 0 volts, the values steadily increase up to oX3E7F. However, when I move the joystick towards 5 volts, instead of a steady pitch bend down, I get dithers around oX0122 and oX0132 before going to oX0010 then jumping up to oX7F71 then steadily decreasing in value until it bottoms out at oX4032 which means the overall pitch bend down is still higher than center on the joystick.
I have not programmed for the Mega before. I’m guessing there’s an issue with either the handling of midi pitch bend commands or more likely converting the ADC values to the 14bit midi format.
Code is attached. Pitch bend code is lines 114-123,
Any help is appreciated.
type [code]
// Final version: 37-key MIDI keyboard + Program Change + CC switches + 12 Pots + Joystick
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
const int NUM_KEYS = 37;
const int NUM_PROG_BUTTONS = 8;
const int keyPins[NUM_KEYS] = {
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
};
const int programChangePins[NUM_PROG_BUTTONS] = {40, 41, 42, 43, 44, 45, 46, 47};
const int PIN_ALL_SOUNDS_OFF = 48;
const int PIN_MONO_POLY = 50; // swapped
const int PIN_PORTAMENTO = 49; // swapped
const int baseNote = 36;
bool keyStates[NUM_KEYS];
bool buttonStates[NUM_PROG_BUTTONS];
bool monoPolyState = false;
bool portamentoState = false;
const int NUM_POTS = 12;
const int potPins[NUM_POTS] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11};
const int potCCs[NUM_POTS] = {74, 71, 73, 72, 91, 92, 93, 7, 5, 94, 95, 10};
int potValues[NUM_POTS];
const int JOY_X_PIN = A14;
const int JOY_Y_PIN = A13;
int prevPitchBend = 8192;
int prevCC1 = -1;
int prevCC74 = -1;
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
for (int i = 0; i < NUM_KEYS; i++) {
pinMode(keyPins[i], INPUT_PULLUP);
keyStates[i] = false;
}
for (int i = 0; i < NUM_PROG_BUTTONS; i++) {
pinMode(programChangePins[i], INPUT_PULLUP);
buttonStates[i] = false;
}
pinMode(PIN_ALL_SOUNDS_OFF, INPUT_PULLUP);
pinMode(PIN_MONO_POLY, INPUT_PULLUP);
pinMode(PIN_PORTAMENTO, INPUT_PULLUP);
}
void loop() {
readPotentiometers();
readJoystick();
for (int i = 0; i < NUM_KEYS; i++) {
bool pressed = digitalRead(keyPins[i]) == LOW;
if (pressed != keyStates[i]) {
keyStates[i] = pressed;
if (pressed) {
MIDI.sendNoteOn(baseNote + i, 127, 1);
} else {
MIDI.sendNoteOff(baseNote + i, 0, 1);
}
}
}
for (int i = 0; i < NUM_PROG_BUTTONS; i++) {
bool pressed = digitalRead(programChangePins[i]) == LOW;
if (pressed && !buttonStates[i]) {
buttonStates[i] = true;
MIDI.sendProgramChange(i, 1);
} else if (!pressed) {
buttonStates[i] = false;
}
}
if (digitalRead(PIN_ALL_SOUNDS_OFF) == LOW) {
MIDI.sendControlChange(120, 0, 1);
delay(200);
}
bool monoPressed = digitalRead(PIN_MONO_POLY) == HIGH; // reversed logic
if (monoPressed != monoPolyState) {
monoPolyState = monoPressed;
MIDI.sendControlChange(monoPressed ? 127 : 126, monoPressed ? 127 : 0, 1);
}
bool portamentoPressed = digitalRead(PIN_PORTAMENTO) == LOW;
if (portamentoPressed != portamentoState) {
portamentoState = portamentoPressed;
MIDI.sendControlChange(65, portamentoPressed ? 127 : 0, 1);
}
}
void readPotentiometers() {
for (int i = 0; i < NUM_POTS; i++) {
int rawValue = analogRead(potPins[i]);
int midiValue;
if (potCCs[i] == 10) {
midiValue = map(rawValue, 0, 1023, 127, 0); // Reverse pan
} else {
midiValue = map(rawValue, 0, 1023, 0, 127);
}
if (abs(midiValue - potValues[i]) > 1) {
potValues[i] = midiValue;
MIDI.sendControlChange(potCCs[i], midiValue, 1);
}
}
}
void readJoystick() {
int xRaw = analogRead(JOY_X_PIN);
int yRaw = analogRead(JOY_Y_PIN);
if(xRaw>10){
int bend = map(xRaw, 10, 1023,16383, 50);
bend = constrain(bend, 0, 16383);
if (abs(bend - prevPitchBend) > 4) {
MIDI.sendPitchBend(bend, 1);
prevPitchBend = bend;
}
}
float yVolt = yRaw * (5.0 / 1023.0);
if (yVolt > 2.56) {
int cc1val = map(yVolt * 100, 256, 495, 0, 127);
cc1val = constrain(cc1val, 0, 127);
if (abs(cc1val - prevCC1) > 1) {
MIDI.sendControlChange(1, cc1val, 1);
prevCC1 = cc1val;
prevCC74 = -1;
}
} else if (yVolt < 2.54) {
int cc74val = map(yVolt * 100, 0, 254, 127, 0);
int baseCC74 = potValues[0]; // A0 value
cc74val = constrain(cc74val, baseCC74, 127);
if (abs(cc74val - prevCC74) > 1) {
MIDI.sendControlChange(74, cc74val, 1);
prevCC74 = cc74val;
prevCC1 = -1;
}
}
}
[/code]or paste code here

