Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5a6b38b authored by Antti S. Lankila's avatar Antti S. Lankila
Browse files

Reduce loudness compensation latency and noise

- The equalizer is now updated 100 times per second to follow the
  changes in the estimated loudness. Noise is controlled by restricting
  the adjustment to <= 0.075 dB per adjustment.

- Equalizer now has treble boost, and bass boost is slightly reduced.
parent a97d5444
Loading
Loading
Loading
Loading
+35 −29
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ static int64_t toFixedPoint(float in) {
}

EffectEqualizer::EffectEqualizer()
    : mLoudnessAdjustment(10000.f), mLoudness(50.f)
    : mLoudnessAdjustment(10000.f), mLoudness(50.f), mNextUpdate(0), mNextUpdateInterval(1000), mPowerSquared(0)
{
    for (int32_t i = 0; i < 5; i ++) {
        mBand[i] = 0;
@@ -79,9 +79,10 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD
			return 0;
		}

                /* 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.);
                /* Weigher for estimating bass compensation. */
                mWeigher.setBandPass(2200.0, mSamplingRate, 0.33);
                /* 100 updates per second. */
                mNextUpdateInterval = int32_t(mSamplingRate / 100.);

		int32_t *replyData = (int32_t *) pReplyData;
		*replyData = 0;
@@ -195,10 +196,12 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD
 * sound pressure level.
 *
 * The boost can be calculated as linear scaling of the following adjustment:
 *   62.5 Hz +24 dB
 *    250 Hz +10 dB
 *     20 Hz +40 dB (unmodeled)
 *   62.5 Hz +20 dB
 *    250 Hz  +8 dB
 *   1000 Hz   0 dB
 *   4000 Hz -6 dB
 *   4000 Hz  -3 dB
 *  16000 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
@@ -206,7 +209,7 @@ int32_t EffectEqualizer::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdD
 * 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 };
    const float adj[5] = { 20.0, 8.0, 0.0, -3.0, 6.0 };

    float loudnessLevel = mLoudness + mLoudnessAdjustment;
    if (loudnessLevel > 100.f) {
@@ -236,16 +239,35 @@ void EffectEqualizer::refreshBands()

int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out)
{
    for (uint32_t i = 0; i < in->frameCount; i ++) {
        if (mNextUpdate == 0) {
            float signalPowerDb = logf(mPowerSquared / mNextUpdateInterval / float(int64_t(1) << 48) + 1e-10f) / logf(10.0f) * 10.0f;
            signalPowerDb += 96.0f + 10.0f;

            /* Limit automatic EQ to sub-dB adjustments to limit the noise
             * introduced by updates. */
            if (mLoudness < signalPowerDb - .5) {
                mLoudness += .5;
            } else if (mLoudness > signalPowerDb + .5) {
                mLoudness -= .5;
            } else {
                mLoudness = signalPowerDb;
            }

            /* Update EQ. */
            refreshBands();

    int64_t maximumPowerSquared = 0;
    for (uint32_t i = 0; i < in->frameCount; i ++) {
            mNextUpdate = mNextUpdateInterval;
            mPowerSquared = 0;
        }
        mNextUpdate --;

        int32_t tmpL = read(in, i * 2);
        int32_t tmpR = read(in, i * 2 + 1);

        /* Calculate signal loudness estimate */
        int64_t weight = mWeigher.process(tmpL + tmpR);
        maximumPowerSquared += weight * weight;
        mPowerSquared += weight * weight;
     
        /* first "shelve" is just gain */ 
        tmpL = tmpL * mGain >> 32;
@@ -260,22 +282,6 @@ int32_t EffectEqualizer::process_effect(audio_buffer_t *in, audio_buffer_t *out)
        write(out, i * 2, tmpL);
        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;
}
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ class EffectEqualizer : public Effect {

    Biquad mWeigher;
    float mLoudness;
    int32_t mNextUpdate;
    int32_t mNextUpdateInterval;
    int64_t mPowerSquared;

    void setBand(int32_t idx, float dB);   
    float getAdjustedBand(int32_t idx);