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;
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 */
*/
#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++) { \
} \
} 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) { \
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;
}
}
}
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;
}
}
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)
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;
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)
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;
}