Ein komplettes einfaches XAudio2-Projekt
Die vorhergehenden Themen haben die Initialisierung von XAudio2, das Laden von Daten in einen Audiopuffer und die Wiedergabe dieser Tonspur über XAudio2-Stimmen beschrieben. Das vorliegende Thema führt all diese Schritte in einem einzelnen funktionierenden C++/WinRT-Codebeispiel zusammen, das eine ganz einfache XAudio2-App erstellt, die eine 220-Hz-Sinuswelle abspielt.
Erstellen eines neuen Projekts in Visual Studio
Erstellen Sie in Visual Studio ein neues C++/WinRT-Projekt aus der Vorlage Leere App, gepackt (WinUI 3 in Desktop). Geben Sie dem Projekt den Namen MyXAudio2Project. Dann können Sie den nachfolgenden Quellcode ohne Probleme direkt in die Code-Dateien für das Projekt kopieren.
Öffnen Sie nacheinander die angegebenen Code-Dateien, und überarbeiten Sie sie so, dass sie den angezeigten Beispielen entsprechen.
MainWindow.xaml.idl
namespace MyXAudio2Project
{
[default_interface]
runtimeclass MainWindow : Microsoft.UI.Xaml.Window
{
MainWindow();
}
}
MainWindow.xaml.h
#pragma once
#include "MainWindow.g.h"
#include <xaudio2.h>
// Constant literals.
constexpr WORD BITSPERSSAMPLE = 16; // 16 bits per sample.
constexpr DWORD SAMPLESPERSEC = 44100; // 44,100 samples per second.
constexpr double CYCLESPERSEC = 220.0; // 220 cycles per second (frequency of the audible tone).
constexpr double VOLUME = 0.5; // 50% volume.
constexpr WORD AUDIOBUFFERSIZEINCYCLES = 10; // 10 cycles per audio buffer.
constexpr double PI = 3.14159265358979323846;
// Calculated constants.
constexpr DWORD SAMPLESPERCYCLE = (DWORD)(SAMPLESPERSEC / CYCLESPERSEC); // 200 samples per cycle.
constexpr DWORD AUDIOBUFFERSIZEINSAMPLES = SAMPLESPERCYCLE * AUDIOBUFFERSIZEINCYCLES; // 2,000 samples per buffer.
constexpr UINT32 AUDIOBUFFERSIZEINBYTES = AUDIOBUFFERSIZEINSAMPLES * BITSPERSSAMPLE / 8; // 4,000 bytes per buffer.
namespace winrt::MyXAudio2Project::implementation
{
struct MainWindow : MainWindowT<MainWindow>
{
std::array<byte, AUDIOBUFFERSIZEINBYTES> m_buffer{};
winrt::com_ptr<IXAudio2> m_xAudio2{};
IXAudio2MasteringVoice* m_pXAudio2MasteringVoice{};
IXAudio2SourceVoice* m_pXAudio2SourceVoice{};
MainWindow()
{
// Xaml objects should not call InitializeComponent during construction.
// See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
}
void myButton_Click(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
};
}
namespace winrt::MyXAudio2Project::factory_implementation
{
struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
{
};
}
MainWindow.xaml.cpp
#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif
using namespace winrt;
using namespace Microsoft::UI::Xaml;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace winrt::MyXAudio2Project::implementation
{
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
myButton().Content(box_value(L"Clicked"));
// Initialize XAudio2 (create an engine and a mastering voice).
winrt::check_hresult(::XAudio2Create(m_xAudio2.put(), 0, XAUDIO2_DEFAULT_PROCESSOR));
winrt::check_hresult(m_xAudio2->CreateMasteringVoice(&m_pXAudio2MasteringVoice));
// Define a format.
WAVEFORMATEX waveFormatEx{};
waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
waveFormatEx.nChannels = 1; // 1 channel
waveFormatEx.nSamplesPerSec = SAMPLESPERSEC;
waveFormatEx.nBlockAlign = waveFormatEx.nChannels * BITSPERSSAMPLE / 8;
waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * waveFormatEx.nBlockAlign;
waveFormatEx.wBitsPerSample = BITSPERSSAMPLE;
waveFormatEx.cbSize = 0;
// Create a source voice with that format.
winrt::check_hresult(m_xAudio2->CreateSourceVoice(&m_pXAudio2SourceVoice, &waveFormatEx));
// Fill a buffer.
double phase{};
uint32_t bufferIndex{};
while (bufferIndex < AUDIOBUFFERSIZEINBYTES)
{
phase += (2 * PI) / SAMPLESPERCYCLE;
int16_t sample = (int16_t)(sin(phase) * INT16_MAX * VOLUME);
this->m_buffer[bufferIndex++] = (byte)sample; // Values are little-endian.
this->m_buffer[bufferIndex++] = (byte)(sample >> 8);
}
XAUDIO2_BUFFER xAudio2Buffer{};
xAudio2Buffer.Flags = XAUDIO2_END_OF_STREAM;
xAudio2Buffer.AudioBytes = AUDIOBUFFERSIZEINBYTES;
xAudio2Buffer.pAudioData = m_buffer.data();
xAudio2Buffer.PlayBegin = 0;
xAudio2Buffer.PlayLength = 0;
xAudio2Buffer.LoopBegin = 0;
xAudio2Buffer.LoopLength = 0;
xAudio2Buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
// Submit the buffer to the source voice, and start the voice.
winrt::check_hresult(m_pXAudio2SourceVoice->SubmitSourceBuffer(&xAudio2Buffer));
winrt::check_hresult(m_pXAudio2SourceVoice->Start(0));
}
}
Erstellen und Ausführen
Jetzt sollte das Projekt erstellt und ausgeführt werden. Klicken Sie auf die Schaltfläche, um den Testton mit 220 Hz anzuhören.