Add XAudio2.7 as an compile-time audio driver for vanilla Windows 7

This commit is contained in:
Lior Halphon 2022-06-24 13:27:02 +03:00
parent 9ae2c9fd54
commit fd6b734fd0
2 changed files with 234 additions and 0 deletions

131
SDL/audio/xaudio2_7.c Normal file
View File

@ -0,0 +1,131 @@
#include "xaudio2_7.h"
#include "audio.h"
#define AUDIO_FREQUENCY 96000
static IXAudio2 *xaudio2 = NULL;
static IXAudio2MasteringVoice *master_voice = NULL;
static IXAudio2SourceVoice *source_voice = NULL;
static bool playing = false;
static GB_sample_t sample_pool[0x2000];
static unsigned pos = 0;
#define BATCH_SIZE 256
static const WAVEFORMATEX wave_format = {
.wFormatTag = WAVE_FORMAT_PCM,
.nChannels = 2,
.nSamplesPerSec = AUDIO_FREQUENCY,
.nAvgBytesPerSec = AUDIO_FREQUENCY * 4,
.nBlockAlign = 4,
.wBitsPerSample = 16,
.cbSize = 0
};
static inline HRESULT XAudio2Create(IXAudio2 **ppXAudio2,
UINT32 Flags,
XAUDIO2_PROCESSOR XAudio2Processor)
{
IXAudio2 *pXAudio2;
LoadLibraryEx("xaudio2_7.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
HRESULT hr = CoCreateInstance(&CLSID_XAudio2, NULL, CLSCTX_INPROC_SERVER, &IID_IXAudio2, (void**)&pXAudio2);
if (SUCCEEDED(hr)) {
hr = pXAudio2->lpVtbl->Initialize(pXAudio2, Flags, XAudio2Processor);
}
if (SUCCEEDED(hr)) {
*ppXAudio2 = pXAudio2;
}
else {
pXAudio2->lpVtbl->Release(pXAudio2);
}
return hr;
}
bool GB_audio_is_playing(void)
{
return playing;
}
void GB_audio_set_paused(bool paused)
{
if (paused) {
playing = false;
IXAudio2SourceVoice_Stop(source_voice, 0, XAUDIO2_COMMIT_NOW);
GB_audio_clear_queue();
}
else {
playing = true;
IXAudio2SourceVoice_Start(source_voice, 0, XAUDIO2_COMMIT_NOW);
}
}
void GB_audio_clear_queue(void)
{
pos = 0;
IXAudio2SourceVoice_FlushSourceBuffers(source_voice);
}
unsigned GB_audio_get_frequency(void)
{
return AUDIO_FREQUENCY;
}
size_t GB_audio_get_queue_length(void)
{
static XAUDIO2_VOICE_STATE state;
IXAudio2SourceVoice_GetState(source_voice, &state);
return state.BuffersQueued * BATCH_SIZE + (pos & (BATCH_SIZE - 1));
}
void GB_audio_queue_sample(GB_sample_t *sample)
{
if (!playing) return;
static XAUDIO2_BUFFER buffer = {.AudioBytes = sizeof(*sample) * BATCH_SIZE, };
sample_pool[pos] = *sample;
buffer.pAudioData = (void *)&sample_pool[pos & ~(BATCH_SIZE - 1)];
pos++;
pos &= 0x1fff;
if ((pos & (BATCH_SIZE - 1)) == 0) {
IXAudio2SourceVoice_SubmitSourceBuffer(source_voice, &buffer, NULL);
}
}
void GB_audio_init(void)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) {
fprintf(stderr, "CoInitializeEx failed: %lx\n", hr);
return;
}
hr = XAudio2Create(&xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr)) {
fprintf(stderr, "XAudio2Create failed: %lx\n", hr);
return;
}
hr = IXAudio2_CreateMasteringVoice(xaudio2, &master_voice,
2, // 2 channels
AUDIO_FREQUENCY,
0, // Flags
0, // Device index
NULL // Effect chain
);
if (FAILED(hr)) {
fprintf(stderr, "CreateMasteringVoice failed: %lx\n", hr);
return;
}
hr = IXAudio2_CreateSourceVoice(xaudio2, &source_voice, &wave_format, 0, XAUDIO2_DEFAULT_FREQ_RATIO, NULL, NULL, NULL);
if (FAILED(hr)) {
fprintf(stderr, "CreateSourceVoice failed: %lx\n", hr);
return;
}
}

103
SDL/audio/xaudio2_7.h Normal file
View File

@ -0,0 +1,103 @@
#define INITGUID
#include <Windows.h>
/* Minimal definitions for XAudio2.7 */
typedef UINT32 XAUDIO2_PROCESSOR;
typedef struct XAUDIO2_BUFFER {
UINT32 Flags;
UINT32 AudioBytes;
const BYTE *pAudioData;
UINT32 PlayBegin;
UINT32 PlayLength;
UINT32 LoopBegin;
UINT32 LoopLength;
UINT32 LoopCount;
void *pContext;
} XAUDIO2_BUFFER;
typedef struct XAUDIO2_VOICE_STATE {
void *pCurrentBufferContext;
UINT32 BuffersQueued;
UINT64 SamplesPlayed;
} XAUDIO2_VOICE_STATE;
typedef struct IXAudio2SourceVoice {
struct IXAudio2SourceVoiceVtbl *lpVtbl;
} IXAudio2SourceVoice;
typedef struct IXAudio2SourceVoiceVtbl IXAudio2SourceVoiceVtbl;
#undef INTERFACE
#define INTERFACE IXAudio2SourceVoice
struct IXAudio2SourceVoiceVtbl {
void *voiceMethods[19]; // Unused inherited methods
STDMETHOD(Start) (THIS_ UINT32 Flags, UINT32 OperationSet) PURE;
STDMETHOD(Stop) (THIS_ UINT32 Flags, UINT32 OperationSet) PURE;
STDMETHOD(SubmitSourceBuffer) (THIS_ __in const XAUDIO2_BUFFER *pBuffer, __in_opt const void *pBufferWMA) PURE;
STDMETHOD(FlushSourceBuffers) (THIS) PURE;
STDMETHOD(Discontinuity) (THIS) PURE;
STDMETHOD(ExitLoop) (THIS_ UINT32 OperationSet) PURE;
STDMETHOD_(void, GetState) (THIS_ __out XAUDIO2_VOICE_STATE *pVoiceState) PURE;
};
typedef struct IXAudio2 {
struct IXAudio2Vtbl *lpVtbl;
} IXAudio2;
typedef struct IXAudio2Vtbl IXAudio2Vtbl;
typedef void *IXAudio2MasteringVoice;
#undef INTERFACE
#define INTERFACE IXAudio2
struct IXAudio2Vtbl {
void *QueryInterface;
STDMETHOD_(ULONG, AddRef) (THIS) PURE;
STDMETHOD_(ULONG, Release) (THIS) PURE;
void *GetDeviceCount;
void *GetDeviceDetails;
STDMETHOD(Initialize) (THIS_ UINT32 Flags,
XAUDIO2_PROCESSOR XAudio2Processor) PURE;
void *RegisterForCallbacks;
void *UnregisterForCallbacks;
STDMETHOD(CreateSourceVoice) (THIS_ __deref_out IXAudio2SourceVoice **ppSourceVoice,
__in const WAVEFORMATEX *pSourceFormat,
UINT32 Flags,
float MaxFrequencyRatio,
__in_opt void *pCallback,
__in_opt const void *pSendList,
__in_opt const void *pEffectChain) PURE;
void *CreateSubmixVoice;
STDMETHOD(CreateMasteringVoice) (THIS_ __deref_out IXAudio2MasteringVoice **ppMasteringVoice,
UINT32 InputChannels,
UINT32 InputSampleRate,
UINT32 Flags, UINT32 DeviceIndex,
__in_opt const void *pEffectChain) PURE;
};
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
DEFINE_CLSID(XAudio2, 5a508685, a254, 4fba, 9b, 82, 9a, 24, b0, 03, 06, af);
DEFINE_IID(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb);
#define IXAudio2SourceVoice_Start(This,Flags,OperationSet) ((This)->lpVtbl->Start(This,Flags,OperationSet))
#define IXAudio2SourceVoice_Stop(This,Flags,OperationSet) ((This)->lpVtbl->Stop(This,Flags,OperationSet))
#define IXAudio2SourceVoice_SubmitSourceBuffer(This,pBuffer,pBufferWMA) ((This)->lpVtbl->SubmitSourceBuffer(This,pBuffer,pBufferWMA))
#define IXAudio2SourceVoice_FlushSourceBuffers(This) ((This)->lpVtbl->FlushSourceBuffers(This))
#define IXAudio2SourceVoice_GetState(This,pVoiceState) ((This)->lpVtbl->GetState(This,pVoiceState))
#define IXAudio2_CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceIndex,pEffectChain) ((This)->lpVtbl->CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceIndex,pEffectChain))
#define IXAudio2_CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain) ((This)->lpVtbl->CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain))
#define XAUDIO2_COMMIT_NOW 0
#define XAUDIO2_DEFAULT_PROCESSOR 0xffffffff
#define XAUDIO2_DEFAULT_FREQ_RATIO 2.0f