1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-17 16:50:26 +02:00

Implement initial condition optimization.

Signed-off-by: Max Maisel <max.maisel@posteo.de>
This commit is contained in:
Max Maisel 2020-05-28 09:33:04 +02:00
parent 277f64c4ca
commit ae4189a533
2 changed files with 88 additions and 11 deletions

View File

@ -125,6 +125,14 @@ float SlidingRmsPreprocessor::ProcessSample(float valueL, float valueR)
return DoProcessSample((valueL * valueL + valueR * valueR) / 2.0); return DoProcessSample((valueL * valueL + valueR * valueR) / 2.0);
} }
void SlidingRmsPreprocessor::Reset()
{
mSum = 0;
mPos = 0;
mInsertCount = 0;
std::fill(mWindow.begin(), mWindow.end(), 0);
}
float SlidingRmsPreprocessor::DoProcessSample(float value) float SlidingRmsPreprocessor::DoProcessSample(float value)
{ {
if(mInsertCount > REFRESH_WINDOW_EVERY) if(mInsertCount > REFRESH_WINDOW_EVERY)
@ -183,6 +191,13 @@ float SlidingMaxPreprocessor::ProcessSample(float valueL, float valueR)
return DoProcessSample((fabs(valueL) + fabs(valueR)) / 2.0); return DoProcessSample((fabs(valueL) + fabs(valueR)) / 2.0);
} }
void SlidingMaxPreprocessor::Reset()
{
mPos = 0;
std::fill(mWindow.begin(), mWindow.end(), 0);
std::fill(mMaxes.begin(), mMaxes.end(), 0);
}
float SlidingMaxPreprocessor::DoProcessSample(float value) float SlidingMaxPreprocessor::DoProcessSample(float value)
{ {
size_t oldHead = (mPos-1) % mWindow.size(); size_t oldHead = (mPos-1) % mWindow.size();
@ -207,6 +222,8 @@ float SlidingMaxPreprocessor::DoProcessSample(float value)
EnvelopeDetector::EnvelopeDetector(size_t buffer_size) EnvelopeDetector::EnvelopeDetector(size_t buffer_size)
: mPos(0), : mPos(0),
mInitialCondition(0),
mInitialBlockSize(0),
mLookaheadBuffer(buffer_size, 0), mLookaheadBuffer(buffer_size, 0),
mProcessingBuffer(buffer_size, 0), mProcessingBuffer(buffer_size, 0),
mProcessedBuffer(buffer_size, 0) mProcessedBuffer(buffer_size, 0)
@ -227,6 +244,10 @@ float EnvelopeDetector::ProcessSample(float value)
return retval; return retval;
} }
void EnvelopeDetector::CalcInitialCondition(float value)
{
}
size_t EnvelopeDetector::GetBlockSize() const size_t EnvelopeDetector::GetBlockSize() const
{ {
wxASSERT(mProcessedBuffer.size() == mProcessingBuffer.size()); wxASSERT(mProcessedBuffer.size() == mProcessingBuffer.size());
@ -350,6 +371,28 @@ Pt1EnvelopeDetector::Pt1EnvelopeDetector(
mAttackFactor = 1.0 / (attackTime * rate); mAttackFactor = 1.0 / (attackTime * rate);
mReleaseFactor = 1.0 / (releaseTime * rate); mReleaseFactor = 1.0 / (releaseTime * rate);
mInitialBlockSize = std::min(size_t(rate * sqrt(attackTime)), bufferSize);
}
void Pt1EnvelopeDetector::CalcInitialCondition(float value)
{
mLookaheadBuffer[mPos++] = value;
if(mPos == mInitialBlockSize)
{
float level = 0;
for(size_t i = 0; i < mPos; ++i)
{
if(mLookaheadBuffer[i] >= level)
if(i < mInitialBlockSize / 5)
level += 5 * mAttackFactor * (mLookaheadBuffer[i] - level);
else
level += mAttackFactor * (mLookaheadBuffer[i] - level);
else
level += mReleaseFactor * (mLookaheadBuffer[i] - level);
}
mInitialCondition = level;
mPos = 0;
}
} }
void Pt1EnvelopeDetector::Follow() void Pt1EnvelopeDetector::Follow()
@ -399,12 +442,16 @@ void PipelineBuffer::init(size_t capacity, bool stereo)
size = 0; size = 0;
mCapacity = capacity; mCapacity = capacity;
mBlockBuffer[0].reinit(capacity); mBlockBuffer[0].reinit(capacity);
std::fill(mBlockBuffer[0].get(), mBlockBuffer[0].get() + capacity, 0);
if(stereo) if(stereo)
{
mBlockBuffer[1].reinit(capacity); mBlockBuffer[1].reinit(capacity);
std::fill(mBlockBuffer[1].get(), mBlockBuffer[1].get() + capacity, 0); fill(0, stereo);
} }
void PipelineBuffer::fill(float value, bool stereo)
{
std::fill(mBlockBuffer[0].get(), mBlockBuffer[0].get() + mCapacity, value);
if(stereo)
std::fill(mBlockBuffer[1].get(), mBlockBuffer[1].get() + mCapacity, value);
} }
void PipelineBuffer::free() void PipelineBuffer::free()
@ -1032,6 +1079,7 @@ bool EffectCompressor2::ProcessOne(TrackIterRange<WaveTrack> range)
std::cerr << "LookaheadLen: " << mLookaheadLength << "\n" << std::flush; std::cerr << "LookaheadLen: " << mLookaheadLength << "\n" << std::flush;
#endif #endif
bool first = true;
mProgressVal = 0; mProgressVal = 0;
#ifdef DEBUG_COMPRESSOR2_DUMP_BUFFERS #ifdef DEBUG_COMPRESSOR2_DUMP_BUFFERS
buf_num = 0; buf_num = 0;
@ -1055,6 +1103,21 @@ bool EffectCompressor2::ProcessOne(TrackIterRange<WaveTrack> range)
if(!LoadPipeline(range, blockLen)) if(!LoadPipeline(range, blockLen))
return false; return false;
if(first)
{
first = false;
size_t sampleCount = mEnvelope->InitialConditionSize();
for(size_t i = 0; i < sampleCount; ++i)
{
size_t rp = i % mPipeline[PIPELINE_DEPTH-1].trackSize;
mEnvelope->CalcInitialCondition(
PreprocSample(mPipeline[PIPELINE_DEPTH-1], rp));
}
mPipeline[PIPELINE_DEPTH-2].fill(
mEnvelope->InitialCondition(), mProcStereo);
mPreproc->Reset();
}
if(mPipeline[0].size == 0) if(mPipeline[0].size == 0)
FillPipeline(); FillPipeline();
else else
@ -1156,7 +1219,6 @@ void EffectCompressor2::FillPipeline()
size_t length = mPipeline[PIPELINE_DEPTH-1].size; size_t length = mPipeline[PIPELINE_DEPTH-1].size;
for(size_t rp = mLookaheadLength, wp = 0; wp < length; ++rp, ++wp) for(size_t rp = mLookaheadLength, wp = 0; wp < length; ++rp, ++wp)
{ {
// TODO: correct initial conditions
if(rp < length) if(rp < length)
EnvelopeSample(mPipeline[PIPELINE_DEPTH-2], rp); EnvelopeSample(mPipeline[PIPELINE_DEPTH-2], rp);
else else
@ -1199,14 +1261,17 @@ void EffectCompressor2::ProcessPipeline()
} }
} }
inline float EffectCompressor2::PreprocSample(PipelineBuffer& pbuf, size_t rp)
{
if(mProcStereo)
return mPreproc->ProcessSample(pbuf[0][rp], pbuf[1][rp]);
else
return mPreproc->ProcessSample(pbuf[0][rp]);
}
inline float EffectCompressor2::EnvelopeSample(PipelineBuffer& pbuf, size_t rp) inline float EffectCompressor2::EnvelopeSample(PipelineBuffer& pbuf, size_t rp)
{ {
float preprocessed; return mEnvelope->ProcessSample(PreprocSample(pbuf, rp));
if(mProcStereo)
preprocessed = mPreproc->ProcessSample(pbuf[0][rp], pbuf[1][rp]);
else
preprocessed = mPreproc->ProcessSample(pbuf[0][rp]);
return mEnvelope->ProcessSample(preprocessed);
} }
inline void EffectCompressor2::CompressSample(float env, size_t wp) inline void EffectCompressor2::CompressSample(float env, size_t wp)

View File

@ -28,6 +28,7 @@ class SamplePreprocessor
public: public:
virtual float ProcessSample(float value) = 0; virtual float ProcessSample(float value) = 0;
virtual float ProcessSample(float valueL, float valueR) = 0; virtual float ProcessSample(float valueL, float valueR) = 0;
virtual void Reset() = 0;
}; };
class SlidingRmsPreprocessor : public SamplePreprocessor class SlidingRmsPreprocessor : public SamplePreprocessor
@ -37,6 +38,7 @@ class SlidingRmsPreprocessor : public SamplePreprocessor
virtual float ProcessSample(float value); virtual float ProcessSample(float value);
virtual float ProcessSample(float valueL, float valueR); virtual float ProcessSample(float valueL, float valueR);
virtual void Reset();
static const size_t REFRESH_WINDOW_EVERY = 1048576; // 1 MB static const size_t REFRESH_WINDOW_EVERY = 1048576; // 1 MB
@ -58,6 +60,7 @@ class SlidingMaxPreprocessor : public SamplePreprocessor
virtual float ProcessSample(float value); virtual float ProcessSample(float value);
virtual float ProcessSample(float valueL, float valueR); virtual float ProcessSample(float valueL, float valueR);
virtual void Reset();
private: private:
std::vector<float> mWindow; std::vector<float> mWindow;
@ -75,8 +78,14 @@ class EnvelopeDetector
float ProcessSample(float value); float ProcessSample(float value);
size_t GetBlockSize() const; size_t GetBlockSize() const;
const float* GetBuffer(int idx) const; const float* GetBuffer(int idx) const;
virtual void CalcInitialCondition(float value);
inline float InitialCondition() const { return mInitialCondition; }
inline size_t InitialConditionSize() const { return mInitialBlockSize; }
protected: protected:
size_t mPos; size_t mPos;
float mInitialCondition;
size_t mInitialBlockSize;
std::vector<float> mLookaheadBuffer; std::vector<float> mLookaheadBuffer;
std::vector<float> mProcessingBuffer; std::vector<float> mProcessingBuffer;
std::vector<float> mProcessedBuffer; std::vector<float> mProcessedBuffer;
@ -102,6 +111,7 @@ class Pt1EnvelopeDetector : public EnvelopeDetector
public: public:
Pt1EnvelopeDetector(float rate, float attackTime, float releaseTime, Pt1EnvelopeDetector(float rate, float attackTime, float releaseTime,
size_t buffer_size = 0, bool correctGain = true); size_t buffer_size = 0, bool correctGain = true);
virtual void CalcInitialCondition(float value);
private: private:
double mGainCorrection; double mGainCorrection;
@ -124,6 +134,7 @@ struct PipelineBuffer
void pad_to(size_t len, float value, bool stereo); void pad_to(size_t len, float value, bool stereo);
void swap(PipelineBuffer& other); void swap(PipelineBuffer& other);
void init(size_t size, bool stereo); void init(size_t size, bool stereo);
void fill(float value, bool stereo);
inline size_t capacity() const { return mCapacity; } inline size_t capacity() const { return mCapacity; }
void free(); void free();
@ -182,6 +193,7 @@ private:
bool LoadPipeline(TrackIterRange<WaveTrack> range, size_t len); bool LoadPipeline(TrackIterRange<WaveTrack> range, size_t len);
void FillPipeline(); void FillPipeline();
void ProcessPipeline(); void ProcessPipeline();
inline float PreprocSample(PipelineBuffer& pbuf, size_t rp);
inline float EnvelopeSample(PipelineBuffer& pbuf, size_t rp); inline float EnvelopeSample(PipelineBuffer& pbuf, size_t rp);
inline void CompressSample(float env, size_t wp); inline void CompressSample(float env, size_t wp);
bool PipelineHasData(); bool PipelineHasData();