Problema con timing (e midi note ON/OFF)

Buongiorno a tutti.
Scrivo per trovare un' anima pia che mi aiuti con questo problema (premetto che sono giorni che faccio ricerche).
Ho un codice quasi del tutto funzionante per realizzare uno step sequencer (16 step che si attivano con un tempo calcolato in bpm e funzionante).
Utilizzo un calcolo in bpm che viene inserito tramite un "tap tempo" e due pulsanti, uno che incrementa e uno che decrementa il tempo in passi di 1 bpm.
Il mio problema e' il seguente:

Premetto che sto utilizzando , per il midi, la libreria "control_surface" e una scheda teensy 3.5 che utilizza nativamente il midi via usb (anche se il tutto funziona anche con un arduino con il firmware modificato).

Per ogni step mando un MidiNoteOn e un MidiNoteOff che vanno a pilotare un mio software video (ho bisogno anche del noteoff per rilasciare le clip che vado a triggherare).
Per il NoteOn non ci sono problemi, viene inviato correttamente, pero', ovviamente mandando un segnale di on e di off consecutivamente vengono inviati nello stesso momento, avrei bisogno di capire come inserire un ritardo (senza DELAY) in ogni step in modo che il tutto invii "NoteON - Ritardo - NoteOff".

if (!played) {

  {
      midi.update();
    }
    
    if (stepNum == 0 && state1 == 1) {
      Serial.print("  primo_step  ");
      midi.sendNoteOn(noteAddress0, velocity);
      midi.sendNoteOff(noteAddress0, velocity);
    }
    played = true;

    if (stepNum == 1 && state2 == 1 ) {
     Serial.print("  secondo_step  ");

      midi.sendNoteOn(noteAddress1, velocity);
      midi.sendNoteOff(noteAddress1, velocity);
    }
    played = true;

   if (stepNum == 2 && state3 == 1) {
      Serial.print("  terzo_step  ");
      midi.sendNoteOn(noteAddress2, velocity);
      midi.sendNoteOff(noteAddress2, velocity);
    }
    played = true;

    if (stepNum == 3 && state4 == 1) {
      Serial.print("  quarto_step  ");
      midi.sendNoteOn(noteAddress3, velocity);
      midi.sendNoteOff(noteAddress3, velocity);
    }
    played = true;

 if (stepNum == 4 && state5 == 1) {
      Serial.print("  quinto_step  ");
      midi.sendNoteOn(noteAddress4, velocity);
      midi.sendNoteOff(noteAddress4, velocity);
    }
    played = true;

    if (stepNum == 5 && state6 == 1) {
      Serial.print("  sesto_step  ");
      midi.sendNoteOn(noteAddress5, velocity);
      midi.sendNoteOff(noteAddress5, velocity);
    }
    played = true;

    if (stepNum == 6 && state7 == 1) {
      Serial.print("  settimo_step  ");
      midi.sendNoteOn(noteAddress6, velocity);
      midi.sendNoteOff(noteAddress6, velocity);
    }
    played = true;

   if (stepNum == 7 && state8 == 1) {
      Serial.print("  ottavo_step  ");
      midi.sendNoteOn(noteAddress7, velocity);
      midi.sendNoteOff(noteAddress7, velocity);

    }
    played = true;

       if (stepNum == 8 && state9 == 1) {
      Serial.print("  nono_step  ");
      midi.sendNoteOn(noteAddress8, velocity);
      midi.sendNoteOff(noteAddress8, velocity);
    }
    played = true;

    if (stepNum == 9 && state10 == 1 ) {
     Serial.print("  drcimo_step  ");
      midi.sendNoteOn(noteAddress9, velocity);
      midi.sendNoteOff(noteAddress9, velocity);
    }
    played = true;

 if (stepNum == 10 && state11 == 1) {
      Serial.print("  undicesimo_step  ");
      midi.sendNoteOn(noteAddress10, velocity);
      midi.sendNoteOff(noteAddress10, velocity);
    }
    played = true;

    if (stepNum == 11 && state12 == 1) {
      Serial.print("  dodicesimo_step  ");
      midi.sendNoteOn(noteAddress11, velocity);
      midi.sendNoteOff(noteAddress11, velocity);
    }
    played = true;

 if (stepNum == 12 && state13 == 1) {
      Serial.print("  tredicesimo_step  ");
      midi.sendNoteOn(noteAddress12, velocity);
      midi.sendNoteOff(noteAddress12, velocity);
    }
    played = true;

    if (stepNum == 13 && state14 == 1) {
      Serial.print("  quattordicesimo_step  ");
      midi.sendNoteOn(noteAddress13, velocity);
      midi.sendNoteOff(noteAddress13, velocity);
    }
    played = true;

    if (stepNum == 14 && state15 == 1) {
      Serial.print("  quindicesimo_step  ");
      midi.sendNoteOn(noteAddress14, velocity);
      midi.sendNoteOff(noteAddress14, velocity);
    }
    played = true;

   if (stepNum == 15 && state16 == 1) {
      Serial.print("  sedicesimo_step  ");
      midi.sendNoteOn(noteAddress15, velocity);
      midi.sendNoteOff(noteAddress15, velocity);

    }
    played = true;
  }

Questa e' la parte che manda le note midi ad ogni step:
stepNum e' il numero dello step
played e' un bool che dice che lo step e' stato eseguito
state e' messo in && , mi attiva il send delle note solo se il pulsante relativo allo step e' stato premuto e ha portato state da 0 a 1.
Il Serial.println e' solo per debug sul monitor seriale.

Vi faccio un esempio:
Impostatndo i bpm a 60 (quindi uno step ogni secondo), la lettura dei millis ad ogni step aumenta di 1000 ms, ho bisogno di capire il meccanismo per cui io possa dirgli: e' iniziato lo step, invia MidiNoteOn, aspetta tot ms e invia MidiNoteOff. (Non posso mettere il note off nello step successivo prima del note on perche' mi sballerebbe il tutto).

Se qualcuno ha voglia di perderci 10 minuti io sono qui, se vi serve altro codice o spiegazioni scrivete pure.

Spero di riuscire a fare un bel post con uno step sequencer al 100% funzionante al piu' presto, questo e' l'ultimo scogio da superare.
Grazie a tutti.

Non so se ho capito bene ma ti do una soluzione che forse ti darà una dritta:

  if (stepNum == 1 && state2 == 1 ) {
     Serial.print("  secondo_step  ");

      midi.sendNoteOn(noteAddress1, velocity);
      midi.sendNoteOff(noteAddress0, velocity);
    }

Avrei forse bisogno di tutto il codice ma non è meglio che la variabile noteAddressX sia un array?
In questo modo puoi semplificare il codice

     Serial.print(" step nr: ");
     Serial.print(stepNum);

      midi.sendNoteOn(noteAddress[stepNum], velocity);
      midi.sendNoteOff(noteAddress[stepNum], velocity);
      // If (stepNum)
      //  midi.sendNoteOff(noteAddress[stepNum-1], velocity);
      played = true;

Intanto grazie per la risposta.
Sto utilizzando la libreria midi " control_surface"

Le righe seguenti di codice sono le note che dovrei mandare, solo che mi trovo in difficoltà a capire come metterle in un array, non trovo un'indicazione nella libreria.

const MIDIAddress noteAddress0 = {note(C, 4), CHANNEL_1};
const MIDIAddress noteAddress1 = {note(D, 4), CHANNEL_1};
const MIDIAddress noteAddress2 = {note(E, 4), CHANNEL_1};
const MIDIAddress noteAddress3 = {note(F, 4), CHANNEL_1};
const MIDIAddress noteAddress4 = {note(G, 4), CHANNEL_1};
const MIDIAddress noteAddress5 = {note(A, 4), CHANNEL_1};
const MIDIAddress noteAddress6 = {note(B, 4), CHANNEL_1};
const MIDIAddress noteAddress7 = {note(C, 5), CHANNEL_1};
const MIDIAddress noteAddress8 = {note(C, 2), CHANNEL_1};
const MIDIAddress noteAddress9 = {note(D, 2), CHANNEL_1};
const MIDIAddress noteAddress10 = {note(E, 2), CHANNEL_1};
const MIDIAddress noteAddress11 = {note(F, 2), CHANNEL_1};
const MIDIAddress noteAddress12 = {note(G, 2), CHANNEL_1};
const MIDIAddress noteAddress13 = {note(A, 2), CHANNEL_1};
const MIDIAddress noteAddress14 = {note(B, 2), CHANNEL_1};
const MIDIAddress noteAddress15 = {note(C, 3), CHANNEL_1};

Per non farti impazzire con tutto il codice dello step sequencer che sto realizzando, e che, a parte il note off e un piccolo problema sul tap tempo, funziona correttamente (ma che per ora è ancora veramente incasinato non essendo un grande esperto) ti spiego brevemente come dovrebbe funzionare :

Imposto un tempo in bpm con 4 tap o con 2 pulsanti che incrementano/decrementano.
I bpm diventano una variabile che è messa in un ciclo e fa girare 16 step, intervallati dai millisecondi relativi ai bpm.
Ogni step fa accendere un led digitale(la parte di sketch funziona correttamente).
Ho 16 pulsanti, ognuno, se premuto, "attiva" lo step (ognuno ha una sua autoritenuta software quindi alla prima pressione attiva lo step, alla seconda lo disattiva e così via).
Per "attiva lo step" intendo che lo mette in condizione di inviare la nota midi corrispondente, tramite le variabili "state da 0 a 15".
Quindi se ad esempio ho attivato lo Step 1, state prende il valore di 1 e mi attiva il noteon.
Il problema è che tra noteon e noteoff non c'è ritardo e il mio software midi non lo gradisce.
Se invece do il note off nello step successivo come suggerisci tu è troppo lungo.
Il software che utilizzo manda clip video, lo step sequencer mi serve per mandare chase su diversi ledwall (cioè far ad esempio flashare più schermi alternativamente a tempo con la musica) e oltretutto mi piacerebbe poter modificare la lunghezza del ritardo tra noteOn e noteoff.

Mi sa che se c'è qualcuno di Torino che mi vuole dare una mano ha vinto pranzo e cena almeno :stuck_out_tongue:

OK ho capito.

I bpm diventano una variabile che è messa in un ciclo e fa girare 16 step, intervallati dai millisecondi relativi ai bpm.

posta questa parte del codice

Per gli array ::slight_smile: dovrebbe essere cosi' sperando che un "pro" mi possa correggere se è sbagliato!

MIDIAddress noteAddress[16];
noteAddress[0] = {note(C, 4), CHANNEL_1};
noteAddress[1] = {note(D, 4), CHANNEL_1};
noteAddress[2] = {note(E, 4), CHANNEL_1};
........

Per la tua domanda iniziale, devi usare, come sempre, millis(): prendi il tempo con t=millis(); (dove t è unsigned long) e poi esegui ciò che devi eseguire quando millis()-t>ritardo. All'inizio di ciò che devi eseguire memorizzi di nuovo il tempo per il prossimo intervallo: t=millis().