2010-08-04 4 views
12

Gibt es eine Möglichkeit Ereignisse in C# mit einer Auflösung von wenigen Mikrosekunden zu feuern?Feuerungsereignisse bei Mikrosekunde Auflösung für MIDI-Sequenzer

Ich baue einen MIDI-Sequenzer, und es erfordert ein Ereignis jeden MIDI tick abgefeuert werden, die dann jede Note zu diesem Zeitpunkt registriert werden spielen.

Bei 120 Schlägen pro Minute und bei einer Auflösung von 120 ppqn (Pulse pro Takt/Viertelnote), sollte das Ereignis alle 4,16666 Millisekunden ausgelöst. Moderne Sequenzer haben höhere Auflösungen wie 768ppqn, die erfordern, dass das Ereignis alle 651 Mikrosekunden ausgelöst wird.

Die beste Auflösung für Veranstaltungen kurzzeitige ich gefunden habe, ist von 1 Millisekunde. Wie kann ich darüber hinausgehen?

Dieses Problem muss bereits von einer C# MIDI-Sequenzer oder MIDI-File-Player gelöst wurden. Vielleicht sehe ich das Problem einfach nicht im richtigen Winkel an.

Vielen Dank für Ihre Hilfe.

+0

Ich folge nicht Ihrer Mathematik. Wenn 120ppqn = 41,6666ms, sicherlich 768ppqn! = 651microsec, aber 768ppqn = 1000 * 41.6666 * 120/768 = 6510 microsec? – spender

+0

120 bpm = 1 Takt alle 500 ms, 120 Ticks pro Takt = 500ms/120 = 4.166ms & 768 Ticks pro Takt = 500ms/768 = 0.651ms Es gibt tatsächlich einen Tippfehler in meiner ersten Nummer, ich werde es jetzt korrigieren . Vielen Dank. – Brice

+0

schau dir meine aktualisierte Antwort an – Fredou

Antwort

6

Die meisten Midi-Sequenzer/Midi-Player konvertieren entweder große Zeitblöcke in Wellenform (um Computerlautsprecher abzuspielen) oder nehmen einen großen Block von MIDI-Befehlen (für ein an einen MIDI-Port angeschlossenes externes Gerät). In beiden Fällen wird ein Datenblock auf die Soundkarte kopiert, und die Soundkarte sorgt für ein genaues Timing.

Sie können sich die Multimedia Control APIs ansehen.

Siehe this post over at the Microsoft discussion forum

0

anstelle Timer des Verwendens

Verwendung stopwatch

Beispiel für 10x 1 Sekunde

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()); 
     } 
    } 

AUSGABE:

Ticks: 10.005.392 (die 1,0005392 zweite ist)
Ticks: 10004792
Ticks: 10004376
Ticks: 10005408
Ticks: 10004398
Ticks: 10004426
Ticks: 10004268
Ticks: 10004427
Ticks: 10005161
Ticks: 10004306

die scheinen Art von ok

+0

Danke. Ich habe versucht, Stoppuhr zu verwenden, aber von dem, was ich weiß, erlaubt es nur zu überprüfen verstrichene Zeit zwischen stopwatch.start und stopwatch.stop, es feuert keine Ereignisse in regelmäßigen Abständen – Brice

+0

Er führt 'count ++' in ziemlich regelmäßigen Abständen.Solange absolut nichts anderes auf der Maschine läuft, könnte das funktionieren. –

3

ich glaube, Sie zu g unwahrscheinlich und genau die richtige Auflösung von einem Timer. Ein besserer Ansatz wäre es, den 1 ms genauen Timer zu verwenden, und wenn er ausgelöst wird, um zu überprüfen, welche MIDI-Events anstehen und sie auszulösen.

So gehen die MIDI-Events in einer sortierten Warteschlange, können Sie den ersten flüchtigen Blick, und stellen Sie den Timer so nahe wie möglich zu dieser Zeit zu schießen. Wenn der Timer ausgelöst wird, müssen Sie alle Ereignisse aus der Warteschlange ablaufen lassen, bis Sie auf ein zukünftiges Ereignis treffen. Berechnen Sie die Zeit für dieses Ereignis. Timer neu planen.

Natürlich, wenn Sie auf Ihre Soundkarte ausgeben, ist der Ansatz grundsätzlich verschieden, und Sie sollten die Proben für alle Zeitpunkte werden gezählt.

1

Es ist nicht möglich, Ereignisse zu haben, genau auf Mikrosekunden-Intervalle in .NET gebrannt.

In der Tat, weil Windows selbst kein Echtzeit-Betriebssystem ist, ist das Ausführen von allem mit 100% Genauigkeit zu bestimmten Mikrosekunden, in Benutzermodus-Software, ziemlich unmöglich.

Weitere Informationen dazu, warum dies so schwierig ist, finden Sie im MSDN Magazin Artikel: Implement a Continuously Updating, High-Resolution Time Provider for Windows. Während es sich um Windows NT handelt, gilt dies immer noch für spätere Windows-Versionen.

Der Abschluss dieses Artikels fasst es gut:

Wenn Sie jetzt denken, dass Sie die Systemzeit mit einem fast beliebiger Genauigkeit hier erhalten können, um nur leichte Warnung: vergessen Sie nicht, die Präemptivität eines Multitasking Systems wie Windows NT. Im besten Fall ist der Zeitstempel, den Sie bekommen, nur um die Zeit, die es dauert, um den Leistungszähler zu lesen und dieses Lesen in eine absolute Zeit umzuwandeln. In den schlechtesten Fällen könnte die verstrichene Zeit leicht in der Größenordnung von zehn von Millisekunden liegen.

Obwohl dies könnte zeigen Sie ging durch diese ganze für nichts, seien Sie versichert, dass Sie nicht. Selbst der Aufruf der Win32 API GetSystemTimeAsFileTime (oder gettimeofday unter Unix) unterliegt die gleichen Bedingungen, so dass Sie tatsächlich nicht schlechter als das tun. In die Mehrheit der Fälle, haben Sie gute Ergebnisse. Führen Sie einfach keine alles aus, was Echtzeit Vorhersagbarkeit auf der Grundlage der Zeit Briefmarken in Windows NT erfordert.

+0

Das sollte "im Benutzermodus" heißen, nicht "in Software", weil Kernel-Treiber auch Software sind und mit Sicherheit eine Latenzzeit von unter einer Mikrosekunde haben. –

Verwandte Themen