Un sencillo proyecto XAudio2 completo
En los temas anteriores se mostró cómo inicializar XAudio2, cargar datos en un búfer de audio y, a continuación, reproducir ese audio a través de voces XAudio2. En este tema se extraen todos los pasos juntos en un único ejemplo de código de C++/WinRT que se basa en una aplicación XAudio2 muy sencilla que reproduce una onda senoidal de 220 Hz.
Creación de un proyecto en Visual Studio
En Visual Studio, cree un nuevo proyecto de Aplicación vacía empaquetada (WinUI 3 en escritorio) de C++/WinRT. Si asigna el nombre MyXAudio2Project al proyecto, podrá copiar y pegar el código fuente siguiente directamente en los archivos de código fuente del proyecto sin problemas.
Abra cada uno de los siguientes archivos de código fuente y edítelos para que se parezcan a la lista de código fuente.
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));
}
}
Compilación y ejecución
El proyecto ahora debería compilarse y ejecutarse. Pulse el botón para escuchar un tono de prueba de 220 Hz.