MIDI keyboard - code for matrix

hello Arduino community,
I'm new to Arduino and I try to turn my 1983 organ keyboard into a MIDI keyboard using Arduino UNO
I followed a tutorial and manage to make everything work, except that the keys I press do not match the right note and I don't know how to change it because I'm a total newbie to Arduino code. I need some help to fix it.

Here is my Arduino project :
the code I use, which gives wrong notes to keys

#define NUM_ROWS 4
#define NUM_COLS 13

#define NOTE_ON_CMD 0x90
#define NOTE_OFF_CMD 0x80
#define NOTE_VELOCITY 127

#define SERIAL_RATE 31250

// Row input pins
const int row1Pin = 2;
const int row2Pin = 3;
const int row3Pin = 4;
const int row4Pin = 5;

// 74HC595 pins
const int dataPin = 6;
const int latchPin = 7;
const int clockPin = 8;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS];

// bitmasks for scanning columns
int bits[] =
{
  B00000001,
  B00000010,
  B00000100,
  B00001000,
  B00010000,
  B00100000,
  B01000000,
  B10000000
};

// define first note of keyboard (int note)
void setup()
{
  int note = 31;

  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      keyToMidiMap[rowCtr][colCtr] = note;
      note++;
    }
  }

  // setup pins output/input mode
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);

  pinMode(row1Pin, INPUT);
  pinMode(row2Pin, INPUT);
  pinMode(row3Pin, INPUT);
  pinMode(row4Pin, INPUT);

  Serial.begin(SERIAL_RATE);
}

void loop()
{
  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    //scan next column
    scanColumn(colCtr);

    //get row values at this column
    int rowValue[NUM_ROWS];
    rowValue[0] = digitalRead(row1Pin);
    rowValue[1] = digitalRead(row2Pin);
    rowValue[2] = digitalRead(row3Pin);
    rowValue[3] = digitalRead(row4Pin);

    // process keys pressed
    for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      if (rowValue[rowCtr] != 0 && !keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = true;
        noteOn(rowCtr, colCtr);
      }
    }

    // process keys released
    for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      if (rowValue[rowCtr] == 0 && keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = false;
        noteOff(rowCtr, colCtr);
      }
    }
  }
}

void scanColumn(int colNum)
{
  digitalWrite(latchPin, LOW);

  if (0 <= colNum && colNum <= 7)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr
  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum - 8]); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //left sr
  }
  digitalWrite(latchPin, HIGH);
}

void noteOn(int row, int col)
{
  Serial.write(NOTE_ON_CMD);
  Serial.write(keyToMidiMap[row][col]);
  Serial.write(NOTE_VELOCITY);
}

void noteOff(int row, int col)
{
  Serial.write(NOTE_OFF_CMD);
  Serial.write(keyToMidiMap[row][col]);
  Serial.write(NOTE_VELOCITY);
}

I know I should change the matrix of "keytoMidiMap" and make a table with the corresponding MIDI number notes but I have zero knowledge in coding so I'm totally lost
your help will be much appreciated
thanks a lot

PS: it seems like a matrix like this correspond to my keyboard but how to I include it in the code?

int values[4][13] = {
    {0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 46, 47},
    {0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59},
    {0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71},
    {84, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83}
  };

the 44 key goes from F0 to C4


here is the matrix of wires on the organ keyboard

the scheme I use to plug everything


PS: I also want to set up a sustain switch on pin9 and do not know how to code this.

I would suggest you do some reading on arduino matrix and arrays, that will give you your answer. There is not enough information to fully answer your question.

Is anyone else not seeing any pictures there?

@yoyoslad,
Instead of posting links to your pictures, use the "Attachments ans other options" at the bottom of the Reply box and Attach your pictures. You can Modify:More your original post and change that.

Something about slad1.free.fr is not letting the pictures thru.

I made them links for now so people can at least get to them.

Please provide a link to the tutorial you are following.

thanks for your messages, I edited the post with attached images
I will take a look at matrix and arrays to try to understand something
the tutorial I followed is https://www.instructables.com/Add-MIDI-port-to-Keyboard/

Can you try this, please?

1: Insert your array just before void setup():

int values[4][13] = {
    {0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 46, 47},
    {0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59},
    {0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71},
    {84, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83}
  };

2: Remove these lines from void setup() :

  int note = 31;

  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      keyToMidiMap[rowCtr][colCtr] = note;
      note++;
    }
  }

3: Replace them with these:

  for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
  {
    for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      keyToMidiMap[rowCtr][colCtr] = values[rowCtr][colCtr];
    }
  }

Erik_Baas:
Which note do you hear when you press key "F0" ?

A3

There goes my theory... :wink:

Oh well, would you please check out my idea in reply #5 anyway, and let us know what happens?

thanks Erik for your support, I tried and I get an error message

clavier-midi:40:1: error: expected initializer before 'int'
 int values[4][13] = {
 ^~~
clavier-midi:47:1: error: expected unqualified-id before 'for'
 for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
 ^~~
clavier-midi:47:22: error: 'rowCtr' does not name a type
 for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
                      ^~~~~~
clavier-midi:47:41: error: expected unqualified-id before '++' token
 for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
                                         ^~
clavier-midi:57:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(dataPin, OUTPUT);
          ^
clavier-midi:58:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(clockPin, OUTPUT);
          ^
clavier-midi:59:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(latchPin, OUTPUT);
          ^
clavier-midi:61:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(row1Pin, INPUT);
          ^
clavier-midi:62:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(row2Pin, INPUT);
          ^
clavier-midi:63:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(row3Pin, INPUT);
          ^
clavier-midi:64:10: error: expected constructor, destructor, or type conversion before '(' token
   pinMode(row4Pin, INPUT);
          ^
clavier-midi:66:3: error: 'Serial' does not name a type
   Serial.begin(SERIAL_RATE);
   ^~~~~~
clavier-midi:67:1: error: expected declaration before '}' token
 }
 ^
exit status 1
expected initializer before 'int'

That's weird... I got this running on my Uno, without problems:

#define NUM_ROWS 4
#define NUM_COLS 13

#define NOTE_ON_CMD 0x90
#define NOTE_OFF_CMD 0x80
#define NOTE_VELOCITY 127

#define SERIAL_RATE 31250

// Row input pins
const int row1Pin = 2;
const int row2Pin = 3;
const int row3Pin = 4;
const int row4Pin = 5;

// 74HC595 pins
const int dataPin = 6;
const int latchPin = 7;
const int clockPin = 8;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS];

// bitmasks for scanning columns
int bits[] =
{
  B00000001,
  B00000010,
  B00000100,
  B00001000,
  B00010000,
  B00100000,
  B01000000,
  B10000000
};
// define first note of keyboard (int note)

int values[4][13] = {
  {0, 0, 0, 0, 0, 0, 41, 42, 43, 44, 45, 46, 47},
  {0, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59},
  {0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71},
  {84, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83}
};

void setup() {
  for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
  {
    for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      keyToMidiMap[rowCtr][colCtr] = values[rowCtr][colCtr];
    }
  }

  // setup pins output/input mode
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);

  pinMode(row1Pin, INPUT);
  pinMode(row2Pin, INPUT);
  pinMode(row3Pin, INPUT);
  pinMode(row4Pin, INPUT);

  Serial.begin(SERIAL_RATE);
}

void loop()
{
  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    //scan next column
    scanColumn(colCtr);

    //get row values at this column
    int rowValue[NUM_ROWS];
    rowValue[0] = digitalRead(row1Pin);
    rowValue[1] = digitalRead(row2Pin);
    rowValue[2] = digitalRead(row3Pin);
    rowValue[3] = digitalRead(row4Pin);

    // process keys pressed
    for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      if (rowValue[rowCtr] != 0 && !keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = true;
        noteOn(rowCtr, colCtr);
      }
    }

    // process keys released
    for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      if (rowValue[rowCtr] == 0 && keyPressed[rowCtr][colCtr])
      {
        keyPressed[rowCtr][colCtr] = false;
        noteOff(rowCtr, colCtr);
      }
    }
  }
}

void scanColumn(int colNum)
{
  digitalWrite(latchPin, LOW);

  if (0 <= colNum && colNum <= 7)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr
  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum - 8]); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //left sr
  }
  digitalWrite(latchPin, HIGH);
}

void noteOn(int row, int col)
{
    Serial.write(NOTE_ON_CMD);
    Serial.write(keyToMidiMap[row][col]);
    Serial.write(NOTE_VELOCITY);
}

void noteOff(int row, int col)
{
    Serial.write(NOTE_OFF_CMD);
    Serial.write(keyToMidiMap[row][col]);
    Serial.write(NOTE_VELOCITY);
}

Edit 0:57: fixed two typo's!

ok the code you provided doesn't contain error, I uploaded it to my arduino but no Midi notes are generated

Please try again, I changed two lines of code 5 minutes after posting it. Sorry...

I tried and it works great thanks a lot Erik, you saved me!

one last request, I want to set up a sustain pedal using a pull down switch connected to pin9 as displayed on the scheme, what's the sustain code for this? thanks again for your very helpful work

yoyoslad:
one last request, I want to set up a sustain pedal using a pull down switch connected to pin9 as displayed on the scheme, what's the sustain code for this? thanks again for your very helpful work

In general MIDI, doesn't "sustain" translate to just not sending a "note off" until the sustain pedal is released?

1 Like

it seems like there is a command CC64 for sustain
as we can see in the code below

int ledPin = 12;
int buttonPin = 9;
int buttonState = 0;
int buttonLastState = 0;
int buttonInitState = 0;
int SusStatus = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);

  // Setup serial port for MIDI communication
  Serial.begin(31250);

  // read current button state, a press is detected whenever
  // state changes to anything else than the init state
  buttonInitState = digitalRead(buttonPin);
  // we only want to do something on state changes
  buttonLastState = buttonInitState;
}


void loop() {
  buttonState = digitalRead(buttonPin);

  // has the state changed?
   if (buttonState != buttonLastState) {
     buttonLastState = buttonState;
     if (buttonState != buttonInitState) {
        // button is pressed, send sustain
        // mute and light up LED
        digitalWrite(ledPin, HIGH);
        // send CC 64 on channel 1 with value 127 to sustain
        midiCc(1, 64, 127);
        } else {
        // button released turn off LED and sustain
        digitalWrite(ledPin, LOW);
        midiCc(1, 64, 0);
        }
   
    // workaround to prevent fluttering of button state
    delay(10);
   }
}

void midiCc(int channel, int command, int value) {
  Serial.write(175 + channel);
  Serial.write(command);
  Serial.write(value);
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.