diff options
author | Joerg Mueller <nexyon@gmail.com> | 2011-06-22 00:25:48 +0400 |
---|---|---|
committer | Joerg Mueller <nexyon@gmail.com> | 2011-06-22 00:25:48 +0400 |
commit | d5eaffda23274271e28bf499bd8d4555b0077079 (patch) | |
tree | aeea31ffdddc329474cc62a6c5bd1371daf12f9a /intern | |
parent | c89b4e4b665757e0a164e98985d2f5d1c6843fa0 (diff) |
3D Audio GSoC:
Dynamic resampling for libsamplerate and linear resampling.
Diffstat (limited to 'intern')
-rw-r--r-- | intern/audaspace/FX/AUD_ReverseReader.cpp | 2 | ||||
-rw-r--r-- | intern/audaspace/SRC/AUD_SRCResampleFactory.cpp | 7 | ||||
-rw-r--r-- | intern/audaspace/SRC/AUD_SRCResampleReader.cpp | 57 | ||||
-rw-r--r-- | intern/audaspace/SRC/AUD_SRCResampleReader.h | 17 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_LinearResampleFactory.cpp | 7 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_LinearResampleReader.cpp | 138 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_LinearResampleReader.h | 22 |
7 files changed, 157 insertions, 93 deletions
diff --git a/intern/audaspace/FX/AUD_ReverseReader.cpp b/intern/audaspace/FX/AUD_ReverseReader.cpp index 1a5083d3eb4..73f6830f3fa 100644 --- a/intern/audaspace/FX/AUD_ReverseReader.cpp +++ b/intern/audaspace/FX/AUD_ReverseReader.cpp @@ -76,7 +76,7 @@ void AUD_ReverseReader::read(int& length, bool& eos, sample_t* buffer) const AUD_Specs specs = getSpecs(); const int samplesize = AUD_SAMPLE_SIZE(specs); - sample_t temp[10]; + sample_t temp[AUD_CHANNEL_MAX]; int len = length; diff --git a/intern/audaspace/SRC/AUD_SRCResampleFactory.cpp b/intern/audaspace/SRC/AUD_SRCResampleFactory.cpp index 15e96f6ff1d..3ae2c4fbd06 100644 --- a/intern/audaspace/SRC/AUD_SRCResampleFactory.cpp +++ b/intern/audaspace/SRC/AUD_SRCResampleFactory.cpp @@ -40,10 +40,5 @@ AUD_SRCResampleFactory::AUD_SRCResampleFactory(AUD_Reference<AUD_IFactory> facto AUD_Reference<AUD_IReader> AUD_SRCResampleFactory::createReader() { - AUD_Reference<AUD_IReader> reader = getReader(); - - if(reader->getSpecs().rate != m_specs.rate) - reader = new AUD_SRCResampleReader(reader, m_specs.specs); - - return reader; + return new AUD_SRCResampleReader(getReader(), m_specs.specs); } diff --git a/intern/audaspace/SRC/AUD_SRCResampleReader.cpp b/intern/audaspace/SRC/AUD_SRCResampleReader.cpp index 59854a7a2c4..cd6b0ef8c50 100644 --- a/intern/audaspace/SRC/AUD_SRCResampleReader.cpp +++ b/intern/audaspace/SRC/AUD_SRCResampleReader.cpp @@ -46,17 +46,14 @@ static const char* state_error = "AUD_SRCResampleReader: SRC State couldn't be " AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_Reference<AUD_IReader> reader, AUD_Specs specs) : AUD_EffectReader(reader), - m_sspecs(reader->getSpecs()), - m_factor(double(specs.rate) / double(m_sspecs.rate)), - m_tspecs(specs), + m_rate(specs.rate), + m_channels(reader->getSpecs().channels), m_position(0) { - m_tspecs.channels = m_sspecs.channels; - int error; m_src = src_callback_new(src_callback, SRC_SINC_MEDIUM_QUALITY, - m_sspecs.channels, + m_channels, &error, this); @@ -74,7 +71,11 @@ AUD_SRCResampleReader::~AUD_SRCResampleReader() long AUD_SRCResampleReader::doCallback(float** data) { - int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(m_tspecs); + AUD_Specs specs; + specs.channels = m_channels; + specs.rate = m_rate; + + int length = m_buffer.getSize() / AUD_SAMPLE_SIZE(specs); *data = m_buffer.getBuffer(); m_reader->read(length, m_eos, *data); @@ -84,14 +85,18 @@ long AUD_SRCResampleReader::doCallback(float** data) void AUD_SRCResampleReader::seek(int position) { - m_reader->seek(position / m_factor); + AUD_Specs specs = m_reader->getSpecs(); + double factor = double(m_rate) / double(specs.rate); + m_reader->seek(position / factor); src_reset(m_src); m_position = position; } int AUD_SRCResampleReader::getLength() const { - return m_reader->getLength() * m_factor; + AUD_Specs specs = m_reader->getSpecs(); + double factor = double(m_rate) / double(specs.rate); + return m_reader->getLength() * factor; } int AUD_SRCResampleReader::getPosition() const @@ -101,18 +106,46 @@ int AUD_SRCResampleReader::getPosition() const AUD_Specs AUD_SRCResampleReader::getSpecs() const { - return m_tspecs; + AUD_Specs specs = m_reader->getSpecs(); + specs.rate = m_rate; + return specs; } void AUD_SRCResampleReader::read(int& length, bool& eos, sample_t* buffer) { + AUD_Specs specs = m_reader->getSpecs(); + + double factor = double(m_rate) / double(specs.rate); + + specs.rate = m_rate; + int size = length; - m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_tspecs)); + m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs)); + + if(specs.channels != m_channels) + { + src_delete(m_src); + + m_channels = specs.channels; + + int error; + m_src = src_callback_new(src_callback, + SRC_SINC_MEDIUM_QUALITY, + m_channels, + &error, + this); + + if(!m_src) + { + // XXX printf("%s\n", src_strerror(error)); + AUD_THROW(AUD_ERROR_SRC, state_error); + } + } m_eos = false; - length = src_callback_read(m_src, m_factor, length, buffer); + length = src_callback_read(m_src, factor, length, buffer); m_position += length; diff --git a/intern/audaspace/SRC/AUD_SRCResampleReader.h b/intern/audaspace/SRC/AUD_SRCResampleReader.h index 5b210a61e70..896a742356b 100644 --- a/intern/audaspace/SRC/AUD_SRCResampleReader.h +++ b/intern/audaspace/SRC/AUD_SRCResampleReader.h @@ -44,24 +44,19 @@ class AUD_SRCResampleReader : public AUD_EffectReader { private: /** - * The sample specification of the source. - */ - const AUD_Specs m_sspecs; - - /** - * The resampling factor. + * The sound output buffer. */ - const double m_factor; + AUD_Buffer m_buffer; /** - * The sound output buffer. + * The target sampling rate. */ - AUD_Buffer m_buffer; + AUD_SampleRate m_rate; /** - * The target specification. + * The reader channels. */ - AUD_Specs m_tspecs; + AUD_Channels m_channels; /** * The src state structure. diff --git a/intern/audaspace/intern/AUD_LinearResampleFactory.cpp b/intern/audaspace/intern/AUD_LinearResampleFactory.cpp index 404281a33bb..de23869441f 100644 --- a/intern/audaspace/intern/AUD_LinearResampleFactory.cpp +++ b/intern/audaspace/intern/AUD_LinearResampleFactory.cpp @@ -40,10 +40,5 @@ AUD_LinearResampleFactory::AUD_LinearResampleFactory(AUD_Reference<AUD_IFactory> AUD_Reference<AUD_IReader> AUD_LinearResampleFactory::createReader() { - AUD_Reference<AUD_IReader> reader = getReader(); - - if(reader->getSpecs().rate != m_specs.rate) - reader = new AUD_LinearResampleReader(reader, m_specs.specs); - - return reader; + return new AUD_LinearResampleReader(getReader(), m_specs.specs); } diff --git a/intern/audaspace/intern/AUD_LinearResampleReader.cpp b/intern/audaspace/intern/AUD_LinearResampleReader.cpp index 7e4f7a5b45d..c227baad73b 100644 --- a/intern/audaspace/intern/AUD_LinearResampleReader.cpp +++ b/intern/audaspace/intern/AUD_LinearResampleReader.cpp @@ -34,94 +34,140 @@ #include <cmath> #include <cstring> -#define CC channels + channel +#define CC m_channels + channel AUD_LinearResampleReader::AUD_LinearResampleReader(AUD_Reference<AUD_IReader> reader, AUD_Specs specs) : AUD_EffectReader(reader), - m_sspecs(reader->getSpecs()), - m_factor(float(specs.rate) / float(m_sspecs.rate)), - m_tspecs(specs), + m_rate(specs.rate), + m_channels(reader->getSpecs().channels), m_position(0), - m_sposition(0) + m_cache_pos(0), + m_cache_ok(false) { - m_tspecs.channels = m_sspecs.channels; - m_cache.resize(2 * AUD_SAMPLE_SIZE(m_tspecs)); + specs.channels = m_channels; + m_cache.resize(2 * AUD_SAMPLE_SIZE(specs)); } void AUD_LinearResampleReader::seek(int position) { - m_position = position; - m_sposition = floor(position / m_factor); - m_reader->seek(m_sposition); + position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate)); + m_reader->seek(position); + m_cache_ok = false; + m_cache_pos = 0; } int AUD_LinearResampleReader::getLength() const { - return m_reader->getLength() * m_factor; + return floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate)); } int AUD_LinearResampleReader::getPosition() const { - return m_position; + return floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 2 : 0)) + * m_rate / m_reader->getSpecs().rate); } AUD_Specs AUD_LinearResampleReader::getSpecs() const { - return m_tspecs; + AUD_Specs specs = m_reader->getSpecs(); + specs.rate = m_rate; + return specs; } void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer) { - int samplesize = AUD_SAMPLE_SIZE(m_tspecs); + AUD_Specs specs = m_reader->getSpecs(); + + int samplesize = AUD_SAMPLE_SIZE(specs); int size = length; + float factor = float(m_rate) / float(m_reader->getSpecs().rate); + float spos; + sample_t low, high; + eos = false; - m_buffer.assureSize(size * AUD_SAMPLE_SIZE(m_sspecs)); + if(factor == 1 && (!m_cache_ok || m_cache_pos == 0)) + { + // can read directly! + m_reader->read(length, eos, buffer); + return; + } - int need = ceil((m_position + length) / m_factor) + 1 - m_sposition; - int len = need; - sample_t* buf = m_buffer.getBuffer(); + // check for channels changed - m_reader->read(len, eos, buf); + if(specs.channels != m_channels) + { + m_cache.resize(2 * samplesize); + m_channels = specs.channels; + m_cache_ok = false; + } - if(len < need) - length = floor((m_sposition + len - 1) * m_factor) - m_position; + int len; + sample_t* buf; - float spos; - sample_t low, high; - int channels = m_sspecs.channels; + if(m_cache_ok) + { + int need = ceil(length / factor - (1 - m_cache_pos)); + + len = need; + + m_buffer.assureSize((len + 3) * samplesize); + buf = m_buffer.getBuffer(); + + memcpy(buf, m_cache.getBuffer(), 2 * samplesize); + m_reader->read(len, eos, buf + 2 * m_channels); - for(int channel = 0; channel < channels; channel++) + if(len < need) + length = floor((len + (1 - m_cache_pos)) * factor); + } + else { - for(int i = 0; i < length; i++) - { - spos = (m_position + i) / m_factor - m_sposition; + int need = ceil(length / factor) + 1; + + len = need; - if(floor(spos) < 0) + m_buffer.assureSize((len + 1) * samplesize); + buf = m_buffer.getBuffer(); + + m_reader->read(len, eos, buf); + + if(len < need) + { + if(eos) { - low = m_cache.getBuffer()[(int)(floor(spos) + 2) * CC]; - if(ceil(spos) < 0) - high = m_cache.getBuffer()[(int)(ceil(spos) + 2) * CC]; - else - high = buf[(int)ceil(spos) * CC]; + length = floor(len * factor); + memset(buf + len * m_channels, 0, samplesize); } else - { - low = buf[(int)floor(spos) * CC]; - high = buf[(int)ceil(spos) * CC]; - } + length = ceil((len - 1) * factor); + } + m_cache_ok = true; + m_cache_pos = 0; + } + + for(int channel = 0; channel < m_channels; channel++) + { + for(int i = 0; i < length; i++) + { + spos = (i + 1) / factor + m_cache_pos; + + low = buf[(int)floor(spos) * CC]; + high = buf[(int)ceil(spos) * CC]; + buffer[i * CC] = low + (spos - floor(spos)) * (high - low); } } - if(len > 1) - memcpy(m_cache.getBuffer(), - buf + (len - 2) * channels, - 2 * samplesize); - else if(len == 1) - memcpy(m_cache.getBuffer() + 1 * channels, buf, samplesize); + if(floor(spos) == spos) + { + memcpy(m_cache.getBuffer(), buf + int(floor(spos - 1)) * m_channels, 2 * samplesize); + m_cache_pos = 1; + } + else + { + memcpy(m_cache.getBuffer(), buf + int(floor(spos)) * m_channels, 2 * samplesize); + m_cache_pos = spos - floor(spos); + } - m_sposition += len; - m_position += length; eos &= length < size; } diff --git a/intern/audaspace/intern/AUD_LinearResampleReader.h b/intern/audaspace/intern/AUD_LinearResampleReader.h index f7dd0e96aa6..8e0eac612fa 100644 --- a/intern/audaspace/intern/AUD_LinearResampleReader.h +++ b/intern/audaspace/intern/AUD_LinearResampleReader.h @@ -42,19 +42,14 @@ class AUD_LinearResampleReader : public AUD_EffectReader { private: /** - * The sample specification of the source. - */ - const AUD_Specs m_sspecs; - - /** - * The resampling factor. + * The target specification. */ - const float m_factor; + AUD_SampleRate m_rate; /** - * The target specification. + * The reader channels. */ - AUD_Specs m_tspecs; + AUD_Channels m_channels; /** * The current position. @@ -62,9 +57,9 @@ private: int m_position; /** - * The current reading source position. + * The position in the cache. */ - int m_sposition; + float m_cache_pos; /** * The sound output buffer. @@ -76,6 +71,11 @@ private: */ AUD_Buffer m_cache; + /** + * Whether the cache contains valid data. + */ + bool m_cache_ok; + // hide copy constructor and operator= AUD_LinearResampleReader(const AUD_LinearResampleReader&); AUD_LinearResampleReader& operator=(const AUD_LinearResampleReader&); |