Changed OpenAL latency setting to really reflect how much time it is.

Before these changes each value of latency were actually 5ms, with a
minimum latency of ~10 ms. If it was set to 4 ms on the UI, the actual
latency was 10 + 5 * 4 = 30 ms.
Now 30 ms on the UI means 30 ms on the backend.
This commit is contained in:
LAGonauta 2017-06-17 07:43:37 -03:00 committed by lfsafady
parent 94ba78d717
commit 8fd1af6783
5 changed files with 54 additions and 28 deletions

View File

@ -138,7 +138,7 @@ void OpenALStream::Stop()
// Clean up buffers and sources // Clean up buffers and sources
palDeleteSources(1, &uiSource); palDeleteSources(1, &uiSource);
uiSource = 0; uiSource = 0;
palDeleteBuffers(numBuffers, uiBuffers); palDeleteBuffers(OAL_BUFFERS, uiBuffers.data());
ALCcontext* pContext = palcGetCurrentContext(); ALCcontext* pContext = palcGetCurrentContext();
ALCdevice* pDevice = palcGetContextsDevice(pContext); ALCdevice* pDevice = palcGetContextsDevice(pContext);
@ -230,16 +230,43 @@ void OpenALStream::SoundLoop()
bool fixed32_capable = IsCreativeXFi(); bool fixed32_capable = IsCreativeXFi();
u32 ulFrequency = m_mixer->GetSampleRate(); u32 ulFrequency = m_mixer->GetSampleRate();
numBuffers = SConfig::GetInstance().iLatency + 2; // OpenAL requires a minimum of two buffers
memset(uiBuffers, 0, numBuffers * sizeof(ALuint)); u32 frames_per_buffer;
// Can't have zero samples per buffer
if (SConfig::GetInstance().iLatency > 0)
{
frames_per_buffer = ulFrequency / 1000 * SConfig::GetInstance().iLatency / OAL_BUFFERS;
}
else
{
frames_per_buffer = ulFrequency / 1000 * 1 / OAL_BUFFERS;
}
if (frames_per_buffer > OAL_MAX_FRAMES)
{
frames_per_buffer = OAL_MAX_FRAMES;
}
// DPL2 needs a minimum number of samples to work (FWRDURATION)
if (use_surround && frames_per_buffer < 240)
{
frames_per_buffer = 240;
}
INFO_LOG(AUDIO, "Using %d buffers, each with %d audio frames for a total of %d.", OAL_BUFFERS,
frames_per_buffer, frames_per_buffer * OAL_BUFFERS);
// Should we make these larger just in case the mixer ever sends more samples
// than what we request?
realtimeBuffer.resize(frames_per_buffer * STEREO_CHANNELS);
sampleBuffer.resize(frames_per_buffer * STEREO_CHANNELS);
uiSource = 0; uiSource = 0;
// Clear error state before querying or else we get false positives. // Clear error state before querying or else we get false positives.
ALenum err = palGetError(); ALenum err = palGetError();
// Generate some AL Buffers for streaming // Generate some AL Buffers for streaming
palGenBuffers(numBuffers, (ALuint*)uiBuffers); palGenBuffers(OAL_BUFFERS, (ALuint*)uiBuffers.data());
err = CheckALError("generating buffers"); err = CheckALError("generating buffers");
// Generate a Source to playback the Buffers // Generate a Source to playback the Buffers
@ -261,7 +288,7 @@ void OpenALStream::SoundLoop()
// Block until we have a free buffer // Block until we have a free buffer
int numBuffersProcessed; int numBuffersProcessed;
palGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &numBuffersProcessed); palGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &numBuffersProcessed);
if (numBuffers == numBuffersQueued && !numBuffersProcessed) if (OAL_BUFFERS == numBuffersQueued && !numBuffersProcessed)
{ {
soundSyncEvent.Wait(); soundSyncEvent.Wait();
continue; continue;
@ -270,21 +297,21 @@ void OpenALStream::SoundLoop()
// Remove the Buffer from the Queue. // Remove the Buffer from the Queue.
if (numBuffersProcessed) if (numBuffersProcessed)
{ {
ALuint unqueuedBufferIds[OAL_MAX_BUFFERS]; ALuint unqueuedBufferIds[OAL_BUFFERS];
palSourceUnqueueBuffers(uiSource, numBuffersProcessed, unqueuedBufferIds); palSourceUnqueueBuffers(uiSource, numBuffersProcessed, unqueuedBufferIds);
err = CheckALError("unqueuing buffers"); err = CheckALError("unqueuing buffers");
numBuffersQueued -= numBuffersProcessed; numBuffersQueued -= numBuffersProcessed;
} }
unsigned int numSamples = OAL_MAX_SAMPLES; unsigned int numSamples = frames_per_buffer;
if (use_surround) if (use_surround)
{ {
// DPL2 accepts 240 samples minimum (FWRDURATION) // DPL2 accepts 240 samples minimum (FWRDURATION)
unsigned int minSamples = 240; unsigned int minSamples = 240;
float dpl2[OAL_MAX_SAMPLES * OAL_MAX_BUFFERS * SURROUND_CHANNELS]; float dpl2[OAL_MAX_FRAMES * SURROUND_CHANNELS];
numSamples = m_mixer->MixSurround(dpl2, numSamples); numSamples = m_mixer->MixSurround(dpl2, numSamples);
if (numSamples < minSamples) if (numSamples < minSamples)
@ -306,7 +333,7 @@ void OpenALStream::SoundLoop()
} }
else if (fixed32_capable) else if (fixed32_capable)
{ {
int surround_int32[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; int surround_int32[OAL_MAX_FRAMES * SURROUND_CHANNELS];
for (u32 i = 0; i < numSamples * SURROUND_CHANNELS; ++i) for (u32 i = 0; i < numSamples * SURROUND_CHANNELS; ++i)
{ {
@ -327,7 +354,7 @@ void OpenALStream::SoundLoop()
} }
else else
{ {
short surround_short[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; short surround_short[OAL_MAX_FRAMES * SURROUND_CHANNELS];
for (u32 i = 0; i < numSamples * SURROUND_CHANNELS; ++i) for (u32 i = 0; i < numSamples * SURROUND_CHANNELS; ++i)
{ {
@ -355,7 +382,7 @@ void OpenALStream::SoundLoop()
} }
else else
{ {
numSamples = m_mixer->Mix(realtimeBuffer, numSamples); numSamples = m_mixer->Mix(realtimeBuffer.data(), numSamples);
// Convert the samples from short to float // Convert the samples from short to float
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
@ -366,7 +393,7 @@ void OpenALStream::SoundLoop()
if (float32_capable) if (float32_capable)
{ {
palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO_FLOAT32, sampleBuffer, palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO_FLOAT32, sampleBuffer.data(),
numSamples * FRAME_STEREO_FLOAT, ulFrequency); numSamples * FRAME_STEREO_FLOAT, ulFrequency);
err = CheckALError("buffering float32 data"); err = CheckALError("buffering float32 data");
@ -378,7 +405,7 @@ void OpenALStream::SoundLoop()
else if (fixed32_capable) else if (fixed32_capable)
{ {
// Clamping is not necessary here, samples are always between (-1,1) // Clamping is not necessary here, samples are always between (-1,1)
int stereo_int32[OAL_MAX_SAMPLES * STEREO_CHANNELS * OAL_MAX_BUFFERS]; int stereo_int32[OAL_MAX_FRAMES * STEREO_CHANNELS];
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
stereo_int32[i] = (int)((float)sampleBuffer[i] * (INT64_C(1) << 31)); stereo_int32[i] = (int)((float)sampleBuffer[i] * (INT64_C(1) << 31));
@ -388,7 +415,7 @@ void OpenALStream::SoundLoop()
else else
{ {
// Convert the samples from float to short // Convert the samples from float to short
short stereo[OAL_MAX_SAMPLES * STEREO_CHANNELS * OAL_MAX_BUFFERS]; short stereo[OAL_MAX_FRAMES * STEREO_CHANNELS];
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15)); stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15));
@ -401,7 +428,7 @@ void OpenALStream::SoundLoop()
err = CheckALError("queuing buffers"); err = CheckALError("queuing buffers");
numBuffersQueued++; numBuffersQueued++;
nextBuffer = (nextBuffer + 1) % numBuffers; nextBuffer = (nextBuffer + 1) % OAL_BUFFERS;
palGetSourcei(uiSource, AL_SOURCE_STATE, &iState); palGetSourcei(uiSource, AL_SOURCE_STATE, &iState);
if (iState != AL_PLAYING) if (iState != AL_PLAYING)

View File

@ -17,9 +17,9 @@
#include <OpenAL/include/alc.h> #include <OpenAL/include/alc.h>
#include <OpenAL/include/alext.h> #include <OpenAL/include/alext.h>
#define SFX_MAX_SOURCE 1 // OpenAL requires a minimum of two buffers, three or more recommended
#define OAL_MAX_BUFFERS 32 #define OAL_BUFFERS 3
#define OAL_MAX_SAMPLES 256 #define OAL_MAX_FRAMES 4096
#define STEREO_CHANNELS 2 #define STEREO_CHANNELS 2
#define SURROUND_CHANNELS 6 // number of channels in surround mode #define SURROUND_CHANNELS 6 // number of channels in surround mode
#define SIZE_SHORT 2 #define SIZE_SHORT 2
@ -72,12 +72,11 @@ private:
Common::Event soundSyncEvent; Common::Event soundSyncEvent;
short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS]; std::vector<short> realtimeBuffer;
float sampleBuffer[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; std::vector<float> sampleBuffer;
ALuint uiBuffers[OAL_MAX_BUFFERS]; std::array<ALuint, OAL_BUFFERS> uiBuffers;
ALuint uiSource; ALuint uiSource;
ALfloat fVolume; ALfloat fVolume;
u8 numBuffers;
#endif // _WIN32 #endif // _WIN32
}; };

View File

@ -254,7 +254,7 @@ void SConfig::SaveCoreSettings(IniFile& ini)
core->Set("SelectedLanguage", SelectedLanguage); core->Set("SelectedLanguage", SelectedLanguage);
core->Set("OverrideGCLang", bOverrideGCLanguage); core->Set("OverrideGCLang", bOverrideGCLanguage);
core->Set("DPL2Decoder", bDPL2Decoder); core->Set("DPL2Decoder", bDPL2Decoder);
core->Set("Latency", iLatency); core->Set("AudioLatency", iLatency);
core->Set("AudioStretch", m_audio_stretch); core->Set("AudioStretch", m_audio_stretch);
core->Set("AudioStretchMaxLatency", m_audio_stretch_max_latency); core->Set("AudioStretchMaxLatency", m_audio_stretch_max_latency);
core->Set("MemcardAPath", m_strMemoryCardA); core->Set("MemcardAPath", m_strMemoryCardA);
@ -568,7 +568,7 @@ void SConfig::LoadCoreSettings(IniFile& ini)
core->Get("SelectedLanguage", &SelectedLanguage, 0); core->Get("SelectedLanguage", &SelectedLanguage, 0);
core->Get("OverrideGCLang", &bOverrideGCLanguage, false); core->Get("OverrideGCLang", &bOverrideGCLanguage, false);
core->Get("DPL2Decoder", &bDPL2Decoder, false); core->Get("DPL2Decoder", &bDPL2Decoder, false);
core->Get("Latency", &iLatency, 5); core->Get("AudioLatency", &iLatency, 20);
core->Get("AudioStretch", &m_audio_stretch, false); core->Get("AudioStretch", &m_audio_stretch, false);
core->Get("AudioStretchMaxLatency", &m_audio_stretch_max_latency, 80); core->Get("AudioStretchMaxLatency", &m_audio_stretch_max_latency, 80);
core->Get("MemcardAPath", &m_strMemoryCardA); core->Get("MemcardAPath", &m_strMemoryCardA);
@ -831,7 +831,7 @@ void SConfig::LoadDefaults()
bOverrideGCLanguage = false; bOverrideGCLanguage = false;
bWii = false; bWii = false;
bDPL2Decoder = false; bDPL2Decoder = false;
iLatency = 14; iLatency = 20;
m_audio_stretch = false; m_audio_stretch = false;
m_audio_stretch_max_latency = 80; m_audio_stretch_max_latency = 80;

View File

@ -109,7 +109,7 @@ struct SConfig : NonCopyable
bool bCopyWiiSaveNetplay = true; bool bCopyWiiSaveNetplay = true;
bool bDPL2Decoder = false; bool bDPL2Decoder = false;
int iLatency = 14; int iLatency = 20;
bool m_audio_stretch = false; bool m_audio_stretch = false;
int m_audio_stretch_max_latency = 80; int m_audio_stretch_max_latency = 80;

View File

@ -45,8 +45,8 @@ void AudioConfigPane::InitializeGUI()
m_audio_backend_choice = m_audio_backend_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings); new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings);
m_audio_latency_spinctrl = m_audio_latency_spinctrl =
new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 30); new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 200);
m_audio_latency_label = new wxStaticText(this, wxID_ANY, _("Latency:")); m_audio_latency_label = new wxStaticText(this, wxID_ANY, _("Latency (ms):"));
m_stretch_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Audio Stretching")); m_stretch_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Audio Stretching"));
m_stretch_label = new wxStaticText(this, wxID_ANY, _("Buffer Size:")); m_stretch_label = new wxStaticText(this, wxID_ANY, _("Buffer Size:"));