123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 |
- /*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * 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.
- */
- #define LOG_TAG "DPFrequency"
- //#define LOG_NDEBUG 0
- #include <log/log.h>
- #include "DPFrequency.h"
- #include <algorithm>
- #include <sys/param.h>
- namespace dp_fx {
- using Eigen::MatrixXd;
- #define MAX_BLOCKSIZE 16384 //For this implementation
- #define MIN_BLOCKSIZE 8
- #define CIRCULAR_BUFFER_UPSAMPLE 4 //4 times buffer size
- static constexpr float MIN_ENVELOPE = 1e-6f; //-120 dB
- static constexpr float EPSILON = 0.0000001f;
- static inline bool isZero(float f) {
- return fabs(f) <= EPSILON;
- }
- template <class T>
- bool compareEquality(T a, T b) {
- return (a == b);
- }
- template <> bool compareEquality<float>(float a, float b) {
- return isZero(a - b);
- }
- //TODO: avoid using macro for estimating change and assignment.
- #define IS_CHANGED(c, a, b) { c |= !compareEquality(a,b); \
- (a) = (b); }
- //ChannelBuffers helper
- void ChannelBuffer::initBuffers(unsigned int blockSize, unsigned int overlapSize,
- unsigned int halfFftSize, unsigned int samplingRate, DPBase &dpBase) {
- ALOGV("ChannelBuffer::initBuffers blockSize %d, overlap %d, halfFft %d",
- blockSize, overlapSize, halfFftSize);
- mSamplingRate = samplingRate;
- mBlockSize = blockSize;
- cBInput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
- cBOutput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
- //temp vectors
- input.resize(mBlockSize);
- output.resize(mBlockSize);
- outTail.resize(overlapSize);
- //module vectors
- mPreEqFactorVector.resize(halfFftSize, 1.0);
- mPostEqFactorVector.resize(halfFftSize, 1.0);
- mPreEqBands.resize(dpBase.getPreEqBandCount());
- mMbcBands.resize(dpBase.getMbcBandCount());
- mPostEqBands.resize(dpBase.getPostEqBandCount());
- ALOGV("mPreEqBands %zu, mMbcBands %zu, mPostEqBands %zu",mPreEqBands.size(),
- mMbcBands.size(), mPostEqBands.size());
- DPChannel *pChannel = dpBase.getChannel(0);
- if (pChannel != nullptr) {
- mPreEqInUse = pChannel->getPreEq()->isInUse();
- mMbcInUse = pChannel->getMbc()->isInUse();
- mPostEqInUse = pChannel->getPostEq()->isInUse();
- mLimiterInUse = pChannel->getLimiter()->isInUse();
- }
- mLimiterParams.linkGroup = -1; //no group.
- }
- void ChannelBuffer::computeBinStartStop(BandParams &bp, size_t binStart) {
- bp.binStart = binStart;
- bp.binStop = (int)(0.5 + bp.freqCutoffHz * mBlockSize / mSamplingRate);
- }
- //== LinkedLimiters Helper
- void LinkedLimiters::reset() {
- mGroupsMap.clear();
- }
- void LinkedLimiters::update(int32_t group, int index) {
- mGroupsMap[group].push_back(index);
- }
- void LinkedLimiters::remove(int index) {
- //check all groups and if index is found, remove it.
- //if group is empty afterwards, remove it.
- for (auto it = mGroupsMap.begin(); it != mGroupsMap.end(); ) {
- for (auto itIndex = it->second.begin(); itIndex != it->second.end(); ) {
- if (*itIndex == index) {
- itIndex = it->second.erase(itIndex);
- } else {
- ++itIndex;
- }
- }
- if (it->second.size() == 0) {
- it = mGroupsMap.erase(it);
- } else {
- ++it;
- }
- }
- }
- //== DPFrequency
- void DPFrequency::reset() {
- }
- size_t DPFrequency::getMinBockSize() {
- return MIN_BLOCKSIZE;
- }
- size_t DPFrequency::getMaxBockSize() {
- return MAX_BLOCKSIZE;
- }
- void DPFrequency::configure(size_t blockSize, size_t overlapSize,
- size_t samplingRate) {
- ALOGV("configure");
- mBlockSize = blockSize;
- if (mBlockSize > MAX_BLOCKSIZE) {
- mBlockSize = MAX_BLOCKSIZE;
- } else if (mBlockSize < MIN_BLOCKSIZE) {
- mBlockSize = MIN_BLOCKSIZE;
- } else {
- if (!powerof2(blockSize)) {
- //find next highest power of 2.
- mBlockSize = 1 << (32 - __builtin_clz(blockSize));
- }
- }
- mHalfFFTSize = 1 + mBlockSize / 2; //including Nyquist bin
- mOverlapSize = std::min(overlapSize, mBlockSize/2);
- int channelcount = getChannelCount();
- mSamplingRate = samplingRate;
- mChannelBuffers.resize(channelcount);
- for (int ch = 0; ch < channelcount; ch++) {
- mChannelBuffers[ch].initBuffers(mBlockSize, mOverlapSize, mHalfFFTSize,
- mSamplingRate, *this);
- }
- //effective number of frames processed per second
- mBlocksPerSecond = (float)mSamplingRate / (mBlockSize - mOverlapSize);
- fill_window(mVWindow, RDSP_WINDOW_HANNING_FLAT_TOP, mBlockSize, mOverlapSize);
- //split window into analysis and synthesis. Both are the sqrt() of original
- //window
- Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
- eWindow = eWindow.array().sqrt();
- //compute window rms for energy compensation
- mWindowRms = 0;
- for (size_t i = 0; i < mVWindow.size(); i++) {
- mWindowRms += mVWindow[i] * mVWindow[i];
- }
- //Making sure window rms is not zero.
- mWindowRms = std::max(sqrt(mWindowRms / mVWindow.size()), MIN_ENVELOPE);
- }
- void DPFrequency::updateParameters(ChannelBuffer &cb, int channelIndex) {
- DPChannel *pChannel = getChannel(channelIndex);
- if (pChannel == nullptr) {
- ALOGE("Error: updateParameters null DPChannel %d", channelIndex);
- return;
- }
- //===Input Gain and preEq
- {
- bool changed = false;
- IS_CHANGED(changed, cb.inputGainDb, pChannel->getInputGain());
- //===EqPre
- if (cb.mPreEqInUse) {
- DPEq *pPreEq = pChannel->getPreEq();
- if (pPreEq == nullptr) {
- ALOGE("Error: updateParameters null PreEq for channel: %d", channelIndex);
- return;
- }
- IS_CHANGED(changed, cb.mPreEqEnabled, pPreEq->isEnabled());
- if (cb.mPreEqEnabled) {
- for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
- DPEqBand *pEqBand = pPreEq->getBand(b);
- if (pEqBand == nullptr) {
- ALOGE("Error: updateParameters null PreEqBand for band %d", b);
- return; //failed.
- }
- ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPreEqBands[b];
- IS_CHANGED(changed, pEqBandParams->enabled, pEqBand->isEnabled());
- IS_CHANGED(changed, pEqBandParams->freqCutoffHz,
- pEqBand->getCutoffFrequency());
- IS_CHANGED(changed, pEqBandParams->gainDb, pEqBand->getGain());
- }
- }
- }
- if (changed) {
- float inputGainFactor = dBtoLinear(cb.inputGainDb);
- if (cb.mPreEqInUse && cb.mPreEqEnabled) {
- ALOGV("preEq changed, recomputing! channel %d", channelIndex);
- size_t binNext = 0;
- for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
- ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPreEqBands[b];
- //frequency translation
- cb.computeBinStartStop(*pEqBandParams, binNext);
- binNext = pEqBandParams->binStop + 1;
- float factor = dBtoLinear(pEqBandParams->gainDb);
- if (!pEqBandParams->enabled) {
- factor = inputGainFactor;
- }
- for (size_t k = pEqBandParams->binStart;
- k <= pEqBandParams->binStop && k < mHalfFFTSize; k++) {
- cb.mPreEqFactorVector[k] = factor * inputGainFactor;
- }
- }
- } else {
- ALOGV("only input gain changed, recomputing!");
- //populate PreEq factor with input gain factor.
- for (size_t k = 0; k < mHalfFFTSize; k++) {
- cb.mPreEqFactorVector[k] = inputGainFactor;
- }
- }
- }
- } //inputGain and preEq
- //===EqPost
- if (cb.mPostEqInUse) {
- bool changed = false;
- DPEq *pPostEq = pChannel->getPostEq();
- if (pPostEq == nullptr) {
- ALOGE("Error: updateParameters null postEq for channel: %d", channelIndex);
- return; //failed.
- }
- IS_CHANGED(changed, cb.mPostEqEnabled, pPostEq->isEnabled());
- if (cb.mPostEqEnabled) {
- for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
- DPEqBand *pEqBand = pPostEq->getBand(b);
- if (pEqBand == nullptr) {
- ALOGE("Error: updateParameters PostEqBand NULL for band %d", b);
- return; //failed.
- }
- ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPostEqBands[b];
- IS_CHANGED(changed, pEqBandParams->enabled, pEqBand->isEnabled());
- IS_CHANGED(changed, pEqBandParams->freqCutoffHz,
- pEqBand->getCutoffFrequency());
- IS_CHANGED(changed, pEqBandParams->gainDb, pEqBand->getGain());
- }
- if (changed) {
- ALOGV("postEq changed, recomputing! channel %d", channelIndex);
- size_t binNext = 0;
- for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
- ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPostEqBands[b];
- //frequency translation
- cb.computeBinStartStop(*pEqBandParams, binNext);
- binNext = pEqBandParams->binStop + 1;
- float factor = dBtoLinear(pEqBandParams->gainDb);
- if (!pEqBandParams->enabled) {
- factor = 1.0;
- }
- for (size_t k = pEqBandParams->binStart;
- k <= pEqBandParams->binStop && k < mHalfFFTSize; k++) {
- cb.mPostEqFactorVector[k] = factor;
- }
- }
- }
- } //enabled
- }
- //===MBC
- if (cb.mMbcInUse) {
- DPMbc *pMbc = pChannel->getMbc();
- if (pMbc == nullptr) {
- ALOGE("Error: updateParameters Mbc NULL for channel: %d", channelIndex);
- return;
- }
- cb.mMbcEnabled = pMbc->isEnabled();
- if (cb.mMbcEnabled) {
- bool changed = false;
- for (unsigned int b = 0; b < getMbcBandCount(); b++) {
- DPMbcBand *pMbcBand = pMbc->getBand(b);
- if (pMbcBand == nullptr) {
- ALOGE("Error: updateParameters MbcBand NULL for band %d", b);
- return; //failed.
- }
- ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[b];
- pMbcBandParams->enabled = pMbcBand->isEnabled();
- IS_CHANGED(changed, pMbcBandParams->freqCutoffHz,
- pMbcBand->getCutoffFrequency());
- pMbcBandParams->gainPreDb = pMbcBand->getPreGain();
- pMbcBandParams->gainPostDb = pMbcBand->getPostGain();
- pMbcBandParams->attackTimeMs = pMbcBand->getAttackTime();
- pMbcBandParams->releaseTimeMs = pMbcBand->getReleaseTime();
- pMbcBandParams->ratio = pMbcBand->getRatio();
- pMbcBandParams->thresholdDb = pMbcBand->getThreshold();
- pMbcBandParams->kneeWidthDb = pMbcBand->getKneeWidth();
- pMbcBandParams->noiseGateThresholdDb = pMbcBand->getNoiseGateThreshold();
- pMbcBandParams->expanderRatio = pMbcBand->getExpanderRatio();
- }
- if (changed) {
- ALOGV("mbc changed, recomputing! channel %d", channelIndex);
- size_t binNext= 0;
- for (unsigned int b = 0; b < getMbcBandCount(); b++) {
- ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[b];
- pMbcBandParams->previousEnvelope = 0;
- //frequency translation
- cb.computeBinStartStop(*pMbcBandParams, binNext);
- binNext = pMbcBandParams->binStop + 1;
- }
- }
- }
- }
- //===Limiter
- if (cb.mLimiterInUse) {
- bool changed = false;
- DPLimiter *pLimiter = pChannel->getLimiter();
- if (pLimiter == nullptr) {
- ALOGE("Error: updateParameters Limiter NULL for channel: %d", channelIndex);
- return;
- }
- cb.mLimiterEnabled = pLimiter->isEnabled();
- if (cb.mLimiterEnabled) {
- IS_CHANGED(changed, cb.mLimiterParams.linkGroup ,
- (int32_t)pLimiter->getLinkGroup());
- cb.mLimiterParams.attackTimeMs = pLimiter->getAttackTime();
- cb.mLimiterParams.releaseTimeMs = pLimiter->getReleaseTime();
- cb.mLimiterParams.ratio = pLimiter->getRatio();
- cb.mLimiterParams.thresholdDb = pLimiter->getThreshold();
- cb.mLimiterParams.postGainDb = pLimiter->getPostGain();
- }
- if (changed) {
- ALOGV("limiter changed, recomputing linkGroups for %d", channelIndex);
- mLinkedLimiters.remove(channelIndex); //in case it was already there.
- mLinkedLimiters.update(cb.mLimiterParams.linkGroup, channelIndex);
- }
- }
- //=== Output Gain
- cb.outputGainDb = pChannel->getOutputGain();
- }
- size_t DPFrequency::processSamples(const float *in, float *out, size_t samples) {
- const float *pIn = in;
- float *pOut = out;
- int channelCount = mChannelBuffers.size();
- if (channelCount < 1) {
- ALOGW("warning: no Channels ready for processing");
- return 0;
- }
- //**Check if parameters have changed and update
- for (int ch = 0; ch < channelCount; ch++) {
- updateParameters(mChannelBuffers[ch], ch);
- }
- //**separate into channels
- for (size_t k = 0; k < samples; k += channelCount) {
- for (int ch = 0; ch < channelCount; ch++) {
- mChannelBuffers[ch].cBInput.write(*pIn++);
- }
- }
- //**process all channelBuffers
- processChannelBuffers(mChannelBuffers);
- //** estimate how much data is available in ALL channels
- size_t available = mChannelBuffers[0].cBOutput.availableToRead();
- for (int ch = 1; ch < channelCount; ch++) {
- available = std::min(available, mChannelBuffers[ch].cBOutput.availableToRead());
- }
- //** make sure to output just what the buffer can handle
- if (available > samples/channelCount) {
- available = samples/channelCount;
- }
- //**Prepend zeroes if necessary
- size_t fill = samples - (channelCount * available);
- for (size_t k = 0; k < fill; k++) {
- *pOut++ = 0;
- }
- //**interleave channels
- for (size_t k = 0; k < available; k++) {
- for (int ch = 0; ch < channelCount; ch++) {
- *pOut++ = mChannelBuffers[ch].cBOutput.read();
- }
- }
- return samples;
- }
- size_t DPFrequency::processChannelBuffers(CBufferVector &channelBuffers) {
- const int channelCount = channelBuffers.size();
- size_t processedSamples = 0;
- size_t processFrames = mBlockSize - mOverlapSize;
- size_t available = channelBuffers[0].cBInput.availableToRead();
- for (int ch = 1; ch < channelCount; ch++) {
- available = std::min(available, channelBuffers[ch].cBInput.availableToRead());
- }
- while (available >= processFrames) {
- //First pass
- for (int ch = 0; ch < channelCount; ch++) {
- ChannelBuffer * pCb = &channelBuffers[ch];
- //move tail of previous
- std::copy(pCb->input.begin() + processFrames,
- pCb->input.end(),
- pCb->input.begin());
- //read new available data
- for (unsigned int k = 0; k < processFrames; k++) {
- pCb->input[mOverlapSize + k] = pCb->cBInput.read();
- }
- //first stages: fft, preEq, mbc, postEq and start of Limiter
- processedSamples += processFirstStages(*pCb);
- }
- //**compute linked limiters and update levels if needed
- processLinkedLimiters(channelBuffers);
- //final pass.
- for (int ch = 0; ch < channelCount; ch++) {
- ChannelBuffer * pCb = &channelBuffers[ch];
- //linked limiter and ifft
- processLastStages(*pCb);
- //mix tail (and capture new tail
- for (unsigned int k = 0; k < mOverlapSize; k++) {
- pCb->output[k] += pCb->outTail[k];
- pCb->outTail[k] = pCb->output[processFrames + k]; //new tail
- }
- //output data
- for (unsigned int k = 0; k < processFrames; k++) {
- pCb->cBOutput.write(pCb->output[k]);
- }
- }
- available -= processFrames;
- }
- return processedSamples;
- }
- size_t DPFrequency::processFirstStages(ChannelBuffer &cb) {
- //##apply window
- Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
- Eigen::Map<Eigen::VectorXf> eInput(&cb.input[0], cb.input.size());
- Eigen::VectorXf eWin = eInput.cwiseProduct(eWindow); //apply window
- //##fft
- //Note: we are using eigen with the default scaling, which ensures that
- // IFFT( FFT(x) ) = x.
- // TODO: optimize by using the noscale option, and compensate with dB scale offsets
- mFftServer.fwd(cb.complexTemp, eWin);
- size_t cSize = cb.complexTemp.size();
- size_t maxBin = std::min(cSize/2, mHalfFFTSize);
- //== EqPre (always runs)
- for (size_t k = 0; k < maxBin; k++) {
- cb.complexTemp[k] *= cb.mPreEqFactorVector[k];
- }
- //== MBC
- if (cb.mMbcInUse && cb.mMbcEnabled) {
- for (size_t band = 0; band < cb.mMbcBands.size(); band++) {
- ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[band];
- float fEnergySum = 0;
- //apply pre gain.
- float preGainFactor = dBtoLinear(pMbcBandParams->gainPreDb);
- float preGainSquared = preGainFactor * preGainFactor;
- for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
- fEnergySum += std::norm(cb.complexTemp[k]) * preGainSquared; //mag squared
- }
- //Eigen FFT is full spectrum, even if the source was real data.
- // Each half spectrum has half the energy. This is taken into account with the * 2
- // factor in the energy computations.
- // energy = sqrt(sum_components_squared) number_points
- // in here, the fEnergySum is duplicated to account for the second half spectrum,
- // and the windowRms is used to normalize by the expected energy reduction
- // caused by the window used (expected for steady state signals)
- fEnergySum = sqrt(fEnergySum * 2) / (mBlockSize * mWindowRms);
- // updates computed per frame advance.
- float fTheta = 0.0;
- float fFAttSec = pMbcBandParams->attackTimeMs / 1000; //in seconds
- float fFRelSec = pMbcBandParams->releaseTimeMs / 1000; //in seconds
- if (fEnergySum > pMbcBandParams->previousEnvelope) {
- fTheta = exp(-1.0 / (fFAttSec * mBlocksPerSecond));
- } else {
- fTheta = exp(-1.0 / (fFRelSec * mBlocksPerSecond));
- }
- float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * pMbcBandParams->previousEnvelope;
- //preserve for next iteration
- pMbcBandParams->previousEnvelope = fEnv;
- if (fEnv < MIN_ENVELOPE) {
- fEnv = MIN_ENVELOPE;
- }
- const float envDb = linearToDb(fEnv);
- float newLevelDb = envDb;
- //using shorter variables for code clarity
- const float thresholdDb = pMbcBandParams->thresholdDb;
- const float ratio = pMbcBandParams->ratio;
- const float kneeWidthDbHalf = pMbcBandParams->kneeWidthDb / 2;
- const float noiseGateThresholdDb = pMbcBandParams->noiseGateThresholdDb;
- const float expanderRatio = pMbcBandParams->expanderRatio;
- //find segment
- if (envDb > thresholdDb + kneeWidthDbHalf) {
- //compression segment
- newLevelDb = envDb + ((1 / ratio) - 1) * (envDb - thresholdDb);
- } else if (envDb > thresholdDb - kneeWidthDbHalf) {
- //knee-compression segment
- float temp = (envDb - thresholdDb + kneeWidthDbHalf);
- newLevelDb = envDb + ((1 / ratio) - 1) *
- temp * temp / (kneeWidthDbHalf * 4);
- } else if (envDb < noiseGateThresholdDb) {
- //expander segment
- newLevelDb = noiseGateThresholdDb -
- expanderRatio * (noiseGateThresholdDb - envDb);
- }
- float newFactor = dBtoLinear(newLevelDb - envDb);
- //apply post gain.
- newFactor *= dBtoLinear(pMbcBandParams->gainPostDb);
- //apply to this band
- for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
- cb.complexTemp[k] *= newFactor;
- }
- } //end per band process
- } //end MBC
- //== EqPost
- if (cb.mPostEqInUse && cb.mPostEqEnabled) {
- for (size_t k = 0; k < maxBin; k++) {
- cb.complexTemp[k] *= cb.mPostEqFactorVector[k];
- }
- }
- //== Limiter. First Pass
- if (cb.mLimiterInUse && cb.mLimiterEnabled) {
- float fEnergySum = 0;
- for (size_t k = 0; k < maxBin; k++) {
- fEnergySum += std::norm(cb.complexTemp[k]);
- }
- //see explanation above for energy computation logic
- fEnergySum = sqrt(fEnergySum * 2) / (mBlockSize * mWindowRms);
- float fTheta = 0.0;
- float fFAttSec = cb.mLimiterParams.attackTimeMs / 1000; //in seconds
- float fFRelSec = cb.mLimiterParams.releaseTimeMs / 1000; //in seconds
- if (fEnergySum > cb.mLimiterParams.previousEnvelope) {
- fTheta = exp(-1.0 / (fFAttSec * mBlocksPerSecond));
- } else {
- fTheta = exp(-1.0 / (fFRelSec * mBlocksPerSecond));
- }
- float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * cb.mLimiterParams.previousEnvelope;
- //preserve for next iteration
- cb.mLimiterParams.previousEnvelope = fEnv;
- const float envDb = linearToDb(fEnv);
- float newFactorDb = 0;
- //using shorter variables for code clarity
- const float thresholdDb = cb.mLimiterParams.thresholdDb;
- const float ratio = cb.mLimiterParams.ratio;
- if (envDb > thresholdDb) {
- //limiter segment
- newFactorDb = ((1 / ratio) - 1) * (envDb - thresholdDb);
- }
- float newFactor = dBtoLinear(newFactorDb);
- cb.mLimiterParams.newFactor = newFactor;
- } //end Limiter
- return mBlockSize;
- }
- void DPFrequency::processLinkedLimiters(CBufferVector &channelBuffers) {
- const int channelCount = channelBuffers.size();
- for (auto &groupPair : mLinkedLimiters.mGroupsMap) {
- float minFactor = 1.0;
- //estimate minfactor for all linked
- for(int index : groupPair.second) {
- if (index >= 0 && index < channelCount) {
- minFactor = std::min(channelBuffers[index].mLimiterParams.newFactor, minFactor);
- }
- }
- //apply minFactor
- for(int index : groupPair.second) {
- if (index >= 0 && index < channelCount) {
- channelBuffers[index].mLimiterParams.linkFactor = minFactor;
- }
- }
- }
- }
- size_t DPFrequency::processLastStages(ChannelBuffer &cb) {
- float outputGainFactor = dBtoLinear(cb.outputGainDb);
- //== Limiter. last Pass
- if (cb.mLimiterInUse && cb.mLimiterEnabled) {
- //compute factor, with post-gain
- float factor = cb.mLimiterParams.linkFactor * dBtoLinear(cb.mLimiterParams.postGainDb);
- outputGainFactor *= factor;
- }
- //apply to all if != 1.0
- if (!compareEquality(outputGainFactor, 1.0f)) {
- size_t cSize = cb.complexTemp.size();
- size_t maxBin = std::min(cSize/2, mHalfFFTSize);
- for (size_t k = 0; k < maxBin; k++) {
- cb.complexTemp[k] *= outputGainFactor;
- }
- }
- //##ifft directly to output.
- Eigen::Map<Eigen::VectorXf> eOutput(&cb.output[0], cb.output.size());
- mFftServer.inv(eOutput, cb.complexTemp);
- //apply rest of window for resynthesis
- Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
- eOutput = eOutput.cwiseProduct(eWindow);
- return mBlockSize;
- }
- } //namespace dp_fx
|