blob: 59195fc0caeb50f67e12d313cb72160cfd84a69c [file] [log] [blame]
ragoff0a51f2018-03-22 09:55:50 -07001/*
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
17#define LOG_TAG "DPFrequency"
18//#define LOG_NDEBUG 0
19
20#include <log/log.h>
21#include "DPFrequency.h"
22#include <algorithm>
23
24namespace dp_fx {
25
26using Eigen::MatrixXd;
27#define MAX_BLOCKSIZE 16384 //For this implementation
28#define MIN_BLOCKSIZE 8
29
30#define CIRCULAR_BUFFER_UPSAMPLE 4 //4 times buffer size
31
32static constexpr float MIN_ENVELOPE = 0.000001f;
33//helper functionS
34static inline bool isPowerOf2(unsigned long n) {
35 return (n & (n - 1)) == 0;
36}
37static constexpr float EPSILON = 0.0000001f;
38
39static inline bool isZero(float f) {
40 return fabs(f) <= EPSILON;
41}
42
43template <class T>
44bool compareEquality(T a, T b) {
45 return (a == b);
46}
47
48template <> bool compareEquality<float>(float a, float b) {
49 return isZero(a - b);
50}
51
52//TODO: avoid using macro for estimating change and assignment.
53#define IS_CHANGED(c, a, b) { c |= !compareEquality(a,b); \
54 (a) = (b); }
55
56float dBtoLinear(float valueDb) {
57 return pow (10, valueDb / 20.0);
58}
59
60float linearToDb(float value) {
61 return 20 * log10(value);
62}
63
64//ChannelBuffers helper
65void ChannelBuffer::initBuffers(unsigned int blockSize, unsigned int overlapSize,
66 unsigned int halfFftSize, unsigned int samplingRate, DPBase &dpBase) {
67 ALOGV("ChannelBuffer::initBuffers blockSize %d, overlap %d, halfFft %d",
68 blockSize, overlapSize, halfFftSize);
69
70 mSamplingRate = samplingRate;
71 mBlockSize = blockSize;
72
73 cBInput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
74 cBOutput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
75
76 //fill input with half block size...
77 for (unsigned int k = 0; k < mBlockSize/2; k++) {
78 cBInput.write(0);
79 }
80
81 //temp vectors
82 input.resize(mBlockSize);
83 output.resize(mBlockSize);
84 outTail.resize(overlapSize);
85
86 //module vectors
87 mPreEqFactorVector.resize(halfFftSize, 1.0);
88 mPostEqFactorVector.resize(halfFftSize, 1.0);
89
90 mPreEqBands.resize(dpBase.getPreEqBandCount());
91 mMbcBands.resize(dpBase.getMbcBandCount());
92 mPostEqBands.resize(dpBase.getPostEqBandCount());
93 ALOGV("mPreEqBands %zu, mMbcBands %zu, mPostEqBands %zu",mPreEqBands.size(),
94 mMbcBands.size(), mPostEqBands.size());
95
96 DPChannel *pChannel = dpBase.getChannel(0);
97 if (pChannel != NULL) {
98 mPreEqInUse = pChannel->getPreEq()->isInUse();
99 mMbcInUse = pChannel->getMbc()->isInUse();
100 mPostEqInUse = pChannel->getPostEq()->isInUse();
101 mLimiterInUse = pChannel->getLimiter()->isInUse();
102 }
103}
104
105void ChannelBuffer::computeBinStartStop(BandParams &bp, size_t binStart) {
106
107 bp.binStart = binStart;
108 bp.binStop = (int)(0.5 + bp.freqCutoffHz * mBlockSize / mSamplingRate);
109}
110
111//== DPFrequency
112
113void DPFrequency::reset() {
114}
115
116size_t DPFrequency::getMinBockSize() {
117 return MIN_BLOCKSIZE;
118}
119
120size_t DPFrequency::getMaxBockSize() {
121 return MAX_BLOCKSIZE;
122}
123
124void DPFrequency::configure(size_t blockSize, size_t overlapSize,
125 size_t samplingRate) {
126 ALOGV("configure");
127 mBlockSize = blockSize;
128 if (mBlockSize > MAX_BLOCKSIZE) {
129 mBlockSize = MAX_BLOCKSIZE;
130 } else if (mBlockSize < MIN_BLOCKSIZE) {
131 mBlockSize = MIN_BLOCKSIZE;
132 } else {
133 if (!isPowerOf2(blockSize)) {
134 //find next highest power of 2.
135 mBlockSize = 1 << (32 - __builtin_clz(blockSize));
136 }
137 }
138
139 mHalfFFTSize = 1 + mBlockSize / 2; //including Nyquist bin
140 mOverlapSize = std::min(overlapSize, mBlockSize/2);
141
142 int channelcount = getChannelCount();
143 mSamplingRate = samplingRate;
144 mChannelBuffers.resize(channelcount);
145 for (int ch = 0; ch < channelcount; ch++) {
146 mChannelBuffers[ch].initBuffers(mBlockSize, mOverlapSize, mHalfFFTSize,
147 mSamplingRate, *this);
148 }
149
150 //dsp
151 fill_window(mVWindow, RDSP_WINDOW_HANNING_FLAT_TOP, mBlockSize, mOverlapSize);
152}
153
154void DPFrequency::updateParameters(ChannelBuffer &cb, int channelIndex) {
155 DPChannel *pChannel = getChannel(channelIndex);
156
157 if (pChannel == NULL) {
158 ALOGE("Error: updateParameters null DPChannel %d", channelIndex);
159 return;
160 }
161
162 //===Input Gain and preEq
163 {
164 bool changed = false;
165 IS_CHANGED(changed, cb.inputGainDb, pChannel->getInputGain());
166 //===EqPre
167 if (cb.mPreEqInUse) {
168 DPEq *pPreEq = pChannel->getPreEq();
169 if (pPreEq == NULL) {
170 ALOGE("Error: updateParameters null PreEq for channel: %d", channelIndex);
171 return;
172 }
173 IS_CHANGED(changed, cb.mPreEqEnabled, pPreEq->isEnabled());
174 if (cb.mPreEqEnabled) {
175 for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
176 DPEqBand *pEqBand = pPreEq->getBand(b);
177 if (pEqBand == NULL) {
178 ALOGE("Error: updateParameters null PreEqBand for band %d", b);
179 return; //failed.
180 }
181 ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPreEqBands[b];
182 IS_CHANGED(changed, pEqBandParams->enabled, pEqBand->isEnabled());
183 IS_CHANGED(changed, pEqBandParams->freqCutoffHz,
184 pEqBand->getCutoffFrequency());
185 IS_CHANGED(changed, pEqBandParams->gainDb, pEqBand->getGain());
186 }
187 }
188 }
189
190 if (changed) {
191 float inputGainFactor = dBtoLinear(cb.inputGainDb);
192 if (cb.mPreEqInUse && cb.mPreEqEnabled) {
193 ALOGV("preEq changed, recomputing! channel %d", channelIndex);
194 size_t binNext = 0;
195 for (unsigned int b = 0; b < getPreEqBandCount(); b++) {
196 ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPreEqBands[b];
197
198 //frequency translation
199 cb.computeBinStartStop(*pEqBandParams, binNext);
200 binNext = pEqBandParams->binStop + 1;
201 float factor = dBtoLinear(pEqBandParams->gainDb);
202 if (!pEqBandParams->enabled) {
203 factor = inputGainFactor;
204 }
205 for (size_t k = pEqBandParams->binStart;
206 k <= pEqBandParams->binStop && k < mHalfFFTSize; k++) {
207 cb.mPreEqFactorVector[k] = factor * inputGainFactor;
208 }
209 }
210 } else {
211 ALOGV("only input gain changed, recomputing!");
212 //populate PreEq factor with input gain factor.
213 for (size_t k = 0; k < mHalfFFTSize; k++) {
214 cb.mPreEqFactorVector[k] = inputGainFactor;
215 }
216 }
217 }
218 } //inputGain and preEq
219
220 //===EqPost
221 if (cb.mPostEqInUse) {
222 bool changed = false;
223
224 DPEq *pPostEq = pChannel->getPostEq();
225 if (pPostEq == NULL) {
226 ALOGE("Error: updateParameters null postEq for channel: %d", channelIndex);
227 return; //failed.
228 }
229 IS_CHANGED(changed, cb.mPostEqEnabled, pPostEq->isEnabled());
230 if (cb.mPostEqEnabled) {
231 for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
232 DPEqBand *pEqBand = pPostEq->getBand(b);
233 if (pEqBand == NULL) {
234 ALOGE("Error: updateParameters PostEqBand NULL for band %d", b);
235 return; //failed.
236 }
237 ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPostEqBands[b];
238 IS_CHANGED(changed, pEqBandParams->enabled, pEqBand->isEnabled());
239 IS_CHANGED(changed, pEqBandParams->freqCutoffHz,
240 pEqBand->getCutoffFrequency());
241 IS_CHANGED(changed, pEqBandParams->gainDb, pEqBand->getGain());
242 }
243 if (changed) {
244 ALOGV("postEq changed, recomputing! channel %d", channelIndex);
245 size_t binNext = 0;
246 for (unsigned int b = 0; b < getPostEqBandCount(); b++) {
247 ChannelBuffer::EqBandParams *pEqBandParams = &cb.mPostEqBands[b];
248
249 //frequency translation
250 cb.computeBinStartStop(*pEqBandParams, binNext);
251 binNext = pEqBandParams->binStop + 1;
252 float factor = dBtoLinear(pEqBandParams->gainDb);
253 if (!pEqBandParams->enabled) {
254 factor = 1.0;
255 }
256 for (size_t k = pEqBandParams->binStart;
257 k <= pEqBandParams->binStop && k < mHalfFFTSize; k++) {
258 cb.mPostEqFactorVector[k] = factor;
259 }
260 }
261 }
262 } //enabled
263 }
264
265 //===MBC
266 if (cb.mMbcInUse) {
267 DPMbc *pMbc = pChannel->getMbc();
268 if (pMbc == NULL) {
269 ALOGE("Error: updateParameters Mbc NULL for channel: %d", channelIndex);
270 return;
271 }
272 cb.mMbcEnabled = pMbc->isEnabled();
273 if (cb.mMbcEnabled) {
274 bool changed = false;
275 for (unsigned int b = 0; b < getMbcBandCount(); b++) {
276 DPMbcBand *pMbcBand = pMbc->getBand(b);
277 if (pMbcBand == NULL) {
278 ALOGE("Error: updateParameters MbcBand NULL for band %d", b);
279 return; //failed.
280 }
281 ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[b];
282 pMbcBandParams->enabled = pMbcBand->isEnabled();
283 IS_CHANGED(changed, pMbcBandParams->freqCutoffHz,
284 pMbcBand->getCutoffFrequency());
285
286 pMbcBandParams->gainPreDb = pMbcBand->getPreGain();
287 pMbcBandParams->gainPostDb = pMbcBand->getPostGain();
288 pMbcBandParams->attackTimeMs = pMbcBand->getAttackTime();
289 pMbcBandParams->releaseTimeMs = pMbcBand->getReleaseTime();
290 pMbcBandParams->ratio = pMbcBand->getRatio();
291 pMbcBandParams->thresholdDb = pMbcBand->getThreshold();
292 pMbcBandParams->kneeWidthDb = pMbcBand->getKneeWidth();
293 pMbcBandParams->noiseGateThresholdDb = pMbcBand->getNoiseGateThreshold();
294 pMbcBandParams->expanderRatio = pMbcBand->getExpanderRatio();
295
296 }
297
298 if (changed) {
299 ALOGV("mbc changed, recomputing! channel %d", channelIndex);
300 size_t binNext= 0;
301 for (unsigned int b = 0; b < getMbcBandCount(); b++) {
302 ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[b];
303
304 pMbcBandParams->previousEnvelope = 0;
305
306 //frequency translation
307 cb.computeBinStartStop(*pMbcBandParams, binNext);
308 binNext = pMbcBandParams->binStop + 1;
309 }
310
311 }
312
313 }
314 }
315}
316
317size_t DPFrequency::processSamples(const float *in, float *out, size_t samples) {
318 const float *pIn = in;
319 float *pOut = out;
320
321 int channelCount = mChannelBuffers.size();
322 if (channelCount < 1) {
323 ALOGW("warning: no Channels ready for processing");
324 return 0;
325 }
326
327 //**Check if parameters have changed and update
328 for (int ch = 0; ch < channelCount; ch++) {
329 updateParameters(mChannelBuffers[ch], ch);
330 }
331
332 //**separate into channels
333 for (size_t k = 0; k < samples; k += channelCount) {
334 for (int ch = 0; ch < channelCount; ch++) {
335 mChannelBuffers[ch].cBInput.write(*pIn++);
336 }
337 }
338
339 //TODO: lookahead limiters
340 //TODO: apply linked limiters to all channels.
341 //**Process each Channel
342 for (int ch = 0; ch < channelCount; ch++) {
343 processMono(mChannelBuffers[ch]);
344 }
345
346 //** estimate how much data is available in ALL channels
347 size_t available = mChannelBuffers[0].cBOutput.availableToRead();
348 for (int ch = 1; ch < channelCount; ch++) {
349 available = std::min(available, mChannelBuffers[ch].cBOutput.availableToRead());
350 }
351
352 //** make sure to output just what the buffer can handle
353 if (available > samples/channelCount) {
354 available = samples/channelCount;
355 }
356
357 //**Prepend zeroes if necessary
358 size_t fill = samples - (channelCount * available);
359 for (size_t k = 0; k < fill; k++) {
360 *pOut++ = 0;
361 }
362
363 //**interleave channels
364 for (size_t k = 0; k < available; k++) {
365 for (int ch = 0; ch < channelCount; ch++) {
366 *pOut++ = mChannelBuffers[ch].cBOutput.read();
367 }
368 }
369
370 return samples;
371}
372
373size_t DPFrequency::processMono(ChannelBuffer &cb) {
374
375 size_t processedSamples = 0;
376
377 size_t available = cb.cBInput.availableToRead();
378 while (available >= mBlockSize - mOverlapSize) {
379
380 //move tail of previous
381 for (unsigned int k = 0; k < mOverlapSize; ++k) {
382 cb.input[k] = cb.input[mBlockSize - mOverlapSize + k];
383 }
384
385 //read new available data
386 for (unsigned int k = 0; k < mBlockSize - mOverlapSize; k++) {
387 cb.input[mOverlapSize + k] = cb.cBInput.read();
388 }
389
390 //## Actual process
391 processOneVector(cb.output, cb.input, cb);
392 //##End of Process
393
394 //mix tail (and capture new tail
395 for (unsigned int k = 0; k < mOverlapSize; k++) {
396 cb.output[k] += cb.outTail[k];
397 cb.outTail[k] = cb.output[mBlockSize - mOverlapSize + k]; //new tail
398 }
399
400 //output data
401 for (unsigned int k = 0; k < mBlockSize - mOverlapSize; k++) {
402 cb.cBOutput.write(cb.output[k]);
403 }
404
405 available = cb.cBInput.availableToRead();
406 }
407
408 return processedSamples;
409}
410
411size_t DPFrequency::processOneVector(FloatVec & output, FloatVec & input,
412 ChannelBuffer &cb) {
413
414 //##apply window
415 Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
416 Eigen::Map<Eigen::VectorXf> eInput(&input[0], input.size());
417
418 Eigen::VectorXf eWin = eInput.cwiseProduct(eWindow); //apply window
419
420 //##fft //TODO: refactor frequency transformations away from other stages.
421 mFftServer.fwd(mComplexTemp, eWin);
422
423 size_t cSize = mComplexTemp.size();
424 size_t maxBin = std::min(cSize/2, mHalfFFTSize);
425
426 //== EqPre (always runs)
427 for (size_t k = 0; k < maxBin; k++) {
428 mComplexTemp[k] *= cb.mPreEqFactorVector[k];
429 }
430
431 //== MBC
432 if (cb.mMbcInUse && cb.mMbcEnabled) {
433 for (size_t band = 0; band < cb.mMbcBands.size(); band++) {
434 ChannelBuffer::MbcBandParams *pMbcBandParams = &cb.mMbcBands[band];
435 float fEnergySum = 0;
436
437 //apply pre gain.
438 float preGainFactor = dBtoLinear(pMbcBandParams->gainPreDb);
439 float preGainSquared = preGainFactor * preGainFactor;
440
441 for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
442 float fReal = mComplexTemp[k].real();
443 float fImag = mComplexTemp[k].imag();
444 float fSquare = (fReal * fReal + fImag * fImag) * preGainSquared;
445
446 fEnergySum += fSquare;
447 }
448
449 fEnergySum = sqrt(fEnergySum /2.0);
450 float fTheta = 0.0;
451 float fFAtt = pMbcBandParams->attackTimeMs;
452 float fFRel = pMbcBandParams->releaseTimeMs;
453
454 float fUpdatesPerSecond = 10; //TODO: compute from framerate
455
456
457 if (fEnergySum > pMbcBandParams->previousEnvelope) {
458 fTheta = exp(-1.0 / (fFAtt * fUpdatesPerSecond));
459 } else {
460 fTheta = exp(-1.0 / (fFRel * fUpdatesPerSecond));
461 }
462
463 float fEnv = (1.0 - fTheta) * fEnergySum + fTheta * pMbcBandParams->previousEnvelope;
464
465 //preserve for next iteration
466 pMbcBandParams->previousEnvelope = fEnv;
467
468 float fThreshold = dBtoLinear(pMbcBandParams->thresholdDb);
469 float fNoiseGateThreshold = dBtoLinear(pMbcBandParams->noiseGateThresholdDb);
470
471 float fNewFactor = 1.0;
472
473 if (fEnv > fThreshold) {
474 float fDbAbove = linearToDb(fThreshold / fEnv);
475 float fDbTarget = fDbAbove / pMbcBandParams->ratio;
476 float fDbChange = fDbAbove - fDbTarget;
477 fNewFactor = dBtoLinear(fDbChange);
478 } else if (fEnv < fNoiseGateThreshold) {
479 if (fEnv < MIN_ENVELOPE) {
480 fEnv = MIN_ENVELOPE;
481 }
482 float fDbBelow = linearToDb(fNoiseGateThreshold / fEnv);
483 float fDbTarget = fDbBelow / pMbcBandParams->expanderRatio;
484 float fDbChange = fDbBelow - fDbTarget;
485 fNewFactor = dBtoLinear(fDbChange);
486 }
487
488 //apply post gain.
489 fNewFactor *= dBtoLinear(pMbcBandParams->gainPostDb);
490
491 if (fNewFactor < 0) {
492 fNewFactor = 0;
493 }
494
495 //apply to this band
496 for (size_t k = pMbcBandParams->binStart; k <= pMbcBandParams->binStop; k++) {
497 mComplexTemp[k] *= fNewFactor;
498 }
499
500 } //end per band process
501
502 } //end MBC
503
504 //== EqPost
505 if (cb.mPostEqInUse && cb.mPostEqEnabled) {
506 for (size_t k = 0; k < maxBin; k++) {
507 mComplexTemp[k] *= cb.mPostEqFactorVector[k];
508 }
509 }
510
511 //##ifft directly to output.
512 Eigen::Map<Eigen::VectorXf> eOutput(&output[0], output.size());
513 mFftServer.inv(eOutput, mComplexTemp);
514
515 return mBlockSize;
516}
517
518} //namespace dp_fx