DirectSound: Fixed latency issue that caused sound to cut off within the first second after loading a rom after starting the emulator

This commit is contained in:
Sour 2019-11-24 10:53:53 -05:00
parent eacd07d010
commit 7b20300f6d
8 changed files with 57 additions and 29 deletions

View file

@ -5,7 +5,7 @@ class BaseSoundManager : public IAudioDevice
{ {
public: public:
void ProcessLatency(uint32_t readPosition, uint32_t writePosition); void ProcessLatency(uint32_t readPosition, uint32_t writePosition);
AudioStatistics GetStatistics(); AudioStatistics GetStatistics() override;
protected: protected:
bool _isStereo; bool _isStereo;

View file

@ -17,7 +17,8 @@ class IAudioDevice
virtual void Stop() = 0; virtual void Stop() = 0;
virtual void Pause() = 0; virtual void Pause() = 0;
virtual void ProcessEndOfFrame() = 0; virtual void ProcessEndOfFrame() = 0;
virtual void UpdateSoundSettings() = 0;
virtual string GetAvailableDevices() = 0; virtual string GetAvailableDevices() = 0;
virtual void SetAudioDevice(string deviceName) = 0; virtual void SetAudioDevice(string deviceName) = 0;

View file

@ -92,7 +92,9 @@ void SoundMixer::Reset()
UpdateRates(true); UpdateRates(true);
UpdateEqualizers(true); UpdateEqualizers(true);
if(_audioDevice) {
_audioDevice->UpdateSoundSettings();
}
_previousTargetRate = _sampleRate; _previousTargetRate = _sampleRate;
} }

View file

@ -60,6 +60,10 @@ public:
{ {
} }
virtual void UpdateSoundSettings() override
{
}
virtual void ProcessEndOfFrame() override virtual void ProcessEndOfFrame() override
{ {
} }

View file

@ -8,7 +8,7 @@ SdlSoundManager::SdlSoundManager(shared_ptr<Console> console)
{ {
_console = console; _console = console;
if(InitializeAudio(44100, false)) { if(InitializeAudio(48000, true)) {
_console->GetSoundMixer()->RegisterAudioDevice(this); _console->GetSoundMixer()->RegisterAudioDevice(this);
} }
} }
@ -146,18 +146,25 @@ void SdlSoundManager::WriteToBuffer(uint8_t* input, uint32_t len)
_writePosition = len - remainingBytes; _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) 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 bytesPerSample = (SoundMixer::BitsPerSample / 8) * (isStereo ? 2 : 1);
uint32_t latency = _console->GetSettings()->GetAudioLatency(); UpdateSoundSettings();
if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset || _previousLatency != latency) {
Release();
InitializeAudio(sampleRate, isStereo);
}
WriteToBuffer((uint8_t*)soundBuffer, sampleCount * bytesPerSample); 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; int32_t playWriteByteLatency = _writePosition - _readPosition;
if(playWriteByteLatency < 0) { if(playWriteByteLatency < 0) {
playWriteByteLatency = _bufferSize - _readPosition + _writePosition; playWriteByteLatency = _bufferSize - _readPosition + _writePosition;

View file

@ -10,14 +10,15 @@ public:
SdlSoundManager(shared_ptr<Console> console); SdlSoundManager(shared_ptr<Console> console);
~SdlSoundManager(); ~SdlSoundManager();
void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) override;
void Pause(); void Pause() override;
void Stop(); void Stop() override;
void ProcessEndOfFrame(); void ProcessEndOfFrame() override;
void UpdateSoundSettings() override;
string GetAvailableDevices(); string GetAvailableDevices() override;
void SetAudioDevice(string deviceName); void SetAudioDevice(string deviceName) override;
private: private:
vector<string> GetAvailableDeviceInfo(); vector<string> GetAvailableDeviceInfo();

View file

@ -14,7 +14,7 @@ SoundManager::SoundManager(shared_ptr<Console> console, HWND hwnd)
memset(&_audioDeviceID, 0, sizeof(_audioDeviceID)); memset(&_audioDeviceID, 0, sizeof(_audioDeviceID));
if(InitializeDirectSound(44100, false)) { if(InitializeDirectSound(48000, true)) {
_console->GetSoundMixer()->RegisterAudioDevice(this); _console->GetSoundMixer()->RegisterAudioDevice(this);
} else { } else {
MessageManager::DisplayMessage("Error", "CouldNotInitializeAudioSystem"); 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(); uint32_t latency = _console->GetSettings()->GetAudioLatency();
if(_sampleRate != sampleRate || _isStereo != isStereo || _needReset || latency != _previousLatency) { if(_sampleRate != sampleRate || _needReset || latency != _previousLatency) {
_previousLatency = latency; _previousLatency = latency;
Release(); Release();
InitializeDirectSound(sampleRate, isStereo); InitializeDirectSound(sampleRate, true);
_secondaryBuffer->SetFrequency(sampleRate); _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; DWORD currentPlayCursor, safeWriteCursor;
_secondaryBuffer->GetCurrentPosition(&currentPlayCursor, &safeWriteCursor); _secondaryBuffer->GetCurrentPosition(&currentPlayCursor, &safeWriteCursor);
@ -298,7 +309,7 @@ void SoundManager::PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32
CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize); CopyToSecondaryBuffer((uint8_t*)soundBuffer, soundBufferSize);
if(!_playing) { 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) { if(_lastWriteOffset >= byteLatency / 2) {
Play(); Play();
} }

View file

@ -18,16 +18,18 @@ public:
~SoundManager(); ~SoundManager();
void Release(); void Release();
void ProcessEndOfFrame(); void ProcessEndOfFrame() override;
void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo); void UpdateSoundSettings() override;
void Play(); void PlayBuffer(int16_t *soundBuffer, uint32_t bufferSize, uint32_t sampleRate, bool isStereo) override;
void Pause(); void Pause() override;
void Stop(); void Stop() override;
string GetAvailableDevices(); string GetAvailableDevices() override;
void SetAudioDevice(string deviceName); void SetAudioDevice(string deviceName) override;
private: private:
void Play();
vector<SoundDeviceInfo> GetAvailableDeviceInfo(); vector<SoundDeviceInfo> GetAvailableDeviceInfo();
static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext); static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext);
bool InitializeDirectSound(uint32_t sampleRate, bool isStereo); bool InitializeDirectSound(uint32_t sampleRate, bool isStereo);