Help me to understand the code...MIDI KEYBOARD

Hello!

I'm trying to understand the MIDI keyboard code which I found one book. The code is below.

Please, could someone explain to me what does it mean when there is this line in the loop():

scanKeys(keyState[row + col + blk]);

I do understand that this a function called scanKeys, but I don't understand how it is used here.

And why there are always these keysState-statements in every case:

for example:

keyState[row + col + blk] = 1;
keyState[row + col + blk] = 0;
keyState[row + col + blk] = 2;
etc.

I'm wondering why these are used? What difference it makes if Arduino knows that the keyState is now keyState 1...or 2...or whatever...? I don't understand.

Thank you!

/**********************************************
To read keys on a 25 note Fatar Keyboard using an 8x5=40 matrix, and
produce velocity sensitive MIDI Output
**********************************************/

#include <math.h>

// define the pins we use

#define ROW0 14
#define ROW1 15
#define ROW2 16
#define ROW3 17
#define ROW4 18
#define ROW5 19
#define ROW6 20
#define ROW7 21

#define MK0 22
#define MK1 24
#define MK2 26
#define MK3 28
#define MK4 30
#define BR0 23
#define BR1 25
#define BR2 27
#define BR3 29
#define BR4 31

#define LedPin 13 // for midi out status
#define thresholdTime_max 2400
#define constrain_min 1
#define constrain_max 200
#define log_multiplier 25

int note;

byte noteOn = 0x90;
byte noteOff = 0x80;
byte firstNote = 36; // Note C2
byte channel = 0; // MIDI channel 1
byte velocityOn;
byte velocityOff;

int constrainTimeOn;
int constrainTimeOff;
double logTime1;
double logTime2;

int keyState[40];
int x, col, row, blk;

unsigned long startTime1[40];
unsigned long startTime2[40];
unsigned long startTimeOn;
unsigned long startTimeOff;

int MK[5] = { MK0, MK1, MK2, MK3, MK4};
int BR[5] = { BR0, BR1, BR2, BR3, BR4};
int ROW[8] = { ROW0, ROW1, ROW2, ROW3, ROW4, ROW5,
ROW6, ROW7};

void setup() {
for (x = 0; x < 8; x++) {
pinMode(ROW[x], INPUT_PULLUP);
}
for (x = 0; x < 5; x++) {
pinMode(MK[x], OUTPUT);
pinMode(BR[x], OUTPUT);
digitalWrite(MK[x], HIGH);
digitalWrite(BR[x], HIGH);
}

// initialize all to 0's
for (x = 0; x < 40; x++) {
startTime1[x] = 0;
startTime2[x] = 0;
keyState[x] = 0;
OnFlag[40] = 0;
}

pinMode(LedPin, OUTPUT);
Serial.begin(31250); // set serial baud rate
}

//----------------End of Setup-----------------

void loop() {
blk = 0;
for (col = 0; col < 5; col++) {
for (row = 0; row < 8; row++) {
scanKeys(keyState[row + col + blk]);
}
blk = blk + 7;
}
}
//----------------End of main Loop-------------

//--------------Start of Functions-------------

void scanKeys(int var) {
switch (var) {

case 0:

digitalWrite(BR[col], LOW); // Switch BR ON
if (digitalRead(ROW[row]) == LOW) { // BR key is pressed
startTime1[row + col + blk] = millis();
keyState[row + col + blk] = 1;
}
digitalWrite(BR[col], HIGH); // Switch BR OFF
break;

//-----------------------------------------

case 1:

if (digitalRead(ROW[row]) == HIGH) { //No key pressed
keyState[row + col + blk] = 2;
}
break;

//-----------------------------------------

case 2:

digitalWrite(MK[col], LOW); // Switch MK ON
if (digitalRead(ROW[row]) == LOW) { // MK key is pressed
startTimeOn = millis() - startTime1[row + col + blk];
logTime1 = log_multiplier * log(startTimeOn);
if (startTimeOn > thresholdTime_max) {
keyState[row + col + blk] = 0;
digitalWrite(MK[col], HIGH); // Switch MK OFF
break;
}
constrainTimeOn = constrain(logTime1, constrain_min,
constrain_max);
velocityOn = map(constrainTimeOn, constrain_min, constrain_max,
127, 1); // Linear Curve
note = row + col + blk;
midiSend(noteOn + channel , firstNote + note, velocityOn); // send
midi note on
keyState[row + col + blk] = 3;
}
digitalWrite(MK[col], HIGH); // Switch MK OFF
break;

//-----------------------------------------

case 3 :

digitalWrite(MK[col], LOW); // Switch MK ON
if (digitalRead(ROW[row]) == HIGH) { // MK key is released
startTime2[row + col + blk] = millis();
keyState[row + col + blk] = 4;
}
digitalWrite(MK[col], HIGH); // Switch MK OFF
break;

//-----------------------------------------

case 4:

digitalWrite(BR[col], LOW); // Switch BR ON
if (digitalRead(ROW[row]) == HIGH) { // BR key reached top
startTimeOff = millis() - startTime2[row + col + blk];
logTime2 = log_multiplier * log(startTimeOff);
constrainTimeOff = constrain(logTime2, constrain_min,
constrain_max);
velocityOff = map(constrainTimeOff, constrain_max,
constrain_min, 1, 127); // Linear Curve
note = row + col + blk;
midiSend(noteOff + channel, firstNote + note, velocityOff); // send
midi note off
keyState[row + col + blk] = 0;
}
digitalWrite(BR[col], HIGH); // Switch BR OFF
break;

//-----------------------------------------

default:
break;
}
}

//---------------------------------------------
// Send a general MIDI message

void midiSend(byte cmd, byte data1, byte data2) {
digitalWrite(LedPin, HIGH); // indicate we're sending MIDI data
Serial.write(cmd);
Serial.write(data1);
Serial.write(data2);
digitalWrite(LedPin, LOW);
}

this function scan and stores current state of a key of key matrix(launchpad?)

Which book did you find that in?
Is the code suppose to work, or does the book give that as an exercise in how to correct a non-working code? Looks to me like it would not function properly.

The code is from this book:

Yes, it should be a working code.


void loop() {
  blk = 0;
  for (col = 0; col < 5; col++) {
    for (row = 0; row < 8; row++) {
      scanKeys(keyState[row + col + blk]);
    }
    blk = blk + 7;
  }
}

Looks like an attempt to convert row/column to an array index, but it would be clearer to use (col * 8 + row), since incrementing blk by 7 makes the sequence difficult to understand. I would also consider it bad programming to be using global variables in the for loops, then referencing those in a function, particularly since you can pass the sum to the function and don't really need to re-calculate that inside the function multiple times.

I'm trying to edit the book's code for my own needs and learning and decided to try to modify the code for only one break and one make key just for testing purposes.

This is the code that I tried to make. Is this correct way to do it with only one break and make switches?

/*******************************************************
MIDI KEYBOARD TEST WITH ONLY 1 BREAK AND 1 MAKE SWITCHES
*******************************************************/

#include <math.h>

#define BREAK1 2
#define MAKE1 3

#define LedPin 13 // for midi out status
#define thresholdTime_max 2400
#define constrain_min 1
#define constrain_max 200
#define log_multiplier 25

int note;

byte noteOn = 0x90;
byte noteOff = 0x80;
byte firstNote = 36; // Note C2
byte channel = 0; // MIDI channel 1
byte velocityOn;
byte velocityOff;

int constrainTimeOn;
int constrainTimeOff;
double logTime1;
double logTime2;

int keyState;
int x;

unsigned long startTime1;
unsigned long startTime2;
unsigned long startTimeOn;
unsigned long startTimeOff;

//--------------------------------------------

void setup() {

pinMode(MAKE1, INPUT_PULLUP);
pinMode(BREAK1, INPUT_PULLUP);

startTime1 = 0;
startTime2 = 0;
keyState = 0;

pinMode(LedPin, OUTPUT);
Serial.begin(31250); // set serial baud rate
}

//----------------End of Setup-----------------

void loop() {

scanKeys(keyState);

}

//----------------End of main Loop-------------

//--------------Start of Functions-------------

void scanKeys(int var) {
switch (var) {

case 0: // BREAK key is pressed

if (digitalRead(BREAK1) == LOW) { 
startTime1 = millis();
keyState = 1;
}
break;

//-----------------------------------------

case 1: //No BREAK-key pressed

if (digitalRead(BREAK1) == HIGH) {
keyState = 2;
}
break;

//-----------------------------------------

case 2: // MAKE key is pressed

if (digitalRead(MAKE1) == LOW) {
startTimeOn = millis() - startTime1;
logTime1 = log_multiplier * log(startTimeOn);
if (startTimeOn > thresholdTime_max) {
keyState = 0;
break;
}

constrainTimeOn = constrain(logTime1, constrain_min,
constrain_max);
velocityOn = map(constrainTimeOn, constrain_min, constrain_max,
127, 1); // Linear Curve
note = 0;
midiSend(noteOn + channel , firstNote + note, velocityOn); // send midi note on
keyState = 3;
}
break;

//-----------------------------------------

case 3 : // MAKE key is released

if (digitalRead(MAKE1) == HIGH) { 
startTime2 = millis();
keyState = 4;
}
break;

//-----------------------------------------

case 4: // BREAK key reached top

if (digitalRead(BREAK1) == HIGH) { 
startTimeOff = millis() - startTime2;
logTime2 = log_multiplier * log(startTimeOff);
constrainTimeOff = constrain(logTime2, constrain_min,
constrain_max);
velocityOff = map(constrainTimeOff, constrain_max,
constrain_min, 1, 127); // Linear Curve
note = 0;
midiSend(noteOff + channel, firstNote + note, velocityOff); // send midi note off
keyState = 0;
}
break;

//-----------------------------------------

default:
break;
}
}

//---------------------------------------------
// Send a general MIDI message

void midiSend(byte cmd, byte data1, byte data2) {
digitalWrite(LedPin, HIGH); // indicate we're sending MIDI data
Serial.write(cmd);
Serial.write(data1);
Serial.write(data2);
digitalWrite(LedPin, LOW);
}

So, how to modify it so that it scans one break and one make switch?

Note that 'blk' is 'col * 7'. Adding 'col + blk' to row give you 'col * 8 + row', the traditional way to index a one-dimensional array as if it were two-dimensional. The advantage is that it uses addition instead of multiplication.

Keeping track of when the two contacts on each key change to calculate a velocity value.

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