Midi Keyboard/ Octave change

Hey guys,

I am buiding myself a midi keyboard based on an old organ keyboard.
The keyboard has a 4x12 scan matrix and the note range is from F2 - C6.
I am using two 74HC595 shift registers, an arduino uno and a code that i mixed together from two different instructions i found on the internet. Everything works just fine.

Now to my question:

i want to add two buttons that change the octave of the keyboard, one button for octave up and one button for octave down.

Since i am a total newbie to programming i have no idea what to do. I can only think of a solution that is hardware based but that would just waste digital inputs of my arduino.
I hope you can give me some tips and solution approach. :slight_smile:

Btw i hope my english isn't to bad, i am german.
:roll_eyes:

This is the code i am working with right now.

#define NUM_ROWS 4
#define NUM_COLS 12

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

//MIDI baud rate
#define SERIAL_RATE 31250

// Pin Definitions

// 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[4][12] =   
{ 
 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,
 68,69,70,71,
 72,73,74,75,
 76,77,78,79,
 80,81,82,83,  
 };
 
// bitmasks for scanning columns
int bits[] =
{ 
  B11111110,
  B11111101,
  B11111011,
  B11110111,
  B11101111,
  B11011111,
  B10111111,
  B01111111
};

void setup()
{
  // 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, 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);
}

All you have to do is add or subtract an offset to the MIDI note number.

Regards,
Ray L.

hey Ray,

thanks for the quick reply!

I understand the idea of adding or substracting an offset to the midi note number,
i have major problems putting it in program code tho.

these are the midi note numbers i am using, am i right?

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,
68,69,70,71,
72,73,74,75,
76,77,78,79,
80,81,82,83,

i know how to write the code for the button but i dont know how to fill the if part.

const int buttonPin = 9; 

int buttonState = 0;

void setup() {

  pinMode(buttonPin, INPUT);
}

void loop() {

  buttonState = digitalRead(buttonPin);

if (buttonState == HIGH) {

midi note number + 12 

}

i know my attempt is rediculous, but as i said i am totally new to programming :smiley:

I played a little bit with the code and i found out that when i add an +1 to the serial.write line after "row" that the octave changes

Serial.write(keyToMidiMap[row + 1][col]);

Now i have to write an command for the button that does this, but i have no idea how :frowning:
can someone help me?

i came up with this solution now which almost works but still has a problem.

void noteOn(int row, int col)
{
   buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
  Serial.write(NOTE_ON_CMD);
  Serial.write(keyToMidiMap[row+1][col]);
  Serial.write(NOTE_VELOCITY);
} else
  Serial.write(NOTE_ON_CMD);
  Serial.write(keyToMidiMap[row][col]);
  Serial.write(NOTE_VELOCITY);

}

void noteOff(int row, int col)
{
   buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
  Serial.write(NOTE_OFF_CMD);
  Serial.write(keyToMidiMap[row+1][col]);
  Serial.write(NOTE_VELOCITY);
} else
  Serial.write(NOTE_OFF_CMD);
  Serial.write(keyToMidiMap[row][col]);
  Serial.write(NOTE_VELOCITY);
}

when i know press the key F2 on my keyboard in combination with the button i get the notes F2 and F3 at the same time...

so it didnt actually change the octave but it only added an additional octave to it :confused:

Edit: found the problem: forget to add braces to the else parts :slight_smile:

So have you figured out how to add octave shift buttons? I'll be adding MIDI to Casio SA-10 based on Evan Kale's YouTube video, but I'd also like to do add the octave down and octave up buttons.