Go Down

Topic: DIY MIDI keyboard dual button matrix  (Read 848 times) previous topic - next topic

milamter

so I've been trying to make this project, there's 2 8x8 button matrix both are sensitive, I'd like to make it non sensitive first. I did make the first 32 notes of 61, and make sound on hairless MIDI, can't make bitwig to get the signal tho, I will try with ableton. I'm using a MIDI to USB adapter. And now i need to add the other half, I have two 4x8 matrix , how could I mix those two ??
cause there are not the same row or column. thanks.


 
Code: [Select]


#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

#define NUM_ROWS 4
#define NUM_COLS 8

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

#define SERIAL_RATE 9600

const int row1Pin = 2;
const int row2Pin = 3;
const int row3Pin = 4;
const int row4Pin = 5;

const int dataPin = 11;
const int latchPin = 12;
const int clockPin = 13;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS] = {
                                        36, 37, 38, 39,
                                        40, 41, 42, 43,
                                        44, 45, 46, 47,
                                        48, 49, 50, 51,
                                        52, 53, 54, 55,
                                        56, 57, 58, 59,
                                        60, 61, 62, 63,
                                        64, 65, 66, 67,
                                        };

int bits[] =
{
  B11111110,
  B11111101,
  B11111011,
  B11110111,
  B11101111,
  B11011111,
  B10111111,
  B01111111
};


void setup()
{
  int note = 30;

  for(int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    for(int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      note++;
    }
  }
  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)
  {
  scanColumn(colCtr);

  int rowValue[NUM_ROWS];
  rowValue[0] = !digitalRead(row1Pin);
  rowValue[1] = !digitalRead(row2Pin);
  rowValue[2] = !digitalRead(row3Pin);
  rowValue[3] = !digitalRead(row4Pin);

  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, bits[colNum]); //left sr
  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111); //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);
}


Grumpy_Mike

#1
Jan 29, 2020, 05:49 am Last Edit: Jan 29, 2020, 05:51 am by Grumpy_Mike
Quote
there's 2 8x8 button matrix both are sensitive, I'd like to make it non sensitive first.
What does this mean?

Quote
can't make bitwig to get the signal tho,
And this?

Please read this:-
How to use this forum it will tell you what you need to ask a question here. Minimum we need to see a schematic.

What Arduino are you using?
You use 9600 baud, that is not a MIDI speed.

milamter

#2
Jan 29, 2020, 05:23 pm Last Edit: Jan 29, 2020, 05:51 pm by milamter
Thanks for the fast reply. ok, so what i mean with two 8x8 matrix, is that i have 2 different, separated matrix, both 8x8, 2 buttons for each of the 32 notes. Bitwig is the DAW / program I am using, also is 9600 because I'm using hairless MIDI and loopmidi so i can connect directly by usb, I'm using arduino uno, 2 shift registers
Last night I made some progress, now it shows and plays in the daw, the 61 notes perfectly but the array is kinda weird, i had to put some non existing notes(all those 11, that would be the sensitive ones)

now, I only need to define half of the buttons half velocity and the others with 127, and have no idea how to do this because it is defined once for all keys,  there's a simple schematic, also there are 10 k resistors on the wires connected to digital pins 2-9 to 5v, as it is a pull up. thanks again :D 

also is my first post so tell me anything I'm doing wrong

Code: [Select]


#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

#define NUM_ROWS 8
#define NUM_COLS 16

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

#define SERIAL_RATE 9600

const int row1Pin = 2;
const int row2Pin = 3;
const int row3Pin = 4;
const int row4Pin = 5;
const int row5Pin = 6;
const int row6Pin = 7;
const int row7Pin = 8;
const int row8Pin = 9;


const int dataPin = 11;
const int latchPin = 12;
const int clockPin = 13;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS] = {                      //8X
                                        36, 37, 38, 39, 40, 41, 42, 43,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        44, 45, 46, 47, 48, 49, 50, 51,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        52, 53, 54, 55, 56, 57, 58, 59,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        64, 65, 66, 67, 12, 11, 11, 11,
                                        13, 11, 11, 11, 41, 11, 11, 11,  //8
                                        11, 11, 11, 11, 68, 69, 70, 71,
                                        72, 73, 74, 75, 11, 11, 11, 11,
                                        16, 11, 11, 11, 76, 77, 78, 79,
                                        80, 81, 82, 83, 11, 11, 11, 11,
                                        18, 11, 11, 11, 84, 85, 86, 87,
                                        88, 89, 90, 91, 11, 11, 11, 11,
                                        11, 11, 11, 11, 92, 93, 94, 95,
                                        96,                                        //16
                                        };

int bits[] =
{
  B11111110,
  B11111101,
  B11111011,
  B11110111,
  B11101111,
  B11011111,
  B10111111,
  B01111111
};


void setup()
{
  int note = 64;

  for(int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    for(int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      note++;
    }
  }
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);

  pinMode(row1Pin, INPUT);
  pinMode(row2Pin, INPUT);
  pinMode(row3Pin, INPUT);
  pinMode(row4Pin, INPUT);
  pinMode(row5Pin, INPUT);
  pinMode(row6Pin, INPUT);
  pinMode(row7Pin, INPUT);
  pinMode(row8Pin, INPUT);

  Serial.begin(SERIAL_RATE);  
}
void loop()
{
  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
  scanColumn(colCtr);

  int rowValue[NUM_ROWS];
  rowValue[0] = !digitalRead(row1Pin);
  rowValue[1] = !digitalRead(row2Pin);
  rowValue[2] = !digitalRead(row3Pin);
  rowValue[3] = !digitalRead(row4Pin);
  rowValue[4] = !digitalRead(row5Pin);
  rowValue[5] = !digitalRead(row6Pin);
  rowValue[6] = !digitalRead(row7Pin);
  rowValue[7] = !digitalRead(row8Pin);

  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, B11111111); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr
  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum-8]); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111); //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);
}




Grumpy_Mike

Well that schematic apart from having horrendous colours making it almost impossible to read does not show any matrix of buttons, the whole point of your problem.

You still have not said what you mean by sensitivity keys, and why this is a problem.

You should not use 9600 baud is will add a bottleneck and slow the whole midi process down. Hairless will work a lot faster than that, it should be run as fast as you can.

milamter

I know how to connect the wires, I need help with the code.
I got 2 buttons for each note and want to make one of those buttons half velocity and the other 127 so I can get sensitive keys.
How could I achieve this?, defining a velocity of 127 to half keys in the matrix and the other just half ?

Grumpy_Mike

#5
Jan 30, 2020, 04:57 pm Last Edit: Jan 30, 2020, 04:57 pm by Grumpy_Mike
Quote
I know how to connect the wires, I need help with the code.
You very well might, but without me knowing how you connected the wires I can't help you with the code can I?

Quote
How could I achieve this?, defining a velocity of 127 to half keys in the matrix and the other just half ?
Well that is unusual but if that is what you want that will do it.

However there is little point because you just need a single pot on an analogue input, you read the pot and divide it by eight
Code: [Select]
velocity = analogRead (0) << 3;
Then use that value of velocity for all keys.

milamter

there, a better schematic, sorry for the first one.
I have 8 wires of the matrix that correspond to the hard pressed and are disconnected, I would connect them to the analog ports as digital, I did read it is possible.


Quote
Well that is unusual but if that is what you want that will do it.
but how can i do this?
-should I make 2 arrays? one for each matrix, but I would have to use same note for 2 buttons and I find it harder to define different velocity.

-make 2 arrays one for soft pressed and other for hard pressed, I think this is it, but don't know how to write the code

-simply make some of the code twice, something like this:

Code: [Select]

#define NUM_ROWS_HARD
#define NUM_COL_HARD
#define NUM_ROWS_SOFT
#define NUM_COL_SOFT


and repeat all the other parts of the code where those variables are called.


this is the only part of the code where NOTE_VELOCITY is called:

Code: [Select]

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 don't know where those col and row are defined, is it on here?


Code: [Select]

{
  int note = 64;       //i've changed this and doesn't make any change, i guess it is bc I i defned it in the
                             //     array 

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


milamter

just connected the remaining wires of the matrix

Code: [Select]

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

#define NUM_ROWS 16
#define NUM_COLS 16

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

#define SERIAL_RATE 19200

const int row1Pin = 3;
const int row2Pin = 4;
const int row3Pin = 5;
const int row4Pin = 6;
const int row5Pin = 7;
const int row6Pin = 8;
const int row7Pin = 9;
const int row8Pin = 10;
const int row9Pin = A0;
const int row10Pin = A1;
const int row11Pin = A2;
const int row12Pin = A3;
const int row13Pin = A4;
const int row14Pin = A5;
const int row15Pin = 2;
const int row16Pin = 0;


const int dataPin = 11;
const int latchPin = 12;
const int clockPin = 13;

boolean keyPressed[NUM_ROWS][NUM_COLS];
uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS] = {                      //8X
                                        36, 37, 38, 39, 40, 41, 42, 43,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        44, 45, 46, 47, 48, 49, 50, 51,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        52, 53, 54, 55, 56, 57, 58, 59,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        60, 61, 62, 63, 64, 65, 66, 67,
                                        68, 69, 70, 71, 13, 11, 11, 11, //8
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        68, 69, 70, 71, 72, 73, 74, 75,
                                        16, 11, 11, 11, 16, 11, 11, 11,
                                        76, 77, 78, 79, 80, 81, 82, 83,
                                        18, 11, 11, 11, 11, 11, 11, 11,
                                        84, 85, 86, 87, 88, 89, 90, 91,
                                        11, 11, 11, 11, 11, 11, 11, 11,
                                        92, 93, 94, 95, 96,                          //16
                                        };

int bits[] =
{
  B11111110,
  B11111101,
  B11111011,
  B11110111,
  B11101111,
  B11011111,
  B10111111,
  B01111111
};


void setup()
{
  int note = 64;

  for(int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
    for(int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr)
    {
      keyPressed[rowCtr][colCtr] = false;
      note++;
    }
  }
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);

  pinMode(row1Pin, INPUT);
  pinMode(row2Pin, INPUT);
  pinMode(row3Pin, INPUT);
  pinMode(row4Pin, INPUT);
  pinMode(row5Pin, INPUT);
  pinMode(row6Pin, INPUT);
  pinMode(row7Pin, INPUT);
  pinMode(row8Pin, INPUT);
  pinMode(row9Pin, INPUT);
  pinMode(row10Pin, INPUT);
  pinMode(row11Pin, INPUT);
  pinMode(row12Pin, INPUT);
  pinMode(row13Pin, INPUT);
  pinMode(row14Pin, INPUT);
  pinMode(row13Pin, INPUT);
  pinMode(row14Pin, INPUT);

  Serial.begin(SERIAL_RATE); 
}
void loop()
{
  for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr)
  {
  scanColumn(colCtr);

  int rowValue[NUM_ROWS];
  rowValue[0] = !digitalRead(row1Pin);
  rowValue[1] = !digitalRead(row2Pin);
  rowValue[2] = !digitalRead(row3Pin);
  rowValue[3] = !digitalRead(row4Pin);
  rowValue[4] = !digitalRead(row5Pin);
  rowValue[5] = !digitalRead(row6Pin);
  rowValue[6] = !digitalRead(row7Pin);
  rowValue[7] = !digitalRead(row8Pin);
  rowValue[8] = !digitalRead(row9Pin);
  rowValue[9] = !digitalRead(row10Pin);
  rowValue[10] = !digitalRead(row11Pin);
  rowValue[11] = !digitalRead(row12Pin);
  rowValue[12] = !digitalRead(row13Pin);
  rowValue[13] = !digitalRead(row14Pin);
  rowValue[14] = !digitalRead(row15Pin);
  rowValue[15] = !digitalRead(row16Pin);
 
 

  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, B11111111); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr
  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum-8]); //right sr
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111); //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);
}


haven't arranged them on the array yet, so they show as note 0, velocity 127. I need to show as velocity 60 or something like that, heeeelp is the last thing and can solder and finish this.

Grumpy_Mike

#8
Jan 31, 2020, 08:50 am Last Edit: Jan 31, 2020, 08:57 am by Grumpy_Mike
Quote
but how can i do this?
You make one array, but you know from the column or row number which keyboard you are addressing. So as well as using the column and row number to address your array you use one of those numbers ( don't know which as it is a bit hard to see from the code ) with a simple if statement. If it is below half the maximum it is keyboard 1 and so set the velocity to 64 or else set the velocity to 127.

PS. Thanks for the diagram but you still haven't shown the switches in the matrix. Is there a diode in series with each switch, and what direction is it pointing? You only need to show one switch wiring not them all. If you have no diodes then you can only press one key at once. Pressing more than one key will result in "phantom key presses". That is two keys pressed will result in four keys being detected.

I would also expect to see some pull down resistors on either the column or row lines as well otherwise things will float. Especially as the pins have been set to be just inputs so you are not using the internal pull up resistors.

milamter

Quote
You make one array, but you know from the column or row number which keyboard you are addressing. So as well as using the column and row number to address your array you use one of those numbers ( don't know which as it is a bit hard to see from the code ) with a simple if statement. If it is below half the maximum it is keyboard 1 and so set the velocity to 64 or else set the velocity to 127.
OK, so only one array, in an specific order so soft pressed

i came up with this array

Code: [Select]

  36, 37, 38, 39, 40, 41, 42, 43, 11, 11, 11, 11, 11, 11, 11,
  44, 45, 46, 47, 48, 49, 50, 51, 11, 11, 11, 11, 11, 11, 11,
  52, 53, 54, 55, 56, 57, 58, 59, 11, 11, 11, 11, 11, 11, 11,
  60, 61, 62, 63, 64, 65, 66, 67, 11, 11, 11, 11, 11, 11, 11,
  11, 11, 11, 11, 11, 11, 11, 11, 68, 69, 70, 71, 72, 73, 74,
  11, 11, 11, 11, 11, 11, 11, 11, 75, 76, 77, 78, 79, 80, 81,
  11, 11, 11, 11, 11, 11, 11, 11, 82, 83, 84, 85, 86, 87, 88,
  11, 11, 11, 11, 11, 11, 11, 11, 89, 90, 91, 92, 93, 94, 95,
  36, 37, 38, 39, 40, 41, 42, 43, 11, 11, 11, 11, 11, 11, 11,
  44, 45, 46, 47, 48, 49, 50, 51, 11, 11, 11, 11, 11, 11, 11,
  52, 53, 54, 55, 56, 57, 58, 59, 11, 11, 11, 11, 11, 11, 11,
  60, 61, 62, 63, 64, 65, 66, 67, 11, 11, 11, 11, 11, 11, 11,
  11, 11, 11, 11, 11, 11, 11, 11, 68, 69, 70, 71, 72, 73, 74,
  11, 11, 11, 11, 11, 11, 11, 11, 75, 76, 77, 78, 79, 80, 81,
  11, 11, 11, 11, 11, 11, 11, 11, 82, 83, 84, 85, 86, 87, 88,
  11, 11, 11, 11, 11, 11, 11, 11, 89, 90, 91, 92, 93, 94, 95,


still wird all those 11 to fill it up.

still don't know how to make that simple if statement, tried this with no luck
Code: [Select]

  if  (rowValue <= 8) {NOTE_VELOCITY = 70}
  else {NOTE_VELOCITY = 126};

Grumpy_Mike

Quote
still don't know how to make that simple if statement, tried this with no luck
Yes that should do it. Are you sure you are using the correct value, have you tried it with the column?

Also you have the semicolons in the wrong place.

How are you testing this? It makes sense to print out what you are getting before trying to turn it into MIDI.

Like:-
Code: [Select]
  if  (rowValue <= 8) {
            NOTE_VELOCITY = 70;
            Serial.Println(NOTE_VELOCITY);
}
  else {
            NOTE_VELOCITY = 126;
             Serial.Println(NOTE_VELOCITY); 
};

Go Up