Files
test2/extern/audaspace/src/fx/AnimateableTimeStretchPitchScaleReader.cpp
Jörg Müller 719e207fcc Audaspace: port changes from upstream.
More accurate seeking for animated time stretching.
2025-09-09 08:13:42 +02:00

97 lines
3.4 KiB
C++

/*******************************************************************************
* Copyright 2009-2025 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "fx/AnimateableTimeStretchPitchScaleReader.h"
#include "IReader.h"
AUD_NAMESPACE_BEGIN
AnimateableTimeStretchPitchScaleReader::AnimateableTimeStretchPitchScaleReader(std::shared_ptr<IReader> reader, float fps, std::shared_ptr<AnimateableProperty> timeStretch,
std::shared_ptr<AnimateableProperty> pitchScale, StretcherQuality quality, bool preserveFormant) :
TimeStretchPitchScaleReader(reader, timeStretch->readSingle(0), pitchScale->readSingle(0), quality, preserveFormant),
m_fps(fps),
m_timeStretch(timeStretch),
m_pitchScale(pitchScale)
{
}
void AnimateableTimeStretchPitchScaleReader::read(int& length, bool& eos, sample_t* buffer)
{
int position = getPosition();
double time = double(position) / double(m_reader->getSpecs().rate);
float frame = time * m_fps;
float timeRatio = m_timeStretch->readSingle(frame);
setTimeRatio(timeRatio);
float pitchScale = m_pitchScale->readSingle(frame);
setPitchScale(pitchScale);
TimeStretchPitchScaleReader::read(length, eos, buffer);
}
void AnimateableTimeStretchPitchScaleReader::seek(int position)
{
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);
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