Why are these two NOT identical?

Hi, I have an old 88 key piano keybed. Its just the buttons and 2 ribbon cables, and I'm trying to get a little arduino device going that can play MIDI notes depending on the key pressed. I finally achieved a prototype that has 2 keys working the way I want, but when I tried to convert the pattern into a function, it stopped working the way I wanted. For some reason, the 2 versions of the code are NOT identical, but I don't really understand why. Any insights would be appreciated.

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();

int latchClock = 12;  // Latch pin to 12 chip
int shiftClock = 11; // Clock pin to 11 chip
int serialData = 10;  // Data pin to 14 chip
int clearPin = 13;

//These gates will eventually be an 88 element array...
bool gate77 = 0; 
bool gate78 = 0;

//This array is used to scan the outputs of the keybed ribbon in conjunction with the shift register...
byte myByte[9] = {0b01111111,
                  0b10111111,
                  0b11011111,
                  0b11101111,
                  0b11110111,
                  0b11111011,
                  0b11111101,
                  0b11111110
                 };
byte byteHigh = 0b11111111;

//These will eventually hold multiple inputs and their current states, but right not only element 0 is used...
int rowState[9] = {1, 1, 1, 1, 1, 1, 1, 1};
int inputPin[9] = {14, 2, 2, 2, 2, 2, 2, 2}; 

void setup() {
  Serial.begin(31250); //MIDI serial baud rate
  MIDI.begin(MIDI_CHANNEL_OMNI);

  pinMode(A0, INPUT);
  pinMode(2, INPUT);

  pinMode(latchClock, OUTPUT);
  pinMode(serialData, OUTPUT);
  pinMode(shiftClock, OUTPUT);
  pinMode(clearPin, OUTPUT);

  digitalWrite(clearPin, LOW); 
  digitalWrite(clearPin, HIGH);
}

void loop() {
  for (int i = 0; i < 8; i++) {
    shiftDouble(byteHigh, byteHigh); //make all outputs high
    shiftDouble(myByte[i], byteHigh); //then a specific one low
    for (int j = 0; j < 8; j++) { //read ALL inputs for EACH output i above
      rowState[j] = digitalRead(inputPin[j]);
    }

    /* Below is the part of the code under question. This uncommented version
     * works perfectly. Basically what makes a note trigger is the combination of
     * an output pulled LOW (handled by the for loop i) and an input read LOW (handled
     * by the rowState array). The gates make it to where the notes don't retrigger,
     * that you can hold multiple notes at once and they release as expected.
     */
    if (i == 0) {
      if (rowState[0] == 0 && gate77 == 0) {
        MIDI.sendNoteOn(77, 63, 1); //plays pitch of F5
        gate77 = 1;
      }
      else if (rowState[0] == 1 && gate77 == 1) {
        MIDI.sendNoteOff(77, 0, 1);
        gate77 = 0;
      }
    }
    //---------------
    if (i == 1) {
      if (rowState[0] == 0 && gate78 == 0) {
        MIDI.sendNoteOn(78, 63, 1); //plays pitch of F5#
        gate78 = 1;
      }
      else if (rowState[0] == 1 && gate78 == 1) {
        MIDI.sendNoteOff(78, 0, 1);
        gate78 = 0;
      }
    }
    /* However this code, along with the function definition below, does not.
     *  I don't understand why they wouldn't be identical in the assembler.
     * if (i==0){gateNote(rowState[0],gate77,77);}
     * if (i==1){gateNote(rowState[0],gate78,78);}
     * 
      */
  }
}

//This handles the 2 shift registers for an eventual 16 outputs
void shiftDouble(byte topChip, byte bottomChip) {
  digitalWrite(latchClock, LOW); //so outputs dont change while shifting
  shiftOut(serialData, shiftClock, LSBFIRST, bottomChip); //shift out the bits
  shiftOut(serialData, shiftClock, LSBFIRST, topChip); //shift out the bits
  digitalWrite(latchClock, HIGH); //change outputs with shifted in values
}

//Function that tried to convert the working code into a one-liner but failed...
//void gateNote(int myRowState, int myGate, int myNote){
//        if (myRowState == 0 && myGate == 0) { 
//        MIDI.sendNoteOn(myNote, 63, 1);
//        myGate = 1;
//      }
//      else if (myRowState == 1 && myGate == 1) {
//        MIDI.sendNoteOff(myNote, 0, 1);
//        myGate = 0;
//      }
//}

I should mention the behavior of both versions of the code as well.

When I press a single key with the working version, a single MIDI NoteOn is sent. When I release, a single NoteOff is sent.

But when I press a single key with the NOT-working version, multiple MIDI NoteOns are sent over and over again. When I release, no NoteOff is sent.

the value of myGate is being passed to gateNote(). it's value is being modified in the function but not returned to the calling function -- gate77 or gate78 are not being changed.

you can pass a pointer/reference by adding an "&"

void gateNote(int myRowState, int &myGate, int myNote){

Thanks, that fixed it. Should this always be done when a variable gets assigned something new in a function?

edit: if that variable is part of the function definition I mean

this is one approach (and preferrable)

a similar approach is to pass a pointer. this approach is essentially the same except it forces the compiler to pass a valid pointer value. (no need for the function to check for a null pointer)

another approach is to return the value of the variable being changed. this only works for one value and it may (??) not make sense for a function that controls tones to return the state of the tone.

Did you mean "pass a reference"?

that's what int &myGate is
see C++ Funcitons - Pass By Reference

Yes, but you wrote "pass a pointer".
A pointer can be null, and the compiler is not forced to check.

you're right.
what i was trying to say is passing a pointer (e.g *myGate) is similar to passing by "reference" (e.g &myGate) but the code should check that the pointer is not null

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