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:
void ProcessLatency(uint32_t readPosition, uint32_t writePosition);
AudioStatistics GetStatistics();
AudioStatistics GetStatistics() override;
protected:
bool _isStereo;

View file

@ -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;

View file

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

View file

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

View file

@ -8,7 +8,7 @@ SdlSoundManager::SdlSoundManager(shared_ptr<Console> 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;

View file

@ -10,14 +10,15 @@ public:
SdlSoundManager(shared_ptr<Console> 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<string> GetAvailableDeviceInfo();

View file

@ -14,7 +14,7 @@ SoundManager::SoundManager(shared_ptr<Console> 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(&currentPlayCursor, &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();
}

View file

@ -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<SoundDeviceInfo> GetAvailableDeviceInfo();
static bool CALLBACK DirectSoundEnumProc(LPGUID lpGUID, LPCWSTR lpszDesc, LPCSTR lpszDrvName, LPVOID lpContext);
bool InitializeDirectSound(uint32_t sampleRate, bool isStereo);