mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-10 13:30:01 -05:00
New plugin interface with readv/writev support.
Initial code.
This commit is contained in:
parent
e7d099089c
commit
098b4b6a96
15 changed files with 1820 additions and 1742 deletions
|
|
@ -86,7 +86,7 @@ static void adpcm_init_state(adpcm_state_t * state_ptr)
|
|||
state_ptr->io_shift = 4;
|
||||
}
|
||||
|
||||
static inline char adpcm_encoder(int sl, adpcm_state_t * state)
|
||||
static char adpcm_encoder(int sl, adpcm_state_t * state)
|
||||
{
|
||||
short diff; /* Difference between sl and predicted sample */
|
||||
short pred_diff; /* Predicted difference to next sample */
|
||||
|
|
@ -147,7 +147,7 @@ static inline char adpcm_encoder(int sl, adpcm_state_t * state)
|
|||
}
|
||||
|
||||
|
||||
static inline int adpcm_decoder(unsigned char code, adpcm_state_t * state)
|
||||
static int adpcm_decoder(unsigned char code, adpcm_state_t * state)
|
||||
{
|
||||
short pred_diff; /* Predicted difference to next sample */
|
||||
short step; /* holds previous StepSize value */
|
||||
|
|
@ -197,397 +197,174 @@ static inline int adpcm_decoder(unsigned char code, adpcm_state_t * state)
|
|||
* Basic Ima-ADPCM plugin
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
_S8_ADPCM,
|
||||
_U8_ADPCM,
|
||||
_S16LE_ADPCM,
|
||||
_U16LE_ADPCM,
|
||||
_S16BE_ADPCM,
|
||||
_U16BE_ADPCM,
|
||||
_ADPCM_S8,
|
||||
_ADPCM_U8,
|
||||
_ADPCM_S16LE,
|
||||
_ADPCM_U16LE,
|
||||
_ADPCM_S16BE,
|
||||
_ADPCM_U16BE
|
||||
} combination_t;
|
||||
typedef void (*adpcm_f)(adpcm_state_t *state, void *src_ptr, void *dst_ptr, int samples);
|
||||
|
||||
struct adpcm_private_data {
|
||||
combination_t cmd;
|
||||
typedef struct adpcm_private_data {
|
||||
adpcm_f func;
|
||||
adpcm_state_t state;
|
||||
} adpcm_t;
|
||||
|
||||
#define ADPCM_FUNC_DECODE(name, dsttype, val) \
|
||||
static void adpcm_decode_##name(adpcm_state_t *state, \
|
||||
void *src_ptr, void *dst_ptr, int samples) \
|
||||
{ \
|
||||
unsigned char *src = src_ptr; \
|
||||
dsttype *dst = dst_ptr; \
|
||||
unsigned int s; \
|
||||
samples <<= 1; \
|
||||
while (samples--) { \
|
||||
if (state->io_shift) \
|
||||
state->io_buffer = *src++; \
|
||||
s = adpcm_decoder((state->io_buffer >> state->io_shift) & 0x0f, state); \
|
||||
*dst++ = val; \
|
||||
state->io_shift ^= 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ADPCM_FUNC_ENCODE(name, srctype, val) \
|
||||
static void adpcm_encode_##name(adpcm_state_t *state, \
|
||||
void *src_ptr, void *dst_ptr, int samples) \
|
||||
{ \
|
||||
srctype *src = src_ptr; \
|
||||
unsigned char *dst = dst_ptr; \
|
||||
unsigned int s; \
|
||||
samples <<= 1; \
|
||||
while (samples--) { \
|
||||
s = *src++; \
|
||||
state->io_buffer |= adpcm_encoder((signed short)(val), state) << state->io_shift; \
|
||||
if (state->io_shift == 0) { \
|
||||
*dst++ = state->io_buffer & 0xff; \
|
||||
state->io_buffer = 0; \
|
||||
} \
|
||||
state->io_shift ^= 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
ADPCM_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
|
||||
ADPCM_FUNC_DECODE(s8, u_int8_t, s >> 8)
|
||||
ADPCM_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
|
||||
ADPCM_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
|
||||
ADPCM_FUNC_DECODE(s16n, u_int16_t, s)
|
||||
ADPCM_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
|
||||
ADPCM_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
|
||||
ADPCM_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
|
||||
ADPCM_FUNC_DECODE(s24n, u_int32_t, s << 8)
|
||||
ADPCM_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
|
||||
ADPCM_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
|
||||
ADPCM_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
|
||||
ADPCM_FUNC_DECODE(s32n, u_int32_t, s << 16)
|
||||
ADPCM_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
|
||||
|
||||
ADPCM_FUNC_ENCODE(u8, u_int8_t, s << 8)
|
||||
ADPCM_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
|
||||
ADPCM_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
|
||||
ADPCM_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
|
||||
ADPCM_FUNC_ENCODE(s16n, u_int16_t, s)
|
||||
ADPCM_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
|
||||
ADPCM_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
|
||||
ADPCM_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
|
||||
ADPCM_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
|
||||
ADPCM_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
|
||||
ADPCM_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
|
||||
ADPCM_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
|
||||
ADPCM_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
|
||||
ADPCM_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
|
||||
|
||||
/* wide, sign, swap endian */
|
||||
static adpcm_f adpcm_functions_decode[4 * 4 * 2 * 2] = {
|
||||
adpcm_decode_u8, /* decode:8-bit:unsigned:none */
|
||||
adpcm_decode_u8, /* decode:8-bit:unsigned:swap */
|
||||
adpcm_decode_s8, /* decode:8-bit:signed:none */
|
||||
adpcm_decode_s8, /* decode:8-bit:signed:swap */
|
||||
adpcm_decode_u16n, /* decode:16-bit:unsigned:none */
|
||||
adpcm_decode_u16s, /* decode:16-bit:unsigned:swap */
|
||||
adpcm_decode_s16n, /* decode:16-bit:signed:none */
|
||||
adpcm_decode_s16s, /* decode:16-bit:signed:swap */
|
||||
adpcm_decode_u24n, /* decode:24-bit:unsigned:none */
|
||||
adpcm_decode_u24s, /* decode:24-bit:unsigned:swap */
|
||||
adpcm_decode_s24n, /* decode:24-bit:signed:none */
|
||||
adpcm_decode_s24s, /* decode:24-bit:signed:swap */
|
||||
adpcm_decode_u32n, /* decode:32-bit:unsigned:none */
|
||||
adpcm_decode_u32s, /* decode:32-bit:unsigned:swap */
|
||||
adpcm_decode_s32n, /* decode:32-bit:signed:none */
|
||||
adpcm_decode_s32s, /* decode:32-bit:signed:swap */
|
||||
};
|
||||
|
||||
static void adpcm_conv_u8bit_adpcm(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
/* wide, sign, swap endian */
|
||||
static adpcm_f adpcm_functions_encode[4 * 2 * 2] = {
|
||||
adpcm_encode_u8, /* encode:8-bit:unsigned:none */
|
||||
adpcm_encode_u8, /* encode:8-bit:unsigned:swap */
|
||||
adpcm_encode_s8, /* encode:8-bit:signed:none */
|
||||
adpcm_encode_s8, /* encode:8-bit:signed:swap */
|
||||
adpcm_encode_u16n, /* encode:16-bit:unsigned:none */
|
||||
adpcm_encode_u16s, /* encode:16-bit:unsigned:swap */
|
||||
adpcm_encode_s16n, /* encode:16-bit:signed:none */
|
||||
adpcm_encode_s16s, /* encode:16-bit:signed:swap */
|
||||
adpcm_encode_u24n, /* encode:24-bit:unsigned:none */
|
||||
adpcm_encode_u24s, /* encode:24-bit:unsigned:swap */
|
||||
adpcm_encode_s24n, /* encode:24-bit:signed:none */
|
||||
adpcm_encode_s24s, /* encode:24-bit:signed:swap */
|
||||
adpcm_encode_u32n, /* encode:32-bit:unsigned:none */
|
||||
adpcm_encode_u32s, /* encode:32-bit:unsigned:swap */
|
||||
adpcm_encode_s32n, /* encode:32-bit:signed:none */
|
||||
adpcm_encode_s32s, /* encode:32-bit:signed:swap */
|
||||
};
|
||||
|
||||
static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
|
||||
const snd_pcm_plugin_voice_t *src_voices,
|
||||
const snd_pcm_plugin_voice_t *dst_voices,
|
||||
size_t samples)
|
||||
{
|
||||
unsigned int pcm;
|
||||
adpcm_t *data;
|
||||
int voice;
|
||||
|
||||
while (size-- > 0) {
|
||||
pcm = ((*src_ptr++) ^ 0x80) << 8;
|
||||
|
||||
state_ptr->io_buffer |= adpcm_encoder((signed short)(pcm), state_ptr) << state_ptr->io_shift;
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr++ = state_ptr->io_buffer & 0xff;
|
||||
state_ptr->io_buffer = 0;
|
||||
}
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr = state_ptr->io_buffer & 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_s8bit_adpcm(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
unsigned int pcm;
|
||||
|
||||
while (size-- > 0) {
|
||||
pcm = *src_ptr++ << 8;
|
||||
|
||||
state_ptr->io_buffer |= adpcm_encoder((signed short)(pcm), state_ptr) << state_ptr->io_shift;
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr++ = state_ptr->io_buffer & 0xff;
|
||||
state_ptr->io_buffer = 0;
|
||||
}
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr = state_ptr->io_buffer & 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_s16bit_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
state_ptr->io_buffer |= adpcm_encoder((signed short)(*src_ptr++), state_ptr) << state_ptr->io_shift;
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr++ = state_ptr->io_buffer & 0xff;
|
||||
state_ptr->io_buffer = 0;
|
||||
}
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr = state_ptr->io_buffer & 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_s16bit_swap_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
state_ptr->io_buffer |= adpcm_encoder((signed short)(bswap_16(*src_ptr++)), state_ptr) << state_ptr->io_shift;
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr++ = state_ptr->io_buffer & 0xff;
|
||||
state_ptr->io_buffer = 0;
|
||||
}
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr = state_ptr->io_buffer & 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_u16bit_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
state_ptr->io_buffer |= adpcm_encoder((signed short)((*src_ptr++) ^ 0x8000), state_ptr) << state_ptr->io_shift;
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr++ = state_ptr->io_buffer & 0xff;
|
||||
state_ptr->io_buffer = 0;
|
||||
}
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr = state_ptr->io_buffer & 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_u16bit_swap_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
state_ptr->io_buffer |= adpcm_encoder((signed short)(bswap_16(*src_ptr++) ^ 0x8000), state_ptr) << state_ptr->io_shift;
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr++ = state_ptr->io_buffer & 0xff;
|
||||
state_ptr->io_buffer = 0;
|
||||
}
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
if (!(state_ptr->io_shift)) {
|
||||
*dst_ptr = state_ptr->io_buffer & 0xf0;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_adpcm_u8bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
if (state_ptr->io_shift) {
|
||||
state_ptr->io_buffer = *src_ptr++;
|
||||
}
|
||||
*dst_ptr++ = (adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) >> 8) ^ 0x80;
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_adpcm_s8bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
if (state_ptr->io_shift) {
|
||||
state_ptr->io_buffer = *src_ptr++;
|
||||
}
|
||||
*dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) >> 8;
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_adpcm_s16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
if (state_ptr->io_shift) {
|
||||
state_ptr->io_buffer = *src_ptr++;
|
||||
}
|
||||
*dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr);
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_adpcm_swap_s16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
if (state_ptr->io_shift) {
|
||||
state_ptr->io_buffer = *src_ptr++;
|
||||
}
|
||||
*dst_ptr++ = bswap_16(adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr));
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_adpcm_u16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
if (state_ptr->io_shift) {
|
||||
state_ptr->io_buffer = *src_ptr++;
|
||||
}
|
||||
*dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) ^ 0x8000;
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm_conv_adpcm_swap_u16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
|
||||
{
|
||||
while (size-- > 0) {
|
||||
if (state_ptr->io_shift) {
|
||||
state_ptr->io_buffer = *src_ptr++;
|
||||
}
|
||||
*dst_ptr++ = bswap_16(adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) ^ 0x8000);
|
||||
state_ptr->io_shift ^= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t adpcm_transfer(snd_pcm_plugin_t * plugin,
|
||||
char *src_ptr, size_t src_size,
|
||||
char *dst_ptr, size_t dst_size)
|
||||
{
|
||||
struct adpcm_private_data *data;
|
||||
|
||||
if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
|
||||
dst_ptr == NULL || dst_size < 0)
|
||||
if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
|
||||
return -EINVAL;
|
||||
if (src_size == 0)
|
||||
if (samples == 0)
|
||||
return 0;
|
||||
data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
|
||||
if (data == NULL)
|
||||
return -EINVAL;
|
||||
switch (data->cmd) {
|
||||
case _U8_ADPCM:
|
||||
if ((dst_size << 1) < src_size)
|
||||
return -EINVAL;
|
||||
adpcm_conv_u8bit_adpcm(&data->state, src_ptr, dst_ptr, src_size);
|
||||
return src_size >> 1;
|
||||
case _S8_ADPCM:
|
||||
if ((dst_size << 1) < src_size)
|
||||
return -EINVAL;
|
||||
adpcm_conv_s8bit_adpcm(&data->state, src_ptr, dst_ptr, src_size);
|
||||
return src_size >> 1;
|
||||
case _S16LE_ADPCM:
|
||||
if ((dst_size << 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_s16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_s16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size >> 2;
|
||||
case _U16LE_ADPCM:
|
||||
if ((dst_size << 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_u16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_u16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size >> 2;
|
||||
case _S16BE_ADPCM:
|
||||
if ((dst_size << 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_s16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_s16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size >> 2;
|
||||
case _U16BE_ADPCM:
|
||||
if ((dst_size << 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_u16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_u16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size >> 2;
|
||||
case _ADPCM_U8:
|
||||
if ((dst_size >> 1) < src_size)
|
||||
return -EINVAL;
|
||||
adpcm_conv_adpcm_u8bit(&data->state, src_ptr, dst_ptr, src_size << 1);
|
||||
return src_size << 1;
|
||||
case _ADPCM_S8:
|
||||
if ((dst_size >> 1) < src_size)
|
||||
return -EINVAL;
|
||||
adpcm_conv_adpcm_s8bit(&data->state, src_ptr, dst_ptr, src_size << 1);
|
||||
return src_size << 1;
|
||||
case _ADPCM_S16LE:
|
||||
if ((dst_size >> 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_adpcm_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_adpcm_swap_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size << 2;
|
||||
case _ADPCM_U16LE:
|
||||
if ((dst_size >> 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_adpcm_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_adpcm_swap_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size << 2;
|
||||
case _ADPCM_S16BE:
|
||||
if ((dst_size >> 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_adpcm_swap_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_adpcm_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size << 2;
|
||||
case _ADPCM_U16BE:
|
||||
if ((dst_size << 2) < src_size)
|
||||
return -EINVAL;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
adpcm_conv_adpcm_swap_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
adpcm_conv_adpcm_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
|
||||
#else
|
||||
#error "Have to be coded..."
|
||||
#endif
|
||||
return src_size << 2;
|
||||
default:
|
||||
return -EIO;
|
||||
data = (adpcm_t *)plugin->extra_data;
|
||||
/* FIXME */
|
||||
if (plugin->src_format.interleave) {
|
||||
data->func(&data->state,
|
||||
src_voices[0].addr,
|
||||
dst_voices[0].addr,
|
||||
samples * plugin->src_format.voices);
|
||||
} else {
|
||||
for (voice = 0; voice < plugin->src_format.voices; voice++) {
|
||||
if (src_voices[voice].addr == NULL)
|
||||
continue;
|
||||
data->func(&data->state,
|
||||
src_voices[voice].addr,
|
||||
dst_voices[voice].addr,
|
||||
samples);
|
||||
}
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
static int adpcm_action(snd_pcm_plugin_t * plugin,
|
||||
snd_pcm_plugin_action_t action,
|
||||
unsigned long udata)
|
||||
{
|
||||
struct adpcm_private_data *data;
|
||||
adpcm_t *data;
|
||||
|
||||
if (plugin == NULL)
|
||||
return -EINVAL;
|
||||
data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
|
||||
data = (adpcm_t *)plugin->extra_data;
|
||||
if (action == PREPARE)
|
||||
adpcm_init_state(&data->state);
|
||||
return 0; /* silenty ignore other actions */
|
||||
}
|
||||
|
||||
static ssize_t adpcm_src_size(snd_pcm_plugin_t * plugin, size_t size)
|
||||
{
|
||||
struct adpcm_private_data *data;
|
||||
|
||||
if (!plugin || size <= 0)
|
||||
return -EINVAL;
|
||||
data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
|
||||
switch (data->cmd) {
|
||||
case _U8_ADPCM:
|
||||
case _S8_ADPCM:
|
||||
return size * 2;
|
||||
case _ADPCM_U8:
|
||||
case _ADPCM_S8:
|
||||
return size / 2;
|
||||
case _U16LE_ADPCM:
|
||||
case _S16LE_ADPCM:
|
||||
case _U16BE_ADPCM:
|
||||
case _S16BE_ADPCM:
|
||||
return size * 4;
|
||||
case _ADPCM_U16LE:
|
||||
case _ADPCM_S16LE:
|
||||
case _ADPCM_U16BE:
|
||||
case _ADPCM_S16BE:
|
||||
return size / 4;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t adpcm_dst_size(snd_pcm_plugin_t * plugin, size_t size)
|
||||
{
|
||||
struct adpcm_private_data *data;
|
||||
|
||||
if (!plugin || size <= 0)
|
||||
return -EINVAL;
|
||||
data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
|
||||
switch (data->cmd) {
|
||||
case _U8_ADPCM:
|
||||
case _S8_ADPCM:
|
||||
return size / 2;
|
||||
case _ADPCM_U8:
|
||||
case _ADPCM_S8:
|
||||
return size * 2;
|
||||
case _U16LE_ADPCM:
|
||||
case _S16LE_ADPCM:
|
||||
case _U16BE_ADPCM:
|
||||
case _S16BE_ADPCM:
|
||||
return size / 4;
|
||||
case _ADPCM_U16LE:
|
||||
case _ADPCM_S16LE:
|
||||
case _ADPCM_U16BE:
|
||||
case _ADPCM_S16BE:
|
||||
return size * 4;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
int snd_pcm_plugin_build_adpcm(snd_pcm_format_t * src_format,
|
||||
snd_pcm_format_t * dst_format,
|
||||
snd_pcm_plugin_t ** r_plugin)
|
||||
int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
|
||||
snd_pcm_format_t *src_format,
|
||||
snd_pcm_format_t *dst_format,
|
||||
snd_pcm_plugin_t **r_plugin)
|
||||
{
|
||||
struct adpcm_private_data *data;
|
||||
snd_pcm_plugin_t *plugin;
|
||||
combination_t cmd;
|
||||
int endian, src_width, dst_width, sign;
|
||||
adpcm_f func;
|
||||
|
||||
if (!r_plugin || !src_format || !dst_format)
|
||||
return -EINVAL;
|
||||
|
|
@ -602,39 +379,49 @@ int snd_pcm_plugin_build_adpcm(snd_pcm_format_t * src_format,
|
|||
return -EINVAL;
|
||||
|
||||
if (dst_format->format == SND_PCM_SFMT_IMA_ADPCM) {
|
||||
switch (src_format->format) {
|
||||
case SND_PCM_SFMT_U8: cmd = _U8_ADPCM; break;
|
||||
case SND_PCM_SFMT_S8: cmd = _S8_ADPCM; break;
|
||||
case SND_PCM_SFMT_U16_LE: cmd = _U16LE_ADPCM; break;
|
||||
case SND_PCM_SFMT_S16_LE: cmd = _S16LE_ADPCM; break;
|
||||
case SND_PCM_SFMT_U16_BE: cmd = _U16BE_ADPCM; break;
|
||||
case SND_PCM_SFMT_S16_BE: cmd = _S16BE_ADPCM; break;
|
||||
default:
|
||||
if (!snd_pcm_format_linear(src_format->format))
|
||||
return -EINVAL;
|
||||
}
|
||||
sign = snd_pcm_format_signed(src_format->format);
|
||||
src_width = snd_pcm_format_width(src_format->format);
|
||||
if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
|
||||
return -EINVAL;
|
||||
dst_width = 8;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
endian = snd_pcm_format_big_endian(src_format->format);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
endian = snd_pcm_format_little_endian(src_format->format);
|
||||
#else
|
||||
#error "Unsupported endian..."
|
||||
#endif
|
||||
func = ((adpcm_f(*)[2][2])adpcm_functions_encode)[src_width/8][sign][endian];
|
||||
} else if (src_format->format == SND_PCM_SFMT_IMA_ADPCM) {
|
||||
switch (dst_format->format) {
|
||||
case SND_PCM_SFMT_U8: cmd = _ADPCM_U8; break;
|
||||
case SND_PCM_SFMT_S8: cmd = _ADPCM_S8; break;
|
||||
case SND_PCM_SFMT_U16_LE: cmd = _ADPCM_U16LE; break;
|
||||
case SND_PCM_SFMT_S16_LE: cmd = _ADPCM_S16LE; break;
|
||||
case SND_PCM_SFMT_U16_BE: cmd = _ADPCM_U16BE; break;
|
||||
case SND_PCM_SFMT_S16_BE: cmd = _ADPCM_S16BE; break;
|
||||
default:
|
||||
if (!snd_pcm_format_linear(dst_format->format))
|
||||
return -EINVAL;
|
||||
}
|
||||
sign = snd_pcm_format_signed(dst_format->format);
|
||||
dst_width = snd_pcm_format_width(dst_format->format);
|
||||
if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
|
||||
return -EINVAL;
|
||||
src_width = 8;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
endian = snd_pcm_format_big_endian(dst_format->format);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
endian = snd_pcm_format_little_endian(dst_format->format);
|
||||
#else
|
||||
#error "Unsupported endian..."
|
||||
#endif
|
||||
func = ((adpcm_f(*)[2][2])adpcm_functions_decode)[dst_width/8][sign][endian];
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
plugin = snd_pcm_plugin_build("Ima-ADPCM<->linear conversion",
|
||||
plugin = snd_pcm_plugin_build(handle,
|
||||
"Ima-ADPCM<->linear conversion",
|
||||
src_format,
|
||||
dst_format,
|
||||
sizeof(struct adpcm_private_data));
|
||||
if (plugin == NULL)
|
||||
return -ENOMEM;
|
||||
data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
|
||||
data->cmd = cmd;
|
||||
data = (adpcm_t *)plugin->extra_data;
|
||||
plugin->transfer = adpcm_transfer;
|
||||
plugin->src_size = adpcm_src_size;
|
||||
plugin->dst_size = adpcm_dst_size;
|
||||
plugin->action = adpcm_action;
|
||||
*r_plugin = plugin;
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue