22#define NTDDI_VERSION NTDDI_WIN8
23#define _WIN32_WINNT _WIN32_WINNT_WIN8
29#include <wrl\client.h>
32using Microsoft::WRL::ComPtr;
38typedef HRESULT(__stdcall *
API_XAudio2Create)(_Outptr_ IXAudio2 **ppXAudio2, UINT32
Flags, XAUDIO2_PROCESSOR XAudio2Processor);
46class StreamingVoiceContext :
public IXAudio2VoiceCallback
49 std::vector<BYTE> buffer;
52 IXAudio2SourceVoice *source_voice =
nullptr;
54 StreamingVoiceContext(
int buffer_length)
56 this->buffer.resize(buffer_length);
61 virtual ~StreamingVoiceContext() =
default;
63 HRESULT SubmitBuffer()
66 if (this->source_voice ==
nullptr) {
70 MxMixSamples(this->buffer.data(),
static_cast<uint
>(this->buffer.size() / 4));
72 XAUDIO2_BUFFER buf = { 0 };
73 buf.AudioBytes =
static_cast<UINT32
>(this->buffer.size());
74 buf.pAudioData = this->buffer.data();
76 return source_voice->SubmitSourceBuffer(&buf);
79 STDMETHOD_(
void, OnVoiceProcessingPassStart)(UINT32)
override
83 STDMETHOD_(
void, OnVoiceProcessingPassEnd)()
override
87 STDMETHOD_(
void, OnStreamEnd)()
override
91 STDMETHOD_(
void, OnBufferStart)(
void*)
override
95 STDMETHOD_(
void, OnBufferEnd)(
void*)
override
100 STDMETHOD_(
void, OnLoopEnd)(
void*)
override
104 STDMETHOD_(
void, OnVoiceError)(
void*, HRESULT)
override
109static HMODULE _xaudio_dll_handle;
110static IXAudio2SourceVoice *_source_voice =
nullptr;
111static IXAudio2MasteringVoice *_mastering_voice =
nullptr;
112static ComPtr<IXAudio2> _xaudio2;
113static std::unique_ptr<StreamingVoiceContext> _voice_context;
125 hr = xAudio2Create(_xaudio2.GetAddressOf(), flags, XAUDIO2_DEFAULT_PROCESSOR);
126 } __except (EXCEPTION_EXECUTE_HANDLER) {
127 hr = GetExceptionCode();
142 HRESULT hr = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
145 Debug(driver, 0,
"xaudio2_s: CoInitializeEx failed ({:08x})", (uint)hr);
146 return "Failed to initialise COM";
149 _xaudio_dll_handle = LoadLibraryA(XAUDIO2_DLL_A);
151 if (_xaudio_dll_handle ==
nullptr) {
154 Debug(driver, 0,
"xaudio2_s: Unable to load " XAUDIO2_DLL_A);
155 return "Failed to load XAudio2 DLL";
160 if (xAudio2Create ==
nullptr) {
161 FreeLibrary(_xaudio_dll_handle);
164 Debug(driver, 0,
"xaudio2_s: Unable to find XAudio2Create function in DLL");
165 return "Failed to load XAudio2 DLL";
172 FreeLibrary(_xaudio_dll_handle);
175 Debug(driver, 0,
"xaudio2_s: XAudio2Create failed ({:08x})", (uint)hr);
176 return "Failed to initialise the XAudio2 engine";
180 hr = _xaudio2->CreateMasteringVoice(&_mastering_voice);
184 FreeLibrary(_xaudio_dll_handle);
187 Debug(driver, 0,
"xaudio2_s: CreateMasteringVoice failed ({:08x})", (uint)hr);
188 return "Failed to create a mastering voice";
194 wfex.wFormatTag = WAVE_FORMAT_PCM;
196 wfex.wBitsPerSample = 16;
198 wfex.nBlockAlign = (wfex.nChannels * wfex.wBitsPerSample) / 8;
199 wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
203 bufsize = std::min<int>(bufsize, UINT16_MAX);
205 _voice_context = std::make_unique<StreamingVoiceContext>(bufsize * 4);
207 if (_voice_context ==
nullptr) {
208 _mastering_voice->DestroyVoice();
210 FreeLibrary(_xaudio_dll_handle);
213 return "Failed to create streaming voice context";
216 hr = _xaudio2->CreateSourceVoice(&_source_voice, &wfex, 0, 1.0f, _voice_context.get());
219 _mastering_voice->DestroyVoice();
221 FreeLibrary(_xaudio_dll_handle);
224 Debug(driver, 0,
"xaudio2_s: CreateSourceVoice failed ({:08x})", (uint)hr);
225 return "Failed to create a source voice";
228 _voice_context->source_voice = _source_voice;
229 hr = _source_voice->Start(0, 0);
232 Debug(driver, 0,
"xaudio2_s: _source_voice->Start failed ({:08x})", (uint)hr);
235 return "Failed to start the source voice";
238 MxInitialize(wfex.nSamplesPerSec);
241 hr = _voice_context->SubmitBuffer();
244 Debug(driver, 0,
"xaudio2_s: _voice_context->SubmitBuffer failed ({:08x})", (uint)hr);
247 return "Failed to submit the first audio buffer";
259 _source_voice->DestroyVoice();
261 _voice_context =
nullptr;
263 _mastering_voice->DestroyVoice();
267 FreeLibrary(_xaudio_dll_handle);
Functions related to bit mathematics.
Factory for the XAudio2 sound driver.
std::optional< std::string_view > Start(const StringList ¶m) override
Initialises the XAudio2 driver.
void Stop() override
Terminates the XAudio2 driver.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
int GetDriverParamInt(const StringList &parm, std::string_view name, int def)
Get an integer parameter the list of parameters.
Base for all drivers (video, sound, music, etc).
Functions to mix sound samples.
A number of safeguards to prevent using unsafe methods.
@ Flags
ScriptConfigFlags defining how/when to use this configuration.
Definition of base types and functions in a cross-platform compatible way.
std::vector< std::string > StringList
Type for a list of strings.
Declarations of functions for MS windows systems.
static HRESULT CreateXAudio(API_XAudio2Create xAudio2Create)
Create XAudio2 context with SEH exception checking.
HRESULT(__stdcall * API_XAudio2Create)(_Outptr_ IXAudio2 **ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor)
Definition of the "XAudio2Create" call used to initialise XAudio2.
Base for XAudio2 sound handling.