perex 96d951
From bdf80e58af79d4e989cd8d701d97f888c9e2dadc Mon Sep 17 00:00:00 2001
perex 96d951
From: Zerg Cannibal <cnb_zerg@yahoo.com>
perex 96d951
Date: Mon, 21 Dec 2009 22:19:14 +0100
perex 96d951
Subject: [PATCH] pcm: Fix the sound distortions for S24_3LE stream in pcm_softvol plugin
perex 96d951
perex 96d951
This patch fixes sound distortions in alsa-lib "softvol"
perex 96d951
for S24_3LE sound stream, when softvol slider is not at 0.0dB
perex 96d951
position.
perex 96d951
perex 96d951
Signed-off-by: CannibalZerg <cnb_zerg@yahoo.com>
perex 96d951
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
perex 96d951
---
perex 96d951
 src/pcm/pcm_softvol.c |   22 ++++++++++++++++++++--
perex 96d951
 1 files changed, 20 insertions(+), 2 deletions(-)
perex 96d951
perex 96d951
diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c
perex 96d951
index 637e5cb..2c7c006 100644
perex 96d951
--- a/src/pcm/pcm_softvol.c
perex 96d951
+++ b/src/pcm/pcm_softvol.c
perex 96d951
@@ -107,7 +107,8 @@ static inline int MULTI_DIV_32x16(int a, unsigned short b)
perex 96d951
 	v.i = a;
perex 96d951
 	y.i = 0;
perex 96d951
 #if __BYTE_ORDER == __LITTLE_ENDIAN
perex 96d951
-	x.i = (unsigned int)v.s[0] * b;
perex 96d951
+	x.i = (unsigned short)v.s[0];
perex 96d951
+	x.i *= b;
perex 96d951
 	y.s[0] = x.s[1];
perex 96d951
 	y.i += (int)v.s[1] * b;
perex 96d951
 #else
perex 96d951
@@ -135,6 +136,23 @@ static inline int MULTI_DIV_int(int a, unsigned int b, int swap)
perex 96d951
 	return swap ? (int)bswap_32(fraction) : fraction;
perex 96d951
 }
perex 96d951
 
perex 96d951
+/* always little endian */
perex 96d951
+static inline int MULTI_DIV_24(int a, unsigned int b)
perex 96d951
+{
perex 96d951
+	unsigned int gain = b >> VOL_SCALE_SHIFT;
perex 96d951
+	int fraction;
perex 96d951
+	fraction = MULTI_DIV_32x16(a, b & VOL_SCALE_MASK);
perex 96d951
+	if (gain) {
perex 96d951
+		long long amp = (long long)a * gain + fraction;
perex 96d951
+		if (amp > (int)0x7fffff)
perex 96d951
+			amp = (int)0x7fffff;
perex 96d951
+		else if (amp < (int)0x800000)
perex 96d951
+			amp = (int)0x800000;
perex 96d951
+		return (int)amp;
perex 96d951
+	}
perex 96d951
+	return fraction;
perex 96d951
+}
perex 96d951
+
perex 96d951
 static inline short MULTI_DIV_short(short a, unsigned int b, int swap)
perex 96d951
 {
perex 96d951
 	unsigned int gain = b >> VOL_SCALE_SHIFT;
perex 96d951
@@ -223,7 +241,7 @@ static inline short MULTI_DIV_short(short a, unsigned int b, int swap)
perex 96d951
 				tmp = src[0] |				\
perex 96d951
 				      (src[1] << 8) |			\
perex 96d951
 				      (((signed char *) src)[2] << 16);	\
perex 96d951
-				tmp = MULTI_DIV_int(tmp, vol_scale, 0);	\
perex 96d951
+				tmp = MULTI_DIV_24(tmp, vol_scale);	\
perex 96d951
 				dst[0] = tmp;				\
perex 96d951
 				dst[1] = tmp >> 8;			\
perex 96d951
 				dst[2] = tmp >> 16;			\
perex 96d951
-- 
perex 96d951
1.5.5.1
perex 96d951