diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 27f7b16d16ad..417d17da45ad 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -616,7 +616,8 @@ void GameSettingsScreen::CreateViews() { altVolume->SetZeroLabel(a->T("Mute")); altVolume->SetNegativeDisable(a->T("Use global volume")); -#ifdef _WIN32 + // Hide the backend selector in UWP builds (we only support XAudio2 there). +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) if (IsVistaOrHigher()) { static const char *backend[] = { "Auto", "DSound (compatible)", "WASAPI (fast)" }; PopupMultiChoice *audioBackend = audioSettings->Add(new PopupMultiChoice(&g_Config.iAudioBackend, a->T("Audio backend", "Audio backend (restart req.)"), backend, 0, ARRAY_SIZE(backend), a->GetName(), screenManager())); @@ -625,7 +626,7 @@ void GameSettingsScreen::CreateViews() { #endif std::vector micList = Microphone::getDeviceList(); - if (micList.size() >= 1) { + if (!micList.empty()) { audioSettings->Add(new ItemHeader(a->T("Microphone"))); PopupMultiChoiceDynamic *MicChoice = audioSettings->Add(new PopupMultiChoiceDynamic(&g_Config.sMicDevice, a->T("Microphone Device"), micList, nullptr, screenManager())); MicChoice->OnChoice.Handle(this, &GameSettingsScreen::OnMicDeviceChange); diff --git a/UWP/StorageFileLoader.cpp b/UWP/StorageFileLoader.cpp index 3dfced89ded8..81c6dde3ae6c 100644 --- a/UWP/StorageFileLoader.cpp +++ b/UWP/StorageFileLoader.cpp @@ -20,12 +20,13 @@ StorageFileLoader::StorageFileLoader(Windows::Storage::StorageFile ^file) { } StorageFileLoader::~StorageFileLoader() { - initMutex.lock(); - active_ = false; - operationRequested_ = false; - cond_.notify_all(); + { + std::unique_lock lock(mutex_); + active_ = false; + operationRequested_ = false; + cond_.notify_all(); + } thread_->join(); - initMutex.unlock(); } void StorageFileLoader::threadfunc() { diff --git a/UWP/XAudioSoundStream.cpp b/UWP/XAudioSoundStream.cpp index fa4bc4dd294a..ec343dd664a1 100644 --- a/UWP/XAudioSoundStream.cpp +++ b/UWP/XAudioSoundStream.cpp @@ -1,192 +1,185 @@ #include "pch.h" -#include #include +#include +#include + +#include "Common/Log.h" #include "Common/Thread/ThreadUtil.h" #include "XAudioSoundStream.h" #include -#define BUFSIZE 0x80000U +const size_t BUFSIZE = 32 * 1024; class XAudioBackend : public WindowsAudioBackend { public: - XAudioBackend(); - ~XAudioBackend() override; + XAudioBackend(); + ~XAudioBackend() override; - bool Init(HWND window, StreamCallback callback, int sampleRate ) override; // If fails, can safely delete the object - void Update() override; - int GetSampleRate() override { return sampleRate_; } + bool Init(HWND window, StreamCallback callback, int sampleRate) override; // If fails, can safely delete the object + void Update() override; + int GetSampleRate() override { return sampleRate_; } private: - inline int ModBufferSize( int x ) { return ( x + BUFSIZE ) % BUFSIZE; } - bool RunSound(); - bool CreateBuffer(); - bool WriteDataToBuffer( char* soundData, DWORD soundBytes ); - void PollLoop(); + bool RunSound(); + bool CreateBuffer(); + void PollLoop(); - StreamCallback callback_; + StreamCallback callback_ = nullptr; - IXAudio2* xaudioDevice; - IXAudio2MasteringVoice* xaudioMaster; - IXAudio2SourceVoice* xaudioVoice; + IXAudio2 *xaudioDevice = nullptr; + IXAudio2MasteringVoice *xaudioMaster = nullptr; + IXAudio2SourceVoice *xaudioVoice = nullptr; - int sampleRate_; + int sampleRate_ = 0; - char realtimeBuffer_[ BUFSIZE ]; - unsigned cursor_; + char realtimeBuffer_[BUFSIZE]{}; + uint32_t cursor_ = 0; - HANDLE thread_; - HANDLE exitEvent_; + HANDLE thread_ = 0; + HANDLE exitEvent_ = 0; - bool exit = false; + bool exit = false; }; // TODO: Get rid of this static XAudioBackend *g_dsound; -inline int RoundDown128( int x ) { - return x & ( ~127 ); +XAudioBackend::XAudioBackend() { + exitEvent_ = CreateEvent(nullptr, true, true, L""); +} + +inline int RoundDown128(int x) { + return x & (~127); } bool XAudioBackend::CreateBuffer() { - if FAILED( xaudioDevice->CreateMasteringVoice( &xaudioMaster, 2, sampleRate_, 0, 0, NULL ) ) - return false; - - WAVEFORMATEX waveFormat; - waveFormat.cbSize = sizeof( waveFormat ); - waveFormat.nAvgBytesPerSec = sampleRate_ * 4; - waveFormat.nBlockAlign = 4; - waveFormat.nChannels = 2; - waveFormat.nSamplesPerSec = sampleRate_; - waveFormat.wBitsPerSample = 16; - waveFormat.wFormatTag = WAVE_FORMAT_PCM; - - if FAILED( xaudioDevice->CreateSourceVoice( &xaudioVoice, &waveFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr ) ) - return false; - - return true; + if FAILED(xaudioDevice->CreateMasteringVoice(&xaudioMaster, 2, sampleRate_, 0, 0, NULL)) + return false; + + WAVEFORMATEX waveFormat; + waveFormat.cbSize = sizeof(waveFormat); + waveFormat.nAvgBytesPerSec = sampleRate_ * 4; + waveFormat.nBlockAlign = 4; + waveFormat.nChannels = 2; + waveFormat.nSamplesPerSec = sampleRate_; + waveFormat.wBitsPerSample = 16; + waveFormat.wFormatTag = WAVE_FORMAT_PCM; + + if FAILED(xaudioDevice->CreateSourceVoice(&xaudioVoice, &waveFormat, 0, 1.0, nullptr, nullptr, nullptr)) + return false; + + xaudioVoice->SetFrequencyRatio(1.0); + return true; } bool XAudioBackend::RunSound() { - if FAILED( XAudio2Create( &xaudioDevice, 0, XAUDIO2_DEFAULT_PROCESSOR ) ) { - xaudioDevice = NULL; - return false; - } - - XAUDIO2_DEBUG_CONFIGURATION dbgCfg; - ZeroMemory( &dbgCfg, sizeof( dbgCfg ) ); - dbgCfg.TraceMask = XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL; - //dbgCfg.BreakMask = XAUDIO2_LOG_ERRORS; - xaudioDevice->SetDebugConfiguration( &dbgCfg ); - - if ( !CreateBuffer() ) { - xaudioDevice->Release(); - xaudioDevice = NULL; - return false; - } - - cursor_ = 0; - - if FAILED( xaudioVoice->Start( 0, XAUDIO2_COMMIT_NOW ) ) { - xaudioDevice->Release(); - xaudioDevice = NULL; - return false; - } - - thread_ = (HANDLE)_beginthreadex( 0, 0, []( void* param ) - { + if FAILED(XAudio2Create(&xaudioDevice, 0, XAUDIO2_DEFAULT_PROCESSOR)) { + xaudioDevice = NULL; + return false; + } + + XAUDIO2_DEBUG_CONFIGURATION dbgCfg; + ZeroMemory(&dbgCfg, sizeof(dbgCfg)); + dbgCfg.TraceMask = XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL; + //dbgCfg.BreakMask = XAUDIO2_LOG_ERRORS; + xaudioDevice->SetDebugConfiguration(&dbgCfg); + + if (!CreateBuffer()) { + xaudioDevice->Release(); + xaudioDevice = NULL; + return false; + } + + cursor_ = 0; + + if FAILED(xaudioVoice->Start(0, XAUDIO2_COMMIT_NOW)) { + xaudioDevice->Release(); + xaudioDevice = NULL; + return false; + } + + thread_ = (HANDLE)_beginthreadex(0, 0, [](void* param) + { setCurrentThreadName("XAudio2"); - XAudioBackend *backend = (XAudioBackend *)param; - backend->PollLoop(); - return 0U; - }, ( void * )this, 0, 0 ); - SetThreadPriority( thread_, THREAD_PRIORITY_ABOVE_NORMAL ); + XAudioBackend *backend = (XAudioBackend *)param; + backend->PollLoop(); + return 0U; + }, (void *)this, 0, 0); + SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL); - return true; -} - -XAudioBackend::XAudioBackend() : xaudioDevice( nullptr ) { - exitEvent_ = CreateEvent( nullptr, true, true, L"" ); + return true; } XAudioBackend::~XAudioBackend() { - if ( !xaudioDevice ) - return; + if (!xaudioDevice) + return; - if ( !xaudioVoice ) - return; + if (!xaudioVoice) + return; - exit = true; - WaitForSingleObject( exitEvent_, INFINITE ); - CloseHandle( exitEvent_ ); + exit = true; + WaitForSingleObject(exitEvent_, INFINITE); + CloseHandle(exitEvent_); - xaudioDevice->Release(); + xaudioDevice->Release(); } -bool XAudioBackend::Init(HWND window, StreamCallback _callback, int sampleRate ) { - callback_ = _callback; - sampleRate_ = sampleRate; - return RunSound(); +bool XAudioBackend::Init(HWND window, StreamCallback _callback, int sampleRate) { + callback_ = _callback; + sampleRate_ = sampleRate; + return RunSound(); } void XAudioBackend::Update() { } -bool XAudioBackend::WriteDataToBuffer( char* soundData, DWORD soundBytes ) { - XAUDIO2_BUFFER xaudioBuffer; - ZeroMemory( &xaudioBuffer, sizeof( xaudioBuffer ) ); - xaudioBuffer.pAudioData = (const BYTE*)soundData; - xaudioBuffer.AudioBytes = soundBytes; - - if FAILED( xaudioVoice->SubmitSourceBuffer( &xaudioBuffer, NULL ) ) - return false; - - return true; -} - -void XAudioBackend::PollLoop() -{ - ResetEvent( exitEvent_ ); +void XAudioBackend::PollLoop() { + ResetEvent(exitEvent_); - while ( !exit ) - { - XAUDIO2_VOICE_STATE state; - xaudioVoice->GetState( &state ); + while (!exit) { + XAUDIO2_VOICE_STATE state; + xaudioVoice->GetState(&state); - if ( state.BuffersQueued < 1 ) - { - int a = 0; - a++; - } + // TODO: Still plenty of tuning to do here. + // 4 seems to work fine. + if (state.BuffersQueued > 4) { + Sleep(1); + continue; + } - unsigned bytesRequired = ( sampleRate_ * 4 ) / 100; + uint32_t bytesRequired = (sampleRate_ * 4) / 100; - while ( bytesRequired ) - { - unsigned bytesLeftInBuffer = BUFSIZE - cursor_; - unsigned readCount = std::min( bytesRequired, bytesLeftInBuffer ); + uint32_t bytesLeftInBuffer = BUFSIZE - cursor_; + uint32_t readCount = std::min(bytesRequired, bytesLeftInBuffer); - int numBytesRendered = 4 * ( *callback_ )( (short*)&realtimeBuffer_[ cursor_ ], readCount / 4, 16, sampleRate_, 2 ); + // realtimeBuffer_ is just used as a ring of scratch space to be submitted, since SubmitSourceBuffer doesn't + // take ownership of the data. It needs to be big enough to fit the max number of buffers we check for + // above, which it is, easily. - WriteDataToBuffer( &realtimeBuffer_[ cursor_ ], numBytesRendered ); - cursor_ += numBytesRendered; - if ( cursor_ >= BUFSIZE ) - { - cursor_ = 0; - bytesLeftInBuffer = BUFSIZE; - } + int stereoSamplesRendered = (*callback_)((short*)&realtimeBuffer_[cursor_], readCount / 4, 16, sampleRate_, 2); + int numBytesRendered = 2 * sizeof(short) * stereoSamplesRendered; - bytesRequired -= numBytesRendered; - } + XAUDIO2_BUFFER xaudioBuffer{}; + xaudioBuffer.pAudioData = (const BYTE*)&realtimeBuffer_[cursor_]; + xaudioBuffer.AudioBytes = numBytesRendered; - Sleep( 2 ); - } + if FAILED(xaudioVoice->SubmitSourceBuffer(&xaudioBuffer, NULL)) { + WARN_LOG(AUDIO, "XAudioBackend: Failed writing bytes"); + } + cursor_ += numBytesRendered; + if (cursor_ >= BUFSIZE) { + cursor_ = 0; + bytesLeftInBuffer = BUFSIZE; + } + } - SetEvent( exitEvent_ ); + SetEvent(exitEvent_); } -WindowsAudioBackend *CreateAudioBackend( AudioBackendType type ) { - return new XAudioBackend(); +WindowsAudioBackend *CreateAudioBackend(AudioBackendType type) { + // Only one type available on UWP. + return new XAudioBackend(); }