mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 02:12:09 -05:00
LibAudio: Make ResampleHelper templated for different sample types
Previously, ResampleHelper was fixed on handling double's, which makes it unsuitable for the upcoming FLAC loader that needs to resample integers. For this reason, ResampleHelper is templated to support theoretically any type of sample, though only the necessary i32 and double are templated right now. The ResampleHelper implementations are moved from WavLoader.cpp to Buffer.cpp. This also improves some imports in the WavLoader files.
This commit is contained in:
parent
2e00155275
commit
184a9e7e67
4 changed files with 73 additions and 39 deletions
|
@ -5,10 +5,10 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "Buffer.h"
|
||||
#include <AK/Atomic.h>
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibAudio/Buffer.h>
|
||||
|
||||
namespace Audio {
|
||||
|
||||
|
@ -44,7 +44,7 @@ i32 Buffer::allocate_id()
|
|||
}
|
||||
|
||||
template<typename SampleReader>
|
||||
static void read_samples_from_stream(InputMemoryStream& stream, SampleReader read_sample, Vector<Frame>& samples, ResampleHelper& resampler, int num_channels)
|
||||
static void read_samples_from_stream(InputMemoryStream& stream, SampleReader read_sample, Vector<Frame>& samples, ResampleHelper<double>& 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<u8>::max();
|
||||
}
|
||||
|
||||
RefPtr<Buffer> Buffer::from_pcm_data(ReadonlyBytes data, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format)
|
||||
RefPtr<Buffer> Buffer::from_pcm_data(ReadonlyBytes data, ResampleHelper<double>& 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> Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples)
|
||||
RefPtr<Buffer> Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper<double>& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples)
|
||||
{
|
||||
Vector<Frame> fdata;
|
||||
fdata.ensure_capacity(num_samples);
|
||||
|
@ -166,4 +166,54 @@ RefPtr<Buffer> Buffer::from_pcm_stream(InputMemoryStream& stream, ResampleHelper
|
|||
return Buffer::create_with_samples(move(fdata));
|
||||
}
|
||||
|
||||
template<typename SampleType>
|
||||
ResampleHelper<SampleType>::ResampleHelper(double source, double target)
|
||||
: m_ratio(source / target)
|
||||
{
|
||||
}
|
||||
template ResampleHelper<i32>::ResampleHelper(double, double);
|
||||
template ResampleHelper<double>::ResampleHelper(double, double);
|
||||
|
||||
template<typename SampleType>
|
||||
Vector<SampleType> ResampleHelper<SampleType>::resample(Vector<SampleType> to_resample)
|
||||
{
|
||||
Vector<SampleType> 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<i32> ResampleHelper<i32>::resample(Vector<i32>);
|
||||
template Vector<double> ResampleHelper<double>::resample(Vector<double>);
|
||||
|
||||
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 += 1;
|
||||
}
|
||||
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 > 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<i32>::read_sample(i32&, i32&);
|
||||
template bool ResampleHelper<double>::read_sample(double&, double&);
|
||||
|
||||
}
|
||||
|
|
|
@ -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<typename SampleType>
|
||||
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<SampleType> resample(Vector<SampleType> 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<Buffer> {
|
||||
public:
|
||||
static RefPtr<Buffer> from_pcm_data(ReadonlyBytes data, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format);
|
||||
static RefPtr<Buffer> from_pcm_stream(InputMemoryStream& stream, ResampleHelper& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples);
|
||||
static RefPtr<Buffer> from_pcm_data(ReadonlyBytes data, ResampleHelper<double>& resampler, int num_channels, PcmSampleFormat sample_format);
|
||||
static RefPtr<Buffer> from_pcm_stream(InputMemoryStream& stream, ResampleHelper<double>& resampler, int num_channels, PcmSampleFormat sample_format, int num_samples);
|
||||
static NonnullRefPtr<Buffer> create_with_samples(Vector<Frame>&& samples)
|
||||
{
|
||||
return adopt_ref(*new Buffer(move(samples)));
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "WavLoader.h"
|
||||
#include "Buffer.h"
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/NumericLimits.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <LibAudio/Buffer.h>
|
||||
#include <LibAudio/WavLoader.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/FileStream.h>
|
||||
|
||||
|
@ -30,7 +30,7 @@ WavLoaderPlugin::WavLoaderPlugin(const StringView& path)
|
|||
if (!valid)
|
||||
return;
|
||||
|
||||
m_resampler = make<ResampleHelper>(m_sample_rate, m_device_sample_rate);
|
||||
m_resampler = make<ResampleHelper<double>>(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<ResampleHelper>(m_sample_rate, m_device_sample_rate);
|
||||
m_resampler = make<ResampleHelper<double>>(m_sample_rate, m_device_sample_rate);
|
||||
}
|
||||
|
||||
RefPtr<Buffer> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<ResampleHelper> m_resampler;
|
||||
OwnPtr<ResampleHelper<double>> m_resampler;
|
||||
|
||||
u32 m_sample_rate { 0 };
|
||||
u16 m_num_channels { 0 };
|
||||
|
|
Loading…
Add table
Reference in a new issue