mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
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:
parent
91066a98b9
commit
5ba4634ab5
1 changed files with 114 additions and 25 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue