From ae4189a5332b6da93c45a75edc713e7a9e5446f9 Mon Sep 17 00:00:00 2001 From: Max Maisel Date: Thu, 28 May 2020 09:33:04 +0200 Subject: [PATCH] Implement initial condition optimization. Signed-off-by: Max Maisel --- src/effects/Compressor2.cpp | 85 ++++++++++++++++++++++++++++++++----- src/effects/Compressor2.h | 12 ++++++ 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/effects/Compressor2.cpp b/src/effects/Compressor2.cpp index c389f0080..f4916d364 100644 --- a/src/effects/Compressor2.cpp +++ b/src/effects/Compressor2.cpp @@ -125,6 +125,14 @@ float SlidingRmsPreprocessor::ProcessSample(float valueL, float valueR) 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) { if(mInsertCount > REFRESH_WINDOW_EVERY) @@ -183,6 +191,13 @@ float SlidingMaxPreprocessor::ProcessSample(float valueL, float valueR) 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) { size_t oldHead = (mPos-1) % mWindow.size(); @@ -207,6 +222,8 @@ float SlidingMaxPreprocessor::DoProcessSample(float value) EnvelopeDetector::EnvelopeDetector(size_t buffer_size) : mPos(0), + mInitialCondition(0), + mInitialBlockSize(0), mLookaheadBuffer(buffer_size, 0), mProcessingBuffer(buffer_size, 0), mProcessedBuffer(buffer_size, 0) @@ -227,6 +244,10 @@ float EnvelopeDetector::ProcessSample(float value) return retval; } +void EnvelopeDetector::CalcInitialCondition(float value) +{ +} + size_t EnvelopeDetector::GetBlockSize() const { wxASSERT(mProcessedBuffer.size() == mProcessingBuffer.size()); @@ -350,6 +371,28 @@ Pt1EnvelopeDetector::Pt1EnvelopeDetector( mAttackFactor = 1.0 / (attackTime * 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() @@ -399,12 +442,16 @@ void PipelineBuffer::init(size_t capacity, bool stereo) size = 0; mCapacity = capacity; mBlockBuffer[0].reinit(capacity); - std::fill(mBlockBuffer[0].get(), mBlockBuffer[0].get() + capacity, 0); if(stereo) - { 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() @@ -1032,6 +1079,7 @@ bool EffectCompressor2::ProcessOne(TrackIterRange range) std::cerr << "LookaheadLen: " << mLookaheadLength << "\n" << std::flush; #endif + bool first = true; mProgressVal = 0; #ifdef DEBUG_COMPRESSOR2_DUMP_BUFFERS buf_num = 0; @@ -1055,6 +1103,21 @@ bool EffectCompressor2::ProcessOne(TrackIterRange range) if(!LoadPipeline(range, blockLen)) 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) FillPipeline(); else @@ -1156,7 +1219,6 @@ void EffectCompressor2::FillPipeline() size_t length = mPipeline[PIPELINE_DEPTH-1].size; for(size_t rp = mLookaheadLength, wp = 0; wp < length; ++rp, ++wp) { - // TODO: correct initial conditions if(rp < length) EnvelopeSample(mPipeline[PIPELINE_DEPTH-2], rp); else @@ -1199,14 +1261,17 @@ void EffectCompressor2::ProcessPipeline() } } -inline float EffectCompressor2::EnvelopeSample(PipelineBuffer& pbuf, size_t rp) +inline float EffectCompressor2::PreprocSample(PipelineBuffer& pbuf, size_t rp) { - float preprocessed; if(mProcStereo) - preprocessed = mPreproc->ProcessSample(pbuf[0][rp], pbuf[1][rp]); + return mPreproc->ProcessSample(pbuf[0][rp], pbuf[1][rp]); else - preprocessed = mPreproc->ProcessSample(pbuf[0][rp]); - return mEnvelope->ProcessSample(preprocessed); + return mPreproc->ProcessSample(pbuf[0][rp]); +} + +inline float EffectCompressor2::EnvelopeSample(PipelineBuffer& pbuf, size_t rp) +{ + return mEnvelope->ProcessSample(PreprocSample(pbuf, rp)); } inline void EffectCompressor2::CompressSample(float env, size_t wp) diff --git a/src/effects/Compressor2.h b/src/effects/Compressor2.h index f1b26e13d..9e223075d 100644 --- a/src/effects/Compressor2.h +++ b/src/effects/Compressor2.h @@ -28,6 +28,7 @@ class SamplePreprocessor public: virtual float ProcessSample(float value) = 0; virtual float ProcessSample(float valueL, float valueR) = 0; + virtual void Reset() = 0; }; class SlidingRmsPreprocessor : public SamplePreprocessor @@ -37,6 +38,7 @@ class SlidingRmsPreprocessor : public SamplePreprocessor virtual float ProcessSample(float value); virtual float ProcessSample(float valueL, float valueR); + virtual void Reset(); 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 valueL, float valueR); + virtual void Reset(); private: std::vector mWindow; @@ -75,8 +78,14 @@ class EnvelopeDetector float ProcessSample(float value); size_t GetBlockSize() 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: size_t mPos; + float mInitialCondition; + size_t mInitialBlockSize; std::vector mLookaheadBuffer; std::vector mProcessingBuffer; std::vector mProcessedBuffer; @@ -102,6 +111,7 @@ class Pt1EnvelopeDetector : public EnvelopeDetector public: Pt1EnvelopeDetector(float rate, float attackTime, float releaseTime, size_t buffer_size = 0, bool correctGain = true); + virtual void CalcInitialCondition(float value); private: double mGainCorrection; @@ -124,6 +134,7 @@ struct PipelineBuffer void pad_to(size_t len, float value, bool stereo); void swap(PipelineBuffer& other); void init(size_t size, bool stereo); + void fill(float value, bool stereo); inline size_t capacity() const { return mCapacity; } void free(); @@ -182,6 +193,7 @@ private: bool LoadPipeline(TrackIterRange range, size_t len); void FillPipeline(); void ProcessPipeline(); + inline float PreprocSample(PipelineBuffer& pbuf, size_t rp); inline float EnvelopeSample(PipelineBuffer& pbuf, size_t rp); inline void CompressSample(float env, size_t wp); bool PipelineHasData();