From 8fd1af6783e8a6976c787c74553d1b71e81a75cb Mon Sep 17 00:00:00 2001 From: LAGonauta Date: Sat, 17 Jun 2017 07:43:37 -0300 Subject: [PATCH 1/5] 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. --- Source/Core/AudioCommon/OpenALStream.cpp | 57 ++++++++++++++----- Source/Core/AudioCommon/OpenALStream.h | 13 ++--- Source/Core/Core/ConfigManager.cpp | 6 +- Source/Core/Core/ConfigManager.h | 2 +- .../Core/DolphinWX/Config/AudioConfigPane.cpp | 4 +- 5 files changed, 54 insertions(+), 28 deletions(-) diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index 21b2ae0acc..8276cd266f 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -138,7 +138,7 @@ void OpenALStream::Stop() // Clean up buffers and sources palDeleteSources(1, &uiSource); uiSource = 0; - palDeleteBuffers(numBuffers, uiBuffers); + palDeleteBuffers(OAL_BUFFERS, uiBuffers.data()); ALCcontext* pContext = palcGetCurrentContext(); ALCdevice* pDevice = palcGetContextsDevice(pContext); @@ -230,16 +230,43 @@ void OpenALStream::SoundLoop() bool fixed32_capable = IsCreativeXFi(); 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; // Clear error state before querying or else we get false positives. ALenum err = palGetError(); // Generate some AL Buffers for streaming - palGenBuffers(numBuffers, (ALuint*)uiBuffers); + palGenBuffers(OAL_BUFFERS, (ALuint*)uiBuffers.data()); err = CheckALError("generating buffers"); // Generate a Source to playback the Buffers @@ -261,7 +288,7 @@ void OpenALStream::SoundLoop() // Block until we have a free buffer int numBuffersProcessed; palGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &numBuffersProcessed); - if (numBuffers == numBuffersQueued && !numBuffersProcessed) + if (OAL_BUFFERS == numBuffersQueued && !numBuffersProcessed) { soundSyncEvent.Wait(); continue; @@ -270,21 +297,21 @@ void OpenALStream::SoundLoop() // Remove the Buffer from the Queue. if (numBuffersProcessed) { - ALuint unqueuedBufferIds[OAL_MAX_BUFFERS]; + ALuint unqueuedBufferIds[OAL_BUFFERS]; palSourceUnqueueBuffers(uiSource, numBuffersProcessed, unqueuedBufferIds); err = CheckALError("unqueuing buffers"); numBuffersQueued -= numBuffersProcessed; } - unsigned int numSamples = OAL_MAX_SAMPLES; + unsigned int numSamples = frames_per_buffer; if (use_surround) { // DPL2 accepts 240 samples minimum (FWRDURATION) 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); if (numSamples < minSamples) @@ -306,7 +333,7 @@ void OpenALStream::SoundLoop() } 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) { @@ -327,7 +354,7 @@ void OpenALStream::SoundLoop() } 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) { @@ -355,7 +382,7 @@ void OpenALStream::SoundLoop() } else { - numSamples = m_mixer->Mix(realtimeBuffer, numSamples); + numSamples = m_mixer->Mix(realtimeBuffer.data(), numSamples); // Convert the samples from short to float for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) @@ -366,7 +393,7 @@ void OpenALStream::SoundLoop() 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); err = CheckALError("buffering float32 data"); @@ -378,7 +405,7 @@ void OpenALStream::SoundLoop() else if (fixed32_capable) { // 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) stereo_int32[i] = (int)((float)sampleBuffer[i] * (INT64_C(1) << 31)); @@ -388,7 +415,7 @@ void OpenALStream::SoundLoop() else { // 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) stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15)); @@ -401,7 +428,7 @@ void OpenALStream::SoundLoop() err = CheckALError("queuing buffers"); numBuffersQueued++; - nextBuffer = (nextBuffer + 1) % numBuffers; + nextBuffer = (nextBuffer + 1) % OAL_BUFFERS; palGetSourcei(uiSource, AL_SOURCE_STATE, &iState); if (iState != AL_PLAYING) diff --git a/Source/Core/AudioCommon/OpenALStream.h b/Source/Core/AudioCommon/OpenALStream.h index 78c0a616a1..ee7ae47813 100644 --- a/Source/Core/AudioCommon/OpenALStream.h +++ b/Source/Core/AudioCommon/OpenALStream.h @@ -17,9 +17,9 @@ #include #include -#define SFX_MAX_SOURCE 1 -#define OAL_MAX_BUFFERS 32 -#define OAL_MAX_SAMPLES 256 +// OpenAL requires a minimum of two buffers, three or more recommended +#define OAL_BUFFERS 3 +#define OAL_MAX_FRAMES 4096 #define STEREO_CHANNELS 2 #define SURROUND_CHANNELS 6 // number of channels in surround mode #define SIZE_SHORT 2 @@ -72,12 +72,11 @@ private: Common::Event soundSyncEvent; - short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS]; - float sampleBuffer[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; - ALuint uiBuffers[OAL_MAX_BUFFERS]; + std::vector realtimeBuffer; + std::vector sampleBuffer; + std::array uiBuffers; ALuint uiSource; ALfloat fVolume; - u8 numBuffers; #endif // _WIN32 }; diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 19af3de572..c2e6940042 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -254,7 +254,7 @@ void SConfig::SaveCoreSettings(IniFile& ini) core->Set("SelectedLanguage", SelectedLanguage); core->Set("OverrideGCLang", bOverrideGCLanguage); core->Set("DPL2Decoder", bDPL2Decoder); - core->Set("Latency", iLatency); + core->Set("AudioLatency", iLatency); core->Set("AudioStretch", m_audio_stretch); core->Set("AudioStretchMaxLatency", m_audio_stretch_max_latency); core->Set("MemcardAPath", m_strMemoryCardA); @@ -568,7 +568,7 @@ void SConfig::LoadCoreSettings(IniFile& ini) core->Get("SelectedLanguage", &SelectedLanguage, 0); core->Get("OverrideGCLang", &bOverrideGCLanguage, 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("AudioStretchMaxLatency", &m_audio_stretch_max_latency, 80); core->Get("MemcardAPath", &m_strMemoryCardA); @@ -831,7 +831,7 @@ void SConfig::LoadDefaults() bOverrideGCLanguage = false; bWii = false; bDPL2Decoder = false; - iLatency = 14; + iLatency = 20; m_audio_stretch = false; m_audio_stretch_max_latency = 80; diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 9a97b68df0..e40b6bf320 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -109,7 +109,7 @@ struct SConfig : NonCopyable bool bCopyWiiSaveNetplay = true; bool bDPL2Decoder = false; - int iLatency = 14; + int iLatency = 20; bool m_audio_stretch = false; int m_audio_stretch_max_latency = 80; diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp index 5e940ffb22..c9f3c6b0e1 100644 --- a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp @@ -45,8 +45,8 @@ void AudioConfigPane::InitializeGUI() m_audio_backend_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings); m_audio_latency_spinctrl = - new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 30); - m_audio_latency_label = new wxStaticText(this, wxID_ANY, _("Latency:")); + new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 200); + m_audio_latency_label = new wxStaticText(this, wxID_ANY, _("Latency (ms):")); m_stretch_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Audio Stretching")); m_stretch_label = new wxStaticText(this, wxID_ANY, _("Buffer Size:")); From d9d51fe0c479702b7f0dfbdc788e7f2821162a6b Mon Sep 17 00:00:00 2001 From: lfsafady Date: Sat, 17 Jun 2017 17:16:32 -0300 Subject: [PATCH 2/5] Renamed some variables to the current coding standard and some to better fit what they really are. --- Source/Core/AudioCommon/OpenALStream.cpp | 163 +++++++++++------------ Source/Core/AudioCommon/OpenALStream.h | 16 +-- 2 files changed, 88 insertions(+), 91 deletions(-) diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index 8276cd266f..4a3bd1cee8 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -100,27 +100,27 @@ bool OpenALStream::Start() return false; } - const char* defaultDeviceName = palcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); - INFO_LOG(AUDIO, "Found OpenAL device %s", defaultDeviceName); + const char* default_device_dame = palcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + INFO_LOG(AUDIO, "Found OpenAL device %s", default_device_dame); - ALCdevice* pDevice = palcOpenDevice(defaultDeviceName); - if (!pDevice) + ALCdevice* device = palcOpenDevice(default_device_dame); + if (!device) { - PanicAlertT("OpenAL: can't open device %s", defaultDeviceName); + PanicAlertT("OpenAL: can't open device %s", default_device_dame); return false; } - ALCcontext* pContext = palcCreateContext(pDevice, nullptr); - if (!pContext) + ALCcontext* context = palcCreateContext(device, nullptr); + if (!context) { - palcCloseDevice(pDevice); - PanicAlertT("OpenAL: can't create context for device %s", defaultDeviceName); + palcCloseDevice(device); + PanicAlertT("OpenAL: can't create context for device %s", default_device_dame); return false; } - palcMakeContextCurrent(pContext); + palcMakeContextCurrent(context); m_run_thread.Set(); - thread = std::thread(&OpenALStream::SoundLoop, this); + m_thread = std::thread(&OpenALStream::SoundLoop, this); return true; } @@ -128,37 +128,37 @@ void OpenALStream::Stop() { m_run_thread.Clear(); // kick the thread if it's waiting - soundSyncEvent.Set(); + m_sound_sync_event.Set(); - thread.join(); + m_thread.join(); - palSourceStop(uiSource); - palSourcei(uiSource, AL_BUFFER, 0); + palSourceStop(m_source); + palSourcei(m_source, AL_BUFFER, 0); // Clean up buffers and sources - palDeleteSources(1, &uiSource); - uiSource = 0; - palDeleteBuffers(OAL_BUFFERS, uiBuffers.data()); + palDeleteSources(1, &m_source); + m_source = 0; + palDeleteBuffers(OAL_BUFFERS, m_buffers.data()); - ALCcontext* pContext = palcGetCurrentContext(); - ALCdevice* pDevice = palcGetContextsDevice(pContext); + ALCcontext* context = palcGetCurrentContext(); + ALCdevice* device = palcGetContextsDevice(context); palcMakeContextCurrent(nullptr); - palcDestroyContext(pContext); - palcCloseDevice(pDevice); + palcDestroyContext(context); + palcCloseDevice(device); } void OpenALStream::SetVolume(int volume) { - fVolume = (float)volume / 100.0f; + m_volume = (float)volume / 100.0f; - if (uiSource) - palSourcef(uiSource, AL_GAIN, fVolume); + if (m_source) + palSourcef(m_source, AL_GAIN, m_volume); } void OpenALStream::Update() { - soundSyncEvent.Set(); + m_sound_sync_event.Set(); } void OpenALStream::Clear(bool mute) @@ -167,11 +167,11 @@ void OpenALStream::Clear(bool mute) if (m_muted) { - palSourceStop(uiSource); + palSourceStop(m_source); } else { - palSourcePlay(uiSource); + palSourcePlay(m_source); } } @@ -229,17 +229,17 @@ void OpenALStream::SoundLoop() // we just check if one is being used. bool fixed32_capable = IsCreativeXFi(); - u32 ulFrequency = m_mixer->GetSampleRate(); + u32 frequency = m_mixer->GetSampleRate(); 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; + frames_per_buffer = frequency / 1000 * SConfig::GetInstance().iLatency / OAL_BUFFERS; } else { - frames_per_buffer = ulFrequency / 1000 * 1 / OAL_BUFFERS; + frames_per_buffer = frequency / 1000 * 1 / OAL_BUFFERS; } if (frames_per_buffer > OAL_MAX_FRAMES) @@ -258,84 +258,81 @@ void OpenALStream::SoundLoop() // 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; + m_realtime_buffer.resize(frames_per_buffer * STEREO_CHANNELS); + m_sample_buffer.resize(frames_per_buffer * STEREO_CHANNELS); + m_source = 0; // Clear error state before querying or else we get false positives. ALenum err = palGetError(); // Generate some AL Buffers for streaming - palGenBuffers(OAL_BUFFERS, (ALuint*)uiBuffers.data()); + palGenBuffers(OAL_BUFFERS, (ALuint*)m_buffers.data()); err = CheckALError("generating buffers"); // Generate a Source to playback the Buffers - palGenSources(1, &uiSource); + palGenSources(1, &m_source); err = CheckALError("generating sources"); // Set the default sound volume as saved in the config file. - palSourcef(uiSource, AL_GAIN, fVolume); + palSourcef(m_source, AL_GAIN, m_volume); // TODO: Error handling // ALenum err = alGetError(); - unsigned int nextBuffer = 0; - unsigned int numBuffersQueued = 0; - ALint iState = 0; + unsigned int next_buffer = 0; + unsigned int num_buffers_queued = 0; + ALint state = 0; while (m_run_thread.IsSet()) { // Block until we have a free buffer - int numBuffersProcessed; - palGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &numBuffersProcessed); - if (OAL_BUFFERS == numBuffersQueued && !numBuffersProcessed) + int num_buffers_processed; + palGetSourcei(m_source, AL_BUFFERS_PROCESSED, &num_buffers_processed); + if (num_buffers_queued == OAL_BUFFERS && !num_buffers_processed) { - soundSyncEvent.Wait(); + m_sound_sync_event.Wait(); continue; } // Remove the Buffer from the Queue. - if (numBuffersProcessed) + if (num_buffers_processed) { - ALuint unqueuedBufferIds[OAL_BUFFERS]; - palSourceUnqueueBuffers(uiSource, numBuffersProcessed, unqueuedBufferIds); + ALuint unqueued_buffer_ids[OAL_BUFFERS]; + palSourceUnqueueBuffers(m_source, num_buffers_processed, unqueued_buffer_ids); err = CheckALError("unqueuing buffers"); - numBuffersQueued -= numBuffersProcessed; + num_buffers_queued -= num_buffers_processed; } - unsigned int numSamples = frames_per_buffer; + unsigned int min_frames = frames_per_buffer; if (use_surround) { - // DPL2 accepts 240 samples minimum (FWRDURATION) - unsigned int minSamples = 240; - float dpl2[OAL_MAX_FRAMES * SURROUND_CHANNELS]; - numSamples = m_mixer->MixSurround(dpl2, numSamples); + u32 rendered_frames = m_mixer->MixSurround(dpl2, min_frames); - if (numSamples < minSamples) + if (rendered_frames < min_frames) continue; // zero-out the subwoofer channel - DPL2Decode generates a pretty // good 5.0 but not a good 5.1 output. Sadly there is not a 5.0 // AL_FORMAT_50CHN32 to make this super-explicit. // DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR - for (u32 i = 0; i < numSamples; ++i) + for (u32 i = 0; i < rendered_frames; ++i) { dpl2[i * SURROUND_CHANNELS + 3 /*sub/lfe*/] = 0.0f; } if (float32_capable) { - palBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN32, dpl2, - numSamples * FRAME_SURROUND_FLOAT, ulFrequency); + palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN32, dpl2, + rendered_frames * FRAME_SURROUND_FLOAT, frequency); } else if (fixed32_capable) { int surround_int32[OAL_MAX_FRAMES * SURROUND_CHANNELS]; - for (u32 i = 0; i < numSamples * SURROUND_CHANNELS; ++i) + for (u32 i = 0; i < rendered_frames * SURROUND_CHANNELS; ++i) { // For some reason the ffdshow's DPL2 decoder outputs samples bigger than 1. // Most are close to 2.5 and some go up to 8. Hard clamping here, we need to @@ -349,14 +346,14 @@ void OpenALStream::SoundLoop() surround_int32[i] = (int)dpl2[i]; } - palBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN32, surround_int32, - numSamples * FRAME_SURROUND_INT32, ulFrequency); + palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN32, surround_int32, + rendered_frames * FRAME_SURROUND_INT32, frequency); } else { short surround_short[OAL_MAX_FRAMES * SURROUND_CHANNELS]; - for (u32 i = 0; i < numSamples * SURROUND_CHANNELS; ++i) + for (u32 i = 0; i < rendered_frames * SURROUND_CHANNELS; ++i) { dpl2[i] = dpl2[i] * (1 << 15); if (dpl2[i] > SHRT_MAX) @@ -367,8 +364,8 @@ void OpenALStream::SoundLoop() surround_short[i] = (int)dpl2[i]; } - palBufferData(uiBuffers[nextBuffer], AL_FORMAT_51CHN16, surround_short, - numSamples * FRAME_SURROUND_SHORT, ulFrequency); + palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN16, surround_short, + rendered_frames * FRAME_SURROUND_SHORT, frequency); } err = CheckALError("buffering data"); @@ -382,19 +379,19 @@ void OpenALStream::SoundLoop() } else { - numSamples = m_mixer->Mix(realtimeBuffer.data(), numSamples); + u32 rendered_frames = m_mixer->Mix(m_realtime_buffer.data(), min_frames); // Convert the samples from short to float - for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) - sampleBuffer[i] = static_cast(realtimeBuffer[i]) / (1 << 15); + for (u32 i = 0; i < rendered_frames * STEREO_CHANNELS; ++i) + m_sample_buffer[i] = static_cast(m_realtime_buffer[i]) / (1 << 15); - if (!numSamples) + if (!rendered_frames) continue; if (float32_capable) { - palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO_FLOAT32, sampleBuffer.data(), - numSamples * FRAME_STEREO_FLOAT, ulFrequency); + palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO_FLOAT32, m_sample_buffer.data(), + rendered_frames * FRAME_STEREO_FLOAT, frequency); err = CheckALError("buffering float32 data"); if (err == AL_INVALID_ENUM) @@ -406,35 +403,35 @@ void OpenALStream::SoundLoop() { // Clamping is not necessary here, samples are always between (-1,1) int stereo_int32[OAL_MAX_FRAMES * STEREO_CHANNELS]; - for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) - stereo_int32[i] = (int)((float)sampleBuffer[i] * (INT64_C(1) << 31)); + for (u32 i = 0; i < rendered_frames * STEREO_CHANNELS; ++i) + stereo_int32[i] = (int)((float)m_sample_buffer[i] * (INT64_C(1) << 31)); - palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO32, stereo_int32, - numSamples * FRAME_STEREO_INT32, ulFrequency); + palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO32, stereo_int32, + rendered_frames * FRAME_STEREO_INT32, frequency); } else { // Convert the samples from float to short short stereo[OAL_MAX_FRAMES * STEREO_CHANNELS]; - for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) - stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15)); + for (u32 i = 0; i < rendered_frames * STEREO_CHANNELS; ++i) + stereo[i] = (short)((float)m_sample_buffer[i] * (1 << 15)); - palBufferData(uiBuffers[nextBuffer], AL_FORMAT_STEREO16, stereo, - numSamples * FRAME_STEREO_SHORT, ulFrequency); + palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO16, stereo, + rendered_frames * FRAME_STEREO_SHORT, frequency); } } - palSourceQueueBuffers(uiSource, 1, &uiBuffers[nextBuffer]); + palSourceQueueBuffers(m_source, 1, &m_buffers[next_buffer]); err = CheckALError("queuing buffers"); - numBuffersQueued++; - nextBuffer = (nextBuffer + 1) % OAL_BUFFERS; + num_buffers_queued++; + next_buffer = (next_buffer + 1) % OAL_BUFFERS; - palGetSourcei(uiSource, AL_SOURCE_STATE, &iState); - if (iState != AL_PLAYING) + palGetSourcei(m_source, AL_SOURCE_STATE, &state); + if (state != AL_PLAYING) { // Buffer underrun occurred, resume playback - palSourcePlay(uiSource); + palSourcePlay(m_source); err = CheckALError("occurred resuming playback"); } } diff --git a/Source/Core/AudioCommon/OpenALStream.h b/Source/Core/AudioCommon/OpenALStream.h index ee7ae47813..f16fa2c8a2 100644 --- a/Source/Core/AudioCommon/OpenALStream.h +++ b/Source/Core/AudioCommon/OpenALStream.h @@ -56,7 +56,7 @@ class OpenALStream final : public SoundStream { #ifdef _WIN32 public: - OpenALStream() : uiSource(0) {} + OpenALStream() : m_source(0) {} bool Start() override; void SoundLoop() override; void SetVolume(int volume) override; @@ -67,16 +67,16 @@ public: static bool isValid(); private: - std::thread thread; + std::thread m_thread; Common::Flag m_run_thread; - Common::Event soundSyncEvent; + Common::Event m_sound_sync_event; - std::vector realtimeBuffer; - std::vector sampleBuffer; - std::array uiBuffers; - ALuint uiSource; - ALfloat fVolume; + std::vector m_realtime_buffer; + std::vector m_sample_buffer; + std::array m_buffers; + ALuint m_source; + ALfloat m_volume; #endif // _WIN32 }; From 75af792070d1158a94da76ee706d4563ca58e950 Mon Sep 17 00:00:00 2001 From: lfsafady Date: Sat, 17 Jun 2017 17:21:29 -0300 Subject: [PATCH 3/5] Swapped out the sound_sync_event.Wait() call by a simple std::sleep_for. It seems to make no difference besides allowing lower latencies and more stability on hardware OpenAL cards. Maybe the Wait() call waits for too long, causing buffers underruns. --- Source/Core/AudioCommon/OpenALStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index 4a3bd1cee8..8d9e9cc1c4 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -290,7 +290,7 @@ void OpenALStream::SoundLoop() palGetSourcei(m_source, AL_BUFFERS_PROCESSED, &num_buffers_processed); if (num_buffers_queued == OAL_BUFFERS && !num_buffers_processed) { - m_sound_sync_event.Wait(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } From 9eb209c214a3999547fc572a094e5cd300ed7ace Mon Sep 17 00:00:00 2001 From: LAGonauta Date: Fri, 16 Jun 2017 18:54:19 -0300 Subject: [PATCH 4/5] Removed redundant conversion to float when playing back stereo. --- Source/Core/AudioCommon/OpenALStream.cpp | 38 ++---------------------- Source/Core/AudioCommon/OpenALStream.h | 3 -- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index 8d9e9cc1c4..7693e5336f 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -259,7 +259,6 @@ void OpenALStream::SoundLoop() // Should we make these larger just in case the mixer ever sends more samples // than what we request? m_realtime_buffer.resize(frames_per_buffer * STEREO_CHANNELS); - m_sample_buffer.resize(frames_per_buffer * STEREO_CHANNELS); m_source = 0; // Clear error state before querying or else we get false positives. @@ -381,44 +380,11 @@ void OpenALStream::SoundLoop() { u32 rendered_frames = m_mixer->Mix(m_realtime_buffer.data(), min_frames); - // Convert the samples from short to float - for (u32 i = 0; i < rendered_frames * STEREO_CHANNELS; ++i) - m_sample_buffer[i] = static_cast(m_realtime_buffer[i]) / (1 << 15); - if (!rendered_frames) continue; - if (float32_capable) - { - palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO_FLOAT32, m_sample_buffer.data(), - rendered_frames * FRAME_STEREO_FLOAT, frequency); - - err = CheckALError("buffering float32 data"); - if (err == AL_INVALID_ENUM) - { - float32_capable = false; - } - } - else if (fixed32_capable) - { - // Clamping is not necessary here, samples are always between (-1,1) - int stereo_int32[OAL_MAX_FRAMES * STEREO_CHANNELS]; - for (u32 i = 0; i < rendered_frames * STEREO_CHANNELS; ++i) - stereo_int32[i] = (int)((float)m_sample_buffer[i] * (INT64_C(1) << 31)); - - palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO32, stereo_int32, - rendered_frames * FRAME_STEREO_INT32, frequency); - } - else - { - // Convert the samples from float to short - short stereo[OAL_MAX_FRAMES * STEREO_CHANNELS]; - for (u32 i = 0; i < rendered_frames * STEREO_CHANNELS; ++i) - stereo[i] = (short)((float)m_sample_buffer[i] * (1 << 15)); - - palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO16, stereo, - rendered_frames * FRAME_STEREO_SHORT, frequency); - } + palBufferData(m_buffers[next_buffer], AL_FORMAT_STEREO16, m_realtime_buffer.data(), + rendered_frames * FRAME_STEREO_SHORT, frequency); } palSourceQueueBuffers(m_source, 1, &m_buffers[next_buffer]); diff --git a/Source/Core/AudioCommon/OpenALStream.h b/Source/Core/AudioCommon/OpenALStream.h index f16fa2c8a2..3b9364c571 100644 --- a/Source/Core/AudioCommon/OpenALStream.h +++ b/Source/Core/AudioCommon/OpenALStream.h @@ -26,8 +26,6 @@ #define SIZE_INT32 4 #define SIZE_FLOAT 4 // size of a float in bytes #define FRAME_STEREO_SHORT STEREO_CHANNELS* SIZE_SHORT -#define FRAME_STEREO_FLOAT STEREO_CHANNELS* SIZE_FLOAT -#define FRAME_STEREO_INT32 STEREO_CHANNELS* SIZE_INT32 #define FRAME_SURROUND_FLOAT SURROUND_CHANNELS* SIZE_FLOAT #define FRAME_SURROUND_SHORT SURROUND_CHANNELS* SIZE_SHORT #define FRAME_SURROUND_INT32 SURROUND_CHANNELS* SIZE_INT32 @@ -73,7 +71,6 @@ private: Common::Event m_sound_sync_event; std::vector m_realtime_buffer; - std::vector m_sample_buffer; std::array m_buffers; ALuint m_source; ALfloat m_volume; From db7bb3bda8083699ff390ec7f734491ea33cf019 Mon Sep 17 00:00:00 2001 From: LAGonauta Date: Fri, 16 Jun 2017 18:54:38 -0300 Subject: [PATCH 5/5] Swapped C-style arrays to std::array Also changed C-Style casts to static_cast --- Source/Core/AudioCommon/OpenALStream.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index 7693e5336f..191452b7f3 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -296,8 +296,8 @@ void OpenALStream::SoundLoop() // Remove the Buffer from the Queue. if (num_buffers_processed) { - ALuint unqueued_buffer_ids[OAL_BUFFERS]; - palSourceUnqueueBuffers(m_source, num_buffers_processed, unqueued_buffer_ids); + std::array unqueued_buffer_ids; + palSourceUnqueueBuffers(m_source, num_buffers_processed, unqueued_buffer_ids.data()); err = CheckALError("unqueuing buffers"); num_buffers_queued -= num_buffers_processed; @@ -307,8 +307,8 @@ void OpenALStream::SoundLoop() if (use_surround) { - float dpl2[OAL_MAX_FRAMES * SURROUND_CHANNELS]; - u32 rendered_frames = m_mixer->MixSurround(dpl2, min_frames); + std::array dpl2; + u32 rendered_frames = m_mixer->MixSurround(dpl2.data(), min_frames); if (rendered_frames < min_frames) continue; @@ -324,12 +324,12 @@ void OpenALStream::SoundLoop() if (float32_capable) { - palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN32, dpl2, + palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN32, dpl2.data(), rendered_frames * FRAME_SURROUND_FLOAT, frequency); } else if (fixed32_capable) { - int surround_int32[OAL_MAX_FRAMES * SURROUND_CHANNELS]; + std::array surround_int32; for (u32 i = 0; i < rendered_frames * SURROUND_CHANNELS; ++i) { @@ -342,15 +342,15 @@ void OpenALStream::SoundLoop() else if (dpl2[i] < INT_MIN) surround_int32[i] = INT_MIN; else - surround_int32[i] = (int)dpl2[i]; + surround_int32[i] = static_cast(dpl2[i]); } - palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN32, surround_int32, + palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN32, surround_int32.data(), rendered_frames * FRAME_SURROUND_INT32, frequency); } else { - short surround_short[OAL_MAX_FRAMES * SURROUND_CHANNELS]; + std::array surround_short; for (u32 i = 0; i < rendered_frames * SURROUND_CHANNELS; ++i) { @@ -360,10 +360,10 @@ void OpenALStream::SoundLoop() else if (dpl2[i] < SHRT_MIN) surround_short[i] = SHRT_MIN; else - surround_short[i] = (int)dpl2[i]; + surround_short[i] = static_cast(dpl2[i]); } - palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN16, surround_short, + palBufferData(m_buffers[next_buffer], AL_FORMAT_51CHN16, surround_short.data(), rendered_frames * FRAME_SURROUND_SHORT, frequency); }