From d7ca60b998ebb0b1fb8aa418a3a6cd25609775f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Tue, 17 Aug 2021 00:44:42 +0200 Subject: [PATCH] LibAudio: Resample with integer ratios instead of floats Floating-point ratios are inherently imprecise, and can lead to unpredictable or nondeterministic behavior when resampling and expecting a certain number of resulting samples. Therefore, the resampler now uses integer ratios, with almost identical but fully predictable behavior. This also introduces the reset() function that the FLAC loader will use in the future. --- Userland/Libraries/LibAudio/Buffer.cpp | 29 +++++++++++++++++++------- Userland/Libraries/LibAudio/Buffer.h | 9 +++++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibAudio/Buffer.cpp b/Userland/Libraries/LibAudio/Buffer.cpp index efe6945a5fd..1039f5bb3f6 100644 --- a/Userland/Libraries/LibAudio/Buffer.cpp +++ b/Userland/Libraries/LibAudio/Buffer.cpp @@ -8,6 +8,7 @@ #include "Buffer.h" #include #include +#include #include namespace Audio { @@ -167,18 +168,19 @@ RefPtr Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper } template -ResampleHelper::ResampleHelper(double source, double target) - : m_ratio(source / target) +ResampleHelper::ResampleHelper(u32 source, u32 target) + : m_source(source) + , m_target(target) { } -template ResampleHelper::ResampleHelper(double, double); -template ResampleHelper::ResampleHelper(double, double); +template ResampleHelper::ResampleHelper(u32, u32); +template ResampleHelper::ResampleHelper(u32, u32); template Vector ResampleHelper::resample(Vector to_resample) { Vector resampled; - resampled.ensure_capacity(to_resample.size() * m_ratio); + resampled.ensure_capacity(to_resample.size() * ceil_div(m_source, m_target)); for (auto sample : to_resample) { process_sample(sample, sample); @@ -196,7 +198,7 @@ void ResampleHelper::process_sample(SampleType sample_l, SampleType { m_last_sample_l = sample_l; m_last_sample_r = sample_r; - m_current_ratio += 1; + m_current_ratio += m_target; } template void ResampleHelper::process_sample(i32, i32); template void ResampleHelper::process_sample(double, double); @@ -204,8 +206,8 @@ template void ResampleHelper::process_sample(double, double); template bool ResampleHelper::read_sample(SampleType& next_l, SampleType& next_r) { - if (m_current_ratio > 0) { - m_current_ratio -= m_ratio; + if (m_current_ratio >= m_source) { + m_current_ratio -= m_source; next_l = m_last_sample_l; next_r = m_last_sample_r; return true; @@ -216,4 +218,15 @@ bool ResampleHelper::read_sample(SampleType& next_l, SampleType& nex template bool ResampleHelper::read_sample(i32&, i32&); template bool ResampleHelper::read_sample(double&, double&); +template +void ResampleHelper::reset() +{ + m_current_ratio = 0; + m_last_sample_l = {}; + m_last_sample_r = {}; +} + +template void ResampleHelper::reset(); +template void ResampleHelper::reset(); + } diff --git a/Userland/Libraries/LibAudio/Buffer.h b/Userland/Libraries/LibAudio/Buffer.h index 36191113842..6bf6377b96a 100644 --- a/Userland/Libraries/LibAudio/Buffer.h +++ b/Userland/Libraries/LibAudio/Buffer.h @@ -91,7 +91,7 @@ String sample_format_name(PcmSampleFormat format); template class ResampleHelper { public: - ResampleHelper(double source, double target); + ResampleHelper(u32 source, u32 target); // To be used as follows: // while the resampler doesn't need a new sample, read_sample(current) and store the resulting samples. @@ -103,9 +103,12 @@ public: bool read_sample(SampleType& next_l, SampleType& next_r); Vector resample(Vector to_resample); + void reset(); + private: - const double m_ratio; - double m_current_ratio { 0 }; + const u32 m_source; + const u32 m_target; + u32 m_current_ratio { 0 }; SampleType m_last_sample_l; SampleType m_last_sample_r; };