forked from bartvdbraak/blender
3D Audio GSoC:
Dynamic resampling for libsamplerate and linear resampling.
This commit is contained in:
parent
c89b4e4b66
commit
d5eaffda23
@ -200,10 +200,6 @@ if(NOT WITH_GAMEENGINE AND WITH_PLAYER)
|
||||
message(FATAL_ERROR "WITH_PLAYER requires WITH_GAMEENGINE")
|
||||
endif()
|
||||
|
||||
if(NOT WITH_SAMPLERATE AND (WITH_OPENAL OR WITH_SDL OR WITH_JACK))
|
||||
message(FATAL_ERROR "WITH_OPENAL/WITH_SDL/WITH_JACK require WITH_SAMPLERATE")
|
||||
endif()
|
||||
|
||||
if(NOT WITH_IMAGE_OPENJPEG AND WITH_IMAGE_REDCODE)
|
||||
message(FATAL_ERROR "WITH_IMAGE_REDCODE requires WITH_IMAGE_OPENJPEG")
|
||||
endif()
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -43,25 +43,20 @@
|
||||
class AUD_SRCResampleReader : public AUD_EffectReader
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The sample specification of the source.
|
||||
*/
|
||||
const AUD_Specs m_sspecs;
|
||||
|
||||
/**
|
||||
* The resampling factor.
|
||||
*/
|
||||
const double m_factor;
|
||||
|
||||
/**
|
||||
* The sound output buffer.
|
||||
*/
|
||||
AUD_Buffer m_buffer;
|
||||
|
||||
/**
|
||||
* The target specification.
|
||||
* The target sampling rate.
|
||||
*/
|
||||
AUD_Specs m_tspecs;
|
||||
AUD_SampleRate m_rate;
|
||||
|
||||
/**
|
||||
* The reader channels.
|
||||
*/
|
||||
AUD_Channels m_channels;
|
||||
|
||||
/**
|
||||
* The src state structure.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
m_buffer.assureSize(size * AUD_SAMPLE_SIZE(m_sspecs));
|
||||
|
||||
int need = ceil((m_position + length) / m_factor) + 1 - m_sposition;
|
||||
int len = need;
|
||||
sample_t* buf = m_buffer.getBuffer();
|
||||
|
||||
m_reader->read(len, eos, buf);
|
||||
|
||||
if(len < need)
|
||||
length = floor((m_sposition + len - 1) * m_factor) - m_position;
|
||||
|
||||
float factor = float(m_rate) / float(m_reader->getSpecs().rate);
|
||||
float spos;
|
||||
sample_t low, high;
|
||||
int channels = m_sspecs.channels;
|
||||
eos = false;
|
||||
|
||||
for(int channel = 0; channel < channels; channel++)
|
||||
if(factor == 1 && (!m_cache_ok || m_cache_pos == 0))
|
||||
{
|
||||
// can read directly!
|
||||
m_reader->read(length, eos, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for channels changed
|
||||
|
||||
if(specs.channels != m_channels)
|
||||
{
|
||||
m_cache.resize(2 * samplesize);
|
||||
m_channels = specs.channels;
|
||||
m_cache_ok = false;
|
||||
}
|
||||
|
||||
int len;
|
||||
sample_t* buf;
|
||||
|
||||
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);
|
||||
|
||||
if(len < need)
|
||||
length = floor((len + (1 - m_cache_pos)) * factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
int need = ceil(length / factor) + 1;
|
||||
|
||||
len = need;
|
||||
|
||||
m_buffer.assureSize((len + 1) * samplesize);
|
||||
buf = m_buffer.getBuffer();
|
||||
|
||||
m_reader->read(len, eos, buf);
|
||||
|
||||
if(len < need)
|
||||
{
|
||||
if(eos)
|
||||
{
|
||||
length = floor(len * factor);
|
||||
memset(buf + len * m_channels, 0, samplesize);
|
||||
}
|
||||
else
|
||||
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 = (m_position + i) / m_factor - m_sposition;
|
||||
spos = (i + 1) / factor + m_cache_pos;
|
||||
|
||||
low = buf[(int)floor(spos) * CC];
|
||||
high = buf[(int)ceil(spos) * CC];
|
||||
|
||||
if(floor(spos) < 0)
|
||||
{
|
||||
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];
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -41,20 +41,15 @@
|
||||
class AUD_LinearResampleReader : public AUD_EffectReader
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The sample specification of the source.
|
||||
*/
|
||||
const AUD_Specs m_sspecs;
|
||||
|
||||
/**
|
||||
* The resampling factor.
|
||||
*/
|
||||
const float m_factor;
|
||||
|
||||
/**
|
||||
* The target specification.
|
||||
*/
|
||||
AUD_Specs m_tspecs;
|
||||
AUD_SampleRate m_rate;
|
||||
|
||||
/**
|
||||
* The reader channels.
|
||||
*/
|
||||
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&);
|
||||
|
Loading…
Reference in New Issue
Block a user