Add support for S32_3LE and byte-swapped S16/S32 to softvol

Here's a patch which adds support for S24_3LE and byte-swapped S16 and
S32 to softvol.  I've tested S24_3LE and byte-swapped S16 on powerpc
with snd-usb-audio.  All other cases are untested so far.
(Config at http://blog.blackdown.de/static/alsa/USB-Audio.conf)

Signed-off-by: Juergen Kreileder <jk@blackdown.de>
This commit is contained in:
Juergen Kreileder 2006-03-21 16:55:25 +00:00 committed by Takashi Iwai
parent 91066a98b9
commit 5ba4634ab5

View file

@ -96,10 +96,10 @@ typedef union {
int i;
short s[2];
} val_t;
static inline int MULTI_DIV_int(int a, unsigned short b)
static inline int MULTI_DIV_int(int a, unsigned short b, int swap)
{
val_t v, x, y;
v.i = a;
v.i = swap ? bswap_32(a) : a;
y.i = 0;
#if __BYTE_ORDER == __LITTLE_ENDIAN
x.i = (unsigned int)v.s[0] * b;
@ -110,11 +110,14 @@ static inline int MULTI_DIV_int(int a, unsigned short b)
y.s[1] = x.s[0];
y.i += (int)v.s[0] * b;
#endif
return y.i;
return swap ? bswap_32(y.i) : y.i;
}
/* (16bit x 16bit) >> 16 */
#define MULTI_DIV_short(src,scale) (((int)(src) * (scale)) >> VOL_SCALE_SHIFT)
#define MULTI_DIV_short(src, scale, swap) \
(swap \
? bswap_16(((short) bswap_16(src) * (scale)) >> VOL_SCALE_SHIFT) \
: (((int) (src) * (scale)) >> VOL_SCALE_SHIFT))
#endif /* DOC_HIDDEN */
@ -125,7 +128,7 @@ static inline int MULTI_DIV_int(int a, unsigned short b)
*/
#ifndef DOC_HIDDEN
#define CONVERT_AREA(TYPE) do { \
#define CONVERT_AREA(TYPE, swap) do { \
unsigned int ch, fr; \
TYPE *src, *dst; \
for (ch = 0; ch < channels; ch++) { \
@ -150,15 +153,55 @@ static inline int MULTI_DIV_int(int a, unsigned short b)
} \
} else { \
while (fr--) { \
*dst = MULTI_DIV_##TYPE(*src, vol_scale);\
*dst = (TYPE) MULTI_DIV_##TYPE(*src, vol_scale, swap); \
src += src_step; \
dst += dst_step; \
} \
} \
} \
} while (0)
#define CONVERT_AREA_S24_3LE() do { \
unsigned int ch, fr; \
unsigned char *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); \
dst_step = snd_pcm_channel_area_step(dst_area); \
GET_VOL_SCALE; \
fr = frames; \
if (! vol_scale) { \
while (fr--) { \
dst[0] = dst[1] = dst[2] = 0; \
dst += dst_step; \
} \
} else if (vol_scale == 0xffff) { \
while (fr--) { \
dst[0] = src[0]; \
dst[1] = src[1]; \
dst[2] = src[2]; \
src += dst_step; \
dst += src_step; \
} \
} else { \
while (fr--) { \
tmp = src[0] | \
(src[1] << 8) | \
(((signed char *) src)[2] << 16); \
tmp = MULTI_DIV_int(tmp, vol_scale, 0); \
dst[0] = tmp; \
dst[1] = tmp >> 8; \
dst[2] = tmp >> 16; \
src += dst_step; \
dst += src_step; \
} \
} \
} \
} while (0)
#define GET_VOL_SCALE \
switch (ch) { \
@ -204,12 +247,24 @@ static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol,
vol[0] = svol->dB_value[svol->cur_vol[0]];
vol[1] = svol->dB_value[svol->cur_vol[1]];
vol_c = svol->dB_value[(svol->cur_vol[0] + svol->cur_vol[1]) / 2];
if (svol->sformat == SND_PCM_FORMAT_S16) {
switch (svol->sformat) {
case SND_PCM_FORMAT_S16_LE:
case SND_PCM_FORMAT_S16_BE:
/* 16bit samples */
CONVERT_AREA(short);
} else {
CONVERT_AREA(short,
!snd_pcm_format_cpu_endian(svol->sformat));
break;
case SND_PCM_FORMAT_S32_LE:
case SND_PCM_FORMAT_S32_BE:
/* 32bit samples */
CONVERT_AREA(int);
CONVERT_AREA(int,
!snd_pcm_format_cpu_endian(svol->sformat));
break;
case SND_PCM_FORMAT_S24_3LE:
CONVERT_AREA_S24_3LE();
break;
default:
break;
}
}
@ -240,12 +295,24 @@ static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol,
}
vol_scale = svol->dB_value[svol->cur_vol[0]];
if (svol->sformat == SND_PCM_FORMAT_S16) {
switch (svol->sformat) {
case SND_PCM_FORMAT_S16_LE:
case SND_PCM_FORMAT_S16_BE:
/* 16bit samples */
CONVERT_AREA(short);
} else {
CONVERT_AREA(short,
!snd_pcm_format_cpu_endian(svol->sformat));
break;
case SND_PCM_FORMAT_S32_LE:
case SND_PCM_FORMAT_S32_BE:
/* 32bit samples */
CONVERT_AREA(int);
CONVERT_AREA(int,
!snd_pcm_format_cpu_endian(svol->sformat));
break;
case SND_PCM_FORMAT_S24_3LE:
CONVERT_AREA_S24_3LE();
break;
default:
break;
}
}
@ -287,14 +354,25 @@ static int snd_pcm_softvol_close(snd_pcm_t *pcm)
return 0;
}
static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm,
snd_pcm_hw_params_t *params)
{
int err;
snd_pcm_softvol_t *svol = pcm->private_data;
snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
snd_pcm_format_mask_t format_mask = {
{ (1U << SND_PCM_FORMAT_S16) | (1U << SND_PCM_FORMAT_S32) }
{
(1ULL << SND_PCM_FORMAT_S16_LE) |
(1ULL << SND_PCM_FORMAT_S16_BE) |
(1ULL << SND_PCM_FORMAT_S32_LE) |
(1ULL << SND_PCM_FORMAT_S32_BE),
(1ULL << (SND_PCM_FORMAT_S24_3LE - 32))
}
};
if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) {
snd_pcm_format_mask_none(&format_mask);
snd_pcm_format_mask_set(&format_mask, svol->sformat);
}
err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
&access_mask);
if (err < 0)
@ -396,9 +474,13 @@ static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * param
snd_pcm_generic_hw_params);
if (err < 0)
return err;
if (slave->format != SND_PCM_FORMAT_S16 &&
slave->format != SND_PCM_FORMAT_S32) {
SNDERR("softvol supports only S16 or S32");
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_S32_LE &&
slave->format != SND_PCM_FORMAT_S32_BE) {
SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE "
" or S32_BE");
return -EINVAL;
}
svol->sformat = slave->format;
@ -619,8 +701,11 @@ int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
int err;
assert(pcmp && slave);
if (sformat != SND_PCM_FORMAT_UNKNOWN &&
sformat != SND_PCM_FORMAT_S16 &&
sformat != SND_PCM_FORMAT_S32)
sformat != SND_PCM_FORMAT_S16_LE &&
sformat != SND_PCM_FORMAT_S16_BE &&
sformat != SND_PCM_FORMAT_S24_3LE &&
sformat != SND_PCM_FORMAT_S32_LE &&
sformat != SND_PCM_FORMAT_S32_BE)
return -EINVAL;
svol = calloc(1, sizeof(*svol));
if (! svol)
@ -808,9 +893,13 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
if (err < 0)
return err;
if (sformat != SND_PCM_FORMAT_UNKNOWN &&
sformat != SND_PCM_FORMAT_S16 &&
sformat != SND_PCM_FORMAT_S32) {
SNDERR("only S16 or S32 format is supported");
sformat != SND_PCM_FORMAT_S16_LE &&
sformat != SND_PCM_FORMAT_S16_BE &&
sformat != SND_PCM_FORMAT_S24_3LE &&
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");
snd_config_delete(sconf);
return -EINVAL;
}