Dieser Artikel wurde maschinell übersetzt.

Der DirectX-Faktor

Tongenerierung in Windows 8 mithilfe von XAudio2

Charles Petzold

Charles PetzoldEine Windows-Speicher-app für Windows 8 kann MP3 oder WMA Audiodateien problemlos mit MediaElement — einfach geben Sie es ein URI oder einen Stream zu der Sounddatei.Windows Store apps können auch spielen, API für das streaming von Video- oder Audiodateien auf externe Geräte zugreifen.

Aber was ist, wenn Sie mehr brauchen anspruchsvolle audio-Bearbeitung?Vielleicht möchten Sie den Inhalt einer Audiodatei auf dem Weg in die Hardware ändern oder klingt dynamisch generieren.

Eine Windows-Speicher-app kann auch diese Arbeitsplätze durch DirectX ausführen.Windows 8 unterstützt zwei DirectX-Komponenten zur Klangerzeugung und Verarbeitung — Core Audio und XAudio2.In den großen Plan der Dinge beide sind eher Low-Level-Schnittstellen, aber Core Audio ist niedriger als XAudio2 und richtet sich mehr an Anwendungen, die eine engere Verbindung zu audio-Hardware erfordern.

XAudio2 ist der Nachfolger von DirectSound und die Xbox XAudio-Bibliothek, und es ist wahrscheinlich die beste Wahl für Windows Store apps, die interessante Dinge mit Ton zu tun müssen.Während XAudio2 in erster Linie für Spiele gedacht ist, das sollte nicht hindern uns Verwendung für ernstere Zwecke — wie musizieren oder der Geschäftsbenutzer mit lustigen Geräuschen unterhaltsam.

XAudio2 Version 2.8 ist eine integrierte Komponente von Windows 8.Wie der Rest von DirectX basiert die XAudio2 Programmierschnittstelle auf comWährend es theoretisch mögliche Zugriff XAudio2 von jeder Programmiersprache unterstützt von Windows 8 ist, ist die meisten natürliche und einfachste Sprache für XAudio2 C++.Arbeiten mit Ton erfordert häufig Hochleistungs-Code, so dass C++ in dieser Hinsicht auch eine gute Wahl ist.

Ein erstes Programm XAudio2

Lassen Sie uns beginnen, schreiben ein Programm, das XAudio2 verwendet, um eine einfache 5-Sekunden-als Reaktion auf einen Tastendruck sound wiederzugeben.Da Sie möglicherweise neu für Windows 8 und DirectX Programmierung, nehme ich es ein wenig langsam.

Ich gehe davon aus, dass Sie eine Version von Visual Studio installiert haben, die zum Erstellen von Windows-Store apps geeignet ist.Wählen Sie im Dialogfeld Neues Projekt Visual C++ und Windows Store am linken, und leere App (XAML) in der Liste der verfügbaren Vorlagen.Ich gab mein Projekt den Namen SimpleAudio, und finden Sie das Projekt unter den herunterladbaren Code für diesen Artikel.

Beim Bau einer ausführbaren Datei, die XAudio2 verwendet, müssen Sie das Programm mit der xaudio2.lib-Importbibliothek verknüpfen.Öffnen Sie das Eigenschaften-Dialogfeld Projekt durch Auswählen des letzten Elements auf im Menü Projekt oder durch den Projektnamen im Projektmappen-Explorer mit der rechten Maustaste und wählen Sie Eigenschaften.Wählen Sie in der linken Spalte Konfigurationseigenschaften und dann Linker und Input.Klicken Sie zusätzliche Abhängigkeiten (das oberste Element) und den kleinen Pfeil.Klicken Sie auf Bearbeiten, und geben Sie xaudio2.lib im Feld.

Sie wollen auch einen Verweis auf die xaudio2.h-Headerdatei, so fügen Sie die folgende Anweisung in die vorkompilierte Header-Liste im pch.h:

#include <xaudio2.h>

In die Datei MainPage.XAML fügte ich einen TextBlock für das anzeigen Fehler, dass das Programm das Arbeiten mit der XAudio2-API und eine Schaltfläche für die Wiedergabe eines Sounds auftreten kann. Diese Zeilen sind in Abbildung 1 aufgeführt.

Abbildung 1 die Datei MainPage.XAML für SimpleAudio

<Page x:Class="SimpleAudio.MainPage" ...
>
  <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock Name="errorText"
               FontSize="24"
               TextWrapping="Wrap"
               HorizontalAlignment="Center"
               VerticalAlignment="Center" />
    <Button Name="submitButton"
            Content="Submit Audio Button"
            Visibility="Collapsed"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Click="OnSubmitButtonClick" />
  </Grid>
</Page>

Der Großteil der Header-Datei MainPage.xaml.h zeigt Abbildung 2. Ich habe die Erklärung der OnNavigatedTo-Methode entfernt, weil ich es nicht verwenden. Der Click-Ereignishandler für die Schaltfläche wird deklariert, da vier Felder im Zusammenhang mit der Nutzung des Programms XAudio2.

Abbildung 2 der MainPage.xaml.h-Headerdatei für SimpleAudio

namespace SimpleAudio
{
  public ref class MainPage sealed
  {
  private:
    Microsoft::WRL::ComPtr<IXAudio2> pXAudio2;
    IXAudio2MasteringVoice * pMasteringVoice;
    IXAudio2SourceVoice * pSourceVoice;
    byte soundData[2 * 5 * 44100];
  public:
    MainPage();
  private:
    void OnSubmitButtonClick(Platform::Object^ sender,
      Windows::UI::Xaml::RoutedEventArgs^ args);
  };
}

Jedes Programm, das XAudio2 nutzen möchte, muss ein Objekt erstellen, die IXAudio2-Schnittstelle implementiert. (Sie sehen, wie dies in Kürze geschieht.) IXAudio2 wird von der berühmten IUnknown in COM abgeleitet, und es ist inhärent Verweiszählung, was bedeutet, dass es seine eigenen Ressourcen werden gelöscht, wenn es nicht mehr von einem Programm verwiesen wird. Die ComPtr (COM-Schnittstellenzeiger) Klasse im Namespace Microsoft::WRL verwandelt einen Zeiger auf ein COM-Objekt in ein "intelligenter Zeiger", die eine eigene Referenzen. Dies ist die empfohlene Vorgehensweise für das Arbeiten mit COM-Objekten in einer Windows-Speicher-app.

Jede nicht-triviale XAudio2 Programm braucht auch Zeiger auf Objekte, die die IXAudio2MasteringVoice und die IXaudio2SourceVoice-Schnittstelle implementieren. Im XAudio2 Sprachgebrauch ist eine "Stimme" ein Objekt, das erzeugt oder ändert die audio-Daten. Die mastering-Stimme ist im Prinzip ein sound-Mixer, der versammelt alle individuellen Stimmen und bereitet sie für die Ton-Generation-Hardware. Haben Sie nur eine davon, aber möglicherweise eine Reihe von Quelle Stimmen, die separate Klänge zu erzeugen. (Es gibt auch Möglichkeiten, Filter oder Effekte auf Quelle Stimmen anzuwenden.)

Die IXAudio2MasterVoice und IXAudio2SourceVoice-Zeiger sind nicht Verweiszählung; ihren Lebenszeiten unterliegen dem IXAudio2-Objekt.

Ich habe auch ein großes Array für 5 Sekunden Geräuschdaten Wert enthalten:

byte soundData[5 * 2 * 44100];

In ein richtiges Programm, Sie werden ein Array dieser Größe zur Laufzeit zuweisen möchten — und es loswerden, wenn Sie es nicht benötigen – aber Sie werden sehen, kurz, warum ich es so getan.

Wie berechnet ich die Arraygröße? Obwohl XAudio2 komprimierte Audiodaten unterstützt, werden die meisten Programme, die Sound erzeugen bei bekannt als Puls-Code-Modulation oder PCM Format bleiben. Ton in PCM-Wellenformen werden durch eine feste Größe bei einer fixen Abtastrate Werte dargestellt. Für Musik auf CDs ist die Abtastrate 44.100 Mal pro Sekunde, mit 2 Bytes pro Probe in Stereo, für eine Gesamtmenge von 176.400 Byte Daten für 1 Sekunde Audio. (Beim Klänge in einer Anwendung einbetten Komprimierung empfohlen. XAudio2 unterstützt ADPCM; WMA und MP3 sind auch in die Media Foundation-Engine unterstützt.)

Dieses Programm habe ich auch entschieden, eine Abtastrate von 44.100 mit 2 Bytes pro Probe zu verwenden. In C++ ist jede Probe deshalb einen kurzen. Ich hafte mit Mono-Ton im Moment, so dass 88.200 Byte pro Sekunde Audio erforderlich sind. Bei der Array-Zuweisung, die für 5 Sekunden mit 5 multipliziert wird.

Erstellen der Objekte

Viel von der MainPage.xaml.cpp-Datei erscheint Abbildung 3. Alle die XAudio2 Initialisierung erfolgt im Konstruktor MainPage. Es beginnt mit einem Aufruf von XAudio2Create um einen Zeiger auf ein Objekt zu erhalten, die IXAudio2-Schnittstelle implementiert. Dies ist der erste Schritt bei der Verwendung von XAudio2. Im Gegensatz zu einigen COM-Schnittstellen ist kein Aufruf von CoCreateInstance erforderlich.

Abbildung 3 MainPage.xaml.cpp

MainPage::MainPage()
{
  InitializeComponent();
  // Create an IXAudio2 object
  HRESULT hr = XAudio2Create(&pXAudio2);
  if (FAILED(hr))
  {
    errorText->Text = "XAudio2Create failure: " + hr.ToString();
    return;
  }
  // Create a mastering voice
  hr = pXAudio2->CreateMasteringVoice(&pMasteringVoice);
  if (FAILED(hr))
  {
    errorText->Text = "CreateMasteringVoice failure: " + hr.ToString();
    return;
  }
  // Create a source voice
  WAVEFORMATEX waveformat;
  waveformat.wFormatTag = WAVE_FORMAT_PCM;
  waveformat.
nChannels = 1;
  waveformat.
nSamplesPerSec = 44100;
  waveformat.
nAvgBytesPerSec = 44100 * 2;
  waveformat.
nBlockAlign = 2;
  waveformat.wBitsPerSample = 16;
  waveformat.cbSize = 0;
  hr = pXAudio2->CreateSourceVoice(&pSourceVoice, &waveformat);
  if (FAILED(hr))
  {
    errorText->Text = "CreateSourceVoice failure: " + hr.ToString();
    return;
  }
  // Start the source voice
  hr = pSourceVoice->Start();
  if (FAILED(hr))
  {
    errorText->Text = "Start failure: " + hr.ToString();
    return;
  }
  // Fill the array with sound data
  for (int index = 0, second = 0; second < 5; second++)
  {
    for (int cycle = 0; cycle < 441; cycle++)
    {
      for (int sample = 0; sample < 100; sample++)
      {
        short value = sample < 50 ?
32767 : -32768;
        soundData[index++] = value & 0xFF;
        soundData[index++] = (value >> 8) & 0xFF;
      }
    }
  }
  // Make the button visible
  submitButton->Visibility = Windows::UI::Xaml::Visibility::Visible;
}
void MainPage::OnSubmitButtonClick(Object^ sender, 
  RoutedEventArgs^ args)
{
  // Create a button to reference the byte array
  XAUDIO2_BUFFER buffer = { 0 };
  buffer.AudioBytes = 2 * 5 * 44100;
  buffer.pAudioData = soundData;
  buffer.Flags = XAUDIO2_END_OF_STREAM;
  buffer.PlayBegin = 0;
  buffer.PlayLength = 5 * 44100;
  // Submit the buffer
  HRESULT hr = pSourceVoice->SubmitSourceBuffer(&buffer);
  if (FAILED(hr))
  {
    errorText->Text = "SubmitSourceBuffer failure: " + hr.ToString();
    submitButton->Visibility = 
      Windows::UI::Xaml::Visibility::Collapsed;
    return;
  }
}

Sobald das IXAudio2-Objekt erstellt wurde, rufen Sie die Methoden CreateMasteringVoice und CreateSourceVoice Zeiger auf die anderen beiden Schnittstellen als Felder in der Headerdatei definiert.

Der CreateSourceVoice-Aufruf erfordert eine WAVEFORMATEX-Struktur, die jedem vertraut sein wird, mit Audio in der Win32-API gearbeitet hat. Diese Struktur definiert die Art der Audiodaten, die Sie für diese besondere Stimme verwenden werden. (Andere Quelle stimmen können unterschiedliche Formate). Für PCM sind nur drei Zahlen wirklich relevant: die Sampling-Rate (44.100 in diesem Beispiel), die Größe jeder Probe (2 Byte oder 16 Bit) und die Anzahl der Kanäle (1 hier). Die anderen Felder basieren auf diesen: NAvgBytesPerSec Feld ist das Produkt aus nSamplesPerSec und nBlockAlign nBlockAlign Bereich ist nChannels Mal wBitsPerSample geteilt durch 8 Aber ich habe alle Felder mit explizite Werte in diesem Beispiel gezeigt.

Sobald das IXAudio2SourceVoice-Objekt abgerufen wird, kann die Start-Methode auf sie aufgerufen werden. Zu diesem Zeitpunkt XAudio2 spielt im Prinzip, aber wir haben nicht wirklich gegeben alle Audiodaten zu spielen. Eine Stop-Methode ist auch verfügbar, und ein richtiges Programm würden diese beiden Methoden verwenden, um Steuern, wann die Geräusche sollte und sollte nicht spielen.

Alle vier dieser Aufrufe sind nicht so einfach, wie sie in diesem Code erscheinen! Alle verfügen über zusätzliche Argumente, aber bequeme Standardwerte definiert sind und ich haben einfach entschieden, vorerst die Standardeinstellungen zu übernehmen.

Praktisch alle Funktion und Methodenaufrufe in DirectX zurück HRESULT-Werte um Erfolg oder Fehler anzugeben. Es gibt verschiedene Strategien für den Umgang mit diesen Fehlern. Ich habe einfach zum Anzeigen des Fehlercode mit TextBlock definiert in der XAML-Datei und Weiterverarbeitung Stop gewählt.

PCM-Audio-Daten

Der Konstruktor schließt mit dem Füllen des Arrays SoundData mit audio-Daten, aber das Array ist nicht auf die IXAudio2SourceVoice tatsächlich über gegabelt, bis die Schaltfläche gedrückt wird.

Klang ist Schwingung, und die Menschen reagieren empfindlich auf Schwingungen in der Luft etwa im Bereich von 20 Hz (oder Zyklen pro Sekunde) bis 20.000 Hz. Middle C auf dem Klavier ist ca. 261,6 Hz.

Genommen Sie an, Sie arbeiten mit einer Abtastrate von 44.100 Hz und 16-Bit-Samples und Audiodaten für eine Wellenform mit einer Frequenz von 4.410 Hz, generieren, die nur hinter den höchsten Schlüssel auf einem Klavier ist möchten. Jeder Zyklus solch einer Wellenform erfordert 10 Proben von vorzeichenbehaftete 16-Bit-Werte. Diese 10 Werte würde 4.410 mal für jede Sekunde der Sound wiederholt werden.

Eine Wellenform mit einer Frequenz von 441 Hz — ganz in der Nähe von 440 Hz, entspricht dem A dreigestrichenen verwendet als Standard tuning — mit 100 Proben gerendert. 441 Mal für jede Sekunde der Sound würde dieser Zyklus wiederholt werden.

Da PCM eine Konstante Abtastrate beinhaltet, scheinen tieffrequente Geräusche zu sein gesampelt und Grieben, die bei einer viel höheren Auflösung als hohe Töne. Ist nicht dies ein Problem? Haben nicht 4.410 Hz Wellenform mit nur 10 Proben gerendert viel Verzerrung im Vergleich mit der Wellenform 441 Hz?

Es stellt sich heraus, dass jede Verzerrung Quantisierung im Rastermaß bei Frequenzen größer als die halbe Abtastrate auftritt. (Dieses bekannt als die Nyquist-Frequenz nach Bell Labs Harry Nyquist Engineering.) Einer der Gründe, die für Audio-CD eine Abtastfrequenz von 44.100 Hz gewählt wurde ist, dass die Nyquist-Frequenz 22.050 Hz ist und menschlichen Gehörs von ca. 20.000 Hz maxes. Mit anderen Worten ist die Quantisierung Verzerrung bei einer Abtastrate von 44.100 Hz, unhörbar für den Menschen.

Das SimpleAudio-Programm erzeugt eine algorithmisch einfache Wellenform — ein Rechtecksignal mit einer Frequenz von 441 Hz. Es gibt 100 Proben pro Zyklus. In jedem Zyklus werden die ersten 50 maximale positive Werte (32.767 beim Umgang mit kurze Ganzzahlen) und die nächsten 50 sind maximale negative Werte (32.768). Beachten Sie, dass diese kurze Werte in das Bytearray mit dem low-Byte zuerst gespeichert werden müssen:

soundData[index + 0] = value & 0xFF;
soundData[index + 1] = (value >> 8) & 0xFF;

Bisher hat nichts wirklich gespielt. Dies geschieht in den Click-Ereignishandler für die Schaltfläche. Die XAUDIO2_BUFFER-Struktur ist zum das Byte-Array mit einer Anzahl von Bytes und eine Dauer angegeben als die Anzahl der Beispiele zu verweisen. Dieser Puffer wird an die SubmitSourceBuffer-Methode des IXAudio2SourceVoice-Objekts übergeben. Wenn die Start-Methode bereits aufgerufen wurde (wie es in diesem Beispiel), beginnt sofort mit dem Spielen der Klang.

Ich vermute, dass ich nicht zu erwähnen, dass der Sound asynchron wiedergegeben. Der SubmitSourceBuffer-Aufruf zurückgegeben wird sofort, während der eigentliche Vorgang Daten an die Soundhardware Schaufeln ein eigenen Thread gewidmet ist. Die XAUDIO2_BUFFER an SubmitSourceBuffer übergeben nach dem Aufruf verworfen werden kann — wie es in diesem Programm ist, wenn der Click-Ereignishandler beendet ist und die lokale Variable außerhalb des Gültigkeitsbereichs geht — aber das eigentliche Array von Bytes im zugänglich Speicher verbleiben muss. In der Tat kann Ihr Programm diese Bytes bearbeiten, wie der Sound wiedergegeben wird. Allerdings gibt es viel besseren Techniken (mit Callback-Methoden), die Ihr Programm Sounddaten dynamisch generieren lassen.

Ohne mit einem Rückruf, um festzustellen, wann der Ton abgeschlossen hat, muss dieses Programm, das SoundData-Array für die Dauer des Programms zu behalten.

Drücken Sie die Taste mehrmals, und jedem Aufruf einen anderen Puffer gespielt werden, nach Abschluss der vorherige Puffer effektiv Warteschlangen. Bewegt sich das Programm im Hintergrund, der Ton ausgeschaltet ist, jedoch weiterhin in der Stille zu spielen. Mit anderen Worten, wenn Sie klicken und verschieben das Programm im Hintergrund für mindestens 5 Sekunden, wird nichts spielen gibt das Programm in den Vordergrund.

Die Merkmale des Klangs

Ein Großteil der Sound hören wir im täglichen Leben gleichzeitig aus einer Vielzahl von unterschiedlichen Quellen kommt und ist daher recht komplex. Jedoch in einigen Fällen — und besonders im Umgang mit musikalischen Klängen — einzelne Töne können mit nur ein paar Merkmale definiert werden:

  • Amplitude, die mit unseren Sinnen als Band interpretiert wird.
  • Frequenz, die als Tonhöhe interpretiert wird.
  • Raum, der in der audio-Wiedergabe mit mehreren Lautsprechern imitiert werden kann.
  • Klang, die bezieht sich auf die Mischung von Obertönen in einem Ton und den wahrgenommenen Unterschied zwischen einer Trompete und Klavier, zum Beispiel darstellt.

Das SoundCharacteristics-Projekt zeigt diese vier Eigenschaften isoliert. Es hält die 44.100 Sample-Rate und 16-Bit-Samples des Projektes SimpleAudio aber erzeugt Klang in Stereo. Für zwei Kanäle des Klangs müssen die Daten verzahnt werden: eine 16-Bit-Probe für den linken Kanal, gefolgt von einer 16-Bit-Probe für den rechten Kanal.

Die MainPage.xaml.h-Headerdatei für SoundCharacteristics werden einige Konstanten definiert:

static const int sampleRate = 44100;
static const int seconds = 5;
static const int channels = 2;
static const int samples = seconds * sampleRate;

Es definiert außerdem vier Arrays für Audiodaten, aber diese sind vom Typ short statt Byte:

short volumeSoundData[samples * channels];
short pitchSoundData[samples * channels];
short spaceSoundData[samples * channels];
short timbreSoundData[samples * channels];

Verwendung von kurzen Arrays erleichtert die Initialisierung da nicht die Wellenform der 16-Bit-Werte in zwei Hälften aufgeteilt werden müssen. Eine einfache Umwandlung kann das Array von der XAUDIO2_BUFFER verwiesen werden, wenn Sie die Sounddaten einreichen. Diese Arrays haben doppelt so viele Bytes wie das Array in SimpleAudio, weil ich in diesem Programm Stereo benutze.

Alle vier dieser Arrays sind in der MainPage-Konstruktor initialisiert. Zur Demonstration Band eine 441 Hz Rechteckwelle ist noch beteiligt, aber es beginnt bei 0 (null) Lautstärke, ruft immer lauter in den ersten 2 Sekunden und dann in Band über die letzten 2 Sekunden sinkt. Abbildung 4 zeigt den Code VolumeSoundData initialisiert werden.

Abbildung 4 Sounddaten in Band für SoundCharacteristics geändert

for (int index = 0, sample = 0; sample < samples; sample++)
{
  double t = 1;
  if (sample < 2 * samples / 5)
    t = sample / (2.0 * samples / 5);
  else if (sample > 3 * samples / 5)
    t = (samples - sample) / (2.0 * samples / 5);
  double amplitude = pow(2, 15 * t) - 1;
  short waveform = sample % 100 < 50 ?
1 : -1;
  short value = short(amplitude * waveform);
  volumeSoundData[index++] = value;
  volumeSoundData[index++] = value;
}

Die menschliche Wahrnehmung des Volumens ist logarithmisch: Jede Verdoppelung der Amplitude einer Wellenform des entspricht eine Zunahme des Volumens um 6 dB. (Die 16-Bit Amplitude für Audio-CD verwendet hat ein Dynamikumfang von 96 Dezibel). Der Code in Abbildung 4 , die Lautstärke ändern zuerst berechnet einen Wert von t, die steigt linear von 0 auf 1 und dann sinkt auf 0 zurück. Die Amplitude-Variable wird mit der pow-Funktion und reicht von 0 bis 32.767 berechnet. Dies ist eine Rechteckwelle multipliziert, die Werte 1 und-1 hat. Das Ergebnis wird in das Array zweimal hinzugefügt: Erstens für den linken Kanal, dann für den rechten Kanal.

Die menschliche Wahrnehmung der Frequenz ist auch logarithmisch. Viel von der Welt-Musik organisiert die Tonhöhe um das Intervall der Oktave, die eine Verdoppelung der Frequenz ist. Die ersten beiden Noten des Chors von "Somewhere over the Rainbow" sind eine Oktave Sprung, ob es von einem Bass oder ein Sopran gesungen wird. Abbildung 5 zeigt Code, der über den Bereich von zwei Oktaven Tonhöhe variiert: von 220 bis 880 basierend auf einem Wert von t, die (wie im Beispiel Volume) geht von 0 bis 1 und dann wieder nach unten auf 0.

Abbildung 5 Sounddaten in Frequenz ändert sich für SoundCharacteristics

double angle = 0;
for (int index = 0, sample = 0; sample < samples; sample++)
{
  double t = 1;
  if (sample < 2 * samples / 5)
    t = sample / (2.0 * samples / 5);
  else if (sample > 3 * samples / 5)
    t = (samples - sample) / (2.0 * samples / 5);
  double frequency = 220 * pow(2, 2 * t);
  double angleIncrement = 360 * frequency / waveformat.
nSamplesPerSec;
  angle += angleIncrement;
  while (angle > 360)
    angle -= 360;
  short value = angle < 180 ?
32767 : -32767;
  pitchSoundData[index++] = value;
  pitchSoundData[index++] = value;
}

In früheren Beispielen wählte ich eine Frequenz von 441 Hz, weil es sauber in die Abtastrate von 44.100 teilt. Im allgemeinen Fall die Sampling-Rate ist ein ganzzahliges Vielfaches der Frequenz nicht und deshalb keine ganzzahlige Anzahl von Samples pro Periode werden. Stattdessen verwaltet dieses Programm eine unverankerte Punkt AngleIncrement-Variable, die ist proportional zur Frequenz und verwendet, um einen Winkelwert zu erhöhen, der reicht von 0 bis 360. Dieses Winkelmaß wird dann verwendet, um die Wellenform zu konstruieren.

Die Demonstration für Raum verschiebt den Ton von der Mitte an den linken Kanal, dann nach rechts, dann zurück in die Mitte. Die Klangfarbe-Demo startet mit einer Sinus-Kurve bei 441 Hz Wellenform. Eine Sinus-Kurve ist die mathematische Darstellung der grundlegendste Art der Vibration — die Lösung der Differentialgleichung, wo Kraft umgekehrt proportional zum Hubraum ist. Alle andere periodischen Wellenformen enthalten Obertöne, die auch Sinuswellen sind aber mit Frequenzen, die integrale Vielfache der Grundfrequenz sind. Die Klangfarbe Demo ändert die Wellenform reibungslos von einer Sinuswelle zu einer Welle Dreieck zu einer quadratischen Welle, zu einem Sägezahn, bei der Erhöhung des harmonischen Inhalts des Klanges.

Das Gesamtbild

Obwohl ich gerade gezeigt habe, wie Sie Lautstärke, Tonhöhe, Raum und Klang durch die Generierung von Sounddaten für ein einzelnes Objekt IXAudio2SourceVoice steuern können, enthält das Objekt selbst Methoden, um das Volumen und Raum und sogar die Frequenz ändern. (Eine "3D" Raum-Anlage wird auch unterstützt). Es ist, zwar möglich, zusammengesetzte Sounddaten zu generieren, die eine Reihe von einzelnen Tönen mit einer Hand kombiniert können mehrere IXAudio2SourceVoice-Objekte erstellen und alle zusammen durch die gleichen mastering Stimme zu spielen.

XAudio2 definiert außerdem eine IXAudioSubmixVoice, die Sie filtern und anderen Effekten, wie Nachhall oder Echo definieren kann. Filter haben die Möglichkeit, die Klangfarbe der vorhandenen Töne dynamisch ändern, die erheblich dazu beitragen kann, interessante und realistische musikalische Töne erstellen.

Vielleicht ist die wesentlichste Verbesserung über was ich, in diesen beiden Programmen gezeigt habe Arbeiten mit XAudio2 Callback-Funktionen erforderlich. Statt zu Beginn und große Stücke von Sounddaten zu initialisieren, wie diese beiden Programme tun, ist es wesentlich sinnvoller für ein Programm Daten dynamisch zu generieren, wie es gespielt wird.

Charles Petzold ist ein langjähriger Beitrag zum MSDN Magazine und Autor von "Programming Windows, 6th Edition" (O' Reilly Media, 2012), ein Buch über das Schreiben von Anwendungen für Windows 8. Seiner Website lautet charlespetzold.com.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Scott Selfon