From b125b8175fa46edd1bd33749b9c085dd9f5d6ee7 Mon Sep 17 00:00:00 2001 From: Axel Nana Date: Sun, 25 Aug 2024 04:51:20 +0100 Subject: [PATCH] fix(mixer): Improved dynamic sample rate conversion. Signed-off-by: Axel Nana --- .../Audio/Amplitude/DSP/AudioConverter.h | 3 +++ src/DSP/AudioConverter.cpp | 25 ++++++++++++++++--- src/Mixer/Amplimix.cpp | 11 +++++--- src/Mixer/Amplimix.h | 1 + 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/SparkyStudios/Audio/Amplitude/DSP/AudioConverter.h b/include/SparkyStudios/Audio/Amplitude/DSP/AudioConverter.h index f02de04f..342766c2 100644 --- a/include/SparkyStudios/Audio/Amplitude/DSP/AudioConverter.h +++ b/include/SparkyStudios/Audio/Amplitude/DSP/AudioConverter.h @@ -158,6 +158,9 @@ namespace SparkyStudios::Audio::Amplitude ChannelConversionMode _channelConversionMode; bool _needResampling; + bool _srcInitialized; + + Settings _settings; }; } // namespace SparkyStudios::Audio::Amplitude diff --git a/src/DSP/AudioConverter.cpp b/src/DSP/AudioConverter.cpp index a0b05167..d4359446 100644 --- a/src/DSP/AudioConverter.cpp +++ b/src/DSP/AudioConverter.cpp @@ -21,6 +21,8 @@ namespace SparkyStudios::Audio::Amplitude AudioConverter::AudioConverter() : _resampler(nullptr) , _channelConversionMode(kChannelConversionModeDisabled) + , _needResampling(false) + , _srcInitialized(false) { _resampler = Resampler::Construct("default"); Reset(); @@ -42,8 +44,15 @@ namespace SparkyStudios::Audio::Amplitude else return false; // Unsupported channel conversion mode - _needResampling = settings.m_sourceChannelCount != settings.m_targetChannelCount; - _resampler->Initialize(settings.m_targetChannelCount, settings.m_sourceSampleRate, settings.m_targetSampleRate); + _needResampling = settings.m_sourceSampleRate != settings.m_targetSampleRate; + + if (_needResampling) + { + _resampler->Initialize(settings.m_targetChannelCount, settings.m_sourceSampleRate, settings.m_targetSampleRate); + _srcInitialized = true; + } + + _settings = settings; return true; } @@ -78,7 +87,17 @@ namespace SparkyStudios::Audio::Amplitude void AudioConverter::SetSampleRate(AmUInt64 sourceSampleRate, AmUInt64 targetSampleRate) { _needResampling = sourceSampleRate != targetSampleRate; - _resampler->SetSampleRate(sourceSampleRate, targetSampleRate); + + _settings.m_sourceSampleRate = sourceSampleRate; + _settings.m_targetSampleRate = targetSampleRate; + + if (!_needResampling) + return; + + if (_srcInitialized) + _resampler->SetSampleRate(sourceSampleRate, targetSampleRate); + else + _resampler->Initialize(_settings.m_targetChannelCount, sourceSampleRate, targetSampleRate); } AmUInt64 AudioConverter::GetRequiredInputFrameCount(AmUInt64 outputFrameCount) const diff --git a/src/Mixer/Amplimix.cpp b/src/Mixer/Amplimix.cpp index 8c34b438..130b6e18 100644 --- a/src/Mixer/Amplimix.cpp +++ b/src/Mixer/Amplimix.cpp @@ -17,7 +17,7 @@ #include #include -#define AMPLIMIX_STORE(A, C) std::atomic_store_explicit(A, C, std::memory_order_release) +#define AMPLIMIX_STORE(A, C) std::atomic_store_explicit(A, (C), std::memory_order_release) #define AMPLIMIX_LOAD(A) std::atomic_load_explicit(A, std::memory_order_acquire) #define AMPLIMIX_CSWAP(A, E, C) std::atomic_compare_exchange_strong_explicit(A, E, C, std::memory_order_acq_rel, std::memory_order_acquire) @@ -529,6 +529,10 @@ namespace SparkyStudios::Audio::Amplitude AMPLIMIX_STORE(&lay->userPlaySpeed, speed); // atomically set cursor to start position based on given argument AMPLIMIX_STORE(&lay->cursor, lay->start); + // store the base sample rate ratio for this source + AMPLIMIX_STORE( + &lay->baseSampleRateRatio, + static_cast(sound->format.GetSampleRate()) / static_cast(_device.mRequestedOutputSampleRate)); // Initialize the converter lay->dataConverter = ampoolnew(MemoryPoolKind::Amplimix, AudioConverter); @@ -1064,9 +1068,8 @@ namespace SparkyStudios::Audio::Amplitude { currentSpeed = AM_Lerp(currentSpeed, 0.75f, playSpeed); - const AmReal32 basePitch = - static_cast(layer->snd->format.GetSampleRate()) / static_cast(_device.mRequestedOutputSampleRate); - const AmReal32 sampleRateRatio = basePitch * currentSpeed; + const AmReal32 baseSampleRateRatio = AMPLIMIX_LOAD(&layer->baseSampleRateRatio); + const AmReal32 sampleRateRatio = baseSampleRateRatio * currentSpeed; AMPLIMIX_STORE(&layer->targetPlaySpeed, playSpeed); AMPLIMIX_STORE(&layer->sampleRateRatio, sampleRateRatio); diff --git a/src/Mixer/Amplimix.h b/src/Mixer/Amplimix.h index 0cfa48fb..1e1e2dbb 100644 --- a/src/Mixer/Amplimix.h +++ b/src/Mixer/Amplimix.h @@ -76,6 +76,7 @@ namespace SparkyStudios::Audio::Amplitude _Atomic(AmReal32) playSpeed; // current sound playback speed _Atomic(AmReal32) targetPlaySpeed; // computed (real) sound playback speed _Atomic(AmReal32) sampleRateRatio; // sample rate ratio + _Atomic(AmReal32) baseSampleRateRatio; // base sample rate ratio AudioConverter* dataConverter; // miniaudio resampler & channel converter