2010-08-04 8 views
12

C'è un modo per attivare eventi in C# con una risoluzione di pochi microsecondi?Eventi di attivazione con risoluzione al microsecondo per sequencer midi

Sto costruendo un sequencer MIDI e richiede l'attivazione di un evento ogni tick MIDI, che riprodurrà quindi qualsiasi nota registrata in quel momento.

A 120 battiti al minuto e con una risoluzione di 120 ppqn (impulsi per battito/semiminima), tale evento dovrebbe generare ogni 4.16666 millisecondi. I sequencer moderni hanno risoluzioni più elevate come 768ppqn che richiederebbero che l'evento venga attivato ogni 651 microsecondi.

La migliore risoluzione per gli eventi a breve termine che ho trovato è di 1 millisecondo. Come posso andare oltre?

Questo problema deve essere già stato risolto da un sequencer MIDI C# o da un lettore di file MIDI. Forse sto solo non guardando il problema attraverso l'angolo retto.

Grazie per il vostro aiuto.

+0

Non seguo i tuoi calcoli. Se 120ppqn = 41.6666ms, sicuramente 768ppqn! = 651microsec, ma 768ppqn = 1000 * 41.6666 * 120/768 = 6510 microsec? – spender

+0

120 bpm = 1 battito ogni 500 ms, 120 tick per battito = 500ms/120 = 4.166ms & 768 tick per beat = 500ms/768 = 0.651ms Esiste davvero un refuso nel mio primo numero, lo correggerò ora . Grazie. – Brice

+0

guarda la mia risposta aggiornata – Fredou

risposta

6

La maggior parte dei sequencer midi/lettori midi convertirà grandi blocchi di tempo in forma d'onda (per la riproduzione tramite altoparlanti del computer) o prenderà un grande blocco di istruzioni MIDI (per un dispositivo esterno collegato a una porta MIDI). In entrambi i casi, un blocco di dati viene copiato sulla scheda audio e la scheda audio si occupa del tempo esatto.

Si potrebbe voler guardare le API di controllo multimediale.

Vedi this post over at the Microsoft discussion forum

0

invece di utilizzare timer

uso stopwatch

esempio, per 10x 1 secondo

static void Main(string[] args) 
    { 
     Stopwatch masterSW; 
     Stopwatch sw=null; 
     int count; 

     sw = Stopwatch.StartNew(); 
     sw.Reset(); 

     for (int i = 0; i < 10; i++) 
     { 
      count = 0; 
      masterSW = Stopwatch.StartNew(); 
      while (count!=1536) //1537*651 microsecond is about a second (1.0005870 second) 
      { 
       if (!sw.IsRunning) 
        sw.Start(); 

       if (sw.Elapsed.Ticks >= 6510) 
       { 
        count++; 
        sw.Reset(); 
       } 
      } 

      Debug.WriteLine("Ticks: " + masterSW.Elapsed.Ticks.ToString()); 
     } 
    } 

stamperà:

zecche: 10.005.392 (che è 1,0005,392 mila secondo)
zecche: 10.004.792
Zecche: 10.004.376
zecche: 10.005.408
zecche: 10.004.398
zecche: 10.004.426
zecche: 10.004.268
zecche: 10.004.427
zecche: 10.005.161
zecche: 10004306

che sembrano un po 'ok

+0

Grazie. Ho provato a utilizzare il cronometro ma, da quello che so, consente solo di controllare il tempo trascorso tra stopwatch.start e stopwatch.stop, non attiva eventi ad intervalli regolari – Brice

+0

Sta eseguendo 'count ++ 'ad intervalli abbastanza regolari.Finché non funziona assolutamente niente sulla macchina, questo potrebbe funzionare. –

3

Penso che sia improbabile che g et esattamente la risoluzione corretta da un timer. Un approccio migliore sarebbe utilizzare il timer accurato di 1 ms e, quando viene attivato, verificare quali eventi MIDI sono in sospeso e attivarli.

Quindi, gli eventi MIDI vanno in una coda ordinata, si sbircia il primo e si imposta il timer per sparare il più vicino possibile a quel momento. Quando il timer scatta, consuma tutti gli eventi dalla coda che sono trascorsi, fino a quando non incontri un evento futuro. Calcola il tempo per questo evento. Riprogrammare il timer.

Naturalmente, se si sta trasmettendo alla scheda audio, l'approccio è fondamentalmente diverso e si dovrebbero contare i campioni per tutti i tempi.

1

Non è possibile avere gli eventi con precisione sparati su intervalli di microsecondi in .NET.

Infatti, poiché Windows stesso non è un sistema operativo in tempo reale, eseguire qualsiasi operazione con una precisione del 100% su determinati microsecondi, nel software in modalità utente, è praticamente impossibile.

Per ulteriori informazioni sul motivo per cui è così difficile, consultare l'articolo della rivista MSDN: Implement a Continuously Updating, High-Resolution Time Provider for Windows. Mentre parla di Windows NT, questo si applica in genere alle versioni successive di Windows.

La conclusione di questo articolo riassume bene:

Se ora si pensa che è possibile ottenere l'ora di sistema con una quasi precisione arbitraria qui, solo un lieve avvertimento : non dimenticare il valore di default di un sistema multitasking come Windows NT. Nel miglior caso , il timestamp che si ottiene è con il tempo necessario per leggere il contatore delle prestazioni e trasformare questa lettura in un tempo assoluto. Nei casi peggiori , il tempo trascorso potrebbe essere facilmente nell'ordine di decine di millisecondi.

Anche se questo potrebbe indicare che hai passato tutto questo per nulla, non è sicuro che hai no. Anche eseguendo la chiamata all'API WinGetSystemTimeAsFileTime (o gettimeofday sotto Unix) è soggetto a le stesse condizioni, quindi non stai facendo niente di peggio di . Nella maggior parte dei casi, nella versione , avrai buoni risultati. Semplicemente non eseguire nulla che richieda la previsione in tempo reale sulla base del tempo timbri in Windows NT.

+0

Questo dovrebbe dire "in modalità utente", non "in software", perché i driver del kernel sono anche software e sono certamente in grado di temporizzazione/latenza di secondo-microsecondo. –