Completed linear plugin

This commit is contained in:
Abramo Bagnara 1999-12-25 15:25:46 +00:00
parent cde18e13bc
commit 8738da23d8
2 changed files with 265 additions and 306 deletions

View file

@ -101,114 +101,98 @@ ssize_t snd_pcm_plugin_hardware_size(PLUGIN_BASE *pb, int channel, size_t trf_si
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)
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 {
int format = params->format.format;
if ((snd_pcm_plugin_formats(hwinfo->formats) & (1 << format)) == 0)
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;
}
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;
big1 = !big1;
}
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;
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;
_found:
hwparams->format.format = format1;
} else {
int i;
switch (format) {
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;
#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 {
return -EINVAL;
}
break;
#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;
}
}
}
/* voices */
if (params->format.voices < hwinfo->min_voices ||

View file

@ -23,6 +23,8 @@
#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>
@ -38,101 +40,152 @@
* 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,
@ -148,51 +201,12 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
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)
if (src_size % data->src_sample_size != 0)
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:
if (dst_size < src_size*data->dst_sample_size/data->src_sample_size)
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;
}
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)
@ -202,27 +216,9 @@ 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)
@ -232,27 +228,9 @@ 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,
@ -261,8 +239,8 @@ 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;
@ -279,69 +257,66 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
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;
}
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;
}
src_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;
}
src_width = 2;
break;
default:
return -EINVAL;
}
switch (dst_width) {
case 8:
dst_width = 0;
break;
case 16:
dst_width = 1;
break;
case 32:
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;