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> #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 /// Anything integral -> 16 bit signed machine-endian audio converter
template<class Target> template<class Target>
class BitdepthConvertAudioProvider : public AudioProviderConverter { class BitdepthConvertAudioProvider : public AudioProviderWrapper {
int src_bytes_per_sample; int src_bytes_per_sample;
public: 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) if (bytes_per_sample > 8)
throw agi::AudioProviderOpenError("Audio format converter: audio with bitdepths greater than 64 bits/sample is currently unsupported", 0); 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 /// Floating point -> 16 bit signed machine-endian audio converter
template<class Source, class Target> template<class Source, class Target>
class FloatConvertAudioProvider : public AudioProviderConverter { class FloatConvertAudioProvider : public AudioProviderWrapper {
public: 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); bytes_per_sample = sizeof(Target);
float_samples = false; float_samples = false;
} }
@ -123,10 +105,10 @@ public:
}; };
/// Non-mono 16-bit signed machine-endian -> mono 16-bit signed machine endian converter /// 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; int src_channels;
public: 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) if (bytes_per_sample != 2)
throw agi::InternalError("DownmixAudioProvider requires 16-bit input", 0); throw agi::InternalError("DownmixAudioProvider requires 16-bit input", 0);
if (channels == 1) if (channels == 1)
@ -154,9 +136,9 @@ public:
/// Sample doubler with linear interpolation for the agi::util::make_unique<samples> /// Sample doubler with linear interpolation for the agi::util::make_unique<samples>
/// Requires 16-bit mono input /// Requires 16-bit mono input
class SampleDoublingAudioProvider : public AudioProviderConverter { class SampleDoublingAudioProvider : public AudioProviderWrapper {
public: 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) if (source->GetBytesPerSample() != 2)
throw agi::InternalError("UpsampleAudioProvider requires 16-bit input", 0); throw agi::InternalError("UpsampleAudioProvider requires 16-bit input", 0);
if (source->GetChannels() != 1) if (source->GetChannels() != 1)

View File

@ -89,14 +89,9 @@ public:
} }
HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br) { HDAudioProvider::HDAudioProvider(std::unique_ptr<AudioProvider> src, agi::BackgroundRunner *br)
bytes_per_sample = src->GetBytesPerSample(); : AudioProviderWrapper(std::move(src))
num_samples = src->GetNumSamples(); {
channels = src->GetChannels();
sample_rate = src->GetSampleRate();
filename = src->GetFilename();
float_samples = src->AreSamplesFloat();
// Check free space // Check free space
if ((uint64_t)num_samples * channels * bytes_per_sample > agi::fs::FreeSpace(cache_dir())) 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); 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 { try {
{ {
agi::io::Save out(diskCacheFilename, true); 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 (...) { catch (...) {
agi::fs::Remove(diskCacheFilename); agi::fs::Remove(diskCacheFilename);

View File

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

View File

@ -21,13 +21,8 @@
#include "audio_provider_lock.h" #include "audio_provider_lock.h"
LockAudioProvider::LockAudioProvider(std::unique_ptr<AudioProvider> src) 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 { void LockAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const {

View File

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

View File

@ -46,23 +46,17 @@
#define CacheBits 22 #define CacheBits 22
#define CacheBlockSize (1 << CacheBits) #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 { try {
blockcache.resize((src->GetNumSamples() * src->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits); blockcache.resize((source->GetNumSamples() * source->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits);
} }
catch (std::bad_alloc const&) { catch (std::bad_alloc const&) {
throw agi::AudioCacheOpenError("Couldn't open audio, not enough ram available.", 0); throw agi::AudioCacheOpenError("Couldn't open audio, not enough ram available.", 0);
} }
// Copy parameters br->Run(std::bind(&RAMAudioProvider::FillCache, this, source.get(), std::placeholders::_1));
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));
} }
void RAMAudioProvider::FillCache(AudioProvider *source, agi::ProgressSink *ps) { void RAMAudioProvider::FillCache(AudioProvider *source, agi::ProgressSink *ps) {

View File

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

View File

@ -73,6 +73,23 @@ public:
virtual bool NeedsCache() const { return false; } 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> { class AudioProviderFactory : public Factory1<AudioProvider, agi::fs::path> {
public: public:
static void RegisterProviders(); static void RegisterProviders();