diff mbox

[v2] pcm: softvol: add support for S24_LE

Message ID 20170913142110.31072-1-joerg.krause@embedded.rocks (mailing list archive)
State New, archived
Headers show

Commit Message

Jörg Krause Sept. 13, 2017, 2:21 p.m. UTC
Tested with the Wolfson WM8524 DAC on a i.MX6UL board and the following
ALSA configuration file using the pcm test utility from alsa-lib:

"""
$ cat /etc/asound.conf
pcm.!default {
    type plug
    slave.pcm "softvol"
}
pcm.softvol {
    type softvol
    slave {
        pcm "hw:0"
    }
    control {
        name "Master"
        card 0
    }
}
ctl.!default {
    type hw
    card 0
}
ctl.softvol {
    type hw
    card 0
}

$ pcm -D softvol -o S24_LE -c 2 -r 48000
"""

The data in the Synchronous Audio Interface (SAI) of the i.MX6UL is
aligned the following way:

"""
31 30 29 28 | 27 26 25 24 | 23 22 21 20 | .. | 3 2 1 0
## ## ## ##   ## ## ## ## [           DATA[23:0]       ]
"""

Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
---
v2:
 * add CONVERT_AREA_S24_LE algorithm instead of using the same one as S32_LE
---
 src/pcm/pcm_softvol.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 53 insertions(+), 3 deletions(-)

Comments

Takashi Iwai Sept. 18, 2017, 1:38 p.m. UTC | #1
On Wed, 13 Sep 2017 16:21:10 +0200,
Jörg Krause wrote:
> 
> Tested with the Wolfson WM8524 DAC on a i.MX6UL board and the following
> ALSA configuration file using the pcm test utility from alsa-lib:
> 
> """
> $ cat /etc/asound.conf
> pcm.!default {
>     type plug
>     slave.pcm "softvol"
> }
> pcm.softvol {
>     type softvol
>     slave {
>         pcm "hw:0"
>     }
>     control {
>         name "Master"
>         card 0
>     }
> }
> ctl.!default {
>     type hw
>     card 0
> }
> ctl.softvol {
>     type hw
>     card 0
> }
> 
> $ pcm -D softvol -o S24_LE -c 2 -r 48000
> """
> 
> The data in the Synchronous Audio Interface (SAI) of the i.MX6UL is
> aligned the following way:
> 
> """
> 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | .. | 3 2 1 0
> ## ## ## ##   ## ## ## ## [           DATA[23:0]       ]
> """
> 
> Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
> ---
> v2:
>  * add CONVERT_AREA_S24_LE algorithm instead of using the same one as S32_LE

Thanks, applied.

There can be more generic for S24 in general, but it's OK to take this
as the first step.


Takashi
diff mbox

Patch

diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c
index 1fe5784d..68a35b56 100644
--- a/src/pcm/pcm_softvol.c
+++ b/src/pcm/pcm_softvol.c
@@ -251,6 +251,44 @@  static inline short MULTI_DIV_short(short a, unsigned int b, int swap)
 		}							\
 	}								\
 } while (0)
+
+#define CONVERT_AREA_S24_LE() do {					\
+	unsigned int ch, fr;						\
+	int *src, *dst;							\
+	int tmp;							\
+	for (ch = 0; ch < channels; ch++) {				\
+		src_area = &src_areas[ch];				\
+		dst_area = &dst_areas[ch];				\
+		src = snd_pcm_channel_area_addr(src_area, src_offset);	\
+		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);	\
+		src_step = snd_pcm_channel_area_step(src_area)		\
+				/ sizeof(int);				\
+		dst_step = snd_pcm_channel_area_step(dst_area)		\
+				/ sizeof(int);				\
+		GET_VOL_SCALE;						\
+		fr = frames;						\
+		if (! vol_scale) {					\
+			while (fr--) {					\
+				*dst = 0;				\
+				dst += dst_step;			\
+			}						\
+		} else if (vol_scale == 0xffff) {			\
+			while (fr--) {					\
+				*dst = *src;				\
+				src += dst_step;			\
+				dst += src_step;			\
+			}						\
+		} else {						\
+			while (fr--) {					\
+				tmp = *src << 8;			\
+				tmp = (signed int) tmp >> 8;		\
+				*dst = MULTI_DIV_24(tmp, vol_scale);	\
+				src += dst_step;			\
+				dst += src_step;			\
+			}						\
+		}							\
+	}								\
+} while (0)
 		
 #define GET_VOL_SCALE \
 	switch (ch) { \
@@ -315,6 +353,10 @@  static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol,
 		CONVERT_AREA(int,
 			     !snd_pcm_format_cpu_endian(svol->sformat));
 		break;
+	case SND_PCM_FORMAT_S24_LE:
+		/* 24bit samples */
+		CONVERT_AREA_S24_LE();
+		break;
 	case SND_PCM_FORMAT_S24_3LE:
 		CONVERT_AREA_S24_3LE();
 		break;
@@ -366,6 +408,10 @@  static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol,
 		CONVERT_AREA(int,
 			     !snd_pcm_format_cpu_endian(svol->sformat));
 		break;
+	case SND_PCM_FORMAT_S24_LE:
+		/* 24bit samples */
+		CONVERT_AREA_S24_LE();
+		break;
 	case SND_PCM_FORMAT_S24_3LE:
 		CONVERT_AREA_S24_3LE();
 		break;
@@ -422,6 +468,7 @@  static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm,
 		{
 			(1ULL << SND_PCM_FORMAT_S16_LE) |
 			(1ULL << SND_PCM_FORMAT_S16_BE) |
+			(1ULL << SND_PCM_FORMAT_S24_LE) |
 			(1ULL << SND_PCM_FORMAT_S32_LE) |
  			(1ULL << SND_PCM_FORMAT_S32_BE),
 			(1ULL << (SND_PCM_FORMAT_S24_3LE - 32))
@@ -577,10 +624,11 @@  static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * param
 	if (slave->format != SND_PCM_FORMAT_S16_LE &&
 	    slave->format != SND_PCM_FORMAT_S16_BE &&
 	    slave->format != SND_PCM_FORMAT_S24_3LE && 
+	    slave->format != SND_PCM_FORMAT_S24_LE &&
 	    slave->format != SND_PCM_FORMAT_S32_LE &&
 	    slave->format != SND_PCM_FORMAT_S32_BE) {
-		SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE "
-		       " or S32_BE");
+		SNDERR("softvol supports only S16_LE, S16_BE, S24_LE, S24_3LE, "
+		       "S32_LE or S32_BE");
 		return -EINVAL;
 	}
 	svol->sformat = slave->format;
@@ -863,6 +911,7 @@  int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
 	    sformat != SND_PCM_FORMAT_S16_LE &&
 	    sformat != SND_PCM_FORMAT_S16_BE &&
 	    sformat != SND_PCM_FORMAT_S24_3LE && 
+	    sformat != SND_PCM_FORMAT_S24_LE &&
 	    sformat != SND_PCM_FORMAT_S32_LE &&
 	    sformat != SND_PCM_FORMAT_S32_BE)
 		return -EINVAL;
@@ -1082,9 +1131,10 @@  int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
 		    sformat != SND_PCM_FORMAT_S16_LE &&
 		    sformat != SND_PCM_FORMAT_S16_BE &&
 		    sformat != SND_PCM_FORMAT_S24_3LE && 
+		    sformat != SND_PCM_FORMAT_S24_LE &&
 		    sformat != SND_PCM_FORMAT_S32_LE &&
 		    sformat != SND_PCM_FORMAT_S32_BE) {
-			SNDERR("only S16_LE, S16_BE, S24_3LE, S32_LE or S32_BE format is supported");
+			SNDERR("only S16_LE, S16_BE, S24_LE, S24_3LE, S32_LE or S32_BE format is supported");
 			snd_config_delete(sconf);
 			return -EINVAL;
 		}