mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 19:57:44 +00:00
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.
This commit is contained in:
parent
262488ea33
commit
5d01db3493
7 changed files with 169 additions and 149 deletions
|
@ -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<i32> next_id;
|
||||
|
@ -161,83 +136,4 @@ ErrorOr<NonnullRefPtr<Buffer>> Buffer::from_pcm_stream(InputMemoryStream& stream
|
|||
return Buffer::create_with_samples(move(fdata));
|
||||
}
|
||||
|
||||
template<typename SampleType>
|
||||
ResampleHelper<SampleType>::ResampleHelper(u32 source, u32 target)
|
||||
: m_source(source)
|
||||
, m_target(target)
|
||||
{
|
||||
VERIFY(source > 0);
|
||||
VERIFY(target > 0);
|
||||
}
|
||||
template ResampleHelper<i32>::ResampleHelper(u32, u32);
|
||||
template ResampleHelper<double>::ResampleHelper(u32, u32);
|
||||
|
||||
template<typename SampleType>
|
||||
Vector<SampleType> ResampleHelper<SampleType>::resample(Vector<SampleType> to_resample)
|
||||
{
|
||||
Vector<SampleType> 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<i32> ResampleHelper<i32>::resample(Vector<i32>);
|
||||
template Vector<double> ResampleHelper<double>::resample(Vector<double>);
|
||||
|
||||
ErrorOr<NonnullRefPtr<Buffer>> resample_buffer(ResampleHelper<double>& resampler, Buffer const& to_resample)
|
||||
{
|
||||
Vector<Sample> resampled;
|
||||
resampled.ensure_capacity(to_resample.sample_count() * ceil_div(resampler.source(), resampler.target()));
|
||||
for (size_t i = 0; i < static_cast<size_t>(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<typename SampleType>
|
||||
void ResampleHelper<SampleType>::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<i32>::process_sample(i32, i32);
|
||||
template void ResampleHelper<double>::process_sample(double, double);
|
||||
|
||||
template<typename SampleType>
|
||||
bool ResampleHelper<SampleType>::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<i32>::read_sample(i32&, i32&);
|
||||
template bool ResampleHelper<double>::read_sample(double&, double&);
|
||||
|
||||
template<typename SampleType>
|
||||
void ResampleHelper<SampleType>::reset()
|
||||
{
|
||||
m_current_ratio = 0;
|
||||
m_last_sample_l = {};
|
||||
m_last_sample_r = {};
|
||||
}
|
||||
|
||||
template void ResampleHelper<i32>::reset();
|
||||
template void ResampleHelper<double>::reset();
|
||||
|
||||
}
|
||||
|
|
|
@ -17,58 +17,15 @@
|
|||
#include <AK/Types.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/kmalloc.h>
|
||||
#include <LibAudio/Resampler.h>
|
||||
#include <LibAudio/Sample.h>
|
||||
#include <LibAudio/SampleFormats.h>
|
||||
#include <LibCore/AnonymousBuffer.h>
|
||||
#include <string.h>
|
||||
|
||||
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<typename SampleType>
|
||||
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<SampleType> resample(Vector<SampleType> 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<Buffer> {
|
||||
public:
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
set(SOURCES
|
||||
Buffer.cpp
|
||||
Resampler.cpp
|
||||
SampleFormats.cpp
|
||||
ConnectionFromClient.cpp
|
||||
Loader.cpp
|
||||
WavLoader.cpp
|
||||
|
|
28
Userland/Libraries/LibAudio/Resampler.cpp
Normal file
28
Userland/Libraries/LibAudio/Resampler.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "Resampler.h"
|
||||
#include "Buffer.h"
|
||||
#include "Sample.h"
|
||||
|
||||
namespace Audio {
|
||||
|
||||
ErrorOr<NonnullRefPtr<Buffer>> resample_buffer(ResampleHelper<double>& resampler, Buffer const& to_resample)
|
||||
{
|
||||
Vector<Sample> resampled;
|
||||
resampled.ensure_capacity(to_resample.sample_count() * ceil_div(resampler.source(), resampler.target()));
|
||||
for (size_t i = 0; i < static_cast<size_t>(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));
|
||||
}
|
||||
|
||||
}
|
74
Userland/Libraries/LibAudio/Resampler.h
Normal file
74
Userland/Libraries/LibAudio/Resampler.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
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<typename SampleType>
|
||||
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<NonnullRefPtr<Buffer>> resample_buffer(ResampleHelper<double>& resampler, Buffer const& to_resample);
|
||||
|
||||
}
|
36
Userland/Libraries/LibAudio/SampleFormats.cpp
Normal file
36
Userland/Libraries/LibAudio/SampleFormats.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>.
|
||||
*
|
||||
* 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");
|
||||
}
|
||||
|
||||
}
|
27
Userland/Libraries/LibAudio/SampleFormats.h
Normal file
27
Userland/Libraries/LibAudio/SampleFormats.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue