summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiarhei Siamashka <siarhei.siamashka@nokia.com>2011-03-14 15:07:38 -0300
committerLuiz Augusto von Dentz <luiz.dentz-von@nokia.com>2011-03-14 15:07:38 -0300
commit84d91fb7084118730229fb83e2fc5479bc8f35f2 (patch)
tree2835a50792ca7ec729a2bee7d32aafe4dc233609
parent4d2f0daba17617bb60e0bd40f7a0329181dc09e4 (diff)
downloadpulseaudio-panda-84d91fb7084118730229fb83e2fc5479bc8f35f2.tar.gz
pulseaudio-panda-84d91fb7084118730229fb83e2fc5479bc8f35f2.tar.bz2
pulseaudio-panda-84d91fb7084118730229fb83e2fc5479bc8f35f2.zip
sbc: added saturated clipping of decoder output to 16-bit
This prevents overflows and audible artefacts for the audio files which originally had loudness maximized. Music from audio CD disks is an example of such files, see http://en.wikipedia.org/wiki/Loudness_war
-rw-r--r--src/modules/bluetooth/sbc/sbc.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/src/modules/bluetooth/sbc/sbc.c b/src/modules/bluetooth/sbc/sbc.c
index 5c546ca8..3af0a03c 100644
--- a/src/modules/bluetooth/sbc/sbc.c
+++ b/src/modules/bluetooth/sbc/sbc.c
@@ -534,6 +534,16 @@ static void sbc_decoder_init(struct sbc_decoder_state *state,
state->offset[ch][i] = (10 * i + 10);
}
+static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s)
+{
+ if (s > 0x7FFF)
+ return 0x7FFF;
+ else if (s < -0x8000)
+ return -0x8000;
+ else
+ return s;
+}
+
static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
struct sbc_frame *frame, int ch, int blk)
{
@@ -562,7 +572,7 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
k = (i + 4) & 0xf;
/* Store in output, Q0 */
- frame->pcm_sample[ch][blk * 4 + i] = SCALE4_STAGED1(
+ frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1(
MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
@@ -572,7 +582,7 @@ static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
- MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4])))))))))));
+ MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4]))))))))))));
}
}
@@ -607,8 +617,8 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
for (idx = 0, i = 0; i < 8; i++, idx += 5) {
k = (i + 8) & 0xf;
- /* Store in output */
- frame->pcm_sample[ch][blk * 8 + i] = SCALE8_STAGED1( // Q0
+ /* Store in output, Q0 */
+ frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1(
MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
@@ -618,7 +628,7 @@ static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
- MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4])))))))))));
+ MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4]))))))))))));
}
}