summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorAntti S. Lankila <alankila@ubuntu.bel.fi>2010-08-03 18:16:49 +0300
committerAntti S. Lankila <alankila@ubuntu.bel.fi>2010-08-03 18:16:49 +0300
commit37066353a830f08771919d7dc170e67c02dd2e8c (patch)
treebce119a7a142a3d342f5e5dadd66ae7550ddd639 /libs
parent3d36f9004fd59bd0d24ea5002943ea624088b328 (diff)
downloadframeworks_base-37066353a830f08771919d7dc170e67c02dd2e8c.zip
frameworks_base-37066353a830f08771919d7dc170e67c02dd2e8c.tar.gz
frameworks_base-37066353a830f08771919d7dc170e67c02dd2e8c.tar.bz2
Fix some shortcomings of the audio level estimation
Use crude approximation of the equal loudness curves (a single 2nd order bandpass at 1 kHz). Because we must be stateless, the filter is always reset first, which somewhat damages the behavior. Limit adjustment range to 30 dB to avoid problems when sound goes very quiet. Make ramp up fast and ramp down slow. This gives reasonable response to transients between periods of silence.
Diffstat (limited to 'libs')
-rw-r--r--libs/audioflinger/AudioDSP.cpp81
-rw-r--r--libs/audioflinger/AudioDSP.h7
-rw-r--r--libs/audioflinger/AudioMixer.cpp15
3 files changed, 71 insertions, 32 deletions
diff --git a/libs/audioflinger/AudioDSP.cpp b/libs/audioflinger/AudioDSP.cpp
index a0ae416..24f99fc 100644
--- a/libs/audioflinger/AudioDSP.cpp
+++ b/libs/audioflinger/AudioDSP.cpp
@@ -107,6 +107,13 @@ void Biquad::setRC(float center_frequency, float sampling_frequency)
setCoefficients(1, a1, 0, b0, 0, 0);
}
+void Biquad::reset()
+{
+ mY0 = 0;
+ state.i32.mX = 0;
+ state.i32.mY = 0;
+}
+
/*
* Peaking equalizer, low shelf and high shelf are taken from
* the good old Audio EQ Cookbook by Robert Bristow-Johnson.
@@ -159,6 +166,21 @@ void Biquad::setHighShelf(float center_frequency, float sampling_frequency, floa
setCoefficients(a0, a1, a2, b0, b1, b2);
}
+void Biquad::setBandPass(float center_frequency, float sampling_frequency, float resonance)
+{
+ float w0 = 2 * (float) M_PI * center_frequency / sampling_frequency;
+ float alpha = sinf(w0) / (2*resonance);
+
+ float b0 = sinf(w0)/2;
+ float b1 = 0;
+ float b2 = -sinf(w0)/2;
+ float a0 = 1 + alpha;
+ float a1 = -2*cosf(w0);
+ float a2 = 1 - alpha;
+
+ setCoefficients(a0, a1, a2, b0, b1, b2);
+}
+
/* returns output scaled by fixedPoint factor */
inline int32_t Biquad::process(int16_t x0)
{
@@ -228,6 +250,7 @@ EffectCompression::~EffectCompression()
void EffectCompression::configure(const float samplingFrequency)
{
Effect::configure(samplingFrequency);
+ mWeighter.setBandPass(1000, samplingFrequency, sqrtf(2)/2);
}
void EffectCompression::setRatio(float compressionRatio)
@@ -241,34 +264,19 @@ void EffectCompression::process(int32_t *inout, int32_t frames)
int32_t EffectCompression::estimateLevel(const int16_t *audioData, int32_t frames, int32_t samplesPerFrame)
{
- /* FIXME: find a cheap approximation of equal loudness curve and apply
- * it here. Something like replaygain's, but not so darn expensive. */
+ mWeighter.reset();
uint32_t power = 0;
- int32_t samples = frames * samplesPerFrame;
- for (int32_t i = 0; i < samples; i ++) {
- int16_t tmp = *audioData ++;
- power += tmp * tmp >> 16;
- }
-
- /* FIXME: code below should be ported to integer. */
- float signalPower = (65536.0f*power) / samples / 32768.0f / 32768.0f;
- /* -50 .. 0 dB.
- * We don't go to -100 dB because of the >> 16 losing bits above. */
- float signalPowerDb = logf(signalPower + 1e-5f) / logf(10) * 10;
- /* target 83 dB SPL */
- signalPowerDb += 96 - 83;
-
- /* now we have an estimate of the signal power in range from
- * -96 dB to 0 dB. Now we estimate what level we want. */
- float desiredLevelDb = signalPowerDb / mCompressionRatio;
+ for (int32_t i = 0; i < frames; i ++) {
+ int16_t tmp = *audioData;
+ audioData += samplesPerFrame;
- /* turn back to multiplier */
- float correctionDb = desiredLevelDb - signalPowerDb;
+ int32_t out = mWeighter.process(tmp) >> 12;
+ power += out * out >> 16;
+ }
- return int32_t(65536 * powf(10, correctionDb / 20));
+ return power;
}
-
EffectTone::EffectTone()
{
for (int32_t i = 0; i < 5; i ++) {
@@ -480,9 +488,32 @@ int32_t AudioDSP::estimateLevel(const int16_t *input, int32_t frames, int32_t sa
{
if (! mCompressionEnable) {
return 65536;
- } else {
- return mCompression.estimateLevel(input, frames, samplesPerFrame);
}
+
+ /* Analyze both channels separately, pick the maximum power measured. */
+ int maximumPower = 0;
+ for (int channel = 0; channel < samplesPerFrame; channel ++) {
+ int candidatePower = mCompression.estimateLevel(input + channel, frames, samplesPerFrame);
+ if (candidatePower > maximumPower) {
+ maximumPower = candidatePower;
+ }
+ }
+
+ /* FIXME: code below should be ported to integer. */
+ float signalPower = (65536.0f*maximumPower) / frames / 32768.0f / 32768.0f;
+ /* -30 .. 0 dB. */
+ float signalPowerDb = logf(signalPower + 1e-3f) / logf(10) * 10;
+ /* target 83 dB SPL, and the weighter function peaks at -3 dB */
+ signalPowerDb += 96 - 83 + 3;
+
+ /* now we have an estimate of the signal power in range from
+ * -96 dB to 0 dB. Now we estimate what level we want. */
+ float desiredLevelDb = signalPowerDb / mCompression.mCompressionRatio;
+
+ /* turn back to multiplier */
+ float correctionDb = desiredLevelDb - signalPowerDb;
+
+ return int32_t(65536 * powf(10, correctionDb / 20));
}
/* input is 28-bit interleaved stereo in integer format */
diff --git a/libs/audioflinger/AudioDSP.h b/libs/audioflinger/AudioDSP.h
index e89b0ea..7ac1756 100644
--- a/libs/audioflinger/AudioDSP.h
+++ b/libs/audioflinger/AudioDSP.h
@@ -53,8 +53,10 @@ class Biquad {
Biquad();
void setRC(float cf, float sf);
void setPeakingEqualizer(float cf, float sf, float gain, float bw);
+ void setBandPass(float cf, float sf, float resonance);
void setLowShelf(float cf, float sf, float gain, float slope);
void setHighShelf(float cf, float sf, float gain, float slope);
+ void reset();
int32_t process(int16_t x0);
};
@@ -70,9 +72,12 @@ class Effect {
};
class EffectCompression : public Effect {
- float mCompressionRatio;
+ private:
+ Biquad mWeighter;
public:
+ float mCompressionRatio;
+
EffectCompression();
~EffectCompression();
void configure(const float samplingFrequency);
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index a25a4c0..d53ffc0 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -249,18 +249,21 @@ void AudioMixer::track_t::adjustVolumeRamp(AudioDSP& dsp)
int32_t d = desiredVolume - prevVolume[i];
/* limit change rate to smooth the compressor. */
- int32_t volChangeLimit = prevVolume[i] >> 12;
- if (volChangeLimit == 0) {
- volChangeLimit = 1;
- }
+ int32_t volChangeLimit = (prevVolume[i] >> 11);
+ volChangeLimit += 1;
int32_t volInc = d / int32_t(frameCount);
if (volInc > volChangeLimit) {
volInc = volChangeLimit;
}
- if (volInc < -volChangeLimit) {
- volInc = -volChangeLimit;
+
+ /* Make ramps down slow, but ramps up fast. */
+ volChangeLimit >>= 3;
+ volChangeLimit -= 1;
+ if (volInc < -(volChangeLimit)) {
+ volInc = -(volChangeLimit);
}
+
volumeInc[i] = volInc;
}
}