unsigned int snd_pcm_plugin_formats(unsigned int formats)
{
+ int linfmts = (SND_PCM_FMT_U8 | SND_PCM_FMT_S8 |
+ SND_PCM_FMT_U16_LE | SND_PCM_FMT_S16_LE |
+ SND_PCM_FMT_U16_BE | SND_PCM_FMT_S16_BE |
+ SND_PCM_FMT_U24_LE | SND_PCM_FMT_S16_LE |
+ SND_PCM_FMT_U24_BE | SND_PCM_FMT_S16_BE |
+ SND_PCM_FMT_U32_LE | SND_PCM_FMT_S32_LE |
+ SND_PCM_FMT_U32_BE | SND_PCM_FMT_S32_BE);
formats |= SND_PCM_FMT_MU_LAW;
#ifndef __KERNEL__
formats |= SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM;
#endif
- if (formats & (SND_PCM_FMT_U8|SND_PCM_FMT_S8|
- SND_PCM_FMT_U16_LE|SND_PCM_FMT_S16_LE))
- formats |= SND_PCM_FMT_U8|SND_PCM_FMT_S8|
- SND_PCM_FMT_U16_LE|SND_PCM_FMT_S16_LE;
+
+ if (formats & linfmts)
+ formats |= linfmts;
return formats;
}
+static int preferred_formats[] = {
+ SND_PCM_SFMT_S16_LE,
+ SND_PCM_SFMT_S16_BE,
+ SND_PCM_SFMT_U16_LE,
+ SND_PCM_SFMT_U16_BE,
+ SND_PCM_SFMT_S24_LE,
+ SND_PCM_SFMT_S24_BE,
+ SND_PCM_SFMT_U24_LE,
+ SND_PCM_SFMT_U24_BE,
+ SND_PCM_SFMT_S32_LE,
+ SND_PCM_SFMT_S32_BE,
+ SND_PCM_SFMT_U32_LE,
+ SND_PCM_SFMT_U32_BE,
+ SND_PCM_SFMT_S8,
+ SND_PCM_SFMT_U8
+};
+
int snd_pcm_plugin_hwparams(snd_pcm_channel_params_t *params,
snd_pcm_channel_info_t *hwinfo,
snd_pcm_channel_params_t *hwparams)
{
memcpy(hwparams, params, sizeof(*hwparams));
if ((hwinfo->formats & (1 << params->format.format)) == 0) {
- if ((snd_pcm_plugin_formats(hwinfo->formats) & (1 << params->format.format)) == 0)
+ int format = params->format.format;
+ if ((snd_pcm_plugin_formats(hwinfo->formats) & (1 << format)) == 0)
return -EINVAL;
- switch (params->format.format) {
- case SND_PCM_SFMT_U8:
- if (hwinfo->formats & SND_PCM_FMT_S8) {
- hwparams->format.format = SND_PCM_SFMT_S8;
- } else if (hwinfo->formats & SND_PCM_FMT_U16_LE) {
- hwparams->format.format = SND_PCM_SFMT_U16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_S16_LE) {
- hwparams->format.format = SND_PCM_SFMT_S16_LE;
- } else {
- return -EINVAL;
- }
- break;
- case SND_PCM_SFMT_S8:
- if (hwinfo->formats & SND_PCM_FMT_U8) {
- hwparams->format.format = SND_PCM_SFMT_U8;
- } else if (hwinfo->formats & SND_PCM_FMT_S16_LE) {
- hwparams->format.format = SND_PCM_SFMT_S16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_U16_LE) {
- hwparams->format.format = SND_PCM_SFMT_U16_LE;
- } else {
- return -EINVAL;
- }
- break;
- case SND_PCM_SFMT_S16_LE:
- if (hwinfo->formats & SND_PCM_FMT_U16_LE) {
- hwparams->format.format = SND_PCM_SFMT_U16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_S8) {
- hwparams->format.format = SND_PCM_SFMT_S8;
- } else if (hwinfo->formats & SND_PCM_FMT_U8) {
- hwparams->format.format = SND_PCM_SFMT_U8;
- } else {
- return -EINVAL;
+ if (snd_pcm_format_linear(format)) {
+ int width = snd_pcm_format_width(format);
+ int unsignd = snd_pcm_format_unsigned(format);
+ int big = snd_pcm_format_big_endian(format);
+ int format1;
+ int wid, width1=width;
+ for (wid = 0; wid < 4; ++wid) {
+ int end, big1 = big;
+ for (end = 0; end < 2; ++end) {
+ int sgn, unsignd1 = unsignd;
+ for (sgn = 0; sgn < 2; ++sgn) {
+ format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
+ if (format1 >= 0 &&
+ hwinfo->formats & (1 << format1))
+ goto _found;
+ unsignd1 = !unsignd1;
+ }
+ big1 = !big1;
+ }
+ width1 += 8;
+ if (width1 > 32)
+ width = 8;
}
- break;
- case SND_PCM_SFMT_U16_LE:
- if (hwinfo->formats & SND_PCM_FMT_S16_LE) {
- hwparams->format.format = SND_PCM_SFMT_S16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_U8) {
- hwparams->format.format = SND_PCM_SFMT_U8;
- } else if (hwinfo->formats & SND_PCM_FMT_S8) {
- hwparams->format.format = SND_PCM_SFMT_S8;
- } else {
- return -EINVAL;
- }
- break;
- case SND_PCM_SFMT_MU_LAW:
- if (hwinfo->formats & SND_PCM_FMT_S16_LE) {
- hwparams->format.format = SND_PCM_SFMT_S16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_U16_LE) {
- hwparams->format.format = SND_PCM_SFMT_U16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_S8) {
- hwparams->format.format = SND_PCM_SFMT_S8;
- } else if (hwinfo->formats & SND_PCM_FMT_U8) {
- hwparams->format.format = SND_PCM_SFMT_U8;
- } else {
- return -EINVAL;
- }
- break;
+ return -EINVAL;
+ _found:
+ hwparams->format.format = format1;
+ } else {
+ int i;
+ switch (format) {
+ case SND_PCM_SFMT_MU_LAW:
#ifndef __KERNEL__
- case SND_PCM_SFMT_A_LAW:
- if (hwinfo->formats & SND_PCM_FMT_S16_LE) {
- hwparams->format.format = SND_PCM_SFMT_S16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_U16_LE) {
- hwparams->format.format = SND_PCM_SFMT_U16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_S8) {
- hwparams->format.format = SND_PCM_SFMT_S8;
- } else if (hwinfo->formats & SND_PCM_FMT_U8) {
- hwparams->format.format = SND_PCM_SFMT_U8;
- } else {
- return -EINVAL;
- }
- case SND_PCM_SFMT_IMA_ADPCM:
- if (hwinfo->formats & SND_PCM_FMT_S16_LE) {
- hwparams->format.format = SND_PCM_SFMT_S16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_U16_LE) {
- hwparams->format.format = SND_PCM_SFMT_U16_LE;
- } else if (hwinfo->formats & SND_PCM_FMT_S8) {
- hwparams->format.format = SND_PCM_SFMT_S8;
- } else if (hwinfo->formats & SND_PCM_FMT_U8) {
- hwparams->format.format = SND_PCM_SFMT_U8;
- } else {
+ case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_SFMT_IMA_ADPCM:
+#endif
+ for (i = 0; i < sizeof(preferred_formats) / sizeof(preferred_formats[0]); ++i) {
+ int format1 = preferred_formats[i];
+ if (hwinfo->formats & (1 << format1)) {
+ hwparams->format.format = format1;
+ break;
+ }
+ }
+ if (i == sizeof(preferred_formats)/sizeof(preferred_formats[0]))
+ return -EINVAL;
+ break;
+ default:
return -EINVAL;
}
- break;
-#endif
- default:
- return -EINVAL;
}
}
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
+#define bswap_16(x) __swab16((x))
+#define bswap_32(x) __swab32((x))
#else
#include <stdio.h>
#include <stdlib.h>
* Basic linear conversion plugin
*/
-typedef enum {
- _8BIT_16BIT,
- _8BIT_24BIT,
- _8BIT_32BIT,
- _16BIT_8BIT,
- _16BIT_24BIT,
- _16BIT_32BIT,
- _24BIT_8BIT,
- _24BIT_16BIT,
- _24BIT_32BIT,
- _32BIT_8BIT,
- _32BIT_16BIT,
- _32BIT_24BIT
-} combination_t;
-
-typedef enum {
- NONE = 0,
- SOURCE = 1,
- DESTINATION = 2,
- BOTH = 3,
- SIGN = 4,
- SIGN_NONE = 4,
- SIGN_SOURCE = 5,
- SIGN_DESTINATION = 6,
- SIGN_BOTH = 7,
-} endian_t;
-
+typedef void (*conv_f)(void *src, void *dst, size_t size);
+
struct linear_private_data {
- combination_t cmd;
- endian_t endian;
+ int src_sample_size, dst_sample_size;
+ conv_f func;
};
-static void linear_conv_8bit_16bit(unsigned char *src_ptr,
- unsigned short *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = ((unsigned short)*src_ptr++) << 8;
+#define CONV_FUNC(name, srctype, dsttype, val) \
+static void conv_##name(void *src_ptr, void *dst_ptr, size_t size) \
+{ \
+ unsigned srctype *srcp = src_ptr; \
+ unsigned dsttype *dstp = dst_ptr; \
+ while (size--) { \
+ unsigned srctype src = *srcp++; \
+ *dstp++ = val; \
+ } \
}
-static void linear_conv_8bit_16bit_swap(unsigned char *src_ptr,
- unsigned short *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = (unsigned short)*src_ptr++;
-}
+CONV_FUNC(8_sign, char, char, src ^ 0x80)
-static void linear_conv_sign_8bit_16bit(unsigned char *src_ptr,
- unsigned short *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = (((unsigned short)*src_ptr++) << 8) ^ 0x8000;
-}
+CONV_FUNC(8_16, char, short, (unsigned short)src << 8)
+CONV_FUNC(8_16_end, char, short, (unsigned short)src)
+CONV_FUNC(8_16_sign, char, short, (unsigned short)(src ^ 0x80) << 8)
+CONV_FUNC(8_16_sign_end, char, short, (unsigned short)src ^ 0x80)
-static void linear_conv_sign_8bit_16bit_swap(unsigned char *src_ptr,
- unsigned short *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = ((unsigned short)*src_ptr++) ^ 0x80;
-}
+CONV_FUNC(8_32, char, long, (unsigned long)src << 24)
+CONV_FUNC(8_32_end, char, long, (unsigned long)src)
+CONV_FUNC(8_32_sign, char, long, (unsigned long)(src ^ 0x80) << 24)
+CONV_FUNC(8_32_sign_end, char, long, (unsigned long)src ^ 0x80)
-static void linear_conv_16bit_8bit(unsigned short *src_ptr,
- unsigned char *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = (*src_ptr++) >> 8;
-}
+CONV_FUNC(16_8, short, char, src >> 8)
+CONV_FUNC(16_end_8, short, char, src)
+CONV_FUNC(16_8_sign, short, char, (src >> 8) ^ 0x80)
+CONV_FUNC(16_end_8_sign, short, char, src ^ 0x80;)
-static void linear_conv_16bit_8bit_swap(unsigned short *src_ptr,
- unsigned char *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = (unsigned char)*src_ptr++;
-}
+CONV_FUNC(16_sign, short, short, src ^ 0x8000)
+CONV_FUNC(16_end, short, short, bswap_16(src))
+CONV_FUNC(16_end_sign, short, short, bswap_16(src) ^ 0x8000)
+CONV_FUNC(16_sign_end, short, short, bswap_16(src ^ 0x8000))
+CONV_FUNC(16_end_sign_end, short, short, src ^ 0x80)
-static void linear_conv_sign_16bit_8bit(unsigned short *src_ptr,
- unsigned char *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = (((unsigned short)*src_ptr++) >> 8) ^ 0x80;
-}
+CONV_FUNC(16_32, short, long, (unsigned long)src << 16)
+CONV_FUNC(16_32_sign, short, long, (unsigned long)(src ^ 0x8000) << 16)
+CONV_FUNC(16_32_end, short, long, (unsigned long)bswap_16(src))
+CONV_FUNC(16_32_sign_end, short, long, (unsigned long)bswap_16(src ^ 0x8000))
+CONV_FUNC(16_end_32, short, long, (unsigned long)bswap_16(src) << 16)
+CONV_FUNC(16_end_32_sign, short, long, (unsigned long)(bswap_16(src) ^ 0x8000) << 16)
+CONV_FUNC(16_end_32_end, short, long, (unsigned long)src)
+CONV_FUNC(16_end_32_sign_end, short, long, (unsigned long)src ^ 0x80)
+
+CONV_FUNC(32_8, long, char, src >> 24)
+CONV_FUNC(32_end_8, long, char, src)
+CONV_FUNC(32_8_sign, long, char, (src >> 24) ^ 0x80)
+CONV_FUNC(32_end_8_sign, long, char, src ^ 0x80;)
+
+CONV_FUNC(32_16, long, short, src >> 16)
+CONV_FUNC(32_16_sign, long, short, (src >> 16) ^ 0x8000)
+CONV_FUNC(32_16_end, long, short, bswap_16(src >> 16))
+CONV_FUNC(32_16_sign_end, long, short, bswap_16((src >> 16) ^ 0x8000))
+CONV_FUNC(32_end_16, long, short, bswap_16(src))
+CONV_FUNC(32_end_16_sign, long, short, bswap_16(src) ^ 0x8000)
+CONV_FUNC(32_end_16_end, long, short, src)
+CONV_FUNC(32_end_16_sign_end, long, short, src ^ 0x80)
+
+CONV_FUNC(32_sign, long, long, src ^ 0x80000000)
+CONV_FUNC(32_end, long, long, bswap_32(src))
+CONV_FUNC(32_end_sign, long, long, bswap_32(src) ^ 0x80000000)
+CONV_FUNC(32_sign_end, long, long, bswap_32(src) ^ 0x80)
+CONV_FUNC(32_end_sign_end, long, long, src ^ 0x80)
+
+/* src_wid dst_wid src_endswap, dst_endswap, sign_swap */
+conv_f convert_functions[3][3][2][2][2] = {
+ NULL, /* 8->8: Nothing to do */
+ conv_8_sign, /* 8->8 sign: conv_8_sign */
+ NULL, /* 8->8 dst_end: Nothing to do */
+ conv_8_sign, /* 8->8 dst_end sign: conv_8_sign */
+ NULL, /* 8->8 src_end: Nothing to do */
+ conv_8_sign, /* 8->8 src_end sign: conv_8_sign */
+ NULL, /* 8->8 src_end dst_end: Nothing to do */
+ conv_8_sign, /* 8->8 src_end dst_end sign: conv_8_sign */
+ conv_8_16, /* 8->16: conv_8_16 */
+ conv_8_16_sign, /* 8->16 sign: conv_8_16_sign */
+ conv_8_16_end, /* 8->16 dst_end: conv_8_16_end */
+ conv_8_16_sign_end, /* 8->16 dst_end sign: conv_8_16_sign_end */
+ conv_8_16, /* 8->16 src_end: conv_8_16 */
+ conv_8_16_sign, /* 8->16 src_end sign: conv_8_16_sign */
+ conv_8_16_end, /* 8->16 src_end dst_end: conv_8_16_end */
+ conv_8_16_sign_end, /* 8->16 src_end dst_end sign: conv_8_16_sign_end */
+ conv_8_32, /* 8->32: conv_8_32 */
+ conv_8_32_sign, /* 8->32 sign: conv_8_32_sign */
+ conv_8_32_end, /* 8->32 dst_end: conv_8_32_end */
+ conv_8_32_sign_end, /* 8->32 dst_end sign: conv_8_32_sign_end */
+ conv_8_32, /* 8->32 src_end: conv_8_32 */
+ conv_8_32_sign, /* 8->32 src_end sign: conv_8_32_sign */
+ conv_8_32_end, /* 8->32 src_end dst_end: conv_8_32_end */
+ conv_8_32_sign_end, /* 8->32 src_end dst_end sign: conv_8_32_sign_end */
+ conv_16_8, /* 16->8: conv_16_8 */
+ conv_16_8_sign, /* 16->8 sign: conv_16_8_sign */
+ conv_16_8, /* 16->8 dst_end: conv_16_8 */
+ conv_16_8_sign, /* 16->8 dst_end sign: conv_16_8_sign */
+ conv_16_end_8, /* 16->8 src_end: conv_16_end_8 */
+ conv_16_end_8_sign, /* 16->8 src_end sign: conv_16_end_8_sign */
+ conv_16_end_8, /* 16->8 src_end dst_end: conv_16_end_8 */
+ conv_16_end_8_sign, /* 16->8 src_end dst_end sign: conv_16_end_8_sign */
+ NULL, /* 16->16: Nothing to do */
+ conv_16_sign, /* 16->16 sign: conv_16_sign */
+ conv_16_end, /* 16->16 dst_end: conv_16_end */
+ conv_16_sign_end, /* 16->16 dst_end sign: conv_16_sign_end */
+ conv_16_end, /* 16->16 src_end: conv_16_end */
+ conv_16_end_sign, /* 16->16 src_end sign: conv_16_end_sign */
+ NULL, /* 16->16 src_end dst_end: Nothing to do */
+ conv_16_end_sign_end, /* 16->16 src_end dst_end sign: conv_16_end_sign_end */
+ conv_16_32, /* 16->32: conv_16_32 */
+ conv_16_32_sign, /* 16->32 sign: conv_16_32_sign */
+ conv_16_32_end, /* 16->32 dst_end: conv_16_32_end */
+ conv_16_32_sign_end, /* 16->32 dst_end sign: conv_16_32_sign_end */
+ conv_16_end_32, /* 16->32 src_end: conv_16_end_32 */
+ conv_16_end_32_sign, /* 16->32 src_end sign: conv_16_end_32_sign */
+ conv_16_end_32_end, /* 16->32 src_end dst_end: conv_16_end_32_end */
+ conv_16_end_32_sign_end,/* 16->32 src_end dst_end sign: conv_16_end_32_sign_end */
+ conv_32_8, /* 32->8: conv_32_8 */
+ conv_32_8_sign, /* 32->8 sign: conv_32_8_sign */
+ conv_32_8, /* 32->8 dst_end: conv_32_8 */
+ conv_32_8_sign, /* 32->8 dst_end sign: conv_32_8_sign */
+ conv_32_end_8, /* 32->8 src_end: conv_32_end_8 */
+ conv_32_end_8_sign, /* 32->8 src_end sign: conv_32_end_8_sign */
+ conv_32_end_8, /* 32->8 src_end dst_end: conv_32_end_8 */
+ conv_32_end_8_sign, /* 32->8 src_end dst_end sign: conv_32_end_8_sign */
+ conv_32_16, /* 32->16: conv_32_16 */
+ conv_32_16_sign, /* 32->16 sign: conv_32_16_sign */
+ conv_32_16_end, /* 32->16 dst_end: conv_32_16_end */
+ conv_32_16_sign_end, /* 32->16 dst_end sign: conv_32_16_sign_end */
+ conv_32_end_16, /* 32->16 src_end: conv_32_end_16 */
+ conv_32_end_16_sign, /* 32->16 src_end sign: conv_32_end_16_sign */
+ conv_32_end_16_end, /* 32->16 src_end dst_end: conv_32_end_16_end */
+ conv_32_end_16_sign_end,/* 32->16 src_end dst_end sign: conv_32_end_16_sign_end */
+ NULL, /* 32->32: Nothing to do */
+ conv_32_sign, /* 32->32 sign: conv_32_sign */
+ conv_32_end, /* 32->32 dst_end: conv_32_end */
+ conv_32_sign_end, /* 32->32 dst_end sign: conv_32_sign_end */
+ conv_32_end, /* 32->32 src_end: conv_32_end */
+ conv_32_end_sign, /* 32->32 src_end sign: conv_32_end_sign */
+ NULL, /* 32->32 src_end dst_end: Nothing to do */
+ conv_32_end_sign_end /* 32->32 src_end dst_end sign: conv_32_end_sign_end */
+};
-static void linear_conv_sign_16bit_8bit_swap(unsigned short *src_ptr,
- unsigned char *dst_ptr,
- size_t size)
-{
- while (size--)
- *dst_ptr++ = ((unsigned char)*src_ptr++) ^ 0x80;
-}
static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
char *src_ptr, size_t src_size,
data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
if (data == NULL)
return -EINVAL;
- switch (data->cmd) {
- case _8BIT_16BIT:
- if ((dst_size >> 1) < src_size)
- return -EINVAL;
- switch (data->endian) {
- case NONE:
- linear_conv_8bit_16bit(src_ptr, (short *)dst_ptr, src_size);
- break;
- case DESTINATION:
- linear_conv_8bit_16bit_swap(src_ptr, (short *)dst_ptr, src_size);
- break;
- case SIGN_NONE:
- linear_conv_sign_8bit_16bit(src_ptr, (short *)dst_ptr, src_size);
- break;
- case SIGN_DESTINATION:
- linear_conv_sign_8bit_16bit_swap(src_ptr, (short *)dst_ptr, src_size);
- break;
- default:
- return -EINVAL;
- }
- return src_size << 1;
- case _16BIT_8BIT:
- if (dst_size < (src_size >> 1))
- return -EINVAL;
- src_size >>= 1;
- switch (data->endian) {
- case NONE:
- linear_conv_16bit_8bit((short *)src_ptr, dst_ptr, src_size);
- break;
- case SOURCE:
- linear_conv_16bit_8bit_swap((short *)src_ptr, dst_ptr, src_size);
- break;
- case SIGN_NONE:
- linear_conv_sign_16bit_8bit((short *)src_ptr, dst_ptr, src_size);
- break;
- case SIGN_SOURCE:
- linear_conv_sign_16bit_8bit_swap((short *)src_ptr, dst_ptr, src_size);
- break;
- default:
- return -EINVAL;
- }
- return src_size;
- default:
- return -EIO;
- }
+ if (src_size % data->src_sample_size != 0)
+ return -EINVAL;
+ if (dst_size < src_size*data->dst_sample_size/data->src_sample_size)
+ return -EINVAL;
+ data->func(src_ptr, dst_ptr, src_size / data->src_sample_size);
+ return src_size*data->dst_sample_size/data->src_sample_size;
}
static ssize_t linear_src_size(snd_pcm_plugin_t *plugin, size_t size)
if (!plugin || size <= 0)
return -EINVAL;
data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _8BIT_16BIT:
- case _16BIT_24BIT:
- case _16BIT_32BIT:
- return size / 2;
- case _8BIT_24BIT:
- case _8BIT_32BIT:
- return size / 4;
- case _16BIT_8BIT:
- case _24BIT_16BIT:
- case _32BIT_16BIT:
- return size * 2;
- case _24BIT_8BIT:
- case _32BIT_8BIT:
- return size * 4;
- case _24BIT_32BIT:
- case _32BIT_24BIT:
- return size;
- default:
- return -EIO;
- }
+ if (data == NULL)
+ return -EINVAL;
+ return size*data->src_sample_size/data->dst_sample_size;
}
static ssize_t linear_dst_size(snd_pcm_plugin_t *plugin, size_t size)
if (!plugin || size <= 0)
return -EINVAL;
data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
- switch (data->cmd) {
- case _8BIT_16BIT:
- case _16BIT_24BIT:
- case _16BIT_32BIT:
- return size * 2;
- case _8BIT_24BIT:
- case _8BIT_32BIT:
- return size * 4;
- case _16BIT_8BIT:
- case _24BIT_16BIT:
- case _32BIT_16BIT:
- return size / 2;
- case _24BIT_8BIT:
- case _32BIT_8BIT:
- return size / 4;
- case _24BIT_32BIT:
- case _32BIT_24BIT:
- return size;
- default:
- return -EIO;
- }
+ if (data == NULL)
+ return -EINVAL;
+ return size*data->dst_sample_size/data->src_sample_size;
}
int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
{
struct linear_private_data *data;
snd_pcm_plugin_t *plugin;
- combination_t cmd;
- int width1, width2, endian1, endian2, sign1, sign2;
+ conv_f func;
+ int src_endian, dst_endian, sign, src_width, dst_width;
if (!r_plugin)
return -EINVAL;
snd_pcm_format_linear(dst_format->format)))
return -EINVAL;
- width1 = snd_pcm_format_width(src_format->format);
- sign1 = snd_pcm_format_signed(src_format->format);
- width2 = snd_pcm_format_width(dst_format->format);
- sign2 = snd_pcm_format_signed(dst_format->format);
+ sign = (snd_pcm_format_signed(src_format->format) !=
+ snd_pcm_format_signed(dst_format->format));
+ src_width = snd_pcm_format_width(src_format->format);
+ dst_width = snd_pcm_format_width(dst_format->format);
#if __BYTE_ORDER == __LITTLE_ENDIAN
- endian1 = snd_pcm_format_little_endian(src_format->format);
- endian2 = snd_pcm_format_little_endian(dst_format->format);
+ src_endian = snd_pcm_format_big_endian(src_format->format);
+ dst_endian = snd_pcm_format_big_endian(dst_format->format);
#elif __BYTE_ORDER == __BIG_ENDIAN
- endian1 = snd_pcm_format_big_endian(src_format->format);
- endian2 = snd_pcm_format_big_endian(dst_format->format);
+ src_endian = snd_pcm_format_little_endian(src_format->format);
+ dst_endian = snd_pcm_format_little_endian(dst_format->format);
#else
#error "Unsupported endian..."
#endif
- cmd = _8BIT_16BIT;
- switch (width1) {
+
+ switch (src_width) {
case 8:
- switch (width2) {
- case 16: cmd = _8BIT_16BIT; break;
- case 24: cmd = _8BIT_24BIT; break;
- case 32: cmd = _8BIT_32BIT; break;
- default: return -EINVAL;
- }
+ src_width = 0;
break;
case 16:
- switch (width2) {
- case 8: cmd = _16BIT_8BIT; break;
- case 24: cmd = _16BIT_24BIT; break;
- case 32: cmd = _16BIT_32BIT; break;
- default: return -EINVAL;
- }
+ src_width = 1;
break;
- case 24:
- switch (width2) {
- case 8: cmd = _24BIT_8BIT; break;
- case 16: cmd = _24BIT_16BIT; break;
- case 32: cmd = _24BIT_32BIT; break;
- default: return -EINVAL;
- }
+ case 32:
+ src_width = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (dst_width) {
+ case 8:
+ dst_width = 0;
+ break;
+ case 16:
+ dst_width = 1;
break;
case 32:
- switch (width2) {
- case 8: cmd = _32BIT_8BIT; break;
- case 16: cmd = _32BIT_16BIT; break;
- case 24: cmd = _32BIT_24BIT; break;
- default: return -EINVAL;
- }
+ dst_width = 2;
break;
default:
return -EINVAL;
}
+
+ if (src_endian < 0)
+ src_endian = 0;
+ if (dst_endian < 0)
+ src_endian = 0;
+
+ func = convert_functions[src_width][dst_width][src_endian][dst_endian][sign];
+
+ if (func == NULL)
+ return -EINVAL;
+
plugin = snd_pcm_plugin_build("linear format conversion",
sizeof(struct linear_private_data));
if (plugin == NULL)
return -ENOMEM;
data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
- data->cmd = cmd;
- data->endian = NONE;
- if (endian1 == 0)
- data->endian |= SOURCE;
- if (endian2 == 0)
- data->endian |= DESTINATION;
- if (sign1 != sign2)
- data->endian |= SIGN;
+ data->func = func;
+ data->src_sample_size = 1 << src_width;
+ data->dst_sample_size = 1 << dst_width;
+
plugin->transfer = linear_transfer;
plugin->src_size = linear_src_size;
plugin->dst_size = linear_dst_size;