5.) Interaktionsmodelle


... [ Seminar: Startseite ] ... [ Die Schichtenstruktur ] ... [ 3D-Sound unter DirectXAudio ] ...

Übersicht: Interaktionsmodelle

a) Interaktion in Windows. 21

b) Messages in DirectX Audio. 21

c) Notifications. 24

d) Timing beim Audio. 25

(1) Warum ist das korrekte Timing bei der Audiowiedergabe so wichtig ?. 25

(2) Die Zeitgebung und -messung. 25

(3) Latenzzeit 26

(4) Bumper Length. 26

(5) Performance. 26

e) Timing und Scheduling bei Multimedia. 27

(1) Earliest Deadline First Scheduling. 27

(2) Rate Monotonic Scheduling. 27

(3) Scheduling in Windows und DirectX.. 28



a) Interaktion in Windows

Windows ist event driven (=Ereignis gesteuert). Ereignisse im System werden einer Anwendung in Form einer „Message“ (Nachricht) mitgeteilt. Jede Win32-Anwendung hat einen Event-Handler, der die eingehende Ereignisse verarbeitet. Dieser Event-Handler ist in der Regel in einer Endlosschleife in der WinMain-Hauptroutine enthalten, die alleine für das Message Handling verantwortlich ist.

Die Event-Handler-Funktion muß dabei allerdings nicht für alle Nachrichten eigene Routinen enthalten. Es genügt auf die für das Programm relevanten Messages zu reagieren. Das zentrale Windows Messaging System ist das Herz des Kooperationsmodells in Windows.

Die Nachrichten werden nicht direkt an eine Anwendung geschickt, sondern in Message Queues in einer FIFO-Struktur zwischengespeichert. Die Anwendung kann sich bei Bedarf dort die Nachrichten abholen. Andernfalls werden sie von Windows selbst bearbeitet. Es gibt keine Garantie, in welcher Reihenfolge die Nachrichten ankommen.

Die folgende Grafik gibt einen Überblick über die Nachrichtenverarbeitung in Standard-Windows-Applikationen.

 

Quelle: Andre LaMothe, DirectX-tasy (http://www.gamedev.net/reference/articles/article589.asp)

 

b) Messages in DirectX Audio

DirectMusic arbeitet ebenfalls mit einem umfangreichen Message-System. Es kennt dabei zwei verschiedene Arten von Messages:

Standard MIDI Messages

können nur von MIDI Geräten gelesen werden,

enthalten MIDI-Wiedergabedaten

Performance Messages

Jede andere Form von Nachrichten über oder mit Sounddaten

 

Die DirectMusic Messages landen nicht im Windows Message Handling System, sondern verkehren nur intern in DirectX. In der Regel werden diese Nachrichten automatisch zur Kommunikation zwischen den einzelnen DirectX-Schichten erzeugt. Eine Windows-Anwendung kann allerdings auch selbst Messages in die Warteschlange einreihen (z.B. Tempoänderungen). Sie muß sich dann allerdings auch selbst um die korrekte Adressierung an den zuständigen Toolgraph des Audiopfades kümmern.

Da die Nachrichten nur intern verwendet werden, benötigt die Anwendung auch nicht zwingend ein Message-Handling-System.

 

Je zu spielende Note, können mehrere Nachrichten mit unterschiedlichem Informationsgehalt versendet werden (z.B. Tonhöhe, Tempowechsel, Dynamikänderungen, Instrumentenänderungen). Dabei ist allerdings die Deadline zu beachten. Das ist der späteste Punkt, an welchem die Nachricht ankommen muß, damit die Note zur richtigen Zeit mit den richtigen Werten gespielt werden kann (siehe im einzelnen weiter unten). Nachrichten können auch an mehrere Empfänger geschickt werden. Solche Broadcast- bzw. Multicastnachrichten sind bei globalen Änderungen wie z.B. einem Tempowechsel notwendig.

Beispiele für Nachrichten:

 

Grundstruktur aller Messages:

typedef struct DMUS_PMSG {
 
  DWORD      dwSize;
Größe der Struktur
  REFERENCE_TIME   rtTime;
Referenzzeit, zu der die Message abgespielt werden muß
  MUSIC_TIME mtTime;
(Relative) Musikzeit, zu der die Message abgespielt werden muß
  DWORD      dwFlags;
 
  DWORD      dwPChannel;
Der Empfänger der Nachricht (ein PChannel bzw. spezielle Konstanten für Broadcast- oder Multicastnachrichten)
  DWORD      dwVirtualTrackID;
Identifizierer der Spur
  IDirectMusicTool*  pTool;
Adresse der Tool-Schnittstelle, die als nächstes die Nachricht weiterverarbeitet
  IDirectMusicGraph* pGraph;
Adresse der Toolgraph-Schnittstelle, die als nächstes die Nachricht weiterverarbeitet
  DWORD      dwType;
Typ der Message (z.B. Note, Tempoänderung, Text, Transponieren, Notification)
  DWORD      dwVoiceID;
 
  DWORD      dwGroupID;
 
  IUnknown*  punkUser;
 
} DMUS_PMSG;
 
 

 

 

 

Spezielle Struktur Tempoänderung:

typedef struct DMUS_TEMPO_PMSG {
 
  DMUS_PMSG_PART
Makro, welches die obige Grundstruktur einbindet
  double dblTempo;
Tempoangabe im Bereich DMUS_TEMPO_MIN bis DMUS_TEMPO_MAX
} DMUS_TEMPO_PMSG;
 
 

 

Spezielle Struktur Wiedergabe einer Note

typedef struct DMUS_NOTE_PMSG {
 
  DMUS_PMSG_PART
Makro, welches die obige Grundstruktur einbindet
  MUSIC_TIME mtDuration;
Dauer der Note
  WORD   wMusicValue;     
Wert der Note
  WORD   wMeasure;        
Takt, in welchem die Note gespielt wird
  short  nOffset;
Offset vom Grid, in welchem die Note gespielt wird
  BYTE   bBeat;
Taktschlag, zu welchem die Noten gespielt wird
  BYTE   bGrid;
Offset des Grids vom Taktschlag
  BYTE   bVelocity;
 
  BYTE   bFlags;
 
  BYTE   bTimeRange;
Zufällige Abweichungen von der Platzierung im Takt
  BYTE   bDurRange;
Zufällige Abweichungen von der Spieldauer
  BYTE   bVelRange;
Zufällige Abweichungen von der Lautstärke
  BYTE   bPlayModeFlags;
 
  BYTE   bSubChordLevel;
 
  BYTE   bMidiValue;
MIDI-Wert der Note
  char   cTranspose;
 
} DMUS_NOTE_PMSG;
 
 

 

Die Verwaltung und Steuerung des Nachrichtenversandes übernimmt die Komponente Performance im DirectX-System. Sie sorgt dafür, dass die Message entsprechend ihrer Deadline rechtzeitig zum Empfänger abgeschickt wird. So werden z.B. Tempoänderungen sofort weitergeleitet, während Notenangaben in eine Warteschlange der zu spielenden Noten eingereiht werden. Es gibt auch Messages, die nur informieren und sich auf die Soundwiedergabe nicht auswirken (z.B. die Mitteilung einer Taktartänderung: von 3/4 –Takt auf 4/4-Takt).

Die Messages werden zunächst an Tools im Segment-Toolgraph, dann an den Audiopath-Toolgraph oder den Performance-Toolgraph geschickt. Ein Toolgraph bezeichnet dabei die Zusammenfassung von mehreren Tools. Das erste Tool in einem Toolgraph empfängt die Nachricht. Muß die Nachricht weitergeleitet werden, versieht das Tool sie mit einem Zeiger auf das nächste Tool. Außerdem bekommt die Nachricht ein Flag, welches beschreibt, wann die Nachricht weitergeleitet werden soll. Dieses Flag kann von jedem Tool geändert werden.

Folgende Flags gibt es:

Flag-Name

Inhalt

IMMEDIATE

Sofort

QUEUE

kurz bevor die Note gespielt werden soll (unter Brücksichtigung der Latenzzeit)

ATTIME

genau zur Deadline-Zeit (so z.B. bei Notifications)

 

Tools verarbeiten Messages in einem Thread mit hoher Priorität. Dies soll sicherstellen, dass die Nachrichten schnellstmöglich verarbeitet werden und die Töne nach möglichst kleiner Latenzzeit gespielt werden können (siehe dazu auch weiter unten). Zeitaufwändige Funktionen wie z.B. Grafik- oder Datei-I/O sollten daher nicht in einem Tool integriert sein. Sollen solche Aufgaben dennoch von einem Tool aus gestartet werden, sollte dieses die Aufgabe per Message an einen anderen Thread (z.B. den Haupt-Thread) delegieren.

Die Tools werden jeweils durch einen PChannel („Performance Channel“) eindeutig identifiziert.  Während es im MIDI-Standard nur 16 Kanäle gab, gibt es unter DirectMusic 65536 Kanalgruppen à jeweils 16 PChannels. Für Abwärtskompatibilität wird für ein MIDI-Gerät eine Kanalgruppe verwendet.

Jeder Kanal hat eine begrenzte Anzahl von Stimmen gleichzeitig erklingender Musik. Sollen mehr Noten gespielt werden als Stimmen vorhanden sind, können Prioritäten für einzelne Noten vergeben werden („Channel Priority“). Eine Überlastung des Systems wird damit vermieden.

 

Jede Nachricht kommt, wenn sie nicht zwischendurch verworfen wurde, zum Schluß beim Ausgabe-Tool (Output-Tool) an, welches die Daten ins Midi-Format konvertiert bevor sie an den DirectMusic Synthesizer geschickt werden. Der Synthesizer erzeugt daraus einen Wavesound und schickt ihn an eine Senke, welche wiederum die Daten im PCM-Format an die DirectSound Puffer weiterleitet. Der DirectMusic Synthesizer dient der Klangerzeugung und kann einen Submix vornehmen. Das heißt, er kann mehrere von ihm erzeugte Töne schon einmal vorab abmischen, um sie z.B. danach gemeinsam an einen sekundären Soundpuffer weiterzuleiten, der sie dort mit einem Spezialeffekt belegt.

 

Die folgende Grafik zeigt den Fluß der Audiodaten:

Quelle: MS DirectX 8.1 SDK

 

c) Notifications

 

Von der Message abzugrenzen ist die Notification (Benachrichtigung). Notifications sind spezielle Messages, welche eine Instanz darüber informieren sollen, dass ein bestimmtes Ereignis eingetreten ist. Notifications können im Gegensatz zu Messages auch von Anwendungen empfangen werden. Benachrichtigungen im Bereich Audio sind z.B. wichtig, wenn ein Musiksegment sich dem Ende zuneigt und ein anderes nachfolgen soll oder wenn ein Sound auf ein grafisches Ereignis synchronisiert werden muß.

DirectMusic kann damit beauftragt werden, in diesen Fällen spezielle Benachrichtigungen abzuschicken. Diese werden vor dem Empfang wie Nachrichten in einer FIFO-Struktur zwischengespeichert. Benachrichtigungen mit gleichem Zeitstempel werden in nicht definierter Reihenfolge empfangen.

Wird DirectSound mit einem Ringpuffer verwendet (siehe auch oben), in den die Musikdaten zyklisch hereingeschrieben werden müssen, ist auch Polling möglich, d.h. das regelmäßige Abfragen, ob z.B. der Abspielcursor bereits einen bestimmten Punkt erreicht hat. Nachteil des Pollings ist die Ressourcenverschwendung durch das ständige Abfragen. Benachrichtigungen sind daher in der Regel vorzuziehen.

Die Ereignisüberprüfung und Verwaltung sollte wieder in einem eigenen Thread stattfinden.

Beispiel für einen solchen Thread mit einer Endlosschleife:

 

void WaitForEvent( LPVOID lpv) {

  DWORD dwResult;

  DMUS_NOTIFICATION_PMSG* pPmsg;

  char szCount[4];

  while (TRUE) {

    dwResult = WaitForSingleObject(g_hNotify, 100);

    while (S_OK == g_pPerf->GetNotificationPMsg(&pPmsg)) //S_OK signalisiert,

    {                   //dass noch weitere Nachrichten in Queue sind

     

 

// Checke Notification-Typ und reagiere darauf entsprechend

      ...     

      g_pPerf->FreePMsg((DMUS_PMSG*)pPmsg);

    }

  }

}

 

 

 

d) Timing beim Audio

(1) Warum ist das korrekte Timing bei der Audiowiedergabe so wichtig ?

Wenn mehrere Signale zeitgleich gespielt werden sollen, dürfen sie nur wenige Millisekunden auseinander liegen, um noch als gleichzeitig vom menschlichen Ohr wahrgenommen zu werden. Soundeffekte in einem Spiel sind in der Regel die Reaktion auf irgendein Ereignis. Um den Sound als Ereignis auf eine Eingabe und gleichzeitig synchron mit einer Grafik zu hören, darf ein Zeitunterschied von 40ms nicht überschritten werden. Noch weniger, nämlich nur etwa 10-20 ms darf die Zeit sein, wenn zwei Soundeffekte gleichzeitig erklingen sollen.

 

Um ein Geräusch als akustische Reaktion auf ein Ereignis korrekt wiederzugeben, benötigt man für die Wiedergabe daher ein Echtzeit-Betriebssystem, während die sonstige Programmabarbeitung weiter in Nicht-Echtzeit laufen kann. Echtzeit setzt eine möglichst schnelle, fest definierte Abarbeitungszeit, ein hohes Maß an Einplanbarkeit (Schedulability) und Systemstabilität auch bei Überlast voraus.[1] Die folgende Grafik zeigt diese Aufteilung in Echtzeit und Nicht-Echtzeitbetrieb:

RT- und NRT-Umgebungen

Quelle: Steinmetz, Kapitel Echtzeit

Windows ist kein Echtzeit-Betriebssystem. Es müssen also genug Vorkehrungen getroffen werden, damit der Klang durch alle Schichten möglichst zur richtigen Zeit aus dem Lautsprecher kommt.

Um die Einhaltung der Zeit kümmern sich die im folgenden beschriebenen Komponenten in DirectX.

(2) Die Zeitgebung und -messung

Der Zeitgebung liegt zunächst eine Master Clock im Kernel Mode des Systems zugrunde. Hier handelt es sich um eine Hardware-Zeitgeber, der als Default-Einstellung die Systemuhr verwendet. Möglich sind aber auch andere Hardwarezeitgeber. Die Master Clock liefert etwa alle 100 ns ein Referenzsignal in Form eines 64-Bit-Wertes.

Außerdem gibt es die Music Time, welche relativ zum Tempo mitläuft. Sie startet mit der Performance und erhöht sich defaultmäßig 768 mal pro Viertelnote.

(3) Latenzzeit

Die Latenzzeit ist die Zeitverzögerung zwischen Beginn der Verarbeitung und der Soundausgabe aus den Lautsprecherboxen. Um durch die vielen Schichten des Windows-Systems durchzugelangen, benötigte Audio bei der Einführung von DirectX Mitte der 90er Jahre vom Beginn des Abspielen bis zur Ausgabe über die Lautsprecher 100-200 ms. Bei einer Bildrate von 30 fps würde der Ton somit etwa 5 Bilder und damit deutlich wahrnehmbar zu spät kommen.

Heutzutage können Latenzzeiten von im günstigsten Fall wenigen Millisekunden bis zu 100 Millisekunden im Worst Case auftreten. Aufgrund der Nicht-Echtzeitfähigkeit unter Windows sind die genauen Zeiten nicht vorhersehbar.

(4) Bumper Length

Die Bumper Length ist die Zeitverzögerung zwischen dem Empfang des Ereignisses und dem Beginn der Verarbeitung des Ereignisses (Default: 50ms).

(5) Performance

Das Performance-Objekt fragt durchgehend die Spuren der Segmente ab, ob diese Musik bis zu einem angegebenen spätesten Zeitpunkt zu spielen haben. Ist dies der Fall, senden diese entsprechende Messages, welche dann in eine Warteschlange gereiht werden.

Ist z.B. die Current Time (aktuelle Zeit) 10.000 ms und die Prepare Time (Vorbereitungszeit=Latenzzeit + Bumper Length+Queue Time) 1000 ms (Default-Wert), beträgt die End Time 11.000 ms. D.h. alle neuen Messages, die bis spätestens 11.000 ms gespielt werden müssen, werden an die Warteschlage gehängt. Im Zeitpunkt 10.850 ms (100ms Latenzzeit + 50ms Bumper Length) muß die Performance die Message dann in den Soundpuffer stecken.

 

Die Prepare Time kann verstellt werden. Es empfiehlt sich allerdings, wenn möglich so weit im voraus zu planen. Dieses ist natürlich bei Sounds als direkte Reaktion auf Ereignisse nicht möglich. Diese sollen möglichst schnell gespielt werden und haben daher nicht das Flag DMUS_SEGF_AFTERPREPARETIME gesetzt.

 

Die folgende Grafik zeigt den zeitlichen Ablauf bzw. die Bezeichner der einzelnen Zeiten.

 

Quelle: MS DirectX 8.0 SDK

 

Das Abspielen eines Sounds kann je nach gesetztem Flag zu einer bestimmten Zeit, in einem bestimmen Takt in der Musik, an einer bestimmten Stelle in einem Takt oder zum frühst möglichen Zeitpunkt passieren. Es ist auch möglich, den Sound zu einem Zeitpunkt in der Vergangenheit spielen zu lassen. Dies führt dazu, dass entweder nur noch ein abgeschnittenes Ende des Sounds oder gar nichts mehr gespielt wird.

 

Eine Latenzzeit unter 50ms

 

e) Timing und Scheduling bei Multimedia

 

Wie eben gezeigt sind Multimedia-Anwendungen sehr zeitkritisch. Viele Prozesse haben Deadlines, die eingehalten werden müssen. Über welche Scheduling-Algorithmen kann dies nun am besten erreicht werden ?

Prozesse in Multimediaanwendungen sollten zunächst die Möglichkeit haben, preemptiv zu sein. Das heißt, ein Prozess, der Gefahr läuft nicht rechtzeitig dranzukommen, muß den aktuell laufenden Prozess unterbrechen bzw. vom Scheduler rechtzeitig Rechenzeit zugeteilt bekommen können.[2] Um solche Deadlines von Prozessen zu erkennen und zu verwalten ist in einem Multimedia-Betriebssystem Echtzeit-Scheduling erforderlich. Zwei häufig verwendete Scheduler-Algorithmen dafür sind:

(1) Earliest Deadline First Scheduling

Hierbei gibt jeder Prozess an, zu welchem Zeitpunkt er fertig sein muß. Derjenige, der als erster durch sein muß, kommt auch als erstes dran. Es handelt sich also um dynamisches Scheduling, da bei jedem hinzukommenden Prozess die Deadline-Prüfung und die Vergabe von Prioritäten bzw. die Einordnung in die Abarbeitungswarteschlange vorgenommen werden muß.

Dieser Vorgang ist recht aufwändig, aber sehr effizient und führt zu einer vollständigen CPU-Auslastung.

(2) Rate Monotonic Scheduling

Das Rate Monotonic Scheduling setzt als Randbedingung voraus, dass die zeitkritischen Prozesse periodisch sein müssen und die nicht-periodischen Prozesse nicht zeitkritisch sein dürfen. Dies ist z.B. in der Videobearbeitung / -wiedergabe /-aufnahme die Regel. Dann können die Planungsentscheidungen bzgl. der Prioritätenvergabe statisch vor Beginn des Vorganges festgelegt werden. Zur Laufzeit werden keine Prioritätenänderungen vorgenommen.

Dieses Verfahren ist zwar recht einfach zu implementieren, setzt aber neben der Randbedingung große Vorkenntnisse über die zu erwartenden Prozesse und eine genaue Planung beim Implementieren der Prozesse voraus.

 

(3) Scheduling in Windows und DirectX

Alle Windows-Systeme ab Windows 95 arbeiten mit preemptiven Multitasking. Es arbeiten generell zwei Scheduler in Windows:

-         der primäre Scheduler vergibt ca. alle 20 ms erneut Prioritäten zwischen 0 und 31 für jeden wartenden Thread. Threads, welche keine hohen Prioritäten haben, werden suspendiert.

-         der Timeslice-Scheduler weist den Threads prozentual Rechenzeit zu.

Die Threads werden nach der Round-Robin-Strategie bearbeitet.

Welche speziellen Algorithmen in DirectMusic für das rechtzeitige Bearbeiten der Musikdaten verwendet werden, gibt Microsoft nicht Preis. Das Performance-Objekt, welches die Nachrichten verwaltet, richtet sich aber nach der Deadline und kommt insofern dem Earliest Deadline First Scheduling nahe.



[1] siehe Steinmetz, http://www.et-online.fernuni-hagen.de/lehre/k02415.ws/kap10/10013.htm

[2] siehe auch Tanenbaum, Modern Operating Systems, S.471


... [ Seminar: Startseite ] ... [ Die Schichtenstruktur ] ... [ Interaktionsmodelle ] ... [ 3D-Sound unter DirectXAudio ] ...