diff --git a/Userland/Libraries/LibAudio/Buffer.cpp b/Userland/Libraries/LibAudio/Buffer.cpp index 86a51aa7ac..efe6945a5f 100644 --- a/Userland/Libraries/LibAudio/Buffer.cpp +++ b/Userland/Libraries/LibAudio/Buffer.cpp @@ -5,10 +5,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "Buffer.h" #include #include #include -#include namespace Audio { @@ -44,7 +44,7 @@ i32 Buffer::allocate_id() } template -static void read_samples_from_stream(InputMemoryStream& stream, SampleReader read_sample, Vector& samples, ResampleHelper& resampler, int num_channels) +static void read_samples_from_stream(InputMemoryStream& stream, SampleReader read_sample, Vector& samples, ResampleHelper& resampler, int num_channels) { double norm_l = 0; double norm_r = 0; @@ -127,13 +127,13 @@ static double read_norm_sample_8(InputMemoryStream& stream) return double(sample) / NumericLimits::max(); } -RefPtr Buffer::from_pcm_data(ReadonlyBytes data, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format) +RefPtr Buffer::from_pcm_data(ReadonlyBytes data, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format) { InputMemoryStream stream { data }; return from_pcm_stream(stream, resampler, num_channels, sample_format, data.size() / (pcm_bits_per_sample(sample_format) / 8)); } -RefPtr Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples) +RefPtr Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples) { Vector fdata; fdata.ensure_capacity(num_samples); @@ -166,4 +166,54 @@ RefPtr Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper return Buffer::create_with_samples(move(fdata)); } +template +ResampleHelper::ResampleHelper(double source, double target) + : m_ratio(source / target) +{ +} +template ResampleHelper::ResampleHelper(double, double); +template ResampleHelper::ResampleHelper(double, double); + +template +Vector ResampleHelper::resample(Vector to_resample) +{ + Vector resampled; + resampled.ensure_capacity(to_resample.size() * m_ratio); + for (auto sample : to_resample) { + process_sample(sample, sample); + + while (read_sample(sample, sample)) + resampled.unchecked_append(sample); + } + + return resampled; +} +template Vector ResampleHelper::resample(Vector); +template Vector ResampleHelper::resample(Vector); + +template +void ResampleHelper::process_sample(SampleType sample_l, SampleType sample_r) +{ + m_last_sample_l = sample_l; + m_last_sample_r = sample_r; + m_current_ratio += 1; +} +template void ResampleHelper::process_sample(i32, i32); +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; + next_l = m_last_sample_l; + next_r = m_last_sample_r; + return true; + } + + return false; +} +template bool ResampleHelper::read_sample(i32&, i32&); +template bool ResampleHelper::read_sample(double&, double&); + } diff --git a/Userland/Libraries/LibAudio/Buffer.h b/Userland/Libraries/LibAudio/Buffer.h index 88d0fa0c56..3619111384 100644 --- a/Userland/Libraries/LibAudio/Buffer.h +++ b/Userland/Libraries/LibAudio/Buffer.h @@ -88,25 +88,33 @@ String sample_format_name(PcmSampleFormat format); // Small helper to resample from one playback rate to another // This isn't really "smart", in that we just insert (or drop) samples. // Should do better... +template class ResampleHelper { public: ResampleHelper(double source, double target); - void process_sample(double sample_l, double sample_r); - bool read_sample(double& next_l, double& next_r); + // To be used as follows: + // while the resampler doesn't need a new sample, read_sample(current) and store the resulting samples. + // as long as the resampler needs a new sample, process_sample(current) + + // Stores a new sample + void process_sample(SampleType sample_l, SampleType sample_r); + // Assigns the given sample to its correct value and returns false if there is a new sample required + bool read_sample(SampleType& next_l, SampleType& next_r); + Vector resample(Vector to_resample); private: const double m_ratio; double m_current_ratio { 0 }; - double m_last_sample_l { 0 }; - double m_last_sample_r { 0 }; + SampleType m_last_sample_l; + SampleType m_last_sample_r; }; // A buffer of audio samples, normalized to 44100hz. class Buffer : public RefCounted { public: - static RefPtr from_pcm_data(ReadonlyBytes data, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format); - static RefPtr from_pcm_stream(InputMemoryStream& stream, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples); + static RefPtr from_pcm_data(ReadonlyBytes data, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format); + static RefPtr from_pcm_stream(InputMemoryStream& stream, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples); static NonnullRefPtr create_with_samples(Vector&& samples) { return adopt_ref(*new Buffer(move(samples))); diff --git a/Userland/Libraries/LibAudio/WavLoader.cpp b/Userland/Libraries/LibAudio/WavLoader.cpp index 3353549e20..2734ae4109 100644 --- a/Userland/Libraries/LibAudio/WavLoader.cpp +++ b/Userland/Libraries/LibAudio/WavLoader.cpp @@ -5,11 +5,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "WavLoader.h" +#include "Buffer.h" #include #include #include -#include -#include #include #include @@ -30,7 +30,7 @@ WavLoaderPlugin::WavLoaderPlugin(const StringView& path) if (!valid) return; - m_resampler = make(m_sample_rate, m_device_sample_rate); + m_resampler = make>(m_sample_rate, m_device_sample_rate); } WavLoaderPlugin::WavLoaderPlugin(const ByteBuffer& buffer) @@ -46,7 +46,7 @@ WavLoaderPlugin::WavLoaderPlugin(const ByteBuffer& buffer) if (!valid) return; - m_resampler = make(m_sample_rate, m_device_sample_rate); + m_resampler = make>(m_sample_rate, m_device_sample_rate); } RefPtr WavLoaderPlugin::get_more_samples(size_t max_bytes_to_read_from_input) @@ -284,28 +284,4 @@ bool WavLoaderPlugin::parse_header() return true; } -ResampleHelper::ResampleHelper(double source, double target) - : m_ratio(source / target) -{ -} - -void ResampleHelper::process_sample(double sample_l, double sample_r) -{ - m_last_sample_l = sample_l; - m_last_sample_r = sample_r; - m_current_ratio += 1; -} - -bool ResampleHelper::read_sample(double& next_l, double& next_r) -{ - if (m_current_ratio > 0) { - m_current_ratio -= m_ratio; - next_l = m_last_sample_l; - next_r = m_last_sample_r; - return true; - } - - return false; -} - } diff --git a/Userland/Libraries/LibAudio/WavLoader.h b/Userland/Libraries/LibAudio/WavLoader.h index 4eaa4b9a4b..edef9ed1d3 100644 --- a/Userland/Libraries/LibAudio/WavLoader.h +++ b/Userland/Libraries/LibAudio/WavLoader.h @@ -71,7 +71,7 @@ private: // // It would avoid duplicate resampling code and would allow clients // to be agnostic of the destination audio device's sample rate. - OwnPtr m_resampler; + OwnPtr> m_resampler; u32 m_sample_rate { 0 }; u16 m_num_channels { 0 };