From 5d01db34937894a938bf42a9d1fcd668417b5298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Sun, 23 Jan 2022 15:21:56 +0100 Subject: [PATCH] LibAudio: Split Buffer.{h, cpp} into three files The Buffer files had contained both the ResampleHelper and the sample format utilities. Because the Buffer class (and its file) is going to be deleted soon, this commit separates those two things into their own files. --- Userland/Libraries/LibAudio/Buffer.cpp | 104 ------------------ Userland/Libraries/LibAudio/Buffer.h | 47 +------- Userland/Libraries/LibAudio/CMakeLists.txt | 2 + Userland/Libraries/LibAudio/Resampler.cpp | 28 +++++ Userland/Libraries/LibAudio/Resampler.h | 74 +++++++++++++ Userland/Libraries/LibAudio/SampleFormats.cpp | 36 ++++++ Userland/Libraries/LibAudio/SampleFormats.h | 27 +++++ 7 files changed, 169 insertions(+), 149 deletions(-) create mode 100644 Userland/Libraries/LibAudio/Resampler.cpp create mode 100644 Userland/Libraries/LibAudio/Resampler.h create mode 100644 Userland/Libraries/LibAudio/SampleFormats.cpp create mode 100644 Userland/Libraries/LibAudio/SampleFormats.h diff --git a/Userland/Libraries/LibAudio/Buffer.cpp b/Userland/Libraries/LibAudio/Buffer.cpp index d880ce22d7..1152a6ade3 100644 --- a/Userland/Libraries/LibAudio/Buffer.cpp +++ b/Userland/Libraries/LibAudio/Buffer.cpp @@ -13,31 +13,6 @@ namespace Audio { -u16 pcm_bits_per_sample(PcmSampleFormat format) -{ - switch (format) { - case Uint8: - return 8; - case Int16: - return 16; - case Int24: - return 24; - case Int32: - case Float32: - return 32; - case Float64: - return 64; - default: - VERIFY_NOT_REACHED(); - } -} - -String sample_format_name(PcmSampleFormat format) -{ - bool is_float = format == Float32 || format == Float64; - return String::formatted("PCM {}bit {}", pcm_bits_per_sample(format), is_float ? "Float" : "LE"); -} - i32 Buffer::allocate_id() { static Atomic next_id; @@ -161,83 +136,4 @@ ErrorOr> Buffer::from_pcm_stream(InputMemoryStream& stream return Buffer::create_with_samples(move(fdata)); } -template -ResampleHelper::ResampleHelper(u32 source, u32 target) - : m_source(source) - , m_target(target) -{ - VERIFY(source > 0); - VERIFY(target > 0); -} -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() * ceil_div(m_source, m_target)); - 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); - -ErrorOr> resample_buffer(ResampleHelper& resampler, Buffer const& to_resample) -{ - Vector resampled; - resampled.ensure_capacity(to_resample.sample_count() * ceil_div(resampler.source(), resampler.target())); - for (size_t i = 0; i < static_cast(to_resample.sample_count()); ++i) { - auto sample = to_resample.samples()[i]; - resampler.process_sample(sample.left, sample.right); - - while (resampler.read_sample(sample.left, sample.right)) - resampled.append(sample); - } - - return Buffer::create_with_samples(move(resampled)); -} - -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 += m_target; -} -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 >= m_source) { - m_current_ratio -= m_source; - 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&); - -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 f1dcf64df8..d69090940f 100644 --- a/Userland/Libraries/LibAudio/Buffer.h +++ b/Userland/Libraries/LibAudio/Buffer.h @@ -17,58 +17,15 @@ #include #include #include +#include #include +#include #include #include namespace Audio { using namespace AK::Exponentials; -// Supported PCM sample formats. -enum PcmSampleFormat : u8 { - Uint8, - Int16, - Int24, - Int32, - Float32, - Float64, -}; - -// Most of the read code only cares about how many bits to read or write -u16 pcm_bits_per_sample(PcmSampleFormat format); -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(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. - // 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); - - void reset(); - - u32 source() const { return m_source; } - u32 target() const { return m_target; } - -private: - const u32 m_source; - const u32 m_target; - u32 m_current_ratio { 0 }; - SampleType m_last_sample_l; - SampleType m_last_sample_r; -}; - // A buffer of audio samples. class Buffer : public RefCounted { public: diff --git a/Userland/Libraries/LibAudio/CMakeLists.txt b/Userland/Libraries/LibAudio/CMakeLists.txt index 89554a8091..1f6a863b1f 100644 --- a/Userland/Libraries/LibAudio/CMakeLists.txt +++ b/Userland/Libraries/LibAudio/CMakeLists.txt @@ -1,5 +1,7 @@ set(SOURCES Buffer.cpp + Resampler.cpp + SampleFormats.cpp ConnectionFromClient.cpp Loader.cpp WavLoader.cpp diff --git a/Userland/Libraries/LibAudio/Resampler.cpp b/Userland/Libraries/LibAudio/Resampler.cpp new file mode 100644 index 0000000000..35ed37c536 --- /dev/null +++ b/Userland/Libraries/LibAudio/Resampler.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "Resampler.h" +#include "Buffer.h" +#include "Sample.h" + +namespace Audio { + +ErrorOr> resample_buffer(ResampleHelper& resampler, Buffer const& to_resample) +{ + Vector resampled; + resampled.ensure_capacity(to_resample.sample_count() * ceil_div(resampler.source(), resampler.target())); + for (size_t i = 0; i < static_cast(to_resample.sample_count()); ++i) { + auto sample = to_resample.samples()[i]; + resampler.process_sample(sample.left, sample.right); + + while (resampler.read_sample(sample.left, sample.right)) + resampled.append(sample); + } + + return Buffer::create_with_samples(move(resampled)); +} + +} diff --git a/Userland/Libraries/LibAudio/Resampler.h b/Userland/Libraries/LibAudio/Resampler.h new file mode 100644 index 0000000000..718c9b3ac9 --- /dev/null +++ b/Userland/Libraries/LibAudio/Resampler.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Audio { + +// 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(u32 source, u32 target) + : m_source(source) + , m_target(target) + { + VERIFY(source > 0); + VERIFY(target > 0); + } + + // 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) + { + m_last_sample_l = sample_l; + m_last_sample_r = sample_r; + m_current_ratio += m_target; + } + + // 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) + { + 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; + } + + return false; + } + + void reset() + { + m_current_ratio = 0; + m_last_sample_l = {}; + m_last_sample_r = {}; + } + + u32 source() const { return m_source; } + u32 target() const { return m_target; } + +private: + const u32 m_source; + const u32 m_target; + u32 m_current_ratio { 0 }; + SampleType m_last_sample_l; + SampleType m_last_sample_r; +}; + +class Buffer; +ErrorOr> resample_buffer(ResampleHelper& resampler, Buffer const& to_resample); + +} diff --git a/Userland/Libraries/LibAudio/SampleFormats.cpp b/Userland/Libraries/LibAudio/SampleFormats.cpp new file mode 100644 index 0000000000..740c24e58d --- /dev/null +++ b/Userland/Libraries/LibAudio/SampleFormats.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "SampleFormats.h" + +namespace Audio { + +u16 pcm_bits_per_sample(PcmSampleFormat format) +{ + switch (format) { + case Uint8: + return 8; + case Int16: + return 16; + case Int24: + return 24; + case Int32: + case Float32: + return 32; + case Float64: + return 64; + default: + VERIFY_NOT_REACHED(); + } +} + +String sample_format_name(PcmSampleFormat format) +{ + bool is_float = format == Float32 || format == Float64; + return String::formatted("PCM {}bit {}", pcm_bits_per_sample(format), is_float ? "Float" : "LE"); +} + +} diff --git a/Userland/Libraries/LibAudio/SampleFormats.h b/Userland/Libraries/LibAudio/SampleFormats.h new file mode 100644 index 0000000000..2990ee80b8 --- /dev/null +++ b/Userland/Libraries/LibAudio/SampleFormats.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen . + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Audio { + +// Supported PCM sample formats. +enum PcmSampleFormat : u8 { + Uint8, + Int16, + Int24, + Int32, + Float32, + Float64, +}; + +// Most of the read code only cares about how many bits to read or write +u16 pcm_bits_per_sample(PcmSampleFormat format); +String sample_format_name(PcmSampleFormat format); +}