Extract common stuff for wrapper audio providers to a base class

This commit is contained in:
Thomas Goyne 2013-09-26 20:18:29 -07:00
parent 07ad40dd3f
commit 703b1fc3a7
8 changed files with 39 additions and 57 deletions

View File

@ -31,30 +31,12 @@
#include <limits>
/// Base class for all wrapping converters
class AudioProviderConverter : public AudioProvider {
protected:
std::unique_ptr<AudioProvider> source;
public:
AudioProviderConverter(std::unique_ptr<AudioProvider> src)
: source(std::move(src))
{
channels = source->GetChannels();
num_samples = source->GetNumSamples();
sample_rate = source->GetSampleRate();
bytes_per_sample = source->GetBytesPerSample();
float_samples = source->AreSamplesFloat();
}
agi::fs::path GetFilename() const { return source->GetFilename(); }
};
/// Anything integral -> 16 bit signed machine-endian audio converter
template<class Target>
class BitdepthConvertAudioProvider : public AudioProviderConverter {
class BitdepthConvertAudioProvider : public AudioProviderWrapper {
int src_bytes_per_sample;
public:
BitdepthConvertAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderConverter(std::move(src)) {
BitdepthConvertAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderWrapper(std::move(src)) {
if (bytes_per_sample > 8)
throw agi::AudioProviderOpenError("Audio format converter: audio with bitdepths greater than 64 bits/sample is currently unsupported", 0);
@ -92,9 +74,9 @@ public:
/// Floating point -> 16 bit signed machine-endian audio converter
template<class Source, class Target>
class FloatConvertAudioProvider : public AudioProviderConverter {
class FloatConvertAudioProvider : public AudioProviderWrapper {
public:
FloatConvertAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderConverter(std::move(src)) {
FloatConvertAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderWrapper(std::move(src)) {
bytes_per_sample = sizeof(Target);
float_samples = false;
}
@ -123,10 +105,10 @@ public:
};
/// Non-mono 16-bit signed machine-endian -> mono 16-bit signed machine endian converter
class DownmixAudioProvider : public AudioProviderConverter {
class DownmixAudioProvider : public AudioProviderWrapper {
int src_channels;
public:
DownmixAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderConverter(std::move(src)) {
DownmixAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderWrapper(std::move(src)) {
if (bytes_per_sample != 2)
throw agi::InternalError("DownmixAudioProvider requires 16-bit input", 0);
if (channels == 1)
@ -154,9 +136,9 @@ public:
/// Sample doubler with linear interpolation for the agi::util::make_unique<samples>
/// Requires 16-bit mono input
class SampleDoublingAudioProvider : public AudioProviderConverter {
class SampleDoublingAudioProvider : public AudioProviderWrapper {
public:
SampleDoublingAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderConverter(std::move(src)) {
SampleDoublingAudioProvider(std::unique_ptr<AudioProvider> src) : AudioProviderWrapper(std::move(src)) {
if (source->GetBytesPerSample() != 2)
throw agi::InternalError("UpsampleAudioProvider requires 16-bit input", 0);
if (source->GetChannels() != 1)

View File

@ -89,14 +89,9 @@ public:
}
HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br) {
bytes_per_sample = src->GetBytesPerSample();
num_samples = src->GetNumSamples();
channels = src->GetChannels();
sample_rate = src->GetSampleRate();
filename = src->GetFilename();
float_samples = src->AreSamplesFloat();
HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br)
: AudioProviderWrapper(std::move(src))
{
// Check free space
if ((uint64_t)num_samples * channels * bytes_per_sample > agi::fs::FreeSpace(cache_dir()))
throw agi::AudioCacheOpenError("Not enough free disk space in " + cache_dir().string() + " to cache the audio", 0);
@ -106,9 +101,9 @@ HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::Backgr
try {
{
agi::io::Save out(diskCacheFilename, true);
br->Run(bind(&HDAudioProvider::FillCache, this, src.get(), &out.Get(), std::placeholders::_1));
br->Run(bind(&HDAudioProvider::FillCache, this, source.get(), &out.Get(), std::placeholders::_1));
}
cache_provider = agi::util::make_unique<RawAudioProvider>(diskCacheFilename, src.get());
cache_provider = agi::util::make_unique<RawAudioProvider>(diskCacheFilename, source.get());
}
catch (...) {
agi::fs::Remove(diskCacheFilename);

View File

@ -39,7 +39,7 @@ namespace agi {
class ProgressSink;
}
class HDAudioProvider : public AudioProvider {
class HDAudioProvider : public AudioProviderWrapper {
/// Name of the file which the decoded audio is written to
agi::fs::path diskCacheFilename;
/// Audio provider which reads from the decoded cache

View File

@ -21,13 +21,8 @@
#include "audio_provider_lock.h"
LockAudioProvider::LockAudioProvider(std::unique_ptr<AudioProvider> src)
: source(std::move(src))
: AudioProviderWrapper(std::move(src))
{
channels = source->GetChannels();
num_samples = source->GetNumSamples();
sample_rate = source->GetSampleRate();
bytes_per_sample = source->GetBytesPerSample();
float_samples = source->AreSamplesFloat();
}
void LockAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {

View File

@ -21,8 +21,7 @@
#include <memory>
#include <mutex>
class LockAudioProvider : public AudioProvider {
std::unique_ptr<const AudioProvider> source;
class LockAudioProvider : public AudioProviderWrapper {
mutable std::mutex mutex;
void FillBuffer(void *buf, int64_t start, int64_t count) const;

View File

@ -46,23 +46,17 @@
#define CacheBits 22
#define CacheBlockSize (1 << CacheBits)
RAMAudioProvider::RAMAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br) {
RAMAudioProvider::RAMAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br)
: AudioProviderWrapper(std::move(src))
{
try {
blockcache.resize((src->GetNumSamples() * src->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits);
blockcache.resize((source->GetNumSamples() * source->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits);
}
catch (std::bad_alloc const&) {
throw agi::AudioCacheOpenError("Couldn't open audio, not enough ram available.", 0);
}
// Copy parameters
bytes_per_sample = src->GetBytesPerSample();
num_samples = src->GetNumSamples();
channels = src->GetChannels();
sample_rate = src->GetSampleRate();
filename = src->GetFilename();
float_samples = src->AreSamplesFloat();
br->Run(std::bind(&RAMAudioProvider::FillCache, this, src.get(), std::placeholders::_1));
br->Run(std::bind(&RAMAudioProvider::FillCache, this, source.get(), std::placeholders::_1));
}
void RAMAudioProvider::FillCache(AudioProvider *source, agi::ProgressSink *ps) {

View File

@ -42,7 +42,7 @@ namespace agi {
class ProgressSink;
}
class RAMAudioProvider : public AudioProvider {
class RAMAudioProvider : public AudioProviderWrapper {
#ifdef _MSC_VER
boost::container::stable_vector<char[1 << 22]> blockcache;
#else

View File

@ -73,6 +73,23 @@ public:
virtual bool NeedsCache() const { return false; }
};
/// Helper base class for an audio provider which wraps another provider
class AudioProviderWrapper : public AudioProvider {
protected:
std::unique_ptr<AudioProvider> source;
public:
AudioProviderWrapper(std::unique_ptr<AudioProvider> src)
: source(std::move(src))
{
channels = source->GetChannels();
num_samples = source->GetNumSamples();
sample_rate = source->GetSampleRate();
bytes_per_sample = source->GetBytesPerSample();
float_samples = source->AreSamplesFloat();
filename = source->GetFilename();
}
};
class AudioProviderFactory : public Factory1<AudioProvider, agi::fs::path> {
public:
static void RegisterProviders();