From f4835674ed47589de24170b8ee9e13bc07dd0abb Mon Sep 17 00:00:00 2001 From: Fabrice de Gans Date: Sat, 6 Apr 2024 17:35:42 -0700 Subject: [PATCH] [Audio] Rework audio devices enumeration This moves all of the audio code in the wx frontend to the `src/wx/audio` folder and simplifies many call sites by having one generic API to enumerate audio devices and create the audio driver. In addition, this fixes many corner cases in device enumerations and moves handling of the default device to the respective audio backends, rather than pushing it to the UI. Finally, this changes the `Sound/AudioDevice` setting to use the underlying device ID, rather than the user-facing name. --- src/wx/CMakeLists.txt | 18 +- src/wx/audio/audio.cpp | 76 +++++ src/wx/audio/audio.h | 30 ++ src/wx/{ => audio/internal}/dsound.cpp | 118 ++++---- src/wx/audio/internal/dsound.h | 22 ++ src/wx/{ => audio/internal}/faudio.cpp | 336 +++++++++++---------- src/wx/audio/internal/faudio.h | 22 ++ src/wx/{ => audio/internal}/openal.cpp | 209 +++++++------ src/wx/audio/internal/openal.h | 18 ++ src/wx/{ => audio/internal}/xaudio2.cpp | 381 +++++++++++------------- src/wx/audio/internal/xaudio2.h | 22 ++ src/wx/dialogs/sound-config.cpp | 78 ++--- src/wx/openal.h | 26 -- src/wx/sys.cpp | 32 +- src/wx/wxvbam.h | 21 -- 15 files changed, 758 insertions(+), 651 deletions(-) create mode 100644 src/wx/audio/audio.cpp create mode 100644 src/wx/audio/audio.h rename src/wx/{ => audio/internal}/dsound.cpp (77%) create mode 100644 src/wx/audio/internal/dsound.h rename src/wx/{ => audio/internal}/faudio.cpp (69%) create mode 100644 src/wx/audio/internal/faudio.h rename src/wx/{ => audio/internal}/openal.cpp (64%) create mode 100644 src/wx/audio/internal/openal.h rename src/wx/{ => audio/internal}/xaudio2.cpp (61%) create mode 100644 src/wx/audio/internal/xaudio2.h delete mode 100644 src/wx/openal.h diff --git a/src/wx/CMakeLists.txt b/src/wx/CMakeLists.txt index 4b961c36..6cf1b787 100644 --- a/src/wx/CMakeLists.txt +++ b/src/wx/CMakeLists.txt @@ -6,6 +6,10 @@ endif() include(VbamFunctions) set(VBAM_WX_COMMON + audio/audio.cpp + audio/audio.h + audio/internal/openal.cpp + audio/internal/openal.h background-input.cpp background-input.h cmdevents.cpp @@ -47,8 +51,6 @@ set(VBAM_WX_COMMON gfxviewers.cpp guiinit.cpp ioregs.h - openal.cpp - openal.h opts.cpp opts.h panel.cpp @@ -249,7 +251,7 @@ endif() if(WIN32) target_sources(visualboyadvance-m PRIVATE - dsound.cpp + audio/internal/dsound.cpp wxvbam.rc ) target_link_libraries(visualboyadvance-m @@ -313,7 +315,7 @@ target_link_libraries(visualboyadvance-m ${OPENAL_LIBRARY}) # XAudio2. if(ENABLE_XAUDIO2) - target_sources(visualboyadvance-m PRIVATE xaudio2.cpp) + target_sources(visualboyadvance-m PRIVATE audio/internal/xaudio2.cpp) target_compile_definitions(visualboyadvance-m PRIVATE VBAM_ENABLE_XAUDIO2) endif() @@ -324,7 +326,7 @@ endif() # FAudio. if(ENABLE_FAUDIO) - target_sources(visualboyadvance-m PRIVATE faudio.cpp) + target_sources(visualboyadvance-m PRIVATE audio/internal/faudio.cpp) target_link_libraries(visualboyadvance-m FAudio::FAudio) target_compile_definitions(visualboyadvance-m PRIVATE VBAM_ENABLE_FAUDIO) endif() @@ -607,6 +609,9 @@ add_custom_command( set(VBAM_LOCALIZABLE_FILES ${VBAM_WX_COMMON}) list(APPEND VBAM_LOCALIZABLE_FILES + audio/internal/dsound.cpp + audio/internal/faudio.cpp + audio/internal/xaudio2.cpp autoupdater/autoupdater.h autoupdater/macos/autoupdater.cpp autoupdater/macos/sparkle-wrapper.h @@ -614,11 +619,8 @@ list(APPEND VBAM_LOCALIZABLE_FILES autoupdater/wxmsw/winsparkle-rc.h autoupdater/wxmsw/winsparkle-wrapper.cpp autoupdater/wxmsw/winsparkle-wrapper.h - dsound.cpp - faudio.cpp widgets/dpi-support.cpp widgets/dpi-support-mac.mm - xaudio2.cpp ${CMAKE_SOURCE_DIR}/src/core/gba/gbaLink.cpp ) diff --git a/src/wx/audio/audio.cpp b/src/wx/audio/audio.cpp new file mode 100644 index 00000000..208dad20 --- /dev/null +++ b/src/wx/audio/audio.cpp @@ -0,0 +1,76 @@ +#include "wx/audio/audio.h" + +#include "wx/audio/internal/openal.h" + +#if defined(__WXMSW__) +#include "wx/audio/internal/dsound.h" +#endif + + +#if defined(VBAM_ENABLE_FAUDIO) +#include "wx/audio/internal/faudio.h" +#endif + +#if defined(VBAM_ENABLE_XAUDIO2) +#include "wx/audio/internal/xaudio2.h" +#endif + +namespace audio { + +std::vector EnumerateAudioDevices(const config::AudioApi& audio_api) { + switch (audio_api) { + case config::AudioApi::kOpenAL: + return audio::internal::GetOpenALDevices(); + +#if defined(__WXMSW__) + case config::AudioApi::kDirectSound: + return audio::internal::GetDirectSoundDevices(); +#endif + +#if defined(VBAM_ENABLE_XAUDIO2) + case config::AudioApi::kXAudio2: + return audio::internal::GetXAudio2Devices(); +#endif + +#if defined(VBAM_ENABLE_FAUDIO) + case config::AudioApi::kFAudio: + return audio::internal::GetFAudioDevices(); +#endif + + case config::AudioApi::kLast: + default: + // This should never happen. + assert(false); + return {}; + } +} + +std::unique_ptr CreateSoundDriver(const config::AudioApi& api) { + switch (api) { + case config::AudioApi::kOpenAL: + return audio::internal::CreateOpenALDriver(); + +#if defined(__WXMSW__) + case config::AudioApi::kDirectSound: + return audio::internal::CreateDirectSoundDriver(); +#endif + +#if defined(VBAM_ENABLE_XAUDIO2) + case config::AudioApi::kXAudio2: + return audio::internal::CreateXAudio2Driver(); +#endif + +#if defined(VBAM_ENABLE_FAUDIO) + case config::AudioApi::kFAudio: + return audio::internal::CreateFAudioDriver(); +#endif + + case config::AudioApi::kLast: + default: + // This should never happen. + assert(false); + return nullptr; + } +} + +} // namespace audio diff --git a/src/wx/audio/audio.h b/src/wx/audio/audio.h new file mode 100644 index 00000000..c4937c49 --- /dev/null +++ b/src/wx/audio/audio.h @@ -0,0 +1,30 @@ +#ifndef WX_AUDIO_AUDIO_H_ +#define WX_AUDIO_AUDIO_H_ + +#include +#include + +#include + +#include "core/base/sound_driver.h" +#include "wx/config/option.h" + +namespace audio { + +// Represents an audio device. +struct AudioDevice { + // The device user-friendly name. + wxString name; + // The underlying device ID. + wxString id; +}; + +// Returns the set of audio devices for the given API. +std::vector EnumerateAudioDevices(const config::AudioApi& api); + +// Creates a sound driver for the given API. +std::unique_ptr CreateSoundDriver(const config::AudioApi& api); + +} // namespace audio + +#endif // WX_AUDIO_AUDIO_H_ diff --git a/src/wx/dsound.cpp b/src/wx/audio/internal/dsound.cpp similarity index 77% rename from src/wx/dsound.cpp rename to src/wx/audio/internal/dsound.cpp index 3b54f416..8cccf72c 100644 --- a/src/wx/dsound.cpp +++ b/src/wx/audio/internal/dsound.cpp @@ -2,6 +2,8 @@ #error "This file should only be compiled on Windows" #endif +#include "wx/audio/internal/dsound.h" + // DirectSound8 #define DIRECTSOUND_VERSION 0x0800 #include @@ -24,14 +26,19 @@ extern bool soundBufferLow; +namespace audio { +namespace internal { + +namespace { + class DirectSound : public SoundDriver { private: - LPDIRECTSOUND8 pDirectSound; // DirectSound interface - LPDIRECTSOUNDBUFFER dsbPrimary; // Primary DirectSound buffer - LPDIRECTSOUNDBUFFER dsbSecondary; // Secondary DirectSound buffer + LPDIRECTSOUND8 pDirectSound; // DirectSound interface + LPDIRECTSOUNDBUFFER dsbPrimary; // Primary DirectSound buffer + LPDIRECTSOUNDBUFFER dsbSecondary; // Secondary DirectSound buffer LPDIRECTSOUNDNOTIFY dsbNotify; HANDLE dsbEvent; - WAVEFORMATEX wfx; // Primary buffer wave format + WAVEFORMATEX wfx; // Primary buffer wave format int soundBufferLen; int soundBufferTotalLen; unsigned int soundNextPosition; @@ -45,12 +52,11 @@ public: void pause() override; void reset() override; void resume() override; - void write(uint16_t *finalWave, int length) override; + void write(uint16_t* finalWave, int length) override; void setThrottle(unsigned short throttle_) override; }; -DirectSound::DirectSound() -{ +DirectSound::DirectSound() { pDirectSound = NULL; dsbPrimary = NULL; dsbSecondary = NULL; @@ -60,8 +66,7 @@ DirectSound::DirectSound() soundNextPosition = 0; } -DirectSound::~DirectSound() -{ +DirectSound::~DirectSound() { if (dsbNotify) { dsbNotify->Release(); dsbNotify = NULL; @@ -88,13 +93,13 @@ DirectSound::~DirectSound() } } -bool DirectSound::init(long sampleRate) -{ +bool DirectSound::init(long sampleRate) { HRESULT hr; DWORD freq; DSBUFFERDESC dsbdesc; int i; - hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound8, (LPVOID*)&pDirectSound); + hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound8, + (LPVOID*)&pDirectSound); if (hr != S_OK) { wxLogError(_("Cannot create Direct Sound %08x"), hr); @@ -116,7 +121,8 @@ bool DirectSound::init(long sampleRate) return false; } - if (FAILED(hr = pDirectSound->SetCooperativeLevel((HWND)wxGetApp().frame->GetHandle(), DSSCL_PRIORITY))) { + if (FAILED(hr = pDirectSound->SetCooperativeLevel((HWND)wxGetApp().frame->GetHandle(), + DSSCL_PRIORITY))) { wxLogError(_("Cannot SetCooperativeLevel %08x"), hr); return false; } @@ -158,7 +164,8 @@ bool DirectSound::init(long sampleRate) // Create secondary sound buffer ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY; + dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | + DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY; if (!hw_accel) { dsbdesc.dwFlags |= DSBCAPS_LOCSOFTWARE; @@ -177,7 +184,8 @@ bool DirectSound::init(long sampleRate) return false; } - if (SUCCEEDED(hr = dsbSecondary->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*)&dsbNotify))) { + if (SUCCEEDED(hr = + dsbSecondary->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*)&dsbNotify))) { dsbEvent = CreateEvent(NULL, FALSE, FALSE, NULL); DSBPOSITIONNOTIFY notify[10]; @@ -207,7 +215,7 @@ void DirectSound::setThrottle(unsigned short throttle_) { HRESULT hr; if (throttle_ == 0) - throttle_ = 450; // Close to upper bound on frequency. + throttle_ = 450; // Close to upper bound on frequency. long freq = soundGetSampleRate(); @@ -216,8 +224,7 @@ void DirectSound::setThrottle(unsigned short throttle_) { } } -void DirectSound::pause() -{ +void DirectSound::pause() { LPDIRECTSOUNDBUFFER bufs[] = {dsbPrimary, dsbSecondary}; for (auto buf : bufs) { if (buf == NULL) @@ -231,8 +238,7 @@ void DirectSound::pause() } } -void DirectSound::reset() -{ +void DirectSound::reset() { if (dsbSecondary == NULL) return; @@ -241,8 +247,7 @@ void DirectSound::reset() soundNextPosition = 0; } -void DirectSound::resume() -{ +void DirectSound::resume() { LPDIRECTSOUNDBUFFER bufs[] = {dsbPrimary, dsbSecondary}; for (auto buf : bufs) { if (buf == NULL) @@ -252,8 +257,7 @@ void DirectSound::resume() } } -void DirectSound::write(uint16_t* finalWave, int) -{ +void DirectSound::write(uint16_t* finalWave, int) { if (!pDirectSound) return; @@ -272,7 +276,9 @@ void DirectSound::write(uint16_t* finalWave, int) if (!soundPaused) { while (true) { dsbSecondary->GetCurrentPosition(&play, NULL); - int BufferLeft = ((soundNextPosition <= play) ? play - soundNextPosition : soundBufferTotalLen - soundNextPosition + play); + int BufferLeft = ((soundNextPosition <= play) + ? play - soundNextPosition + : soundBufferTotalLen - soundNextPosition + play); if (BufferLeft > soundBufferLen) { if (BufferLeft > soundBufferTotalLen - (soundBufferLen * 3)) @@ -297,24 +303,12 @@ void DirectSound::write(uint16_t* finalWave, int) // Obtain memory address of write block. // This will be in two parts if the block wraps around. - if (DSERR_BUFFERLOST == (hr = dsbSecondary->Lock( - soundNextPosition, - soundBufferLen, - &lpvPtr1, - &dwBytes1, - &lpvPtr2, - &dwBytes2, - 0))) { + if (DSERR_BUFFERLOST == (hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen, &lpvPtr1, + &dwBytes1, &lpvPtr2, &dwBytes2, 0))) { // If DSERR_BUFFERLOST is returned, restore and retry lock. dsbSecondary->Restore(); - hr = dsbSecondary->Lock( - soundNextPosition, - soundBufferLen, - &lpvPtr1, - &dwBytes1, - &lpvPtr2, - &dwBytes2, - 0); + hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen, &lpvPtr1, &dwBytes1, &lpvPtr2, + &dwBytes2, 0); } soundNextPosition += soundBufferLen; @@ -336,27 +330,33 @@ void DirectSound::write(uint16_t* finalWave, int) } } -std::unique_ptr newDirectSound() -{ - return std::make_unique(); -} +static BOOL CALLBACK DSEnumCB(LPGUID guid, LPCTSTR desc, LPCTSTR /*module*/, LPVOID user) { + std::vector* devices = static_cast*>(user); -struct devnames { - wxArrayString *names, *ids; -}; + if (guid == nullptr) { + devices->push_back({desc, {}}); + return TRUE; + } -static BOOL CALLBACK DSEnumCB(LPGUID guid, LPCTSTR desc, LPCTSTR, LPVOID user) -{ - devnames* dn = (devnames*)user; - dn->names->push_back(desc); - WCHAR buf[32 + 4 + 2 + 1]; // hex digits + "-" + "{}" + \0 - StringFromGUID2(*guid, buf, sizeof(buf)); - dn->ids->push_back(buf); + static constexpr size_t kGuidLength = 32 + 4 + 2 + 1; // hex digits + "-" + "{}" + \0 + std::array device_id; + StringFromGUID2(*guid, device_id.data(), device_id.size()); + + devices->push_back({desc, device_id.data()}); return TRUE; } -bool GetDSDevices(wxArrayString& names, wxArrayString& ids) -{ - devnames dn = { &names, &ids }; - return DirectSoundEnumerate(DSEnumCB, (LPVOID)&dn) == DS_OK; +} // namespace + +std::vector GetDirectSoundDevices() { + std::vector devices; + DirectSoundEnumerateW(DSEnumCB, &devices); + return devices; } + +std::unique_ptr CreateDirectSoundDriver() { + return std::make_unique(); +} + +} // namespace internal +} // namespace audio diff --git a/src/wx/audio/internal/dsound.h b/src/wx/audio/internal/dsound.h new file mode 100644 index 00000000..a9e83ca4 --- /dev/null +++ b/src/wx/audio/internal/dsound.h @@ -0,0 +1,22 @@ +#ifndef WX_AUDIO_INTERNAL_DSOUND_H_ +#define WX_AUDIO_INTERNAL_DSOUND_H_ + +#if !defined(__WXMSW__) +#error "This file should only be included on Windows" +#endif + +#include "wx/audio/audio.h" + +namespace audio { +namespace internal { + +// Returns the set of DirectSound devices. +std::vector GetDirectSoundDevices(); + +// Creates a DirectSound sound driver. +std::unique_ptr CreateDirectSoundDriver(); + +} // namespace internal +} // namespace audio + +#endif // WX_AUDIO_INTERNAL_DSOUND_H_ diff --git a/src/wx/faudio.cpp b/src/wx/audio/internal/faudio.cpp similarity index 69% rename from src/wx/faudio.cpp rename to src/wx/audio/internal/faudio.cpp index a46b5178..e0fe31c0 100644 --- a/src/wx/faudio.cpp +++ b/src/wx/audio/internal/faudio.cpp @@ -1,10 +1,12 @@ +#include #if !defined(VBAM_ENABLE_FAUDIO) #error "This file should only be compiled if FAudio is enabled" #endif -#include +#include "wx/audio/internal/faudio.h" + +#include -#include #include // FAudio @@ -16,63 +18,50 @@ #include #include -#include "core/base/sound_driver.h" #include "core/base/system.h" #include "core/gba/gbaGlobals.h" #include "wx/config/option-proxy.h" +namespace audio { +namespace internal { + namespace { -int GetFADevices(FAudio* fa, wxArrayString* names, wxArrayString* ids, - const wxString* match) -{ +int FAGetDev(FAudio* fa) { + const wxString& audio_device = OPTION(kSoundAudioDevice); + if (audio_device.empty()) { + // Just use the default device. + return 0; + } + uint32_t hr; uint32_t dev_count = 0; hr = FAudio_GetDeviceCount(fa, &dev_count); - if (hr != 0) { wxLogError(_("FAudio: Enumerating devices failed!")); - return -1; - } else { - FAudioDeviceDetails dd; + return 0; + } - for (uint32_t i = 0; i < dev_count; i++) { - hr = FAudio_GetDeviceDetails(fa, i, &dd); - - if (hr != 0) { - continue; - } else { - if (ids) { - ids->push_back((wchar_t*) dd.DeviceID); - names->push_back((wchar_t*) dd.DisplayName); - } else if (*match == wxString((wchar_t*) dd.DeviceID)) - return i; - } + FAudioDeviceDetails dd; + for (uint32_t i = 0; i < dev_count; i++) { + hr = FAudio_GetDeviceDetails(fa, i, &dd); + if (hr != 0) { + continue; + } + const wxString device_id(reinterpret_cast(dd.DeviceID)); + if (audio_device == device_id) { + return i; } } - return -1; -} - -int FAGetDev(FAudio* fa) -{ - const wxString& audio_device = OPTION(kSoundAudioDevice); - if (audio_device.empty()) - return 0; - else { - int ret = GetFADevices(fa, nullptr, nullptr, &audio_device); - return ret < 0 ? 0 : ret; - } + return 0; } class FAudio_BufferNotify : public FAudioVoiceCallback { public: - bool WaitForSignal() { - return WaitForSingleObject(buffer_end_event_, 10000) != WAIT_TIMEOUT; - } + bool WaitForSignal() { return WaitForSingleObject(buffer_end_event_, 10000) != WAIT_TIMEOUT; } - FAudio_BufferNotify() - { + FAudio_BufferNotify() { buffer_end_event_ = nullptr; buffer_end_event_ = CreateEvent(nullptr, FALSE, FALSE, nullptr); assert(buffer_end_event_ != nullptr); @@ -85,8 +74,7 @@ public: OnLoopEnd = &FAudio_BufferNotify::StaticOnLoopEnd; OnVoiceError = &FAudio_BufferNotify::StaticOnVoiceError; } - ~FAudio_BufferNotify() - { + ~FAudio_BufferNotify() { CloseHandle(buffer_end_event_); buffer_end_event_ = nullptr; } @@ -108,8 +96,7 @@ private: static void StaticOnVoiceError(FAudioVoiceCallback*, void*, uint32_t) {} }; -class FAudio_Output - : public SoundDriver { +class FAudio_Output : public SoundDriver { public: FAudio_Output(); ~FAudio_Output(); @@ -139,11 +126,11 @@ private: volatile bool device_changed; FAudio* faud; - FAudioMasteringVoice* mVoice; // listener - FAudioSourceVoice* sVoice; // sound source + FAudioMasteringVoice* mVoice; // listener + FAudioSourceVoice* sVoice; // sound source FAudioBuffer buf; FAudioVoiceState vState; - FAudio_BufferNotify notify; // buffer end notification + FAudio_BufferNotify notify; // buffer end notification }; class FAudio_Device_Notifier : public IMMNotificationClient { @@ -162,7 +149,9 @@ public: ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface); - HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId); + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, + ERole role, + LPCWSTR pwstrDeviceId); HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId); HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId); HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState); @@ -190,14 +179,12 @@ FAudio_Output::FAudio_Output() : buffer_count_(OPTION(kSoundBuffers)) { f_notifier.do_register(this); } -FAudio_Output::~FAudio_Output() -{ +FAudio_Output::~FAudio_Output() { f_notifier.do_unregister(this); close(); } -void FAudio_Output::close() -{ +void FAudio_Output::close() { initialized = false; if (sVoice) { @@ -220,22 +207,20 @@ void FAudio_Output::close() } } -void FAudio_Output::device_change() -{ +void FAudio_Output::device_change() { device_changed = true; } -bool FAudio_Output::init(long sampleRate) -{ +bool FAudio_Output::init(long sampleRate) { if (failed || initialized) return false; uint32_t hr; // Initialize FAudio uint32_t flags = 0; - //#ifdef _DEBUG + // #ifdef _DEBUG // flags = FAUDIO_DEBUG_ENGINE; - //#endif + // #endif hr = FAudioCreate(&faud, flags, FAUDIO_DEFAULT_PROCESSOR); if (hr != 0) { @@ -255,8 +240,8 @@ bool FAudio_Output::init(long sampleRate) static const uint16_t kNumChannels = 2; static const uint16_t kBitsPerSample = 16; static const uint16_t kBlockAlign = kNumChannels * (kBitsPerSample / 8); - FAudioWaveFormatEx wfx { - /*.wFormatTag=*/ FAUDIO_FORMAT_PCM, + FAudioWaveFormatEx wfx{ + /*.wFormatTag=*/FAUDIO_FORMAT_PCM, /*.nChannels=*/kNumChannels, /*.nSamplesPerSec=*/freq_, /*.nAvgBytesPerSec=*/freq_ * kBlockAlign, @@ -286,96 +271,96 @@ bool FAudio_Output::init(long sampleRate) if (OPTION(kSoundUpmix)) { // set up stereo upmixing - FAudioDeviceDetails dd {}; + FAudioDeviceDetails dd{}; assert(FAudio_GetDeviceDetails(faud, 0, &dd) == 0); std::vector matrix(sizeof(float) * 2 * dd.OutputFormat.Format.nChannels); bool matrixAvailable = true; switch (dd.OutputFormat.Format.nChannels) { - case 4: // 4.0 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Back L*/ matrix[4] = 1.0000f; - matrix[5] = 0.0000f; - /*Back R*/ matrix[6] = 0.0000f; - matrix[7] = 1.0000f; - break; + case 4: // 4.0 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Back L*/ matrix[4] = 1.0000f; + matrix[5] = 0.0000f; + /*Back R*/ matrix[6] = 0.0000f; + matrix[7] = 1.0000f; + break; - case 5: // 5.0 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*Side L*/ matrix[6] = 1.0000f; - matrix[7] = 0.0000f; - /*Side R*/ matrix[8] = 0.0000f; - matrix[9] = 1.0000f; - break; + case 5: // 5.0 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*Side L*/ matrix[6] = 1.0000f; + matrix[7] = 0.0000f; + /*Side R*/ matrix[8] = 0.0000f; + matrix[9] = 1.0000f; + break; - case 6: // 5.1 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*LFE */ matrix[6] = 0.0000f; - matrix[7] = 0.0000f; - /*Side L*/ matrix[8] = 1.0000f; - matrix[9] = 0.0000f; - /*Side R*/ matrix[10] = 0.0000f; - matrix[11] = 1.0000f; - break; + case 6: // 5.1 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*LFE */ matrix[6] = 0.0000f; + matrix[7] = 0.0000f; + /*Side L*/ matrix[8] = 1.0000f; + matrix[9] = 0.0000f; + /*Side R*/ matrix[10] = 0.0000f; + matrix[11] = 1.0000f; + break; - case 7: // 6.1 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*LFE */ matrix[6] = 0.0000f; - matrix[7] = 0.0000f; - /*Side L*/ matrix[8] = 1.0000f; - matrix[9] = 0.0000f; - /*Side R*/ matrix[10] = 0.0000f; - matrix[11] = 1.0000f; - /*Back C*/ matrix[12] = 0.7071f; - matrix[13] = 0.7071f; - break; + case 7: // 6.1 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*LFE */ matrix[6] = 0.0000f; + matrix[7] = 0.0000f; + /*Side L*/ matrix[8] = 1.0000f; + matrix[9] = 0.0000f; + /*Side R*/ matrix[10] = 0.0000f; + matrix[11] = 1.0000f; + /*Back C*/ matrix[12] = 0.7071f; + matrix[13] = 0.7071f; + break; - case 8: // 7.1 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*LFE */ matrix[6] = 0.0000f; - matrix[7] = 0.0000f; - /*Back L*/ matrix[8] = 1.0000f; - matrix[9] = 0.0000f; - /*Back R*/ matrix[10] = 0.0000f; - matrix[11] = 1.0000f; - /*Side L*/ matrix[12] = 1.0000f; - matrix[13] = 0.0000f; - /*Side R*/ matrix[14] = 0.0000f; - matrix[15] = 1.0000f; - break; + case 8: // 7.1 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*LFE */ matrix[6] = 0.0000f; + matrix[7] = 0.0000f; + /*Back L*/ matrix[8] = 1.0000f; + matrix[9] = 0.0000f; + /*Back R*/ matrix[10] = 0.0000f; + matrix[11] = 1.0000f; + /*Side L*/ matrix[12] = 1.0000f; + matrix[13] = 0.0000f; + /*Side R*/ matrix[14] = 0.0000f; + matrix[15] = 1.0000f; + break; - default: - matrixAvailable = false; - break; + default: + matrixAvailable = false; + break; } if (matrixAvailable) { @@ -445,8 +430,7 @@ void FAudio_Output::write(uint16_t* finalWave, int) { assert(hr == 0); } -void FAudio_Output::pause() -{ +void FAudio_Output::pause() { if (!initialized || failed) return; @@ -457,8 +441,7 @@ void FAudio_Output::pause() } } -void FAudio_Output::resume() -{ +void FAudio_Output::resume() { if (!initialized || failed) return; @@ -469,8 +452,7 @@ void FAudio_Output::resume() } } -void FAudio_Output::reset() -{ +void FAudio_Output::reset() { if (!initialized || failed) return; @@ -484,8 +466,7 @@ void FAudio_Output::reset() playing = true; } -void FAudio_Output::setThrottle(unsigned short throttle_) -{ +void FAudio_Output::setThrottle(unsigned short throttle_) { if (!initialized || failed) return; @@ -497,28 +478,22 @@ void FAudio_Output::setThrottle(unsigned short throttle_) assert(hr == 0); } -FAudio_Device_Notifier::FAudio_Device_Notifier() - : registered(0) -{ +FAudio_Device_Notifier::FAudio_Device_Notifier() : registered(0) { InitializeCriticalSection(&lock); } -FAudio_Device_Notifier::~FAudio_Device_Notifier() -{ +FAudio_Device_Notifier::~FAudio_Device_Notifier() { DeleteCriticalSection(&lock); } -ULONG STDMETHODCALLTYPE FAudio_Device_Notifier::AddRef() -{ +ULONG STDMETHODCALLTYPE FAudio_Device_Notifier::AddRef() { return 1; } -ULONG STDMETHODCALLTYPE FAudio_Device_Notifier::Release() -{ +ULONG STDMETHODCALLTYPE FAudio_Device_Notifier::Release() { return 1; } -HRESULT STDMETHODCALLTYPE FAudio_Device_Notifier::QueryInterface(REFIID riid, VOID** ppvInterface) -{ +HRESULT STDMETHODCALLTYPE FAudio_Device_Notifier::QueryInterface(REFIID riid, VOID** ppvInterface) { if (IID_IUnknown == riid) { *ppvInterface = (IUnknown*)this; } else if (__uuidof(IMMNotificationClient) == riid) { @@ -562,8 +537,7 @@ HRESULT STDMETHODCALLTYPE FAudio_Device_Notifier::OnPropertyValueChanged(LPCWSTR return S_OK; } -void FAudio_Device_Notifier::do_register(FAudio_Output* p_instance) -{ +void FAudio_Device_Notifier::do_register(FAudio_Output* p_instance) { if (InterlockedIncrement(®istered) == 1) { pEnumerator = nullptr; HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, @@ -579,8 +553,7 @@ void FAudio_Device_Notifier::do_register(FAudio_Output* p_instance) LeaveCriticalSection(&lock); } -void FAudio_Device_Notifier::do_unregister(FAudio_Output* p_instance) -{ +void FAudio_Device_Notifier::do_unregister(FAudio_Output* p_instance) { if (InterlockedDecrement(®istered) == 0) { if (pEnumerator) { pEnumerator->UnregisterEndpointNotificationCallback(this); @@ -601,13 +574,11 @@ void FAudio_Device_Notifier::do_unregister(FAudio_Output* p_instance) LeaveCriticalSection(&lock); } - } // namespace -bool GetFADevices(wxArrayString& names, wxArrayString& ids) -{ - uint32_t hr; +std::vector GetFAudioDevices() { FAudio* fa = nullptr; + uint32_t hr; uint32_t flags = 0; #ifdef _DEBUG flags = FAUDIO_DEBUG_ENGINE; @@ -616,15 +587,40 @@ bool GetFADevices(wxArrayString& names, wxArrayString& ids) if (hr != 0) { wxLogError(_("The FAudio interface failed to initialize!")); - return false; + return {}; + } + + uint32_t dev_count = 0; + hr = FAudio_GetDeviceCount(fa, &dev_count); + if (hr != 0) { + wxLogError(_("FAudio: Enumerating devices failed!")); + return {}; + } + + std::vector devices; + devices.reserve(dev_count + 1); + devices.push_back({_("Default device"), wxEmptyString}); + + for (uint32_t i = 0; i < dev_count; i++) { + FAudioDeviceDetails dd; + hr = FAudio_GetDeviceDetails(fa, i, &dd); + if (hr != 0) { + continue; + } + + const wxString display_name(reinterpret_cast(dd.DisplayName)); + const wxString device_id(reinterpret_cast(dd.DeviceID)); + + devices.push_back({display_name, device_id}); } - GetFADevices(fa, &names, &ids, nullptr); FAudio_Release(fa); - return true; + return devices; } -// Class Declaration -std::unique_ptr newFAudio_Output() { +std::unique_ptr CreateFAudioDriver() { return std::make_unique(); } + +} // namespace internal +} // namespace audio \ No newline at end of file diff --git a/src/wx/audio/internal/faudio.h b/src/wx/audio/internal/faudio.h new file mode 100644 index 00000000..744963dd --- /dev/null +++ b/src/wx/audio/internal/faudio.h @@ -0,0 +1,22 @@ +#ifndef WX_AUDIO_INTERNAL_FAUDIO_H_ +#define WX_AUDIO_INTERNAL_FAUDIO_H_ + +#if !defined(VBAM_ENABLE_FAUDIO) +#error "This file should only be included if FAudio is enabled" +#endif + +#include "wx/audio/audio.h" + +namespace audio { +namespace internal { + +// Returns the set of FAudio devices. +std::vector GetFAudioDevices(); + +// Creates an FAudio sound driver. +std::unique_ptr CreateFAudioDriver(); + +} // namespace internal +} // namespace audio + +#endif // WX_AUDIO_INTERNAL_FAUDIO_H_ diff --git a/src/wx/openal.cpp b/src/wx/audio/internal/openal.cpp similarity index 64% rename from src/wx/openal.cpp rename to src/wx/audio/internal/openal.cpp index a52cc01c..deb84dc8 100644 --- a/src/wx/openal.cpp +++ b/src/wx/audio/internal/openal.cpp @@ -1,18 +1,51 @@ -// === LOGALL writes very detailed informations to vba-trace.log === -//#define LOGALL +#include "wx/audio/internal/openal.h" -#include "wx/openal.h" +// === LOGALL writes very detailed informations to vba-trace.log === +// #define LOGALL + +// on win32 and mac, pointer typedefs only happen with AL_NO_PROTOTYPES +// on mac, ALC_NO_PROTOTYPES as well + +// #define AL_NO_PROTOTYPES 1 + +// on mac, alc pointer typedefs ony happen for ALC if ALC_NO_PROTOTYPES +// unfortunately, there is a bug in the system headers (use of ALCvoid when +// void should be used; shame on Apple for introducing this error, and shame +// on Creative for making a typedef to void in the first place) +// #define ALC_NO_PROTOTYPES 1 + +#include +#include + +// since the ALC typedefs are broken on Mac: + +#ifdef __WXMAC__ +typedef ALCcontext*(ALC_APIENTRY* LPALCCREATECONTEXT)(ALCdevice* device, const ALCint* attrlist); +typedef ALCboolean(ALC_APIENTRY* LPALCMAKECONTEXTCURRENT)(ALCcontext* context); +typedef void(ALC_APIENTRY* LPALCDESTROYCONTEXT)(ALCcontext* context); +typedef ALCdevice*(ALC_APIENTRY* LPALCOPENDEVICE)(const ALCchar* devicename); +typedef ALCboolean(ALC_APIENTRY* LPALCCLOSEDEVICE)(ALCdevice* device); +typedef ALCboolean(ALC_APIENTRY* LPALCISEXTENSIONPRESENT)(ALCdevice* device, + const ALCchar* extname); +typedef const ALCchar*(ALC_APIENTRY* LPALCGETSTRING)(ALCdevice* device, ALCenum param); +#endif #include #include +#include +#include #include -#include "core/base/sound_driver.h" #include "core/gba/gbaGlobals.h" #include "core/gba/gbaSound.h" #include "wx/config/option-proxy.h" +namespace audio { +namespace internal { + +namespace { + // Debug #define ASSERT_SUCCESS assert(AL_NO_ERROR == alGetError()) @@ -22,8 +55,10 @@ #undef winlog #endif // https://stackoverflow.com/a/1306690/262458 -#define winlog(x,...) do {} while(0) -#define debugState() // +#define winlog(x, ...) \ + do { \ + } while (0) +#define debugState() // #endif struct OPENALFNTABLE; @@ -33,13 +68,13 @@ public: OpenAL(); ~OpenAL() override; - static bool GetDevices(wxArrayString& names, wxArrayString& ids); - bool init(long sampleRate); // initialize the sound buffer queue - void setThrottle(unsigned short throttle_); // set game speed - void pause(); // pause the secondary sound buffer - void reset(); // stop and reset the secondary sound buffer - void resume(); // play/resume the secondary sound buffer - void write(uint16_t* finalWave, int length); // write the emulated sound to a sound buffer + bool init(long sampleRate) override; // initialize the sound buffer queue + void setThrottle(unsigned short throttle_) override; // set game speed + void pause() override; // pause the secondary sound buffer + void reset() override; // stop and reset the secondary sound buffer + void resume() override; // play/resume the secondary sound buffer + void write(uint16_t* finalWave, + int length) override; // write the emulated sound to a sound buffer private: bool initialized; @@ -57,20 +92,18 @@ private: #endif }; -OpenAL::OpenAL() -{ +OpenAL::OpenAL() { initialized = false; buffersLoaded = false; - device = NULL; - context = NULL; + device = nullptr; + context = nullptr; buffer = (ALuint*)malloc(OPTION(kSoundBuffers) * sizeof(ALuint)); memset(buffer, 0, OPTION(kSoundBuffers) * sizeof(ALuint)); tempBuffer = 0; source = 0; } -OpenAL::~OpenAL() -{ +OpenAL::~OpenAL() { if (!initialized) return; @@ -83,22 +116,21 @@ OpenAL::~OpenAL() alDeleteBuffers(OPTION(kSoundBuffers), buffer); ASSERT_SUCCESS; free(buffer); - alcMakeContextCurrent(NULL); + alcMakeContextCurrent(nullptr); // Wine incorrectly returns ALC_INVALID_VALUE // and then fails the rest of these functions as well // so there will be a leak under Wine, but that's a bug in Wine, not // this code - //ASSERT_SUCCESS; + // ASSERT_SUCCESS; alcDestroyContext(context); - //ASSERT_SUCCESS; + // ASSERT_SUCCESS; alcCloseDevice(device); - //ASSERT_SUCCESS; - alGetError(); // reset error state + // ASSERT_SUCCESS; + alGetError(); // reset error state } #ifdef LOGALL -void OpenAL::debugState() -{ +void OpenAL::debugState() { ALint value = 0; alGetSourcei(source, AL_SOURCE_STATE, &value); ASSERT_SUCCESS; @@ -107,28 +139,27 @@ void OpenAL::debugState() winlog(" State: "); switch (value) { - case AL_INITIAL: - winlog("AL_INITIAL\n"); - break; + case AL_INITIAL: + winlog("AL_INITIAL\n"); + break; - case AL_PLAYING: - winlog("AL_PLAYING\n"); - break; + case AL_PLAYING: + winlog("AL_PLAYING\n"); + break; - case AL_PAUSED: - winlog("AL_PAUSED\n"); - break; + case AL_PAUSED: + winlog("AL_PAUSED\n"); + break; - case AL_STOPPED: - winlog("AL_STOPPED\n"); - break; + case AL_STOPPED: + winlog("AL_STOPPED\n"); + break; - default: - winlog("!unknown!\n"); - break; + default: + winlog("!unknown!\n"); + break; } - alGetSourcei(source, AL_BUFFERS_QUEUED, &value); ASSERT_SUCCESS; winlog(" Buffers in queue: %i\n", value); @@ -138,21 +169,29 @@ void OpenAL::debugState() } #endif -bool OpenAL::init(long sampleRate) -{ +bool OpenAL::init(long sampleRate) { winlog("OpenAL::init\n"); assert(initialized == false); const wxString& audio_device = OPTION(kSoundAudioDevice); if (!audio_device.empty()) { device = alcOpenDevice(audio_device.utf8_str()); + if (device == nullptr) { + // Might be the default device. Try again. + OPTION(kSoundAudioDevice) = wxEmptyString; + device = alcOpenDevice(nullptr); + } } else { - device = alcOpenDevice(NULL); + device = alcOpenDevice(nullptr); } - assert(device != NULL); - context = alcCreateContext(device, NULL); - assert(context != NULL); + if (!device) { + wxLogError(_("OpenAL: Failed to open audio device")); + return false; + } + + context = alcCreateContext(device, nullptr); + assert(context != nullptr); ALCboolean retVal = alcMakeContextCurrent(context); assert(ALC_TRUE == retVal); alGenBuffers(OPTION(kSoundBuffers), buffer); @@ -178,8 +217,7 @@ void OpenAL::setThrottle(unsigned short throttle_) { ASSERT_SUCCESS; } -void OpenAL::resume() -{ +void OpenAL::resume() { if (!initialized) return; @@ -201,8 +239,7 @@ void OpenAL::resume() debugState(); } -void OpenAL::pause() -{ +void OpenAL::pause() { if (!initialized) return; @@ -224,8 +261,7 @@ void OpenAL::pause() debugState(); } -void OpenAL::reset() -{ +void OpenAL::reset() { if (!initialized) return; @@ -247,9 +283,8 @@ void OpenAL::reset() debugState(); } -void OpenAL::write(uint16_t* finalWave, int length) -{ - (void)length; // unused param +void OpenAL::write(uint16_t* finalWave, int length) { + (void)length; // unused param if (!initialized) return; @@ -327,35 +362,39 @@ void OpenAL::write(uint16_t* finalWave, int length) } } -std::unique_ptr newOpenAL() -{ +} // namespace + +std::vector GetOpenALDevices() { + std::vector devices; + +#ifdef ALC_DEVICE_SPECIFIER + + if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_FALSE) { + // this extension isn't critical to OpenAL operating + return devices; + } + + const char* devs = alcGetString(nullptr, ALC_DEVICE_SPECIFIER); + + while (*devs) { + const wxString device_name(devs, wxConvLibc); + devices.push_back({device_name, device_name}); + devs += strlen(devs) + 1; + } + +#else + + devices.push_back({_("Default device"), wxEmptyString}); + +#endif + + return devices; +} + +std::unique_ptr CreateOpenALDriver() { winlog("newOpenAL\n"); return std::make_unique(); } -bool GetOALDevices(wxArrayString& names, wxArrayString& ids) -{ - return OpenAL::GetDevices(names, ids); -} - -bool OpenAL::GetDevices(wxArrayString& names, wxArrayString& ids) -{ -#ifdef ALC_DEVICE_SPECIFIER - - if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_FALSE) - // this extension isn't critical to OpenAL operating - return true; - - const char* devs = alcGetString(NULL, ALC_DEVICE_SPECIFIER); - - while (*devs) { - names.push_back(wxString(devs, wxConvLibc)); - ids.push_back(names[names.size() - 1]); - devs += strlen(devs) + 1; - } - -#endif - - // should work anyway, but must always use default driver - return true; -} +} // namespace internal +} // namespace audio \ No newline at end of file diff --git a/src/wx/audio/internal/openal.h b/src/wx/audio/internal/openal.h new file mode 100644 index 00000000..8c0bf1df --- /dev/null +++ b/src/wx/audio/internal/openal.h @@ -0,0 +1,18 @@ +#ifndef WX_AUDIO_INTERNAL_OPENAL_H_ +#define WX_AUDIO_INTERNAL_OPENAL_H_ + +#include "wx/audio/audio.h" + +namespace audio { +namespace internal { + +// Returns the set of OpenAL devices. +std::vector GetOpenALDevices(); + +// Creates an OpenAL sound driver. +std::unique_ptr CreateOpenALDriver(); + +} // namespace internal +} // namespace audio + +#endif // WX_AUDIO_INTERNAL_OPENAL_H_ diff --git a/src/wx/xaudio2.cpp b/src/wx/audio/internal/xaudio2.cpp similarity index 61% rename from src/wx/xaudio2.cpp rename to src/wx/audio/internal/xaudio2.cpp index 50402f8f..338fa6ec 100644 --- a/src/wx/xaudio2.cpp +++ b/src/wx/audio/internal/xaudio2.cpp @@ -2,6 +2,8 @@ #error "This file should only be compiled if XAudio2 is enabled" #endif +#include "wx/audio/internal/xaudio2.h" + #include #include @@ -14,78 +16,55 @@ #include #else #include -#endif +#endif #include #include #include #include "core/base/sound_driver.h" -#include "core/base/system.h" // for systemMessage() +#include "core/base/system.h" // for systemMessage() #include "core/gba/gbaGlobals.h" #include "wx/config/option-proxy.h" -int GetXA2Devices(IXAudio2* xa, wxArrayString* names, wxArrayString* ids, - const wxString* match) -{ - HRESULT hr; - UINT32 dev_count = 0; - hr = xa->GetDeviceCount(&dev_count); +namespace audio { +namespace internal { - if (hr != S_OK) { - wxLogError(_("XAudio2: Enumerating devices failed!")); - return true; - } else { - XAUDIO2_DEVICE_DETAILS dd; +namespace { - for (UINT32 i = 0; i < dev_count; i++) { - hr = xa->GetDeviceDetails(i, &dd); - - if (hr != S_OK) { - continue; - } else { - if (ids) { - ids->push_back(dd.DeviceID); - names->push_back(dd.DisplayName); - } else if (*match == dd.DeviceID) - return i; - } - } +int XA2GetDev(IXAudio2* xa) { + const wxString& audio_device = OPTION(kSoundAudioDevice); + if (audio_device.empty()) { + // Just use the default device. + return 0; } - return -1; -} - -bool GetXA2Devices(wxArrayString& names, wxArrayString& ids) -{ - HRESULT hr; - IXAudio2* xa = NULL; - hr = XAudio2Create(&xa, 0); - + uint32_t hr; + uint32_t dev_count = 0; + hr = xa->GetDeviceCount(&dev_count); if (hr != S_OK) { - wxLogError(_("The XAudio2 interface failed to initialize!")); + wxLogError(_("XAudio2: Enumerating devices failed!")); return false; } - GetXA2Devices(xa, &names, &ids, NULL); - xa->Release(); - return true; -} - -static int XA2GetDev(IXAudio2* xa) -{ - const wxString& audio_device = OPTION(kSoundAudioDevice); - if (audio_device.empty()) - return 0; - else { - int ret = GetXA2Devices(xa, NULL, NULL, &audio_device); - return ret < 0 ? 0 : ret; + for (UINT32 i = 0; i < dev_count; i++) { + XAUDIO2_DEVICE_DETAILS dd; + hr = xa->GetDeviceDetails(i, &dd); + if (hr != S_OK) { + continue; + } + const wxString device_id(reinterpret_cast(dd.DeviceID)); + if (audio_device == device_id) { + return i; + } } + + return 0; } class XAudio2_Output; -static void xaudio2_device_changed(XAudio2_Output*); +void xaudio2_device_changed(XAudio2_Output*); class XAudio2_Device_Notifier : public IMMNotificationClient { volatile LONG registered; @@ -97,28 +76,14 @@ class XAudio2_Device_Notifier : public IMMNotificationClient { std::vector instances; public: - XAudio2_Device_Notifier() - : registered(0) - { - InitializeCriticalSection(&lock); - } - ~XAudio2_Device_Notifier() - { - DeleteCriticalSection(&lock); - } + XAudio2_Device_Notifier() : registered(0) { InitializeCriticalSection(&lock); } + ~XAudio2_Device_Notifier() { DeleteCriticalSection(&lock); } - ULONG STDMETHODCALLTYPE AddRef() - { - return 1; - } + ULONG STDMETHODCALLTYPE AddRef() { return 1; } - ULONG STDMETHODCALLTYPE Release() - { - return 1; - } + ULONG STDMETHODCALLTYPE Release() { return 1; } - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) - { + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) { if (IID_IUnknown == riid) { *ppvInterface = (IUnknown*)this; } else if (__uuidof(IMMNotificationClient) == riid) { @@ -131,8 +96,7 @@ public: return S_OK; } - HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole, LPCWSTR pwstrDeviceId) - { + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole, LPCWSTR pwstrDeviceId) { if (flow == eRender && last_device.compare(pwstrDeviceId) != 0) { last_device = pwstrDeviceId; EnterCriticalSection(&lock); @@ -152,11 +116,11 @@ public: HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) { return S_OK; } HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) { return S_OK; } - void do_register(XAudio2_Output* p_instance) - { + void do_register(XAudio2_Output* p_instance) { if (InterlockedIncrement(®istered) == 1) { pEnumerator = NULL; - HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); + HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, + __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); if (SUCCEEDED(hr)) { pEnumerator->RegisterEndpointNotificationCallback(this); @@ -168,8 +132,7 @@ public: LeaveCriticalSection(&lock); } - void do_unregister(XAudio2_Output* p_instance) - { + void do_unregister(XAudio2_Output* p_instance) { if (InterlockedDecrement(®istered) == 0) { if (pEnumerator) { pEnumerator->UnregisterEndpointNotificationCallback(this); @@ -196,22 +159,19 @@ class XAudio2_BufferNotify : public IXAudio2VoiceCallback { public: HANDLE hBufferEndEvent; - XAudio2_BufferNotify() - { + XAudio2_BufferNotify() { hBufferEndEvent = NULL; hBufferEndEvent = CreateEvent(NULL, FALSE, FALSE, NULL); assert(hBufferEndEvent != NULL); } - ~XAudio2_BufferNotify() - { + ~XAudio2_BufferNotify() { CloseHandle(hBufferEndEvent); hBufferEndEvent = NULL; } STDMETHOD_(void, OnBufferEnd) - (void*) - { + (void*) { assert(hBufferEndEvent != NULL); SetEvent(hBufferEndEvent); } @@ -232,13 +192,13 @@ public: }; // Class Declaration -class XAudio2_Output - : public SoundDriver { +class XAudio2_Output : public SoundDriver { public: XAudio2_Output(); ~XAudio2_Output() override; void device_change(); + private: void close(); @@ -247,7 +207,7 @@ private: void pause() override; void reset() override; void resume() override; - void write(uint16_t *finalWave, int length) override; + void write(uint16_t* finalWave, int length) override; void setThrottle(unsigned short throttle_) override; bool failed; @@ -262,16 +222,15 @@ private: volatile bool device_changed; IXAudio2* xaud; - IXAudio2MasteringVoice* mVoice; // listener - IXAudio2SourceVoice* sVoice; // sound source + IXAudio2MasteringVoice* mVoice; // listener + IXAudio2SourceVoice* sVoice; // sound source XAUDIO2_BUFFER buf; XAUDIO2_VOICE_STATE vState; - XAudio2_BufferNotify notify; // buffer end notification + XAudio2_BufferNotify notify; // buffer end notification }; // Class Implementation -XAudio2_Output::XAudio2_Output() -{ +XAudio2_Output::XAudio2_Output() { failed = false; initialized = false; playing = false; @@ -288,14 +247,12 @@ XAudio2_Output::XAudio2_Output() g_notifier.do_register(this); } -XAudio2_Output::~XAudio2_Output() -{ +XAudio2_Output::~XAudio2_Output() { g_notifier.do_unregister(this); close(); } -void XAudio2_Output::close() -{ +void XAudio2_Output::close() { initialized = false; if (sVoice) { @@ -324,13 +281,11 @@ void XAudio2_Output::close() } } -void XAudio2_Output::device_change() -{ +void XAudio2_Output::device_change() { device_changed = true; } -bool XAudio2_Output::init(long sampleRate) -{ +bool XAudio2_Output::init(long sampleRate) { if (failed || initialized) return false; @@ -361,13 +316,8 @@ bool XAudio2_Output::init(long sampleRate) wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; // create sound receiver - hr = xaud->CreateMasteringVoice( - &mVoice, - XAUDIO2_DEFAULT_CHANNELS, - XAUDIO2_DEFAULT_SAMPLERATE, - 0, - XA2GetDev(xaud), - NULL); + hr = xaud->CreateMasteringVoice(&mVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, + 0, XA2GetDev(xaud), NULL); if (hr != S_OK) { wxLogError(_("XAudio2: Creating mastering voice failed!")); @@ -399,89 +349,89 @@ bool XAudio2_Output::init(long sampleRate) bool matrixAvailable = true; switch (dd.OutputFormat.Format.nChannels) { - case 4: // 4.0 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Back L*/ matrix[4] = 1.0000f; - matrix[5] = 0.0000f; - /*Back R*/ matrix[6] = 0.0000f; - matrix[7] = 1.0000f; - break; + case 4: // 4.0 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Back L*/ matrix[4] = 1.0000f; + matrix[5] = 0.0000f; + /*Back R*/ matrix[6] = 0.0000f; + matrix[7] = 1.0000f; + break; - case 5: // 5.0 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*Side L*/ matrix[6] = 1.0000f; - matrix[7] = 0.0000f; - /*Side R*/ matrix[8] = 0.0000f; - matrix[9] = 1.0000f; - break; + case 5: // 5.0 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*Side L*/ matrix[6] = 1.0000f; + matrix[7] = 0.0000f; + /*Side R*/ matrix[8] = 0.0000f; + matrix[9] = 1.0000f; + break; - case 6: // 5.1 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*LFE */ matrix[6] = 0.0000f; - matrix[7] = 0.0000f; - /*Side L*/ matrix[8] = 1.0000f; - matrix[9] = 0.0000f; - /*Side R*/ matrix[10] = 0.0000f; - matrix[11] = 1.0000f; - break; + case 6: // 5.1 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*LFE */ matrix[6] = 0.0000f; + matrix[7] = 0.0000f; + /*Side L*/ matrix[8] = 1.0000f; + matrix[9] = 0.0000f; + /*Side R*/ matrix[10] = 0.0000f; + matrix[11] = 1.0000f; + break; - case 7: // 6.1 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*LFE */ matrix[6] = 0.0000f; - matrix[7] = 0.0000f; - /*Side L*/ matrix[8] = 1.0000f; - matrix[9] = 0.0000f; - /*Side R*/ matrix[10] = 0.0000f; - matrix[11] = 1.0000f; - /*Back C*/ matrix[12] = 0.7071f; - matrix[13] = 0.7071f; - break; + case 7: // 6.1 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*LFE */ matrix[6] = 0.0000f; + matrix[7] = 0.0000f; + /*Side L*/ matrix[8] = 1.0000f; + matrix[9] = 0.0000f; + /*Side R*/ matrix[10] = 0.0000f; + matrix[11] = 1.0000f; + /*Back C*/ matrix[12] = 0.7071f; + matrix[13] = 0.7071f; + break; - case 8: // 7.1 - //Speaker \ Left Source Right Source - /*Front L*/ matrix[0] = 1.0000f; - matrix[1] = 0.0000f; - /*Front R*/ matrix[2] = 0.0000f; - matrix[3] = 1.0000f; - /*Front C*/ matrix[4] = 0.7071f; - matrix[5] = 0.7071f; - /*LFE */ matrix[6] = 0.0000f; - matrix[7] = 0.0000f; - /*Back L*/ matrix[8] = 1.0000f; - matrix[9] = 0.0000f; - /*Back R*/ matrix[10] = 0.0000f; - matrix[11] = 1.0000f; - /*Side L*/ matrix[12] = 1.0000f; - matrix[13] = 0.0000f; - /*Side R*/ matrix[14] = 0.0000f; - matrix[15] = 1.0000f; - break; + case 8: // 7.1 + // Speaker \ Left Source Right Source + /*Front L*/ matrix[0] = 1.0000f; + matrix[1] = 0.0000f; + /*Front R*/ matrix[2] = 0.0000f; + matrix[3] = 1.0000f; + /*Front C*/ matrix[4] = 0.7071f; + matrix[5] = 0.7071f; + /*LFE */ matrix[6] = 0.0000f; + matrix[7] = 0.0000f; + /*Back L*/ matrix[8] = 1.0000f; + matrix[9] = 0.0000f; + /*Back R*/ matrix[10] = 0.0000f; + matrix[11] = 1.0000f; + /*Side L*/ matrix[12] = 1.0000f; + matrix[13] = 0.0000f; + /*Side R*/ matrix[14] = 0.0000f; + matrix[15] = 1.0000f; + break; - default: - matrixAvailable = false; - break; + default: + matrixAvailable = false; + break; } if (matrixAvailable) { @@ -502,8 +452,7 @@ bool XAudio2_Output::init(long sampleRate) return true; } -void XAudio2_Output::write(uint16_t* finalWave, int) -{ +void XAudio2_Output::write(uint16_t* finalWave, int) { if (!initialized || failed) return; @@ -548,13 +497,12 @@ void XAudio2_Output::write(uint16_t* finalWave, int) buf.AudioBytes = soundBufferLen; buf.pAudioData = &buffers[currentBuffer * soundBufferLen]; currentBuffer++; - currentBuffer %= (bufferCount + 1); // + 1 because we need one temporary buffer - HRESULT hr = sVoice->SubmitSourceBuffer(&buf); // send buffer to queue + currentBuffer %= (bufferCount + 1); // + 1 because we need one temporary buffer + HRESULT hr = sVoice->SubmitSourceBuffer(&buf); // send buffer to queue assert(hr == S_OK); } -void XAudio2_Output::pause() -{ +void XAudio2_Output::pause() { if (!initialized || failed) return; @@ -565,8 +513,7 @@ void XAudio2_Output::pause() } } -void XAudio2_Output::resume() -{ +void XAudio2_Output::resume() { if (!initialized || failed) return; @@ -577,8 +524,7 @@ void XAudio2_Output::resume() } } -void XAudio2_Output::reset() -{ +void XAudio2_Output::reset() { if (!initialized || failed) return; @@ -592,8 +538,7 @@ void XAudio2_Output::reset() playing = true; } -void XAudio2_Output::setThrottle(unsigned short throttle_) -{ +void XAudio2_Output::setThrottle(unsigned short throttle_) { if (!initialized || failed) return; @@ -604,12 +549,50 @@ void XAudio2_Output::setThrottle(unsigned short throttle_) assert(hr == S_OK); } -void xaudio2_device_changed(XAudio2_Output* instance) -{ +void xaudio2_device_changed(XAudio2_Output* instance) { instance->device_change(); } -std::unique_ptr newXAudio2_Output() -{ +} // namespace + +std::vector GetXAudio2Devices() { + HRESULT hr; + IXAudio2* xa = nullptr; + hr = XAudio2Create(&xa, 0); + + if (hr != S_OK) { + wxLogError(_("The XAudio2 interface failed to initialize!")); + return {}; + } + + UINT32 dev_count = 0; + hr = xa->GetDeviceCount(&dev_count); + if (hr != S_OK) { + wxLogError(_("XAudio2: Enumerating devices failed!")); + return {}; + } + + std::vector devices; + devices.reserve(dev_count + 1); + devices.push_back({_("Default device"), wxEmptyString}); + + for (UINT32 i = 0; i < dev_count; i++) { + XAUDIO2_DEVICE_DETAILS dd; + hr = xa->GetDeviceDetails(i, &dd); + + if (hr != S_OK) { + continue; + } + devices.push_back({dd.DisplayName, dd.DeviceID}); + } + + xa->Release(); + return devices; +} + +std::unique_ptr CreateXAudio2Driver() { return std::make_unique(); } + +} // namespace internal +} // namespace audio diff --git a/src/wx/audio/internal/xaudio2.h b/src/wx/audio/internal/xaudio2.h new file mode 100644 index 00000000..e05c30d2 --- /dev/null +++ b/src/wx/audio/internal/xaudio2.h @@ -0,0 +1,22 @@ +#ifndef WX_AUDIO_INTERNAL_XAUDIO2_H_ +#define WX_AUDIO_INTERNAL_XAUDIO2_H_ + +#if !defined(VBAM_ENABLE_FAUDIO) +#error "This file should only be included if FAudio is enabled" +#endif + +#include "wx/audio/audio.h" + +namespace audio { +namespace internal { + +// Returns the set of XAudio2 devices. +std::vector GetXAudio2Devices(); + +// Creates an XAudio2 sound driver. +std::unique_ptr CreateXAudio2Driver(); + +} // namespace internal +} // namespace audio + +#endif // WX_AUDIO_INTERNAL_XAUDIO2_H_ diff --git a/src/wx/dialogs/sound-config.cpp b/src/wx/dialogs/sound-config.cpp index ebe9130f..64c07d54 100644 --- a/src/wx/dialogs/sound-config.cpp +++ b/src/wx/dialogs/sound-config.cpp @@ -8,15 +8,16 @@ #include #include +#include #include #include +#include "wx/audio/audio.h" #include "wx/config/option-id.h" #include "wx/config/option-proxy.h" #include "wx/config/option.h" #include "wx/dialogs/validated-child.h" #include "wx/widgets/option-validator.h" -#include "wx/wxvbam.h" namespace dialogs { @@ -103,13 +104,18 @@ private: bool WriteToWindow() override { wxChoice* choice = wxDynamicCast(GetWindow(), wxChoice); assert(choice); - const wxString& device = option()->GetString(); - const int selection = choice->FindString(device); - if (selection == wxNOT_FOUND) { - return true; + + const wxString& device_id = option()->GetString(); + for (size_t i = 0; i < choice->GetCount(); i++) { + const wxString& choide_id = + dynamic_cast(choice->GetClientObject(i))->GetData(); + if (device_id == choide_id) { + choice->SetSelection(i); + return true; + } } - choice->SetSelection(selection); + choice->SetSelection(0); return true; } @@ -121,7 +127,8 @@ private: return option()->SetString(wxEmptyString); } - return option()->SetString(choice->GetString(selection)); + return option()->SetString( + dynamic_cast(choice->GetClientObject(selection))->GetData()); } }; @@ -255,56 +262,21 @@ void SoundConfig::OnBuffersChanged(wxCommandEvent& event) { void SoundConfig::OnAudioApiChanged(wxCommandEvent& event, config::AudioApi audio_api) { audio_device_selector_->Clear(); - audio_device_selector_->Append(_("Default device"), new wxStringClientData(wxEmptyString)); - // Gather device names and IDs. - wxArrayString device_names; - wxArrayString device_ids; - switch (audio_api) { - case config::AudioApi::kOpenAL: - if (!GetOALDevices(device_names, device_ids)) { - return; - } - break; + bool audio_device_found = false; + for (const auto& device : audio::EnumerateAudioDevices(audio_api)) { + const int i = + audio_device_selector_->Append(device.name, new wxStringClientData(device.id)); -#if defined(__WXMSW__) - case config::AudioApi::kDirectSound: - if (!(GetDSDevices(device_names, device_ids))) { - return; - } - break; -#endif - -#if defined(VBAM_ENABLE_XAUDIO2) - case config::AudioApi::kXAudio2: - if (!GetXA2Devices(device_names, device_ids)) { - return; - } - break; -#endif - -#if defined(VBAM_ENABLE_FAUDIO) - case config::AudioApi::kFAudio: - if (!GetFADevices(device_names, device_ids)) { - return; - } - break; -#endif - - case config::AudioApi::kLast: - // This should never happen. - assert(false); - return; + if (!audio_device_found && audio_api == OPTION(kSoundAudioAPI) && + OPTION(kSoundAudioDevice) == device.id) { + audio_device_selector_->SetSelection(i); + audio_device_found = true; + } } - audio_device_selector_->SetSelection(0); - - for (size_t i = 0; i < device_names.size(); i++) { - audio_device_selector_->Append(device_names[i], new wxStringClientData(device_ids[i])); - - if (audio_api == OPTION(kSoundAudioAPI) && OPTION(kSoundAudioDevice) == device_ids[i]) { - audio_device_selector_->SetSelection(i + 1); - } + if (!audio_device_found) { + audio_device_selector_->SetSelection(0); } #if defined(VBAM_ENABLE_XAUDIO2) && defined(VBAM_ENABLE_FAUDIO) diff --git a/src/wx/openal.h b/src/wx/openal.h deleted file mode 100644 index 9a737989..00000000 --- a/src/wx/openal.h +++ /dev/null @@ -1,26 +0,0 @@ -// on win32 and mac, pointer typedefs only happen with AL_NO_PROTOTYPES -// on mac, ALC_NO_PROTOTYPES as well - -//#define AL_NO_PROTOTYPES 1 - -// on mac, alc pointer typedefs ony happen for ALC if ALC_NO_PROTOTYPES -// unfortunately, there is a bug in the system headers (use of ALCvoid when -// void should be used; shame on Apple for introducing this error, and shame -// on Creative for making a typedef to void in the first place) -//#define ALC_NO_PROTOTYPES 1 - -#include -#include - -// since the ALC typedefs are broken on Mac: - -#ifdef __WXMAC__ -typedef ALCcontext*(ALC_APIENTRY* LPALCCREATECONTEXT)(ALCdevice* device, const ALCint* attrlist); -typedef ALCboolean(ALC_APIENTRY* LPALCMAKECONTEXTCURRENT)(ALCcontext* context); -typedef void(ALC_APIENTRY* LPALCDESTROYCONTEXT)(ALCcontext* context); -typedef ALCdevice*(ALC_APIENTRY* LPALCOPENDEVICE)(const ALCchar* devicename); -typedef ALCboolean(ALC_APIENTRY* LPALCCLOSEDEVICE)(ALCdevice* device); -typedef ALCboolean(ALC_APIENTRY* LPALCISEXTENSIONPRESENT)(ALCdevice* device, - const ALCchar* extname); -typedef const ALCchar*(ALC_APIENTRY* LPALCGETSTRING)(ALCdevice* device, ALCenum param); -#endif diff --git a/src/wx/sys.cpp b/src/wx/sys.cpp index 8dd02285..590d181f 100644 --- a/src/wx/sys.cpp +++ b/src/wx/sys.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -11,9 +10,9 @@ #include "core/gb/gbGlobals.h" #include "core/gba/gbaGlobals.h" #include "core/gba/gbaSound.h" +#include "wx/audio/audio.h" #include "wx/config/game-control.h" #include "wx/config/option-proxy.h" -#include "wx/config/option.h" #include "wx/wxvbam.h" // These should probably be in vbamcore @@ -1230,34 +1229,7 @@ class SoundDriver; std::unique_ptr systemSoundInit() { soundShutdown(); - - switch (OPTION(kSoundAudioAPI)) { - case config::AudioApi::kOpenAL: - return newOpenAL(); - -#if defined(__WXMSW__) - case config::AudioApi::kDirectSound: - return newDirectSound(); -#endif - -#if defined(VBAM_ENABLE_XAUDIO2) - case config::AudioApi::kXAudio2: - return newXAudio2_Output(); -#endif - -#if defined(VBAM_ENABLE_FAUDIO) - case config::AudioApi::kFAudio: - return newFAudio_Output(); -#endif - - case config::AudioApi::kLast: - // This should never happen. - assert(false); - return nullptr; - } - - assert(false); - return nullptr; + return audio::CreateSoundDriver(OPTION(kSoundAudioAPI)); } void systemOnWriteDataToSoundBuffer(const uint16_t* finalWave, int length) diff --git a/src/wx/wxvbam.h b/src/wx/wxvbam.h index fc488cb9..2752a3e8 100644 --- a/src/wx/wxvbam.h +++ b/src/wx/wxvbam.h @@ -711,27 +711,6 @@ private: #include "wx/opts.h" -// I should add this to SoundDriver, but wxArrayString is wx-specific -// I suppose I could make subclass wxSoundDriver. maybe later. -class SoundDriver; -extern std::unique_ptr newOpenAL(); -extern bool GetOALDevices(wxArrayString& names, wxArrayString& ids); - -#if defined(__WXMSW__) -extern std::unique_ptr newDirectSound(); -extern bool GetDSDevices(wxArrayString& names, wxArrayString& ids); -#endif // defined(__WXMSW__) - -#if defined(VBAM_ENABLE_XAUDIO2) -extern std::unique_ptr newXAudio2_Output(); -extern bool GetXA2Devices(wxArrayString& names, wxArrayString& ids); -#endif // defined(VBAM_ENABLE_XAUDIO2) - -#if defined(VBAM_ENABLE_FAUDIO) -extern std::unique_ptr newFAudio_Output(); -extern bool GetFADevices(wxArrayString& names, wxArrayString& ids); -#endif // defined(VBAM_ENABLE_FAUDIO) - #if defined(VBAM_ENABLE_DEBUGGER) extern bool debugger; extern void (*dbgMain)();