Audaspace: port changes from upstream.
More accurate seeking for animated time stretching.
This commit is contained in:
@@ -213,9 +213,9 @@ Sequence_setAnimationData(Sequence* self, PyObject* args)
|
||||
}
|
||||
|
||||
py_data_len= PySequence_Size(py_data);
|
||||
|
||||
|
||||
std::vector<float> data;
|
||||
data.resize(py_data_len);
|
||||
data.reserve(py_data_len);
|
||||
|
||||
PyObject* py_value;
|
||||
float value;
|
||||
|
||||
@@ -105,7 +105,7 @@ SequenceEntry_setAnimationData(SequenceEntry* self, PyObject* args)
|
||||
py_data_len= PySequence_Size(py_data);
|
||||
|
||||
std::vector<float> data;
|
||||
data.resize(py_data_len);
|
||||
data.reserve(py_data_len);
|
||||
|
||||
PyObject* py_value;
|
||||
float value;
|
||||
|
||||
@@ -38,16 +38,6 @@ AUD_NAMESPACE_BEGIN
|
||||
class AUD_API TimeStretchPitchScaleReader : public EffectReader
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* The current position.
|
||||
*/
|
||||
int m_position;
|
||||
|
||||
/**
|
||||
* Whether the reader has reached the end of stream.
|
||||
*/
|
||||
bool m_finishedReader;
|
||||
|
||||
/**
|
||||
* The input buffer for the reader.
|
||||
*/
|
||||
@@ -63,11 +53,6 @@ private:
|
||||
*/
|
||||
std::vector<sample_t*> m_channelData;
|
||||
|
||||
/**
|
||||
* Rubberband stretcher.
|
||||
*/
|
||||
std::unique_ptr<RubberBandStretcher> m_stretcher;
|
||||
|
||||
/**
|
||||
* Number of samples that need to be dropped at the beginning or after a seek.
|
||||
*/
|
||||
@@ -77,11 +62,27 @@ private:
|
||||
TimeStretchPitchScaleReader(const TimeStretchPitchScaleReader&) = delete;
|
||||
TimeStretchPitchScaleReader& operator=(const TimeStretchPitchScaleReader&) = delete;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Feeds the number of required zeo samples to the stretcher and queries the amount of samples to drop.
|
||||
* Feeds the number of required zero samples to the stretcher and queries the amount of samples to drop.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Rubberband stretcher.
|
||||
*/
|
||||
std::unique_ptr<RubberBandStretcher> m_stretcher;
|
||||
|
||||
/**
|
||||
* The current position.
|
||||
*/
|
||||
int m_position;
|
||||
|
||||
/**
|
||||
* Whether the reader has reached the end of stream.
|
||||
*/
|
||||
bool m_finishedReader;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new stretcher reader.
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
void read(float position, float* out);
|
||||
|
||||
/**
|
||||
* Reads the property's value at the specified position, assuming there is exactly one value
|
||||
* Reads the property's value at the specified position, assuming there is exactly one value.
|
||||
* \param position The position in the animation in frames.
|
||||
* \return The value at the position.
|
||||
*/
|
||||
@@ -141,6 +141,11 @@ public:
|
||||
* \return Whether the property is animated.
|
||||
*/
|
||||
bool isAnimated() const;
|
||||
|
||||
/**
|
||||
* Returns this object cast as a Buffer.
|
||||
*/
|
||||
const Buffer& getBuffer();
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
|
||||
7
extern/audaspace/include/util/Buffer.h
vendored
7
extern/audaspace/include/util/Buffer.h
vendored
@@ -58,7 +58,12 @@ public:
|
||||
/**
|
||||
* Returns the pointer to the buffer in memory.
|
||||
*/
|
||||
sample_t* getBuffer() const;
|
||||
const sample_t* getBuffer() const;
|
||||
|
||||
/**
|
||||
* Returns the pointer to the buffer in memory.
|
||||
*/
|
||||
sample_t* getBuffer();
|
||||
|
||||
/**
|
||||
* Returns the size of the buffer in bytes.
|
||||
|
||||
7
extern/audaspace/include/util/RingBuffer.h
vendored
7
extern/audaspace/include/util/RingBuffer.h
vendored
@@ -59,7 +59,12 @@ public:
|
||||
/**
|
||||
* Returns the pointer to the ring buffer in memory.
|
||||
*/
|
||||
sample_t* getBuffer() const;
|
||||
const sample_t* getBuffer() const;
|
||||
|
||||
/**
|
||||
* Returns the pointer to the ring buffer in memory.
|
||||
*/
|
||||
sample_t* getBuffer();
|
||||
|
||||
/**
|
||||
* Returns the size of the ring buffer in bytes.
|
||||
|
||||
@@ -45,14 +45,52 @@ void AnimateableTimeStretchPitchScaleReader::read(int& length, bool& eos, sample
|
||||
|
||||
void AnimateableTimeStretchPitchScaleReader::seek(int position)
|
||||
{
|
||||
double time = double(position) / double(m_reader->getSpecs().rate);
|
||||
float frame = time * m_fps;
|
||||
const double sampleRate = double(m_reader->getSpecs().rate);
|
||||
const double samplesPerFrame = sampleRate / m_fps;
|
||||
const double frame = double(position) / samplesPerFrame;
|
||||
|
||||
float timeRatio = m_timeStretch->readSingle(frame);
|
||||
setTimeRatio(timeRatio);
|
||||
float pitchScale = m_pitchScale->readSingle(frame);
|
||||
setPitchScale(pitchScale);
|
||||
TimeStretchPitchScaleReader::seek(position);
|
||||
|
||||
const int totalFrames = static_cast<int>(frame);
|
||||
|
||||
float ratio = 1.0f;
|
||||
|
||||
double inputSamplePos = 0.0;
|
||||
|
||||
const sample_t* animationSamples = m_timeStretch->getBuffer().getBuffer();
|
||||
|
||||
const int bufferFrames = m_timeStretch->getBuffer().getSize() / (sizeof(sample_t) * m_timeStretch->getCount());
|
||||
|
||||
for(int frameIndex = 0; frameIndex < std::min(bufferFrames, totalFrames); frameIndex++)
|
||||
{
|
||||
ratio = std::max(animationSamples[frameIndex], 1.0f / 256.0f);
|
||||
inputSamplePos += samplesPerFrame / ratio;
|
||||
}
|
||||
|
||||
if(totalFrames > bufferFrames)
|
||||
{
|
||||
// The position is past the end of animation buffer and so use the last read ratio
|
||||
// This already includes the fractional frame
|
||||
inputSamplePos += (samplesPerFrame * (frame - bufferFrames)) / ratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The position is before the end of the animation buffer and so read one last time for the remaining fractional frame
|
||||
double remainderFrame = frame - totalFrames;
|
||||
|
||||
float remainderRatio = std::max(m_timeStretch->readSingle(frame), 1.0f / 256.0f);
|
||||
|
||||
inputSamplePos += (samplesPerFrame * remainderFrame) / remainderRatio;
|
||||
}
|
||||
|
||||
m_reader->seek(static_cast<int>(inputSamplePos));
|
||||
m_finishedReader = false;
|
||||
m_stretcher->reset();
|
||||
reset();
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
|
||||
@@ -43,7 +43,7 @@ void TimeStretchPitchScaleReader::reset()
|
||||
}
|
||||
|
||||
TimeStretchPitchScaleReader::TimeStretchPitchScaleReader(std::shared_ptr<IReader> reader, double timeRatio, double pitchScale, StretcherQuality quality, bool preserveFormant) :
|
||||
EffectReader(reader), m_position(0), m_finishedReader(false), m_channelData(reader->getSpecs().channels), m_deinterleaved(reader->getSpecs().channels)
|
||||
EffectReader(reader), m_position(0), m_finishedReader(false), m_deinterleaved(reader->getSpecs().channels), m_channelData(reader->getSpecs().channels)
|
||||
{
|
||||
if (pitchScale < 1.0 / 256.0 || pitchScale > 256.0)
|
||||
AUD_THROW(StateException, "The pitch scale must be between 1/256 and 256");
|
||||
@@ -82,9 +82,6 @@ void TimeStretchPitchScaleReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
|
||||
int samplesize = AUD_SAMPLE_SIZE(m_reader->getSpecs());
|
||||
int channels = m_reader->getSpecs().channels;
|
||||
|
||||
sample_t* buf;
|
||||
|
||||
int samplesRead = 0;
|
||||
|
||||
eos = false;
|
||||
|
||||
@@ -26,13 +26,13 @@ AUD_NAMESPACE_BEGIN
|
||||
AnimateableProperty::AnimateableProperty(int count) :
|
||||
Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false)
|
||||
{
|
||||
std::memset(getBuffer(), 0, count * sizeof(float));
|
||||
std::memset(Buffer::getBuffer(), 0, count * sizeof(float));
|
||||
}
|
||||
|
||||
AnimateableProperty::AnimateableProperty(int count, float value) :
|
||||
Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false)
|
||||
{
|
||||
sample_t* buf = getBuffer();
|
||||
sample_t* buf = Buffer::getBuffer();
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
buf[i] = value;
|
||||
@@ -40,7 +40,7 @@ AnimateableProperty::AnimateableProperty(int count, float value) :
|
||||
|
||||
void AnimateableProperty::updateUnknownCache(int start, int end)
|
||||
{
|
||||
float* buf = getBuffer();
|
||||
float* buf = Buffer::getBuffer();
|
||||
|
||||
// we could do a better interpolation than zero order, but that doesn't work with Blender's animation system
|
||||
// as frames are only written when changing, so to support jumps, we need zero order interpolation here.
|
||||
@@ -63,13 +63,13 @@ void AnimateableProperty::write(const float* data)
|
||||
|
||||
m_isAnimated = false;
|
||||
m_unknown.clear();
|
||||
std::memcpy(getBuffer(), data, m_count * sizeof(float));
|
||||
std::memcpy(Buffer::getBuffer(), data, m_count * sizeof(float));
|
||||
}
|
||||
|
||||
void AnimateableProperty::writeConstantRange(const float* data, int position_start, int position_end)
|
||||
{
|
||||
assureSize(position_end * m_count * sizeof(float), true);
|
||||
float* buffer = getBuffer();
|
||||
float* buffer = Buffer::getBuffer();
|
||||
|
||||
for(int i = position_start; i < position_end; i++)
|
||||
{
|
||||
@@ -92,7 +92,7 @@ void AnimateableProperty::write(const float* data, int position, int count)
|
||||
|
||||
assureSize((count + position) * m_count * sizeof(float), true);
|
||||
|
||||
float* buf = getBuffer();
|
||||
float* buf = Buffer::getBuffer();
|
||||
|
||||
std::memcpy(buf + position * m_count, data, count * m_count * sizeof(float));
|
||||
|
||||
@@ -172,7 +172,7 @@ void AnimateableProperty::read(float position, float* out)
|
||||
|
||||
if(!m_isAnimated)
|
||||
{
|
||||
std::memcpy(out, getBuffer(), m_count * sizeof(float));
|
||||
std::memcpy(out, Buffer::getBuffer(), m_count * sizeof(float));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ void AnimateableProperty::read(float position, float* out)
|
||||
|
||||
if(t == 0)
|
||||
{
|
||||
std::memcpy(out, getBuffer() + int(std::floor(position)) * m_count, m_count * sizeof(float));
|
||||
std::memcpy(out, Buffer::getBuffer() + int(std::floor(position)) * m_count, m_count * sizeof(float));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -202,7 +202,7 @@ void AnimateableProperty::read(float position, float* out)
|
||||
float t3 = t2 * t;
|
||||
float m0, m1;
|
||||
float* p0;
|
||||
float* p1 = getBuffer() + pos;
|
||||
float* p1 = Buffer::getBuffer() + pos;
|
||||
float* p2;
|
||||
float* p3;
|
||||
last *= m_count;
|
||||
@@ -242,4 +242,9 @@ bool AnimateableProperty::isAnimated() const
|
||||
return m_isAnimated;
|
||||
}
|
||||
|
||||
const Buffer& AnimateableProperty::getBuffer()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
|
||||
7
extern/audaspace/src/util/Buffer.cpp
vendored
7
extern/audaspace/src/util/Buffer.cpp
vendored
@@ -36,7 +36,12 @@ Buffer::~Buffer()
|
||||
std::free(m_buffer);
|
||||
}
|
||||
|
||||
sample_t* Buffer::getBuffer() const
|
||||
const sample_t* Buffer::getBuffer() const
|
||||
{
|
||||
return (sample_t*) ALIGN(m_buffer);
|
||||
}
|
||||
|
||||
sample_t* Buffer::getBuffer()
|
||||
{
|
||||
return (sample_t*) ALIGN(m_buffer);
|
||||
}
|
||||
|
||||
7
extern/audaspace/src/util/RingBuffer.cpp
vendored
7
extern/audaspace/src/util/RingBuffer.cpp
vendored
@@ -32,7 +32,12 @@ RingBuffer::RingBuffer(int size) :
|
||||
{
|
||||
}
|
||||
|
||||
sample_t* RingBuffer::getBuffer() const
|
||||
const sample_t* RingBuffer::getBuffer() const
|
||||
{
|
||||
return m_buffer.getBuffer();
|
||||
}
|
||||
|
||||
sample_t* RingBuffer::getBuffer()
|
||||
{
|
||||
return m_buffer.getBuffer();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user