my midi piano doesnt work

hi everybody I am building a midi piano. When you press a button it should go down(noteon signal) on the piano and when you release button should go up(noteoff signal) well I managed to make that happen for 1 button however when I start pressing second or third button program starts acting weirdly such as releasing the first note or not sending note off sign even if I Release it. I am using 64 i/o expander (sx1509) from sparkfun and 16 button pad from sparkfun too. For the processor I am using teensy 3.1 However I am having difficulties to make my code run properly. Maybe it is the reason that I couldn't understood how i/o expander send data(like what type, how etc.)I will attach the code below. I think there is a mistake at func() function but I cant find it Thanks for your help
:slight_smile:

#include <Wire.h>  // Wire.h library is required to use SX1509 lib
#include <sx1509_library.h>  // Include the SX1509 library


const byte SX1509_ADDRESS = 0x3E;  // SX1509 I2C address (00)

// MY teensy3.1 pin definitions
const byte resetPin = 1;
const byte interruptPin = 0;


// Here we'll define the number of rows and columns our keypad
//  matrix has. Each of these values can be between 1 and 8.
//  4x4 = 16 buttons
const byte numRows = 4;
const byte numCols = 4;
// This key map will be used to define what keypress is sent to
//  the computer when a key on the keypad is pressed.
int keyMap[numRows][numCols] = {
  {50,70,3,4},
  {80,90,6,7},
  {9,10,13,11},
  {25,1,53,55}};

// Create a new sx1509Class object
sx1509Class sx1509(SX1509_ADDRESS, resetPin, interruptPin);

void setup()
{
  
  Serial.begin(9600);
  
  // Must first initialize the sx1509:
  sx1509.init();
  // In order to use the keypad, the clock must first be
  // configured. We can call configureClock() with the default
  // parameters (2MHz internal oscillator, no clock in/out).
  sx1509.configClock();
  // Next call the keypad function with the number of rows
  //  and columns.
  //sx1509.keypad(numRows, numCols);  // Basic keypad init
  // There are two optional parameters in the keypad method:
  //  sleepTime and scanTime. Each of these values can be between
  //  0 and 7. If not set, these values default to 0 (sleep off
  //  scan time set to 1ms).
  byte sleepTime = 7;
  byte scanTime = 2;  // Scan time per row
  sx1509.keypad(numRows, numCols, sleepTime, scanTime);  // Advanced keypad init
  // We can also debounce the keypad inputs. The debounceConfig
  //  method takes one parameter. Similar to the scanTime it's a
  //  3-bit value (0-7). This value must be <= scanTime!
  byte debounceTime = 1;   // The debounce config value
  sx1509.debounceConfig(debounceTime);
}

//////////////////////////////////
//// Loop Variables  /////////////
//////////////////////////////////
unsigned int keyData;  // The raw data from the key press register
unsigned int previousKeyData = 0;  // previously read raw data
byte activeRow;  // The row of the button being pressed
byte activeColumn;  // The column of the button being pressed
// These variables are used to emulate a key-hold. While the key
//  is held down, there's a long delay before the second character
//  is printed. Then a shorter delay between the remaining key presses
unsigned int holdCount = 0;
// This behavior is highly dependent on scanTime and debounceConfig
//  which are set in the setup.
const byte holdCountMax = 25;
// These releaseCount variables 
//  The keypad engin on the SX1509 doesn't generate an interrupt
//  when a key is relased. So we'll use this counter to generate
//  releases.
unsigned int releaseCount = 0;  // Our counter
unsigned int releaseCountMax = 100;// Top, in about milliseconds

int oldkey1=0;
int oldkey2=0;
int oldkey3=0;
int newkey1=0;
int newkey2=0;
int newkey3=0;
// The loop will poll the interrupt pin. If the pin
//  is pulled low by the SX1509, we'll read the keypad data and
//  sort it into row and column, and send the corresponding key
//  press out to the computer.
void loop()
{

  if (!digitalRead(interruptPin))
  {
    newkey1=func(); //I think problem is caused by somewhere here
    newkey2=func();
    newkey3=func();
    
    if(oldkey1!=newkey1){
      usbMIDI.sendNoteOn(newkey1, 99, 1);
      usbMIDI.sendNoteOff(oldkey1, 99, 1);
      oldkey1=newkey1;}
      
    if(oldkey2!=newkey2){
      usbMIDI.sendNoteOn(newkey2, 99, 1);
      usbMIDI.sendNoteOff(oldkey2, 99, 1);
      oldkey2=newkey2;}
      
    if(oldkey3!=newkey3){
      usbMIDI.sendNoteOn(newkey3, 99, 1);
      usbMIDI.sendNoteOff(oldkey3, 99, 1);
      oldkey3=newkey3;}
    
    
    
    
    if (keyData != previousKeyData)
    {
      holdCount = 0;
     
    }


    releaseCount = 0;
    // Set keyData as previousKeyData
    previousKeyData = keyData;
  }
  
  // If no keys have been pressed we'll continuously increment
  //  releaseCount. Eventually creating a release, once the count
  //  hits the max.
  releaseCount++;
  if (releaseCount == releaseCountMax)
  {
    releaseCount = 0;
    previousKeyData = 0;
    usbMIDI.sendNoteOff(oldkey1, 99, 1);
    usbMIDI.sendNoteOff(oldkey2, 99, 1);
    usbMIDI.sendNoteOff(oldkey3, 99, 1);
    oldkey1=0;
     oldkey2=0;
      oldkey3=0;
  }
  delay(1);  // This gives releaseCountMax a more intuitive unit
}

// This function scours a byte and returns the position of the 
//  first byte it sees a 1. Great if our data bytes only have
//  a single 1 in them! Should return 0-7 if it sees a 1, 255 otherwise
byte getBitPosition(byte dataByte)
{
  for (int i=0; i<8; i++)
  {
    if (dataByte & (1<<i))
    {
      return i;
    }
  }
  return 255;  // Otherwise return an error
}

int func(){
    keyData = sx1509.readKeyData();
    activeRow = keyData & 0xFF;  // The row is the lower 8-bits
    activeColumn = keyData >> 8;  // column is the upper 8-bits
    activeRow = getBitPosition(activeRow);
    activeColumn = getBitPosition(activeColumn);
    return keyMap[activeRow][activeColumn];
}