Problems with MIDI notes below C1

Hi guys! I'm not an expert in arduino codes but I was making for myself a MIDI to CV to use in my studio....everything works fine but when I press notes below C1 I have a strange response from the arduino...the GATE stay HIGH and the notes looks like high pitch but not always the same note....can someone help me out with this? the code is this

#include <MIDI.h>
#include <SPI.h>

// Note priority is set by pins A0 and A2
// Highest note priority: A0 and A2 high (open)
// Lowest note priority:  A0 low (ground), A2 high (open)
// Last note priority:    A2 low (ground)

#define NP_SEL1 A0  // Note priority is set by pins A0 and A2
#define NP_SEL2 A2  

#define GATE  2
#define TRIG  3
#define CLOCK 4
#define DAC1  8 
#define DAC2  9
#define RESET 10 // Pin per il segnale di reset

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
 pinMode(NP_SEL1, INPUT_PULLUP);
 pinMode(NP_SEL2, INPUT_PULLUP);
 
 pinMode(GATE, OUTPUT);
 pinMode(TRIG, OUTPUT);
 pinMode(CLOCK, OUTPUT);
 pinMode(DAC1, OUTPUT);
 pinMode(DAC2, OUTPUT);
 pinMode(RESET, OUTPUT); // Configura il pin D10 come output reset
 digitalWrite(GATE,LOW);
 digitalWrite(TRIG,LOW);
 digitalWrite(CLOCK,LOW);
 digitalWrite(DAC1,HIGH);
 digitalWrite(DAC2,HIGH);
 digitalWrite(RESET, LOW); //Configura RESET come LOW all'inizio ciclo

 SPI.begin();

 MIDI.begin(1);

// MIDI.begin(MIDI_CHANNEL_OMNI);

 // Set initial pitch bend voltage to 0.5V (mid point).  With Gain = 1X, this is 1023
 // Other DAC outputs will come up as 0V, so don't need to be initialized
 setVoltage(DAC2, 0, 0, 1023);  
}

bool notes[128] = {0}; 
int8_t noteOrder[20] = {0}, orderIndx = {0};
unsigned long trigTimer = 0;

void loop()
{
  int type, noteMsg, velocity, channel, d1, d2;
  static unsigned long clock_timer=0, clock_timeout=0;
  static unsigned int clock_count=0;
  bool S1, S2;

  if ((trigTimer > 0) && (millis() - trigTimer > 20)) { 
    digitalWrite(TRIG,LOW); // Set trigger low after 20 msec 
    trigTimer = 0;  
  }

  if ((clock_timer > 0) && (millis() - clock_timer > 20)) { 
    digitalWrite(CLOCK,LOW); // Set clock pulse low after 20 msec 
    clock_timer = 0;  
  }
  
  if (MIDI.read()) {                    
    byte type = MIDI.getType();
    switch (type) {
      case midi::NoteOn: 
      case midi::NoteOff:
        noteMsg = MIDI.getData1();
        channel = MIDI.getChannel();
        
        if ((noteMsg < 0) || (noteMsg > 127)) break; // Only 128 notes of MIDI are supported

        if (type == midi::NoteOn) velocity = MIDI.getData2();
        else velocity  = 0;  

        if (velocity == 0)  {
          notes[noteMsg] = false;
        }
        else {
          notes[noteMsg] = true;
          // velocity range from 0 to 4095 mV  Left shift d2 by 5 to scale from 0 to 4095, 
          // and choose gain = 2X
          setVoltage(DAC2, 1, 1, velocity<<5);  // DAC1, channel 1, gain = 2X
        }

        // Pins NP_SEL1 and NP_SEL2 indictate note priority
        S1 = digitalRead(NP_SEL1);
        S2 = digitalRead(NP_SEL2);

        if (S1 && S2) { // Highest note priority
          commandTopNote();
        }
        else if (!S1 && S2) { // Lowest note priority
          commandBottomNote();
        }
        else { // Last note priority
           if (notes[noteMsg]) {  // If note is on and using last note priority, add to ordered list
            orderIndx = (orderIndx+1) % 20;
            noteOrder[orderIndx] = noteMsg;                 
          }
          commandLastNote();         
        }
        break;
        
      case midi::PitchBend:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2(); // d2 from 0 to 127, mid point = 64

        // Pitch bend output from 0 to 1023 mV.  Left shift d2 by 4 to scale from 0 to 2047.
        // With DAC gain = 1X, this will yield a range from 0 to 1023 mV.  
        setVoltage(DAC2, 0, 0, d2<<4);  // DAC2, channel 0, gain = 1X
        
        break;

      case midi::ControlChange: 
        d1 = MIDI.getData1();
        d2 = MIDI.getData2(); // From 0 to 127

        // CC range from 0 to 4095 mV  Left shift d2 by 5 to scale from 0 to 4095, 
        // and choose gain = 2X
        setVoltage(DAC1, 1, 1, d2<<5);  // DAC2, channel 1, gain = 2X
        break;
        
      case midi::Clock:
        if (millis() > clock_timeout + 300) clock_count = 0; // Prevents Clock from starting in between quarter notes after clock is restarted!
        clock_timeout = millis();
        
        if (clock_count == 0) {
          digitalWrite(CLOCK,HIGH); // Start clock pulse
          clock_timer=millis();    
        }
        clock_count++;
        if (clock_count == 24) {  // MIDI timing clock sends 24 pulses per quarter note.  Sent pulse only once every 24 pulses
          clock_count = 0;  
        }
        break;
        
      case midi::ActiveSensing: 
        break;

         case midi::Stop:
        // Quando viene ricevuto un messaggio di stop, genera RESET
        generateRESET();
        break;
        
      default:
        d1 = MIDI.getData1();
        d2 = MIDI.getData2();
    }
  }
}

void commandTopNote()
{
  int topNote = 0;
  bool noteActive = false;
  
  for (int i=0; i<128; i++)
  {
    if (notes[i]) {
      topNote = i;
      noteActive = true;
    }
  }

  if (noteActive) 
    commandNote(topNote);
  else // All notes are off, turn off gate
    digitalWrite(GATE,LOW);  
}

void commandBottomNote()
{
  int bottomNote = 0;
  bool noteActive = false;
 
  for (int i=127; i>=0; i--)
  {
    if (notes[i]) {
      bottomNote = i;
      noteActive = true;
    }
  }

  if (noteActive) 
    commandNote(bottomNote);
  else // All notes are off, turn off gate
    digitalWrite(GATE,LOW);
}

void commandLastNote()
{

  int8_t noteIndx;
  
  for (int i=0; i<20; i++) {
    noteIndx = noteOrder[ mod(orderIndx-i, 20) ];
    if (notes[noteIndx]) {
      commandNote(noteIndx);
      return;
    }
  }
  digitalWrite(GATE,LOW);  // All notes are off
}

// Rescale 128 notes to 4096 mV:
//    noteMsg = 0 -> 0 mV 
//    noteMsg = 127 -> 4096 mV
// DAC output will be (4095/127) = 32.283 mV per note, and 564.9655 mV per octive
// Note that DAC output will need to be amplified by 1.77X for the standard 1V/octave 

#define NOTE_SF 32.283f // This value can be tuned if CV output isn't exactly 1V/octave

void commandNote(int noteMsg) {
  digitalWrite(GATE,HIGH);
  digitalWrite(TRIG,HIGH);
  trigTimer = millis();
  
  unsigned int mV = (unsigned int) ((float) noteMsg * NOTE_SF + 0.5); 
  setVoltage(DAC1, 0, 1, mV);  // DAC1, channel 0, gain = 2X
}

// setVoltage -- Set DAC voltage output
// dacpin: chip select pin for DAC.  Note and velocity on DAC1, pitch bend and CC on DAC2
// channel: 0 (A) or 1 (B).  Note and pitch bend on 0, velocity and CC on 2.
// gain: 0 = 1X, 1 = 2X.  
// mV: integer 0 to 4095.  If gain is 1X, mV is in units of half mV (i.e., 0 to 2048 mV).
// If gain is 2X, mV is in units of mV

void setVoltage(int dacpin, bool channel, bool gain, unsigned int mV)
{
  unsigned int command = channel ? 0x9000 : 0x1000;

  command |= gain ? 0x0000 : 0x2000;
  command |= (mV & 0x0FFF);
  
  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
  digitalWrite(dacpin,LOW);
  SPI.transfer(command>>8);
  SPI.transfer(command&0xFF);
  digitalWrite(dacpin,HIGH);
  SPI.endTransaction();
}

void generateRESET() {
  digitalWrite(RESET, HIGH); // Imposta il pin di RESET a HIGH
  delay(30); // Durata dell'impulso PWM (30 millisecondi)
  digitalWrite(RESET, LOW); // Riporta il pin di REET a LOW dopo la durata desiderata dell'impulso
}

int mod(int a, int b)
{
    int r = a % b;
    return r < 0 ? r + b : r;
}

I don't see anything strange in the code, even if I have never made a MIDI to CV. If GATE stays HIGH it seems the received noteON somehow didn't set its notes[] value to true, but I can't find where/why.
I think you should try some serial debugging to track the code execution down (to free up the Serial use MIDI_CREATE_INSTANCE with a SoftwareSerial, so changing the MIDI serial pins) and see what happens. Starting from the MIDI data read:

...
    switch (type) {
      case midi::NoteOn: 
      case midi::NoteOff:
        noteMsg = MIDI.getData1();
        channel = MIDI.getChannel();

        // Add this:
        Serial.print("noteMsg=");Serial.print(noteMsg);
        Serial.print(" channel=");Serial.print(channel);
        Serial.print(" velocity=");Serial.println(MIDI.getData2());

        if ((noteMsg < 0) || (noteMsg > 127)) break; // Only 128 notes of MIDI are supported
...

Btw, AFAIK below C1 there are just three "real" notes (A0, A#0, B0) with MIDI codes 21-23. Frequencies under those notes are likely to be just hums, ranging from 25.96 Hz (MIDI note number 20) down to 8.18 Hz (MIDI note 0). Why you need that?

Is there a chance that the Midi source is the cause. My keyboard sometimes has a sticky note.
Also i would probably set the velocity to 0 or the initial 1023 in case of a note Off

if (type == midi::NoteOn) velocity = MIDI.getData2();
        else velocity  = 0;  

        if (velocity == 0)  {
          notes[noteMsg] = false;
        }
        else {
          notes[noteMsg] = true;
          // velocity range from 0 to 4095 mV  Left shift d2 by 5 to scale from 0 to 4095, 
          // and choose gain = 2X
          setVoltage(DAC2, 1, 1, velocity<<5);  // DAC1, channel 1, gain = 2X
        }

edit : I didn't find anything obvious either, but i am somewhat disturbed by the use of signed variables to deal with an unsigned value protocol.

Also i seems more logical to actually let the

bool notes[128] = {0}; 

array hold the velocities rather than just the noteOn noteOff.
a bool takes up 1 byte as well so space wise it doesn't change much.

That just depends what you do with those frequencies afterwards.