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

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

Various DSP enhancements

- Update headset to a 2nd order shelf filter, drop allpass delays

  A single shelf filter can give a time delay for low frequencies
  and attenuation for high frequencies yielding a headphone virtualization
  directly.

- Make equalizer out of high shelves.

  Cascading 4 high shelves and one global gain gives me 5 controllable bands
  with passthrough characteristics when not used.

- Set loudness target to 93 %

Also correcting a volume-ramping bug which sometimes caused a slow
adjustment to desired volume because of integer truncation and invalid
round down/up algorithm. This should eliminate cases where song starts
super loud.
parent 2246292e
Loading
Loading
Loading
Loading
+21 −33
Original line number Diff line number Diff line
@@ -328,9 +328,6 @@ float EffectCompression::estimateLevel(const int16_t* audioData, int32_t frames,

EffectTone::EffectTone()
{
    for (int32_t i = 0; i < 5; i ++) {
        mBand[i] = 0;
    }
    for (int32_t i = 0; i < 5; i ++) {
        setBand(i, 0);
    }
@@ -345,6 +342,9 @@ EffectTone::~EffectTone() {

void EffectTone::configure(const float samplingFrequency) {
    Effect::configure(samplingFrequency);
    for (int i = 0; i < 5; i ++) {
        mBand[i] = 0;
    }
    refreshBands();
}
 
@@ -354,39 +354,28 @@ void EffectTone::setBand(int32_t band, float dB)
    refreshBands();
}

void EffectTone::refreshBands() {
    mGain = toFixedPoint(powf(10, mBand[0] / 20));

    for (int32_t band = 0; band < 3; band ++) {
        float dB = mBand[band + 1] - mBand[0];
        float centerFrequency = 250.0f * powf(4, band);

        mFilterL[band].setPeakingEqualizer(centerFrequency, mSamplingFrequency, dB, 3.0f);
        mFilterR[band].setPeakingEqualizer(centerFrequency, mSamplingFrequency, dB, 3.0f);
    }

void EffectTone::refreshBands()
{
        int32_t band = 3;

        float dB = mBand[band + 1] - mBand[0];
        float centerFrequency = 250.0f * powf(4, band);
    mGain = toFixedPoint(powf(10, mBand[0] / 20));
    for (int band = 0; band < 4; band ++) {
        float centerFrequency = 62.5f * powf(4, band);
        float dB = mBand[band+1] - mBand[band];

        mFilterL[band].setHighShelf(centerFrequency * 0.5f, mSamplingFrequency, dB, 1.0f);
        mFilterR[band].setHighShelf(centerFrequency * 0.5f, mSamplingFrequency, dB, 1.0f);
        mFilterL[band].setHighShelf(centerFrequency * 2.0f, mSamplingFrequency, dB, 1.0f);
        mFilterR[band].setHighShelf(centerFrequency * 2.0f, mSamplingFrequency, dB, 1.0f);
    }
}

void EffectTone::process(int32_t* inout, int32_t frames)
{
    for (int32_t i = 0; i < frames; i ++) {
        int32_t tmpL = inout[0] >> fixedPointDecimals;
        int32_t tmpR = inout[1] >> fixedPointDecimals;
        /* 16 bits */
       
        /* bass control is really a global gain compensated by other
         * controls */
        tmpL = tmpL * mGain;
        tmpR = tmpR * mGain;
        int32_t tmpL = inout[0];
        int32_t tmpR = inout[1];
        /* 28 bits */
     
        /* first "shelve" is just gain */ 
        tmpL = (tmpL >> fixedPointDecimals) * mGain;
        tmpR = (tmpR >> fixedPointDecimals) * mGain;
        /* 28 bits */
 
        /* evaluate the other filters.
@@ -424,10 +413,9 @@ void EffectHeadphone::configure(const float samplingFrequency) {

    mReverbDelayL.setParameters(mSamplingFrequency, 0.030f);
    mReverbDelayR.setParameters(mSamplingFrequency, 0.030f);
    /* the -3 dB point is around 700 Hz, similar to the classic design
     * in bs2b. */
    mLowpassL.setHighShelf1(1500.0f, mSamplingFrequency, -16.0f);
    mLowpassR.setHighShelf1(1500.0f, mSamplingFrequency, -16.0f);
    /* the -3 dB point is around 650 Hz, giving about 300 us to work with */
    mLowpassL.setHighShelf(800.0f, mSamplingFrequency, -12.0f, 0.72f);
    mLowpassR.setHighShelf(800.0f, mSamplingFrequency, -12.0f, 0.72f);
    /* Rockbox has a 0.3 ms delay line (13 samples at 44100 Hz), but
     * I think it makes the whole effect sound pretty bad so I skipped it! */
}
+1 −1
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ class EffectCompression : public Effect {

class EffectTone : public Effect {
    float mBand[5];
    int32_t mGain;
    int mGain;
    Biquad mFilterL[4], mFilterR[4];

    void refreshBands();
+7 −5
Original line number Diff line number Diff line
@@ -38,8 +38,8 @@ static inline int16_t clamp16(int32_t sample)
    return sample;
}

static int32_t seed = 1;
inline static int32_t prng() {
    static int32_t seed = 1;
    seed = (seed * 12345) + 1103515245;
    return int32_t(seed & 0xfff);
}
@@ -59,6 +59,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, AudioDSP& dsp)
    track_t* t = mState.tracks;
    for (int i=0 ; i<32 ; i++) {
        t->needs = 0;
        t->prevVolume[0] = UNITY_GAIN;
        t->prevVolume[1] = UNITY_GAIN;
        t->volume[0] = UNITY_GAIN;
        t->volume[1] = UNITY_GAIN;
        t->volumeInc[0] = 0;
@@ -255,17 +257,17 @@ void AudioMixer::track_t::adjustVolumeRamp(AudioDSP& dsp, size_t frames)
        int32_t d = desiredVolume - prevVolume[i];

        /* limit change rate to smooth the compressor. */
        int32_t volChangeLimit = (prevVolume[i] >> 10);
        int32_t volChangeLimit = (prevVolume[i] >> 9);

        volChangeLimit += 1;
        volChangeLimit -= 1;
        int32_t volInc = d / int32_t(frames);
        if (volInc < -(volChangeLimit)) {
            volInc = -(volChangeLimit);
        }

        /* Make ramps up slower, but ramps down fast. */
        volChangeLimit >>= 3;
        volChangeLimit -= 1;
        volChangeLimit >>= 4;
        volChangeLimit += 1;
        if (volInc > volChangeLimit) {
            volInc = volChangeLimit;
        }