DPFrequency.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*
  2. * Copyright (C) 2018 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define LOG_TAG "DPFrequency"
  17. //#define LOG_NDEBUG 0
  18. #include <log/log.h>
  19. #include "DPFrequency.h"
  20. #include <algorithm>
  21. #include <sys/param.h>
  22. namespace dp_fx {
  23. using Eigen::MatrixXd;
  24. #define MAX_BLOCKSIZE 16384 //For this implementation
  25. #define MIN_BLOCKSIZE 8
  26. #define CIRCULAR_BUFFER_UPSAMPLE 4 //4 times buffer size
  27. static constexpr float MIN_ENVELOPE = 1e-6f; //-120 dB
  28. static constexpr float EPSILON = 0.0000001f;
  29. static inline bool isZero(float f) {
  30. return fabs(f) <= EPSILON;
  31. }
  32. template <class T>
  33. bool compareEquality(T a, T b) {
  34. return (a == b);
  35. }
  36. template <> bool compareEquality<float>(float a, float b) {
  37. return isZero(a - b);
  38. }
  39. //TODO: avoid using macro for estimating change and assignment.
  40. #define IS_CHANGED(c, a, b) { c |= !compareEquality(a,b); \
  41. (a) = (b); }
  42. //ChannelBuffers helper
  43. void ChannelBuffer::initBuffers(unsigned int blockSize, unsigned int overlapSize,
  44. unsigned int halfFftSize, unsigned int samplingRate, DPBase &dpBase) {
  45. ALOGV("ChannelBuffer::initBuffers blockSize %d, overlap %d, halfFft %d",
  46. blockSize, overlapSize, halfFftSize);
  47. mSamplingRate = samplingRate;
  48. mBlockSize = blockSize;
  49. cBInput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
  50. cBOutput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
  51. //temp vectors
  52. input.resize(mBlockSize);
  53. output.resize(mBlockSize);
  54. outTail.resize(overlapSize);
  55. //module vectors
  56. mPreEqFactorVector.resize(halfFftSize, 1.0);
  57. mPostEqFactorVector.resize(halfFftSize, 1.0);
  58. mPreEqBands.resize(dpBase.getPreEqBandCount());
  59. mMbcBands.resize(dpBase.getMbcBandCount());
  60. mPostEqBands.resize(dpBase.getPostEqBandCount());
  61. ALOGV("mPreEqBands %zu, mMbcBands %zu, mPostEqBands %zu",mPreEqBands.size(),
  62. mMbcBands.size(), mPostEqBands.size());
  63. DPChannel *pChannel = dpBase.getChannel(0);
  64. if (pChannel != nullptr) {
  65. mPreEqInUse = pChannel->getPreEq()->isInUse();
  66. mMbcInUse = pChannel->getMbc()->isInUse();
  67. mPostEqInUse = pChannel->getPostEq()->isInUse();
  68. mLimiterInUse = pChannel->getLimiter()->isInUse();
  69. }
  70. mLimiterParams.linkGroup = -1; //no group.
  71. }
  72. void ChannelBuffer::computeBinStartStop(BandParams &bp, size_t binStart) {
  73. bp.binStart = binStart;
  74. bp.binStop = (int)(0.5 + bp.freqCutoffHz * mBlockSize / mSamplingRate);
  75. }
  76. //== LinkedLimiters Helper
  77. void LinkedLimiters::reset() {
  78. mGroupsMap.clear();
  79. }
  80. void LinkedLimiters::update(int32_t group, int index) {
  81. mGroupsMap[group].push_back(index);
  82. }
  83. void LinkedLimiters::remove(int index) {
  84. //check all groups and if index is found, remove it.
  85. //if group is empty afterwards, remove it.
  86. for (auto it = mGroupsMap.begin(); it != mGroupsMap.end(); ) {
  87. for (auto itIndex = it->second.begin(); itIndex != it->second.end(); ) {
  88. if (*itIndex == index) {
  89. itIndex = it->second.erase(itIndex);
  90. } else {
  91. ++itIndex;
  92. }
  93. }
  94. if (it->second.size() == 0) {
  95. it = mGroupsMap.erase(it);
  96. } else {
  97. ++it;
  98. }
  99. }
  100. }
  101. //== DPFrequency
  102. void DPFrequency::reset() {
  103. }
  104. size_t DPFrequency::getMinBockSize() {
  105. return MIN_BLOCKSIZE;
  106. }
  107. size_t DPFrequency::getMaxBockSize() {
  108. return MAX_BLOCKSIZE;
  109. }
  110. void DPFrequency::configure(size_t blockSize, size_t overlapSize,
  111. size_t samplingRate) {
  112. ALOGV("configure");
  113. mBlockSize = blockSize;
  114. if (mBlockSize > MAX_BLOCKSIZE) {
  115. mBlockSize = MAX_BLOCKSIZE;
  116. } else if (mBlockSize < MIN_BLOCKSIZE) {
  117. mBlockSize = MIN_BLOCKSIZE;
  118. } else {
  119. if (!powerof2(blockSize)) {
  120. //find next highest power of 2.
  121. mBlockSize = 1 << (32 - __builtin_clz(blockSize));
  122. }
  123. }
  124. mHalfFFTSize = 1 + mBlockSize / 2; //including Nyquist bin
  125. mOverlapSize = std::min(overlapSize, mBlockSize/2);
  126. int channelcount = getChannelCount();
  127. mSamplingRate = samplingRate;
  128. mChannelBuffers.resize(channelcount);
  129. for (int ch = 0; ch < channelcount; ch++) {
  130. mChannelBuffers[ch].initBuffers(mBlockSize, mOverlapSize, mHalfFFTSize,
  131. mSamplingRate, *this);
  132. }
  133. //effective number of frames processed per second
  134. mBlocksPerSecond = (float)mSamplingRate / (mBlockSize - mOverlapSize);
  135. fill_window(mVWindow, RDSP_WINDOW_HANNING_FLAT_TOP, mBlockSize, mOverlapSize);
  136. //split window into analysis and synthesis. Both are the sqrt() of original
  137. //window
  138. Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
  139. eWindow = eWindow.array().sqrt();
  140. //compute window rms for energy compensation
  141. mWindowRms = 0;
  142. for (size_t i = 0; i < mVWindow.size(); i++) {
  143. mWindowRms += mVWindow[i] * mVWindow[i];
  144. }
  145. //Making sure window rms is not zero.
  146. mWindowRms = std::max(sqrt(mWindowRms / mVWindow.size()), MIN_ENVELOPE);
  147. }
  148. void DPFrequency::updateParameters(ChannelBuffer &cb, int channelIndex) {
  149. DPChannel *pChannel = getChannel(channelIndex);
  150. if (pChannel == nullptr) {
  151. ALOGE("Error: updateParameters null DPChannel %d", channelIndex);
  152. return;
  153. }
  154. //===Input Gain and preEq
  155. {
  156. bool changed = false;
  157. IS_CHANGED(changed, cb.inputGainDb, pChannel->getInputGain());
  158. //===EqPre
  159. if (cb.mPreEqInUse) {
  160. DPEq *pPreEq = pChannel->getPreEq();
  161. if (pPreEq == nullptr) {
  162. ALOGE("Error: updateParameters null PreEq for channel: %d", channelIndex);
  163. return;
  164. }
  165. IS_CHANGED(changed, cb.mPreEqEnabled, pPreEq->isEnabled());
  166. if (cb.mPreEqEnabled) {
  167. for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
  168. DPEqBand *pEqBand = pPreEq->getBand(b);
  169. if (pEqBand == nullptr) {
  170. ALOGE("Error: updateParameters null PreEqBand for band %d", b);
  171. return; //failed.
  172. }
  173. ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPreEqBands[b];
  174. IS_CHANGED(changed, pEqBandParams->enabled, pEqBand->isEnabled());
  175. IS_CHANGED(changed, pEqBandParams->freqCutoffHz,
  176. pEqBand->getCutoffFrequency());
  177. IS_CHANGED(changed, pEqBandParams->gainDb, pEqBand->getGain());
  178. }
  179. }
  180. }
  181. if (changed) {
  182. float inputGainFactor = dBtoLinear(cb.inputGainDb);
  183. if (cb.mPreEqInUse && cb.mPreEqEnabled) {
  184. ALOGV("preEq changed, recomputing! channel %d", channelIndex);
  185. size_t binNext = 0;
  186. for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
  187. ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPreEqBands[b];
  188. //frequency translation
  189. cb.computeBinStartStop(*pEqBandParams, binNext);
  190. binNext = pEqBandParams->binStop + 1;
  191. float factor = dBtoLinear(pEqBandParams->gainDb);
  192. if (!pEqBandParams->enabled) {
  193. factor = inputGainFactor;
  194. }
  195. for (size_t k = pEqBandParams->binStart;
  196. k <= pEqBandParams->binStop && k < mHalfFFTSize; k++) {
  197. cb.mPreEqFactorVector[k] = factor * inputGainFactor;
  198. }
  199. }
  200. } else {
  201. ALOGV("only input gain changed, recomputing!");
  202. //populate PreEq factor with input gain factor.
  203. for (size_t k = 0; k < mHalfFFTSize; k++) {
  204. cb.mPreEqFactorVector[k] = inputGainFactor;
  205. }
  206. }
  207. }
  208. } //inputGain and preEq
  209. //===EqPost
  210. if (cb.mPostEqInUse) {
  211. bool changed = false;
  212. DPEq *pPostEq = pChannel->getPostEq();
  213. if (pPostEq == nullptr) {
  214. ALOGE("Error: updateParameters null postEq for channel: %d", channelIndex);
  215. return; //failed.
  216. }
  217. IS_CHANGED(changed, cb.mPostEqEnabled, pPostEq->isEnabled());
  218. if (cb.mPostEqEnabled) {
  219. for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
  220. DPEqBand *pEqBand = pPostEq->getBand(b);
  221. if (pEqBand == nullptr) {
  222. ALOGE("Error: updateParameters PostEqBand NULL for band %d", b);
  223. return; //failed.
  224. }
  225. ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPostEqBands[b];
  226. IS_CHANGED(changed, pEqBandParams->enabled, pEqBand->isEnabled());
  227. IS_CHANGED(changed, pEqBandParams->freqCutoffHz,
  228. pEqBand->getCutoffFrequency());
  229. IS_CHANGED(changed, pEqBandParams->gainDb, pEqBand->getGain());
  230. }
  231. if (changed) {
  232. ALOGV("postEq changed, recomputing! channel %d", channelIndex);
  233. size_t binNext = 0;
  234. for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
  235. ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPostEqBands[b];
  236. //frequency translation
  237. cb.computeBinStartStop(*pEqBandParams, binNext);
  238. binNext = pEqBandParams->binStop + 1;
  239. float factor = dBtoLinear(pEqBandParams->gainDb);
  240. if (!pEqBandParams->enabled) {
  241. factor = 1.0;
  242. }
  243. for (size_t k = pEqBandParams->binStart;
  244. k <= pEqBandParams->binStop && k < mHalfFFTSize; k++) {
  245. cb.mPostEqFactorVector[k] = factor;
  246. }
  247. }
  248. }
  249. } //enabled
  250. }
  251. //===MBC
  252. if (cb.mMbcInUse) {
  253. DPMbc *pMbc = pChannel->getMbc();
  254. if (pMbc == nullptr) {
  255. ALOGE("Error: updateParameters Mbc NULL for channel: %d", channelIndex);
  256. return;
  257. }
  258. cb.mMbcEnabled = pMbc->isEnabled();
  259. if (cb.mMbcEnabled) {
  260. bool changed = false;
  261. for (unsigned int b = 0; b < getMbcBandCount(); b++) {
  262. DPMbcBand *pMbcBand = pMbc->getBand(b);
  263. if (pMbcBand == nullptr) {
  264. ALOGE("Error: updateParameters MbcBand NULL for band %d", b);
  265. return; //failed.
  266. }
  267. ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[b];
  268. pMbcBandParams->enabled = pMbcBand->isEnabled();
  269. IS_CHANGED(changed, pMbcBandParams->freqCutoffHz,
  270. pMbcBand->getCutoffFrequency());
  271. pMbcBandParams->gainPreDb = pMbcBand->getPreGain();
  272. pMbcBandParams->gainPostDb = pMbcBand->getPostGain();
  273. pMbcBandParams->attackTimeMs = pMbcBand->getAttackTime();
  274. pMbcBandParams->releaseTimeMs = pMbcBand->getReleaseTime();
  275. pMbcBandParams->ratio = pMbcBand->getRatio();
  276. pMbcBandParams->thresholdDb = pMbcBand->getThreshold();
  277. pMbcBandParams->kneeWidthDb = pMbcBand->getKneeWidth();
  278. pMbcBandParams->noiseGateThresholdDb = pMbcBand->getNoiseGateThreshold();
  279. pMbcBandParams->expanderRatio = pMbcBand->getExpanderRatio();
  280. }
  281. if (changed) {
  282. ALOGV("mbc changed, recomputing! channel %d", channelIndex);
  283. size_t binNext= 0;
  284. for (unsigned int b = 0; b < getMbcBandCount(); b++) {
  285. ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[b];
  286. pMbcBandParams->previousEnvelope = 0;
  287. //frequency translation
  288. cb.computeBinStartStop(*pMbcBandParams, binNext);
  289. binNext = pMbcBandParams->binStop + 1;
  290. }
  291. }
  292. }
  293. }
  294. //===Limiter
  295. if (cb.mLimiterInUse) {
  296. bool changed = false;
  297. DPLimiter *pLimiter = pChannel->getLimiter();
  298. if (pLimiter == nullptr) {
  299. ALOGE("Error: updateParameters Limiter NULL for channel: %d", channelIndex);
  300. return;
  301. }
  302. cb.mLimiterEnabled = pLimiter->isEnabled();
  303. if (cb.mLimiterEnabled) {
  304. IS_CHANGED(changed, cb.mLimiterParams.linkGroup ,
  305. (int32_t)pLimiter->getLinkGroup());
  306. cb.mLimiterParams.attackTimeMs = pLimiter->getAttackTime();
  307. cb.mLimiterParams.releaseTimeMs = pLimiter->getReleaseTime();
  308. cb.mLimiterParams.ratio = pLimiter->getRatio();
  309. cb.mLimiterParams.thresholdDb = pLimiter->getThreshold();
  310. cb.mLimiterParams.postGainDb = pLimiter->getPostGain();
  311. }
  312. if (changed) {
  313. ALOGV("limiter changed, recomputing linkGroups for %d", channelIndex);
  314. mLinkedLimiters.remove(channelIndex); //in case it was already there.
  315. mLinkedLimiters.update(cb.mLimiterParams.linkGroup, channelIndex);
  316. }
  317. }
  318. //=== Output Gain
  319. cb.outputGainDb = pChannel->getOutputGain();
  320. }
  321. size_t DPFrequency::processSamples(const float *in, float *out, size_t samples) {
  322. const float *pIn = in;
  323. float *pOut = out;
  324. int channelCount = mChannelBuffers.size();
  325. if (channelCount < 1) {
  326. ALOGW("warning: no Channels ready for processing");
  327. return 0;
  328. }
  329. //**Check if parameters have changed and update
  330. for (int ch = 0; ch < channelCount; ch++) {
  331. updateParameters(mChannelBuffers[ch], ch);
  332. }
  333. //**separate into channels
  334. for (size_t k = 0; k < samples; k += channelCount) {
  335. for (int ch = 0; ch < channelCount; ch++) {
  336. mChannelBuffers[ch].cBInput.write(*pIn++);
  337. }
  338. }
  339. //**process all channelBuffers
  340. processChannelBuffers(mChannelBuffers);
  341. //** estimate how much data is available in ALL channels
  342. size_t available = mChannelBuffers[0].cBOutput.availableToRead();
  343. for (int ch = 1; ch < channelCount; ch++) {
  344. available = std::min(available, mChannelBuffers[ch].cBOutput.availableToRead());
  345. }
  346. //** make sure to output just what the buffer can handle
  347. if (available > samples/channelCount) {
  348. available = samples/channelCount;
  349. }
  350. //**Prepend zeroes if necessary
  351. size_t fill = samples - (channelCount * available);
  352. for (size_t k = 0; k < fill; k++) {
  353. *pOut++ = 0;
  354. }
  355. //**interleave channels
  356. for (size_t k = 0; k < available; k++) {
  357. for (int ch = 0; ch < channelCount; ch++) {
  358. *pOut++ = mChannelBuffers[ch].cBOutput.read();
  359. }
  360. }
  361. return samples;
  362. }
  363. size_t DPFrequency::processChannelBuffers(CBufferVector &channelBuffers) {
  364. const int channelCount = channelBuffers.size();
  365. size_t processedSamples = 0;
  366. size_t processFrames = mBlockSize - mOverlapSize;
  367. size_t available = channelBuffers[0].cBInput.availableToRead();
  368. for (int ch = 1; ch < channelCount; ch++) {
  369. available = std::min(available, channelBuffers[ch].cBInput.availableToRead());
  370. }
  371. while (available >= processFrames) {
  372. //First pass
  373. for (int ch = 0; ch < channelCount; ch++) {
  374. ChannelBuffer * pCb = &channelBuffers[ch];
  375. //move tail of previous
  376. std::copy(pCb->input.begin() + processFrames,
  377. pCb->input.end(),
  378. pCb->input.begin());
  379. //read new available data
  380. for (unsigned int k = 0; k < processFrames; k++) {
  381. pCb->input[mOverlapSize + k] = pCb->cBInput.read();
  382. }
  383. //first stages: fft, preEq, mbc, postEq and start of Limiter
  384. processedSamples += processFirstStages(*pCb);
  385. }
  386. //**compute linked limiters and update levels if needed
  387. processLinkedLimiters(channelBuffers);
  388. //final pass.
  389. for (int ch = 0; ch < channelCount; ch++) {
  390. ChannelBuffer * pCb = &channelBuffers[ch];
  391. //linked limiter and ifft
  392. processLastStages(*pCb);
  393. //mix tail (and capture new tail
  394. for (unsigned int k = 0; k < mOverlapSize; k++) {
  395. pCb->output[k] += pCb->outTail[k];
  396. pCb->outTail[k] = pCb->output[processFrames + k]; //new tail
  397. }
  398. //output data
  399. for (unsigned int k = 0; k < processFrames; k++) {
  400. pCb->cBOutput.write(pCb->output[k]);
  401. }
  402. }
  403. available -= processFrames;
  404. }
  405. return processedSamples;
  406. }
  407. size_t DPFrequency::processFirstStages(ChannelBuffer &cb) {
  408. //##apply window
  409. Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
  410. Eigen::Map<Eigen::VectorXf> eInput(&cb.input[0], cb.input.size());
  411. Eigen::VectorXf eWin = eInput.cwiseProduct(eWindow); //apply window
  412. //##fft
  413. //Note: we are using eigen with the default scaling, which ensures that
  414. // IFFT( FFT(x) ) = x.
  415. // TODO: optimize by using the noscale option, and compensate with dB scale offsets
  416. mFftServer.fwd(cb.complexTemp, eWin);
  417. size_t cSize = cb.complexTemp.size();
  418. size_t maxBin = std::min(cSize/2, mHalfFFTSize);
  419. //== EqPre (always runs)
  420. for (size_t k = 0; k < maxBin; k++) {
  421. cb.complexTemp[k] *= cb.mPreEqFactorVector[k];
  422. }
  423. //== MBC
  424. if (cb.mMbcInUse && cb.mMbcEnabled) {
  425. for (size_t band = 0; band < cb.mMbcBands.size(); band++) {
  426. ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[band];
  427. float fEnergySum = 0;
  428. //apply pre gain.
  429. float preGainFactor = dBtoLinear(pMbcBandParams->gainPreDb);
  430. float preGainSquared = preGainFactor * preGainFactor;
  431. for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
  432. fEnergySum += std::norm(cb.complexTemp[k]) * preGainSquared; //mag squared
  433. }
  434. //Eigen FFT is full spectrum, even if the source was real data.
  435. // Each half spectrum has half the energy. This is taken into account with the * 2
  436. // factor in the energy computations.
  437. // energy = sqrt(sum_components_squared) number_points
  438. // in here, the fEnergySum is duplicated to account for the second half spectrum,
  439. // and the windowRms is used to normalize by the expected energy reduction
  440. // caused by the window used (expected for steady state signals)
  441. fEnergySum = sqrt(fEnergySum * 2) / (mBlockSize * mWindowRms);
  442. // updates computed per frame advance.
  443. float fTheta = 0.0;
  444. float fFAttSec = pMbcBandParams->attackTimeMs / 1000; //in seconds
  445. float fFRelSec = pMbcBandParams->releaseTimeMs / 1000; //in seconds
  446. if (fEnergySum > pMbcBandParams->previousEnvelope) {
  447. fTheta = exp(-1.0 / (fFAttSec * mBlocksPerSecond));
  448. } else {
  449. fTheta = exp(-1.0 / (fFRelSec * mBlocksPerSecond));
  450. }
  451. float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * pMbcBandParams->previousEnvelope;
  452. //preserve for next iteration
  453. pMbcBandParams->previousEnvelope = fEnv;
  454. if (fEnv < MIN_ENVELOPE) {
  455. fEnv = MIN_ENVELOPE;
  456. }
  457. const float envDb = linearToDb(fEnv);
  458. float newLevelDb = envDb;
  459. //using shorter variables for code clarity
  460. const float thresholdDb = pMbcBandParams->thresholdDb;
  461. const float ratio = pMbcBandParams->ratio;
  462. const float kneeWidthDbHalf = pMbcBandParams->kneeWidthDb / 2;
  463. const float noiseGateThresholdDb = pMbcBandParams->noiseGateThresholdDb;
  464. const float expanderRatio = pMbcBandParams->expanderRatio;
  465. //find segment
  466. if (envDb > thresholdDb + kneeWidthDbHalf) {
  467. //compression segment
  468. newLevelDb = envDb + ((1 / ratio) - 1) * (envDb - thresholdDb);
  469. } else if (envDb > thresholdDb - kneeWidthDbHalf) {
  470. //knee-compression segment
  471. float temp = (envDb - thresholdDb + kneeWidthDbHalf);
  472. newLevelDb = envDb + ((1 / ratio) - 1) *
  473. temp * temp / (kneeWidthDbHalf * 4);
  474. } else if (envDb < noiseGateThresholdDb) {
  475. //expander segment
  476. newLevelDb = noiseGateThresholdDb -
  477. expanderRatio * (noiseGateThresholdDb - envDb);
  478. }
  479. float newFactor = dBtoLinear(newLevelDb - envDb);
  480. //apply post gain.
  481. newFactor *= dBtoLinear(pMbcBandParams->gainPostDb);
  482. //apply to this band
  483. for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
  484. cb.complexTemp[k] *= newFactor;
  485. }
  486. } //end per band process
  487. } //end MBC
  488. //== EqPost
  489. if (cb.mPostEqInUse && cb.mPostEqEnabled) {
  490. for (size_t k = 0; k < maxBin; k++) {
  491. cb.complexTemp[k] *= cb.mPostEqFactorVector[k];
  492. }
  493. }
  494. //== Limiter. First Pass
  495. if (cb.mLimiterInUse && cb.mLimiterEnabled) {
  496. float fEnergySum = 0;
  497. for (size_t k = 0; k < maxBin; k++) {
  498. fEnergySum += std::norm(cb.complexTemp[k]);
  499. }
  500. //see explanation above for energy computation logic
  501. fEnergySum = sqrt(fEnergySum * 2) / (mBlockSize * mWindowRms);
  502. float fTheta = 0.0;
  503. float fFAttSec = cb.mLimiterParams.attackTimeMs / 1000; //in seconds
  504. float fFRelSec = cb.mLimiterParams.releaseTimeMs / 1000; //in seconds
  505. if (fEnergySum > cb.mLimiterParams.previousEnvelope) {
  506. fTheta = exp(-1.0 / (fFAttSec * mBlocksPerSecond));
  507. } else {
  508. fTheta = exp(-1.0 / (fFRelSec * mBlocksPerSecond));
  509. }
  510. float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * cb.mLimiterParams.previousEnvelope;
  511. //preserve for next iteration
  512. cb.mLimiterParams.previousEnvelope = fEnv;
  513. const float envDb = linearToDb(fEnv);
  514. float newFactorDb = 0;
  515. //using shorter variables for code clarity
  516. const float thresholdDb = cb.mLimiterParams.thresholdDb;
  517. const float ratio = cb.mLimiterParams.ratio;
  518. if (envDb > thresholdDb) {
  519. //limiter segment
  520. newFactorDb = ((1 / ratio) - 1) * (envDb - thresholdDb);
  521. }
  522. float newFactor = dBtoLinear(newFactorDb);
  523. cb.mLimiterParams.newFactor = newFactor;
  524. } //end Limiter
  525. return mBlockSize;
  526. }
  527. void DPFrequency::processLinkedLimiters(CBufferVector &channelBuffers) {
  528. const int channelCount = channelBuffers.size();
  529. for (auto &groupPair : mLinkedLimiters.mGroupsMap) {
  530. float minFactor = 1.0;
  531. //estimate minfactor for all linked
  532. for(int index : groupPair.second) {
  533. if (index >= 0 && index < channelCount) {
  534. minFactor = std::min(channelBuffers[index].mLimiterParams.newFactor, minFactor);
  535. }
  536. }
  537. //apply minFactor
  538. for(int index : groupPair.second) {
  539. if (index >= 0 && index < channelCount) {
  540. channelBuffers[index].mLimiterParams.linkFactor = minFactor;
  541. }
  542. }
  543. }
  544. }
  545. size_t DPFrequency::processLastStages(ChannelBuffer &cb) {
  546. float outputGainFactor = dBtoLinear(cb.outputGainDb);
  547. //== Limiter. last Pass
  548. if (cb.mLimiterInUse && cb.mLimiterEnabled) {
  549. //compute factor, with post-gain
  550. float factor = cb.mLimiterParams.linkFactor * dBtoLinear(cb.mLimiterParams.postGainDb);
  551. outputGainFactor *= factor;
  552. }
  553. //apply to all if != 1.0
  554. if (!compareEquality(outputGainFactor, 1.0f)) {
  555. size_t cSize = cb.complexTemp.size();
  556. size_t maxBin = std::min(cSize/2, mHalfFFTSize);
  557. for (size_t k = 0; k < maxBin; k++) {
  558. cb.complexTemp[k] *= outputGainFactor;
  559. }
  560. }
  561. //##ifft directly to output.
  562. Eigen::Map<Eigen::VectorXf> eOutput(&cb.output[0], cb.output.size());
  563. mFftServer.inv(eOutput, cb.complexTemp);
  564. //apply rest of window for resynthesis
  565. Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
  566. eOutput = eOutput.cwiseProduct(eWindow);
  567. return mBlockSize;
  568. }
  569. } //namespace dp_fx