From 7b20300f6d952de30c18bfd25d3d9d66b21ed2f8 Mon Sep 17 00:00:00 2001 From: Sour Date: Sun, 24 Nov 2019 10:53:53 -0500 Subject: [PATCH] DirectSound: Fixed latency issue that caused sound to cut off within the first second after loading a rom after starting the emulator --- Core/BaseSoundManager.h | 2 +- Core/IAudioDevice.h | 3 ++- Core/SoundMixer.cpp | 4 +++- Libretro/LibretroSoundManager.h | 4 ++++ Linux/SdlSoundManager.cpp | 21 ++++++++++++++------- Linux/SdlSoundManager.h | 13 +++++++------ Windows/SoundManager.cpp | 23 +++++++++++++++++------ Windows/SoundManager.h | 16 +++++++++------- 8 files changed, 57 insertions(+), 29 deletions(-) diff --git a/Core/BaseSoundManager.h b/Core/BaseSoundManager.h index f02d289c..4d458d5d 100644 --- a/Core/BaseSoundManager.h +++ b/Core/BaseSoundManager.h @@ -5,7 +5,7 @@ class BaseSoundManager : public IAudioDevice { public: void ProcessLatency(uint32_t readPosition, uint32_t writePosition); - AudioStatistics GetStatistics(); + AudioStatistics GetStatistics() override; protected: bool _isStereo; diff --git a/Core/IAudioDevice.h b/Core/IAudioDevice.h index 105a5111..33e42908 100644 --- a/Core/IAudioDevice.h +++ b/Core/IAudioDevice.h @@ -17,7 +17,8 @@ class IAudioDevice virtual void Stop() = 0; virtual void Pause() = 0; virtual void ProcessEndOfFrame() = 0; - + virtual void UpdateSoundSettings() = 0; + virtual string GetAvailableDevices() = 0; virtual void SetAudioDevice(string deviceName) = 0; diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index cef52765..c323fc90 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -92,7 +92,9 @@ void SoundMixer::Reset() UpdateRates(true); UpdateEqualizers(true); - + if(_audioDevice) { + _audioDevice->UpdateSoundSettings(); + } _previousTargetRate = _sampleRate; } diff --git a/Libretro/LibretroSoundManager.h b/Libretro/LibretroSoundManager.h index 97aa4e19..469a8e64 100644 --- a/Libretro/LibretroSoundManager.h +++ b/Libretro/LibretroSoundManager.h @@ -60,6 +60,10 @@ public: { } + virtual void UpdateSoundSettings() override + { + } + virtual void ProcessEndOfFrame() override { } diff --git a/Linux/SdlSoundManager.cpp b/Linux/SdlSoundManager.cpp index 020edc1e..76c1b8d4 100755 --- a/Linux/SdlSoundManager.cpp +++ b/Linux/SdlSoundManager.cpp @@ -8,7 +8,7 @@ SdlSoundManager::SdlSoundManager(shared_ptr console) { _console = console; - if(InitializeAudio(44100, false)) { + if(InitializeAudio(48000, true)) { _console->GetSoundMixer()->RegisterAudioDevice(this); } } @@ -146,18 +146,25 @@ void SdlSoundManager::WriteToBuffer(uint8_t* input, uint32_t len) _writePosition = len - remainingBytes; } } + +void SdlSoundManager::UpdateSoundSettings() +{ + uint32_t sampleRate = _console->GetSettings()->GetSampleRate(); + uint32_t latency = _console->GetSettings()->GetAudioLatency(); + if(_sampleRate != sampleRate || _needReset || _previousLatency != latency) { + Release(); + InitializeAudio(sampleRate, true); + } +} + void SdlSoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) { uint32_t bytesPerSample = (SoundMixer::BitsPerSample / 8) * (isStereo ? 2 : 1); - uint32_t latency = _console->GetSettings()->GetAudioLatency(); - if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset || _previousLatency != latency) { - Release(); - InitializeAudio(sampleRate, isStereo); - } + UpdateSoundSettings(); WriteToBuffer((uint8_t*)soundBuffer, sampleCount * bytesPerSample); - int32_t byteLatency = (int32_t)((float)(sampleRate * latency) / 1000.0f * bytesPerSample); + int32_t byteLatency = (int32_t)((float)(sampleRate * _previousLatency) / 1000.0f * bytesPerSample); int32_t playWriteByteLatency = _writePosition - _readPosition; if(playWriteByteLatency < 0) { playWriteByteLatency = _bufferSize - _readPosition + _writePosition; diff --git a/Linux/SdlSoundManager.h b/Linux/SdlSoundManager.h index 7a1ea932..b5f35fe1 100755 --- a/Linux/SdlSoundManager.h +++ b/Linux/SdlSoundManager.h @@ -10,14 +10,15 @@ public: SdlSoundManager(shared_ptr console); ~SdlSoundManager(); - void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); - void Pause(); - void Stop(); + void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) override; + void Pause() override; + void Stop() override; - void ProcessEndOfFrame(); + void ProcessEndOfFrame() override; + void UpdateSoundSettings() override; - string GetAvailableDevices(); - void SetAudioDevice(string deviceName); + string GetAvailableDevices() override; + void SetAudioDevice(string deviceName) override; private: vector GetAvailableDeviceInfo(); diff --git a/Windows/SoundManager.cpp b/Windows/SoundManager.cpp index 02965800..5e1906a5 100644 --- a/Windows/SoundManager.cpp +++ b/Windows/SoundManager.cpp @@ -14,7 +14,7 @@ SoundManager::SoundManager(shared_ptr console, HWND hwnd) memset(&_audioDeviceID, 0, sizeof(_audioDeviceID)); - if(InitializeDirectSound(44100, false)) { + if(InitializeDirectSound(48000, true)) { _console->GetSoundMixer()->RegisterAudioDevice(this); } else { MessageManager::DisplayMessage("Error", "CouldNotInitializeAudioSystem"); @@ -279,16 +279,27 @@ void SoundManager::ProcessEndOfFrame() } } -void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) +void SoundManager::UpdateSoundSettings() { - uint32_t bytesPerSample = (SoundMixer::BitsPerSample / 8) * (isStereo ? 2 : 1); + uint32_t sampleRate = _console->GetSettings()->GetSampleRate(); uint32_t latency = _console->GetSettings()->GetAudioLatency(); - if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset || latency != _previousLatency) { + if(_sampleRate != sampleRate || _needReset || latency != _previousLatency) { _previousLatency = latency; Release(); - InitializeDirectSound(sampleRate, isStereo); + InitializeDirectSound(sampleRate, true); _secondaryBuffer->SetFrequency(sampleRate); + + //Force DirectSound to initialize fully by starting and stopping playback + //Otherwise the first play operation takes a little while longer and throws off the sound latency + Play(); + Stop(); } +} + +void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) +{ + UpdateSoundSettings(); + uint32_t bytesPerSample = (SoundMixer::BitsPerSample / 8) * (isStereo ? 2 : 1); DWORD currentPlayCursor, safeWriteCursor; _secondaryBuffer->GetCurrentPosition(¤tPlayCursor, &safeWriteCursor); @@ -298,7 +309,7 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32 CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize); if(!_playing) { - DWORD byteLatency = (int32_t)((float)(sampleRate * latency) / 1000.0f * bytesPerSample); + DWORD byteLatency = (int32_t)((float)(sampleRate * _previousLatency) / 1000.0f * bytesPerSample); if(_lastWriteOffset >= byteLatency / 2) { Play(); } diff --git a/Windows/SoundManager.h b/Windows/SoundManager.h index 9a71c34f..d9209872 100644 --- a/Windows/SoundManager.h +++ b/Windows/SoundManager.h @@ -18,16 +18,18 @@ public: ~SoundManager(); void Release(); - void ProcessEndOfFrame(); - void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); - void Play(); - void Pause(); - void Stop(); + void ProcessEndOfFrame() override; + void UpdateSoundSettings() override; + void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) override; + void Pause() override; + void Stop() override; - string GetAvailableDevices(); - void SetAudioDevice(string deviceName); + string GetAvailableDevices() override; + void SetAudioDevice(string deviceName) override; private: + void Play(); + vector GetAvailableDeviceInfo(); static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext); bool InitializeDirectSound(uint32_t sampleRate, bool isStereo);