Loading media/libeffects/cyanogen-dsp/EffectEqualizer.cpp +83 −21 Original line number Original line Diff line number Diff line Loading @@ -61,17 +61,16 @@ static int64_t toFixedPoint(float in) { } } EffectEqualizer::EffectEqualizer() EffectEqualizer::EffectEqualizer() : mLoudnessAdjustment(10000.f), mLoudness(0.f) { { for (int32_t i = 0; i < 5; i ++) { for (int32_t i = 0; i < 5; i ++) { mBand[i] = 0; mBand[i] = 0; } } refreshBands(); } } int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize, void* pReplyData) int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize, void* pReplyData) { { if (cmdCode == EFFECT_CMD_CONFIGURE) { if (cmdCode == EFFECT_CMD_CONFIGURE) { LOGI("EFFECT_CMD_CONFIGURE"); int32_t ret = Effect::configure(pCmdData); int32_t ret = Effect::configure(pCmdData); if (ret != 0) { if (ret != 0) { LOGE("EFFECT_CMD_CONFIGURE failed"); LOGE("EFFECT_CMD_CONFIGURE failed"); Loading @@ -80,21 +79,20 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return 0; return 0; } } refreshBands(); /* Weigher for estimating bass compensation. Our adjustments have range from 62.5 to 4000 Hz. * Most of the adjustment is at the 62.5 Hz band, so we must concentrate on bass region. */ mWeigher.setLowPass(1000.0, mSamplingRate, sqrtf(2)/2.); int32_t *replyData = (int32_t *) pReplyData; int32_t *replyData = (int32_t *) pReplyData; *replyData = 0; *replyData = 0; LOGI("EFFECT_CMD_CONFIGURE OK"); return 0; return 0; } } if (cmdCode == EFFECT_CMD_GET_PARAM) { if (cmdCode == EFFECT_CMD_GET_PARAM) { effect_param_t *cep = (effect_param_t *) pCmdData; effect_param_t *cep = (effect_param_t *) pCmdData; LOGI("EFFECT_CMD_GET_PARAM + %d bytes of param", cep->psize); if (cep->psize == 4) { if (cep->psize == 4) { int cmd = ((int *) cep)[3]; int32_t cmd = ((int32_t *) cep)[3]; if (cmd == EQ_PARAM_NUM_BANDS) { if (cmd == EQ_PARAM_NUM_BANDS) { LOGI("Requested param: EQ_PARAM_NUM_BANDS"); reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; replyData->vsize = 2; replyData->vsize = 2; Loading @@ -104,7 +102,6 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return 0; return 0; } } if (cmd == EQ_PARAM_LEVEL_RANGE) { if (cmd == EQ_PARAM_LEVEL_RANGE) { LOGI("Requested param: EQ_PARAM_LEVEL_RANGE"); reply1x4_2x2_t *replyData = (reply1x4_2x2_t *) pReplyData; reply1x4_2x2_t *replyData = (reply1x4_2x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; replyData->vsize = 4; replyData->vsize = 4; Loading @@ -115,19 +112,16 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return 0; return 0; } } if (cmd == EQ_PARAM_GET_NUM_OF_PRESETS) { if (cmd == EQ_PARAM_GET_NUM_OF_PRESETS) { LOGI("Requested param: EQ_PARAM_GET_NUM_OF_PRESETS"); reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; replyData->vsize = 2; replyData->vsize = 2; replyData->data = 0; replyData->data = 0; *replySize = sizeof(reply1x4_1x2_t); *replySize = sizeof(reply1x4_1x2_t); LOGI("EQ_PARAM_GET_NUM_OF_PRESETS OK"); return 0; return 0; } } } else if (cep->psize == 8) { } else if (cep->psize == 8) { int cmd = ((int *) cep)[3]; int32_t cmd = ((int32_t *) cep)[3]; int arg = ((int *) cep)[4]; int32_t arg = ((int32_t *) cep)[4]; LOGI("Requested param: %d, %d", cmd, arg); if (cmd == EQ_PARAM_BAND_LEVEL && arg >= 0 && arg < 5) { if (cmd == EQ_PARAM_BAND_LEVEL && arg >= 0 && arg < 5) { reply2x4_1x2_t *replyData = (reply2x4_1x2_t *) pReplyData; reply2x4_1x2_t *replyData = (reply2x4_1x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; Loading Loading @@ -158,9 +152,19 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD if (cmdCode == EFFECT_CMD_SET_PARAM) { if (cmdCode == EFFECT_CMD_SET_PARAM) { effect_param_t *cep = (effect_param_t *) pCmdData; effect_param_t *cep = (effect_param_t *) pCmdData; LOGI("EFFECT_CMD_SET_PARAM, %d", cep->psize); int32_t *replyData = (int32_t *) pReplyData; int32_t *replyData = (int32_t *) pReplyData; if (cep->psize == 6) { int32_t cmd = ((int32_t *) cep)[3]; if (cmd == CUSTOM_EQ_PARAM_LOUDNESS_CORRECTION) { int16_t value = ((int16_t *) cep)[8]; mLoudnessAdjustment = value / 100.0f; LOGI("Setting loudness correction reference to %f dB", mLoudnessAdjustment); *replyData = 0; return 0; } } if (cep->psize == 8) { if (cep->psize == 8) { int32_t cmd = ((int32_t *) cep)[3]; int32_t cmd = ((int32_t *) cep)[3]; int32_t arg = ((int32_t *) cep)[4]; int32_t arg = ((int32_t *) cep)[4]; Loading @@ -170,7 +174,6 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD *replyData = 0; *replyData = 0; int16_t value = ((int16_t *) cep)[10]; int16_t value = ((int16_t *) cep)[10]; mBand[arg] = value / 100.0f; mBand[arg] = value / 100.0f; refreshBands(); return 0; return 0; } } } } Loading @@ -183,12 +186,48 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return Effect::command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); return Effect::command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } } /* Source material: ISO 226:2003 curves. * * On differencing 100 dB curves against 80 dB, 60 dB, 40 dB and 20 dB, a pattern * can be established where each loss of 20 dB of power in signal suggests gradually * decreasing ear sensitivity, until the bottom is reached at 20 dB SPL where no more * boosting is required. Measurements end at 100 dB, which is assumed to be the reference * sound pressure level. * * The boost can be calculated as linear scaling of the following adjustment: * 62.5 Hz +24 dB * 250 Hz +10 dB * 1000 Hz 0 dB * 4000 Hz -6 dB * * The boost will be applied maximally for signals of 20 dB and less, * and linearly decreased for signals 20 dB ... 100 dB, and no adjustment is * made for 100 dB or higher. User must configure a reference level that maps the * digital sound level against the audio. */ float EffectEqualizer::getAdjustedBand(int32_t band) { const float adj[5] = { 24.0, 10.0, 0.0, -6.0, 0.0 }; float loudnessLevel = mLoudness + mLoudnessAdjustment; if (loudnessLevel > 100.f) { loudnessLevel = 100.f; } if (loudnessLevel < 20.f) { loudnessLevel = 20.f; } loudnessLevel = (loudnessLevel - 20) / (100.0 - 20.0); /* Maximum loudness = no adj (reference behavior at 100 dB) */ return mBand[band] + adj[band] * (1. - loudnessLevel); } void EffectEqualizer::refreshBands() void EffectEqualizer::refreshBands() { { mGain = toFixedPoint(powf(10.0f, mBand[0] / 20.0f)); mGain = toFixedPoint(powf(10.0f, getAdjustedBand(0) / 20.0f)); for (int band = 0; band < 4; band ++) { for (int32_t band = 0; band < 4; band ++) { float centerFrequency = 62.5f * powf(4, band); float centerFrequency = 62.5f * powf(4, band); float dB = mBand[band+1] - mBand[band]; float dB = getAdjustedBand(band+1) - getAdjustedBand(band); mFilterL[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); mFilterL[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); mFilterR[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); mFilterR[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); Loading @@ -197,10 +236,17 @@ void EffectEqualizer::refreshBands() int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out) int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out) { { refreshBands(); int64_t maximumPowerSquared = 0; for (uint32_t i = 0; i < in->frameCount; i ++) { for (uint32_t i = 0; i < in->frameCount; i ++) { int32_t tmpL = read(in, i * 2); int32_t tmpL = read(in, i * 2); int32_t tmpR = read(in, i * 2 + 1); int32_t tmpR = read(in, i * 2 + 1); /* Calculate signal loudness estimate */ int64_t weight = mWeigher.process(tmpL + tmpR); maximumPowerSquared += weight * weight; /* first "shelve" is just gain */ /* first "shelve" is just gain */ tmpL = tmpL * mGain >> 32; tmpL = tmpL * mGain >> 32; tmpR = tmpR * mGain >> 32; tmpR = tmpR * mGain >> 32; Loading @@ -214,6 +260,22 @@ int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out) write(out, i * 2, tmpL); write(out, i * 2, tmpL); write(out, i * 2 + 1, tmpR); write(out, i * 2 + 1, tmpR); } } maximumPowerSquared /= in->frameCount; float signalPowerDb = logf(maximumPowerSquared / float(int64_t(1) << 48) + 1e-10f) / logf(10.0f) * 10.0f; signalPowerDb += 96.0f; /* Limit automatic EQ to maximum of 10 dB adjustment rate per second. * a frame-to-frame adjusted should not be very large because adjustments do cause * small glitches at the output. These may be audible if single step is too large. */ float maxAdj = in->frameCount / mSamplingRate * 10.f; if (mLoudness < signalPowerDb - maxAdj) { mLoudness += maxAdj; } else if (mLoudness > signalPowerDb + maxAdj) { mLoudness -= maxAdj; } else { mLoudness = signalPowerDb; } return 0; return 0; } } Loading media/libeffects/cyanogen-dsp/EffectEqualizer.h +11 −0 Original line number Original line Diff line number Diff line Loading @@ -5,13 +5,24 @@ #include "Biquad.h" #include "Biquad.h" #include "Effect.h" #include "Effect.h" #define CUSTOM_EQ_PARAM_LOUDNESS_CORRECTION 1000 class EffectEqualizer : public Effect { class EffectEqualizer : public Effect { private: private: /* Equalizer */ float mBand[5]; float mBand[5]; int64_t mGain; int64_t mGain; Biquad mFilterL[4], mFilterR[4]; Biquad mFilterL[4], mFilterR[4]; /* Automatic equalizer */ float mLoudnessAdjustment; Biquad mWeigher; float mLoudness; void setBand(int32_t idx, float dB); void setBand(int32_t idx, float dB); float getAdjustedBand(int32_t idx); void refreshBands(); void refreshBands(); public: public: Loading Loading
media/libeffects/cyanogen-dsp/EffectEqualizer.cpp +83 −21 Original line number Original line Diff line number Diff line Loading @@ -61,17 +61,16 @@ static int64_t toFixedPoint(float in) { } } EffectEqualizer::EffectEqualizer() EffectEqualizer::EffectEqualizer() : mLoudnessAdjustment(10000.f), mLoudness(0.f) { { for (int32_t i = 0; i < 5; i ++) { for (int32_t i = 0; i < 5; i ++) { mBand[i] = 0; mBand[i] = 0; } } refreshBands(); } } int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize, void* pReplyData) int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize, void* pReplyData) { { if (cmdCode == EFFECT_CMD_CONFIGURE) { if (cmdCode == EFFECT_CMD_CONFIGURE) { LOGI("EFFECT_CMD_CONFIGURE"); int32_t ret = Effect::configure(pCmdData); int32_t ret = Effect::configure(pCmdData); if (ret != 0) { if (ret != 0) { LOGE("EFFECT_CMD_CONFIGURE failed"); LOGE("EFFECT_CMD_CONFIGURE failed"); Loading @@ -80,21 +79,20 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return 0; return 0; } } refreshBands(); /* Weigher for estimating bass compensation. Our adjustments have range from 62.5 to 4000 Hz. * Most of the adjustment is at the 62.5 Hz band, so we must concentrate on bass region. */ mWeigher.setLowPass(1000.0, mSamplingRate, sqrtf(2)/2.); int32_t *replyData = (int32_t *) pReplyData; int32_t *replyData = (int32_t *) pReplyData; *replyData = 0; *replyData = 0; LOGI("EFFECT_CMD_CONFIGURE OK"); return 0; return 0; } } if (cmdCode == EFFECT_CMD_GET_PARAM) { if (cmdCode == EFFECT_CMD_GET_PARAM) { effect_param_t *cep = (effect_param_t *) pCmdData; effect_param_t *cep = (effect_param_t *) pCmdData; LOGI("EFFECT_CMD_GET_PARAM + %d bytes of param", cep->psize); if (cep->psize == 4) { if (cep->psize == 4) { int cmd = ((int *) cep)[3]; int32_t cmd = ((int32_t *) cep)[3]; if (cmd == EQ_PARAM_NUM_BANDS) { if (cmd == EQ_PARAM_NUM_BANDS) { LOGI("Requested param: EQ_PARAM_NUM_BANDS"); reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; replyData->vsize = 2; replyData->vsize = 2; Loading @@ -104,7 +102,6 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return 0; return 0; } } if (cmd == EQ_PARAM_LEVEL_RANGE) { if (cmd == EQ_PARAM_LEVEL_RANGE) { LOGI("Requested param: EQ_PARAM_LEVEL_RANGE"); reply1x4_2x2_t *replyData = (reply1x4_2x2_t *) pReplyData; reply1x4_2x2_t *replyData = (reply1x4_2x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; replyData->vsize = 4; replyData->vsize = 4; Loading @@ -115,19 +112,16 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return 0; return 0; } } if (cmd == EQ_PARAM_GET_NUM_OF_PRESETS) { if (cmd == EQ_PARAM_GET_NUM_OF_PRESETS) { LOGI("Requested param: EQ_PARAM_GET_NUM_OF_PRESETS"); reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; reply1x4_1x2_t *replyData = (reply1x4_1x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; replyData->vsize = 2; replyData->vsize = 2; replyData->data = 0; replyData->data = 0; *replySize = sizeof(reply1x4_1x2_t); *replySize = sizeof(reply1x4_1x2_t); LOGI("EQ_PARAM_GET_NUM_OF_PRESETS OK"); return 0; return 0; } } } else if (cep->psize == 8) { } else if (cep->psize == 8) { int cmd = ((int *) cep)[3]; int32_t cmd = ((int32_t *) cep)[3]; int arg = ((int *) cep)[4]; int32_t arg = ((int32_t *) cep)[4]; LOGI("Requested param: %d, %d", cmd, arg); if (cmd == EQ_PARAM_BAND_LEVEL && arg >= 0 && arg < 5) { if (cmd == EQ_PARAM_BAND_LEVEL && arg >= 0 && arg < 5) { reply2x4_1x2_t *replyData = (reply2x4_1x2_t *) pReplyData; reply2x4_1x2_t *replyData = (reply2x4_1x2_t *) pReplyData; replyData->status = 0; replyData->status = 0; Loading Loading @@ -158,9 +152,19 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD if (cmdCode == EFFECT_CMD_SET_PARAM) { if (cmdCode == EFFECT_CMD_SET_PARAM) { effect_param_t *cep = (effect_param_t *) pCmdData; effect_param_t *cep = (effect_param_t *) pCmdData; LOGI("EFFECT_CMD_SET_PARAM, %d", cep->psize); int32_t *replyData = (int32_t *) pReplyData; int32_t *replyData = (int32_t *) pReplyData; if (cep->psize == 6) { int32_t cmd = ((int32_t *) cep)[3]; if (cmd == CUSTOM_EQ_PARAM_LOUDNESS_CORRECTION) { int16_t value = ((int16_t *) cep)[8]; mLoudnessAdjustment = value / 100.0f; LOGI("Setting loudness correction reference to %f dB", mLoudnessAdjustment); *replyData = 0; return 0; } } if (cep->psize == 8) { if (cep->psize == 8) { int32_t cmd = ((int32_t *) cep)[3]; int32_t cmd = ((int32_t *) cep)[3]; int32_t arg = ((int32_t *) cep)[4]; int32_t arg = ((int32_t *) cep)[4]; Loading @@ -170,7 +174,6 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD *replyData = 0; *replyData = 0; int16_t value = ((int16_t *) cep)[10]; int16_t value = ((int16_t *) cep)[10]; mBand[arg] = value / 100.0f; mBand[arg] = value / 100.0f; refreshBands(); return 0; return 0; } } } } Loading @@ -183,12 +186,48 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD return Effect::command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); return Effect::command(cmdCode, cmdSize, pCmdData, replySize, pReplyData); } } /* Source material: ISO 226:2003 curves. * * On differencing 100 dB curves against 80 dB, 60 dB, 40 dB and 20 dB, a pattern * can be established where each loss of 20 dB of power in signal suggests gradually * decreasing ear sensitivity, until the bottom is reached at 20 dB SPL where no more * boosting is required. Measurements end at 100 dB, which is assumed to be the reference * sound pressure level. * * The boost can be calculated as linear scaling of the following adjustment: * 62.5 Hz +24 dB * 250 Hz +10 dB * 1000 Hz 0 dB * 4000 Hz -6 dB * * The boost will be applied maximally for signals of 20 dB and less, * and linearly decreased for signals 20 dB ... 100 dB, and no adjustment is * made for 100 dB or higher. User must configure a reference level that maps the * digital sound level against the audio. */ float EffectEqualizer::getAdjustedBand(int32_t band) { const float adj[5] = { 24.0, 10.0, 0.0, -6.0, 0.0 }; float loudnessLevel = mLoudness + mLoudnessAdjustment; if (loudnessLevel > 100.f) { loudnessLevel = 100.f; } if (loudnessLevel < 20.f) { loudnessLevel = 20.f; } loudnessLevel = (loudnessLevel - 20) / (100.0 - 20.0); /* Maximum loudness = no adj (reference behavior at 100 dB) */ return mBand[band] + adj[band] * (1. - loudnessLevel); } void EffectEqualizer::refreshBands() void EffectEqualizer::refreshBands() { { mGain = toFixedPoint(powf(10.0f, mBand[0] / 20.0f)); mGain = toFixedPoint(powf(10.0f, getAdjustedBand(0) / 20.0f)); for (int band = 0; band < 4; band ++) { for (int32_t band = 0; band < 4; band ++) { float centerFrequency = 62.5f * powf(4, band); float centerFrequency = 62.5f * powf(4, band); float dB = mBand[band+1] - mBand[band]; float dB = getAdjustedBand(band+1) - getAdjustedBand(band); mFilterL[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); mFilterL[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); mFilterR[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); mFilterR[band].setHighShelf(centerFrequency * 2.0f, mSamplingRate, dB, 1.0f); Loading @@ -197,10 +236,17 @@ void EffectEqualizer::refreshBands() int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out) int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out) { { refreshBands(); int64_t maximumPowerSquared = 0; for (uint32_t i = 0; i < in->frameCount; i ++) { for (uint32_t i = 0; i < in->frameCount; i ++) { int32_t tmpL = read(in, i * 2); int32_t tmpL = read(in, i * 2); int32_t tmpR = read(in, i * 2 + 1); int32_t tmpR = read(in, i * 2 + 1); /* Calculate signal loudness estimate */ int64_t weight = mWeigher.process(tmpL + tmpR); maximumPowerSquared += weight * weight; /* first "shelve" is just gain */ /* first "shelve" is just gain */ tmpL = tmpL * mGain >> 32; tmpL = tmpL * mGain >> 32; tmpR = tmpR * mGain >> 32; tmpR = tmpR * mGain >> 32; Loading @@ -214,6 +260,22 @@ int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out) write(out, i * 2, tmpL); write(out, i * 2, tmpL); write(out, i * 2 + 1, tmpR); write(out, i * 2 + 1, tmpR); } } maximumPowerSquared /= in->frameCount; float signalPowerDb = logf(maximumPowerSquared / float(int64_t(1) << 48) + 1e-10f) / logf(10.0f) * 10.0f; signalPowerDb += 96.0f; /* Limit automatic EQ to maximum of 10 dB adjustment rate per second. * a frame-to-frame adjusted should not be very large because adjustments do cause * small glitches at the output. These may be audible if single step is too large. */ float maxAdj = in->frameCount / mSamplingRate * 10.f; if (mLoudness < signalPowerDb - maxAdj) { mLoudness += maxAdj; } else if (mLoudness > signalPowerDb + maxAdj) { mLoudness -= maxAdj; } else { mLoudness = signalPowerDb; } return 0; return 0; } } Loading
media/libeffects/cyanogen-dsp/EffectEqualizer.h +11 −0 Original line number Original line Diff line number Diff line Loading @@ -5,13 +5,24 @@ #include "Biquad.h" #include "Biquad.h" #include "Effect.h" #include "Effect.h" #define CUSTOM_EQ_PARAM_LOUDNESS_CORRECTION 1000 class EffectEqualizer : public Effect { class EffectEqualizer : public Effect { private: private: /* Equalizer */ float mBand[5]; float mBand[5]; int64_t mGain; int64_t mGain; Biquad mFilterL[4], mFilterR[4]; Biquad mFilterL[4], mFilterR[4]; /* Automatic equalizer */ float mLoudnessAdjustment; Biquad mWeigher; float mLoudness; void setBand(int32_t idx, float dB); void setBand(int32_t idx, float dB); float getAdjustedBand(int32_t idx); void refreshBands(); void refreshBands(); public: public: Loading