diff --git a/Makefile b/Makefile index 7c881a3..c25f38b 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ ifeq ($(PLATFORM),windows32) _ := $(shell chcp 65001) EXESUFFIX:=.exe NATIVE_CC = clang -IWindows -Wno-deprecated-declarations --target=x86_64-pc-windows -SDL_AUDIO_DRIVERS ?= xaudio2 xaudio2_7 sdl +SDL_AUDIO_DRIVERS ?= xaudio2 sdl else EXESUFFIX:= NATIVE_CC := cc @@ -224,6 +224,11 @@ CFLAGS += -IWindows -Drandom=rand --target=x86_64-pc-windows LDFLAGS += -lmsvcrt -lcomdlg32 -luser32 -lshell32 -lole32 -lSDL2main -Wl,/MANIFESTFILE:NUL --target=x86_64-pc-windows SDL_LDFLAGS := -lSDL2 GL_LDFLAGS := -lopengl32 +ifneq ($(REDIST_XAUDIO),) +CFLAGS += -DREDIST_XAUDIO +LDFLAGS += -lxaudio2_9redist +sdl: $(BIN)/SDL/xaudio2_9redist.dll +endif else LDFLAGS += -lc -lm -ldl endif @@ -542,9 +547,10 @@ $(OBJ)/%.res: %.rc cvtres /OUT:"$@" $^ endif -# We must provide SDL2.dll with the Windows port. -$(BIN)/SDL/SDL2.dll: - @$(eval MATCH := $(shell where $$LIB:SDL2.dll)) +# Copy required DLL files for the Windows port +$(BIN)/SDL/%.dll: + -@$(MKDIR) -p $(dir $@) + @$(eval MATCH := $(shell where $$LIB:$(notdir $@))) cp "$(MATCH)" $@ # Tester diff --git a/SDL/audio.c b/SDL/audio.c index 29b3eb0..c1f2fc7 100644 --- a/SDL/audio.c +++ b/SDL/audio.c @@ -15,7 +15,6 @@ bool GB_audio_init(void) const GB_audio_driver_t *drivers[] = { #ifdef _WIN32 GB_AUDIO_DRIVER_REF(XAudio2), - GB_AUDIO_DRIVER_REF(XAudio2_7), #endif GB_AUDIO_DRIVER_REF(SDL), #ifdef ENABLE_OPENAL @@ -97,7 +96,6 @@ const char *GB_audio_driver_name_at_index(unsigned index) const GB_audio_driver_t *drivers[] = { #ifdef _WIN32 GB_AUDIO_DRIVER_REF(XAudio2), - GB_AUDIO_DRIVER_REF(XAudio2_7), #endif GB_AUDIO_DRIVER_REF(SDL), #ifdef ENABLE_OPENAL diff --git a/SDL/audio/xaudio2.c b/SDL/audio/xaudio2.c index e2ca68b..e7fc4f9 100644 --- a/SDL/audio/xaudio2.c +++ b/SDL/audio/xaudio2.c @@ -1,9 +1,25 @@ #define COBJMACROS #include "audio.h" #include +#ifdef REDIST_XAUDIO +#include +#else #include +#endif +#include #include +// This is a hack, but Windows itself is a hack so I don't care +#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(MMDeviceEnumerator, bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e); +DEFINE_IID(IMMDeviceEnumerator, a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6); + + static unsigned audio_frequency = 48000; static IXAudio2 *xaudio2 = NULL; static IXAudio2MasteringVoice *master_voice = NULL; diff --git a/SDL/audio/xaudio2_7.c b/SDL/audio/xaudio2_7.c deleted file mode 100644 index 146450f..0000000 --- a/SDL/audio/xaudio2_7.c +++ /dev/null @@ -1,225 +0,0 @@ -#define COBJMACROS -#include "xaudio2_7.h" -#include "audio.h" -#include - - -static unsigned audio_frequency = 48000; -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 WAVEFORMATEX wave_format = { - .wFormatTag = WAVE_FORMAT_PCM, - .nChannels = 2, - .nBlockAlign = 4, - .wBitsPerSample = 16, - .cbSize = 0 -}; - -static inline HRESULT XAudio2Create(IXAudio2 **out, - UINT32 Flags, - XAUDIO2_PROCESSOR XAudio2Processor) -{ - IXAudio2 *xaudio2; - LoadLibraryEx("xaudio2_7.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); - - HRESULT hr = CoCreateInstance(&CLSID_XAudio2, NULL, CLSCTX_INPROC_SERVER, &IID_IXAudio2, (void **)&xaudio2); - if (SUCCEEDED(hr)) { - hr = xaudio2->lpVtbl->Initialize(xaudio2, Flags, XAudio2Processor); - } - - if (SUCCEEDED(hr)) { - *out = xaudio2; - } - else if (xaudio2) { - xaudio2->lpVtbl->Release(xaudio2); - } - return hr; -} - -static bool _audio_is_playing(void) -{ - return playing; -} - -static void _audio_clear_queue(void) -{ - pos = 0; - IXAudio2SourceVoice_FlushSourceBuffers(source_voice); -} - -static void _audio_set_paused(bool paused) -{ - if (paused) { - playing = false; - IXAudio2SourceVoice_Stop(source_voice, 0, XAUDIO2_COMMIT_NOW); - _audio_clear_queue(); - } - else { - playing = true; - IXAudio2SourceVoice_Start(source_voice, 0, XAUDIO2_COMMIT_NOW); - } - -} - -#define _DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) static const PROPERTYKEY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } -_DEFINE_PROPERTYKEY(_PKEY_AudioEngine_DeviceFormat, 0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, 0); - - -static void update_frequency(void) -{ - HRESULT hr; - IMMDevice *device = NULL; - IMMDeviceEnumerator *enumerator = NULL; - IPropertyStore *store = NULL; - PWAVEFORMATEX deviceFormatProperties; - PROPVARIANT prop; - - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator); - if (FAILED(hr)) return; - - // get default audio endpoint - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eMultimedia, &device); - if (FAILED(hr)) return; - - hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &store); - if (FAILED(hr)) return; - - hr = IPropertyStore_GetValue(store, &_PKEY_AudioEngine_DeviceFormat, &prop); - if (FAILED(hr)) return; - - deviceFormatProperties = (PWAVEFORMATEX)prop.blob.pBlobData; - audio_frequency = deviceFormatProperties->nSamplesPerSec; - if (audio_frequency < 8000 || audio_frequency > 192000) { - // Bogus value, revert to 48KHz - audio_frequency = 48000; - } -} - -static unsigned _audio_get_frequency(void) -{ - return audio_frequency; -} - -static void nop(IXAudio2EngineCallback *this) -{ -} - -static bool _audio_init(void); - -static _Atomic bool needs_restart = false; - -static void critical_error(IXAudio2EngineCallback *this, HRESULT error) -{ - needs_restart = true; -} - - -static size_t _audio_get_queue_length(void) -{ - if (needs_restart) { - _audio_init(); - if (!xaudio2) return 0; - _audio_set_paused(!playing); - } - static XAUDIO2_VOICE_STATE state; - IXAudio2SourceVoice_GetState(source_voice, &state); - - return state.BuffersQueued * BATCH_SIZE + (pos & (BATCH_SIZE - 1)); -} - -static void _audio_queue_sample(GB_sample_t *sample) -{ - if (!playing) return; - - if (needs_restart) { - _audio_init(); - if (!xaudio2) return; - _audio_set_paused(!playing); - } - - 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); - } -} - -static bool _audio_init(void) -{ - if (needs_restart) { - needs_restart = false; - if (xaudio2) { - xaudio2->lpVtbl->Release(xaudio2); - xaudio2 = NULL; - } - } - - HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - if (FAILED(hr)) { - fprintf(stderr, "CoInitializeEx failed: %lx\n", hr); - return false; - } - - hr = XAudio2Create(&xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR); - if (FAILED(hr)) { - fprintf(stderr, "XAudio2Create failed: %lx\n", hr); - return false; - } - - update_frequency(); - - 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 false; - } - - wave_format.nSamplesPerSec = audio_frequency; - wave_format.nAvgBytesPerSec = audio_frequency * 4; - 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 false; - } - - - static IXAudio2EngineCallbackVtbl callbacks = { - nop, - nop, - .OnCriticalError = critical_error - }; - - static IXAudio2EngineCallback callbackObject = { - .lpVtbl = &callbacks - }; - - IXAudio2SourceVoice_RegisterForCallbacks(xaudio2, &callbackObject); - - return true; -} - -static void _audio_deinit(void) -{ - _audio_set_paused(true); -} - -GB_AUDIO_DRIVER(XAudio2_7); diff --git a/SDL/audio/xaudio2_7.h b/SDL/audio/xaudio2_7.h deleted file mode 100644 index 649f410..0000000 --- a/SDL/audio/xaudio2_7.h +++ /dev/null @@ -1,124 +0,0 @@ -#define INITGUID -#include - -/* 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 IXAudio2EngineCallback -DECLARE_INTERFACE(IXAudio2EngineCallback) -{ - // Called by XAudio2 just before an audio processing pass begins. - STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE; - - // Called just after an audio processing pass ends. - STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE; - - // Called in the event of a critical system error which requires XAudio2 - // to be closed down and restarted. The error code is given in Error. - STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE; -}; - -#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; - - STDMETHOD(RegisterForCallbacks) (THIS_ __in IXAudio2EngineCallback *pCallback) PURE; - 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_RegisterForCallbacks(This, pCallback) ((This)->lpVtbl->RegisterForCallbacks(This,pCallback)) -#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 - -// WASAPI extras. This is a hack, but Windows itself is a hack so I don't care -DEFINE_CLSID(MMDeviceEnumerator, bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e); -DEFINE_IID(IMMDeviceEnumerator, a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6);