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:
parent
eacd07d010
commit
7b20300f6d
8 changed files with 57 additions and 29 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,9 @@ void SoundMixer::Reset()
|
||||||
|
|
||||||
UpdateRates(true);
|
UpdateRates(true);
|
||||||
UpdateEqualizers(true);
|
UpdateEqualizers(true);
|
||||||
|
if(_audioDevice) {
|
||||||
|
_audioDevice->UpdateSoundSettings();
|
||||||
|
}
|
||||||
_previousTargetRate = _sampleRate;
|
_previousTargetRate = _sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,10 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void UpdateSoundSettings() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual void ProcessEndOfFrame() override
|
virtual void ProcessEndOfFrame() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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(¤tPlayCursor, &safeWriteCursor);
|
_secondaryBuffer->GetCurrentPosition(¤tPlayCursor, &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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue