mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
Completed linear plugin
This commit is contained in:
parent
cde18e13bc
commit
8738da23d8
2 changed files with 265 additions and 306 deletions
|
|
@ -101,112 +101,96 @@ 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)
|
||||
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;
|
||||
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_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;
|
||||
}
|
||||
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 {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case SND_PCM_SFMT_A_LAW:
|
||||
case SND_PCM_SFMT_IMA_ADPCM:
|
||||
#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue