From e963b9f37181d9936b691d07753b811062cf40dc Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Wed, 12 Apr 2000 20:38:48 +0000 Subject: [PATCH] Removed obsolete interleave plugin. Rewritten and fixed other for efficiency. --- src/pcm/plugin/Makefile.am | 5 +- src/pcm/plugin/adpcm.c | 363 ++++++++-------- src/pcm/plugin/alaw.c | 268 +++++------- src/pcm/plugin/interleave.c | 181 -------- src/pcm/plugin/linear.c | 390 ++++------------- src/pcm/plugin/mmap.c | 8 +- src/pcm/plugin/mulaw.c | 267 +++++------- src/pcm/plugin/plugin_ops.h | 513 ++++++++++++++++++++++ src/pcm/plugin/rate.c | 254 +++++------ src/pcm/plugin/route.c | 829 ++++++++++++++++++++++-------------- 10 files changed, 1634 insertions(+), 1444 deletions(-) delete mode 100644 src/pcm/plugin/interleave.c create mode 100644 src/pcm/plugin/plugin_ops.h diff --git a/src/pcm/plugin/Makefile.am b/src/pcm/plugin/Makefile.am index d350e71f..0f0eb9aa 100644 --- a/src/pcm/plugin/Makefile.am +++ b/src/pcm/plugin/Makefile.am @@ -1,8 +1,7 @@ EXTRA_LTLIBRARIES = libpcmplugin.la -libpcmplugin_la_SOURCES = block.c mmap.c stream.c linear.c interleave.c \ - mulaw.c alaw.c adpcm.c rate.c -# route.c +libpcmplugin_la_SOURCES = block.c mmap.c stream.c linear.c \ + mulaw.c alaw.c adpcm.c rate.c route.c all: libpcmplugin.la diff --git a/src/pcm/plugin/adpcm.c b/src/pcm/plugin/adpcm.c index 455ff0b4..41000217 100644 --- a/src/pcm/plugin/adpcm.c +++ b/src/pcm/plugin/adpcm.c @@ -71,22 +71,35 @@ static short StepSize[89] = { 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; -typedef struct adpcm_state { +typedef struct { int pred_val; /* Calculated predicted value */ int step_idx; /* Previous StepSize lookup index */ - unsigned int io_buffer; /* input / output bit packing buffer */ - int io_shift; /* shift input / output buffer */ -} adpcm_state_t; +} adpcm_voice_t; -static void adpcm_init_state(adpcm_state_t * state_ptr) +typedef void (*adpcm_f)(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples); + +typedef struct adpcm_private_data { + adpcm_f func; + int conv; + adpcm_voice_t voices[0]; +} adpcm_t; + + +static void adpcm_init(snd_pcm_plugin_t *plugin) { - state_ptr->pred_val = 0; - state_ptr->step_idx = 0; - state_ptr->io_buffer = 0; - state_ptr->io_shift = 4; + int voice; + adpcm_t *data = (adpcm_t *)plugin->extra_data; + for (voice = 0; voice < plugin->src_format.voices; voice++) { + adpcm_voice_t *v = &data->voices[voice]; + v->pred_val = 0; + v->step_idx = 0; + } } -static char adpcm_encoder(int sl, adpcm_state_t * state) +static char adpcm_encoder(int sl, adpcm_voice_t * state) { short diff; /* Difference between sl and predicted sample */ short pred_diff; /* Predicted difference to next sample */ @@ -147,7 +160,7 @@ static char adpcm_encoder(int sl, adpcm_state_t * state) } -static int adpcm_decoder(unsigned char code, adpcm_state_t * state) +static int adpcm_decoder(unsigned char code, adpcm_voice_t * state) { short pred_diff; /* Predicted difference to next sample */ short step; /* holds previous StepSize value */ @@ -197,119 +210,122 @@ static int adpcm_decoder(unsigned char code, adpcm_state_t * state) * Basic Ima-ADPCM plugin */ -typedef void (*adpcm_f)(adpcm_state_t *state, void *src_ptr, void *dst_ptr, int samples); - -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; \ - } \ +static void adpcm_decode(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS + adpcm_t *data = (adpcm_t *)plugin->extra_data; + void *put = put16_labels[data->conv]; + int voice; + int nvoices = plugin->src_format.voices; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + int srcbit; + char *dst; + int src_step, srcbit_step, dst_step; + size_t samples1; + adpcm_voice_t *state; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + srcbit = src_voices[voice].offset % 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + src_step = src_voices[voice].next / 8; + srcbit_step = src_voices[voice].next % 8; + dst_step = dst_voices[voice].next / 8; + state = &data->voices[voice]; + samples1 = samples; + while (samples1-- > 0) { + signed short sample; + int v; + if (srcbit) + v = *src & 0x0f; + else + v = (*src >> 4) & 0x0f; + sample = adpcm_decoder(v, state); + goto *put; +#define PUT16_END after +#include "plugin_ops.h" +#undef PUT16_END + after: + src += src_step; + srcbit += srcbit_step; + if (srcbit == 8) { + src++; + srcbit = 0; + } + dst += dst_step; + } + } } -#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; \ - } \ +static void adpcm_encode(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS + adpcm_t *data = (adpcm_t *)plugin->extra_data; + void *get = get16_labels[data->conv]; + int voice; + int nvoices = plugin->src_format.voices; + signed short sample = 0; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + char *dst; + int dstbit; + int src_step, dst_step, dstbit_step; + size_t samples1; + adpcm_voice_t *state; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + dstbit = dst_voices[voice].offset % 8; + src_step = src_voices[voice].next / 8; + dst_step = dst_voices[voice].next / 8; + dstbit_step = dst_voices[voice].next % 8; + state = &data->voices[voice]; + samples1 = samples; + while (samples1-- > 0) { + int v; + goto *get; +#define GET16_END after +#include "plugin_ops.h" +#undef GET16_END + after: + v = adpcm_encoder(sample, state); + if (dstbit) + *dst = (*dst & 0xf0) | v; + else + *dst = (*dst & 0x0f) | (v << 4); + src += src_step; + dst += dst_step; + dstbit += dstbit_step; + if (dstbit == 8) { + dst++; + dstbit = 0; + } + } + } } -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 */ -}; - -/* 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, @@ -318,27 +334,32 @@ static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin, adpcm_t *data; int voice; - if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0) + if (plugin == NULL || src_voices == NULL || dst_voices == NULL) + return -EFAULT; + if (samples < 0) return -EINVAL; if (samples == 0) return 0; - 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); + for (voice = 0; voice < plugin->src_format.voices; voice++) { + if (src_voices[voice].addr != NULL && + dst_voices[voice].addr == NULL) + return -EFAULT; + if (plugin->src_format.format == SND_PCM_SFMT_IMA_ADPCM) { + if (src_voices[voice].offset % 4 != 0 || + src_voices[voice].next % 4 != 0 || + dst_voices[voice].offset % 8 != 0 || + dst_voices[voice].next % 8 != 0) + return -EINVAL; + } else { + if (src_voices[voice].offset % 8 != 0 || + src_voices[voice].next % 8 != 0 || + dst_voices[voice].offset % 4 != 0 || + dst_voices[voice].next % 4 != 0) + return -EINVAL; } } + data = (adpcm_t *)plugin->extra_data; + data->func(plugin, src_voices, dst_voices, samples); return samples; } @@ -346,14 +367,17 @@ static int adpcm_action(snd_pcm_plugin_t * plugin, snd_pcm_plugin_action_t action, unsigned long udata) { - adpcm_t *data; - if (plugin == NULL) return -EINVAL; - data = (adpcm_t *)plugin->extra_data; - if (action == PREPARE) - adpcm_init_state(&data->state); - return 0; /* silenty ignore other actions */ + switch (action) { + case INIT: + case PREPARE: + case DRAIN: + case FLUSH: + adpcm_init(plugin); + break; + } + return 0; /* silenty ignore other actions */ } int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle, @@ -363,64 +387,41 @@ int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle, { struct adpcm_private_data *data; snd_pcm_plugin_t *plugin; - int endian, src_width, dst_width, sign; + snd_pcm_format_t *format; adpcm_f func; - if (!r_plugin || !src_format || !dst_format) + if (r_plugin == NULL) return -EINVAL; *r_plugin = NULL; - if (src_format->interleave != dst_format->interleave && - src_format->voices > 1) - return -EINVAL; if (src_format->rate != dst_format->rate) return -EINVAL; if (src_format->voices != dst_format->voices) return -EINVAL; if (dst_format->format == SND_PCM_SFMT_IMA_ADPCM) { - 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) { - 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; + format = src_format; + func = adpcm_encode; } + else if (src_format->format == SND_PCM_SFMT_IMA_ADPCM) { + format = dst_format; + func = adpcm_decode; + } + else + return -EINVAL; + if (!snd_pcm_format_linear(format->format)) + return -EINVAL; + plugin = snd_pcm_plugin_build(handle, "Ima-ADPCM<->linear conversion", src_format, dst_format, - sizeof(struct adpcm_private_data)); + sizeof(adpcm_t) + src_format->voices * sizeof(adpcm_voice_t)); if (plugin == NULL) return -ENOMEM; data = (adpcm_t *)plugin->extra_data; + data->func = func; + data->conv = getput_index(format->format); plugin->transfer = adpcm_transfer; plugin->action = adpcm_action; *r_plugin = plugin; diff --git a/src/pcm/plugin/alaw.c b/src/pcm/plugin/alaw.c index 5cfcf2c4..13421e5c 100644 --- a/src/pcm/plugin/alaw.c +++ b/src/pcm/plugin/alaw.c @@ -132,108 +132,101 @@ static int alaw2linear(unsigned char a_val) * Basic A-Law plugin */ -typedef void (*alaw_f)(void *src_ptr, void *dst_ptr, int samples); +typedef void (*alaw_f)(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples); typedef struct alaw_private_data { - int src_byte_width; - int dst_byte_width; alaw_f func; + int conv; } alaw_t; -#define ALAW_FUNC_DECODE(name, dsttype, val) \ -static void alaw_decode_##name(void *src_ptr, void *dst_ptr, int samples) \ -{ \ - unsigned char *src = src_ptr; \ - dsttype *dst = dst_ptr; \ - unsigned int s; \ - while (samples--) { \ - s = alaw2linear(*src++); \ - *dst++ = val; \ - } \ +static void alaw_decode(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS + alaw_t *data = (alaw_t *)plugin->extra_data; + void *put = put16_labels[data->conv]; + int voice; + int nvoices = plugin->src_format.voices; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + char *dst; + int src_step, dst_step; + size_t samples1; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + src_step = src_voices[voice].next / 8; + dst_step = dst_voices[voice].next / 8; + samples1 = samples; + while (samples1-- > 0) { + signed short sample = alaw2linear(*src); + goto *put; +#define PUT16_END after +#include "plugin_ops.h" +#undef PUT16_END + after: + src += src_step; + dst += dst_step; + } + } } -#define ALAW_FUNC_ENCODE(name, srctype, val) \ -static void alaw_encode_##name(void *src_ptr, void *dst_ptr, int samples) \ -{ \ - srctype *src = src_ptr; \ - unsigned char *dst = dst_ptr; \ - unsigned int s; \ - while (samples--) { \ - s = *src++; \ - *dst++ = linear2alaw(val); \ - } \ +static void alaw_encode(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS + alaw_t *data = (alaw_t *)plugin->extra_data; + void *get = get16_labels[data->conv]; + int voice; + int nvoices = plugin->src_format.voices; + signed short sample = 0; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + char *dst; + int src_step, dst_step; + size_t samples1; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + src_step = src_voices[voice].next / 8; + dst_step = dst_voices[voice].next / 8; + samples1 = samples; + while (samples1-- > 0) { + goto *get; +#define GET16_END after +#include "plugin_ops.h" +#undef GET16_END + after: + *dst = linear2alaw(sample); + src += src_step; + dst += dst_step; + } + } } -ALAW_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80) -ALAW_FUNC_DECODE(s8, u_int8_t, s >> 8) -ALAW_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000) -ALAW_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000)) -ALAW_FUNC_DECODE(s16n, u_int16_t, s) -ALAW_FUNC_DECODE(s16s, u_int16_t, bswap_16(s)) -ALAW_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000) -ALAW_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000)) -ALAW_FUNC_DECODE(s24n, u_int32_t, s << 8) -ALAW_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8)) -ALAW_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000) -ALAW_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000)) -ALAW_FUNC_DECODE(s32n, u_int32_t, s << 16) -ALAW_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16)) - -ALAW_FUNC_ENCODE(u8, u_int8_t, s << 8) -ALAW_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000) -ALAW_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000) -ALAW_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000)) -ALAW_FUNC_ENCODE(s16n, u_int16_t, s) -ALAW_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s)) -ALAW_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8) -ALAW_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8)) -ALAW_FUNC_ENCODE(s24n, u_int32_t, s >> 8) -ALAW_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8)) -ALAW_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16) -ALAW_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16)) -ALAW_FUNC_ENCODE(s32n, u_int32_t, s >> 16) -ALAW_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16)) - -/* wide, sign, swap endian */ -static alaw_f alaw_functions_decode[4 * 2 * 2] = { - alaw_decode_u8, /* decode:8-bit:unsigned:none */ - alaw_decode_u8, /* decode:8-bit:unsigned:swap */ - alaw_decode_s8, /* decode:8-bit:signed:none */ - alaw_decode_s8, /* decode:8-bit:signed:swap */ - alaw_decode_u16n, /* decode:16-bit:unsigned:none */ - alaw_decode_u16s, /* decode:16-bit:unsigned:swap */ - alaw_decode_s16n, /* decode:16-bit:signed:none */ - alaw_decode_s16s, /* decode:16-bit:signed:swap */ - alaw_decode_u24n, /* decode:24-bit:unsigned:none */ - alaw_decode_u24s, /* decode:24-bit:unsigned:swap */ - alaw_decode_s24n, /* decode:24-bit:signed:none */ - alaw_decode_s24s, /* decode:24-bit:signed:swap */ - alaw_decode_u32n, /* decode:32-bit:unsigned:none */ - alaw_decode_u32s, /* decode:32-bit:unsigned:swap */ - alaw_decode_s32n, /* decode:32-bit:signed:none */ - alaw_decode_s32s, /* decode:32-bit:signed:swap */ -}; - -/* wide, sign, swap endian */ -static alaw_f alaw_functions_encode[4 * 2 * 2] = { - alaw_encode_u8, /* encode:8-bit:unsigned:none */ - alaw_encode_u8, /* encode:8-bit:unsigned:swap */ - alaw_encode_s8, /* encode:8-bit:signed:none */ - alaw_encode_s8, /* encode:8-bit:signed:swap */ - alaw_encode_u16n, /* encode:16-bit:unsigned:none */ - alaw_encode_u16s, /* encode:16-bit:unsigned:swap */ - alaw_encode_s16n, /* encode:16-bit:signed:none */ - alaw_encode_s16s, /* encode:16-bit:signed:swap */ - alaw_encode_u24n, /* encode:24-bit:unsigned:none */ - alaw_encode_u24s, /* encode:24-bit:unsigned:swap */ - alaw_encode_s24n, /* encode:24-bit:signed:none */ - alaw_encode_s24s, /* encode:24-bit:signed:swap */ - alaw_encode_u32n, /* encode:32-bit:unsigned:none */ - alaw_encode_u32s, /* encode:32-bit:unsigned:swap */ - alaw_encode_s32n, /* encode:32-bit:signed:none */ - alaw_encode_s32s, /* encode:32-bit:signed:swap */ -}; - static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin, const snd_pcm_plugin_voice_t *src_voices, const snd_pcm_plugin_voice_t *dst_voices, @@ -242,24 +235,25 @@ static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin, alaw_t *data; int voice; - if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0) + if (plugin == NULL || src_voices == NULL || dst_voices == NULL) + return -EFAULT; + if (samples < 0) return -EINVAL; if (samples == 0) return 0; + for (voice = 0; voice < plugin->src_format.voices; voice++) { + if (src_voices[voice].addr != NULL && + dst_voices[voice].addr == NULL) + return -EFAULT; + if (src_voices[voice].offset % 8 != 0 || + src_voices[voice].next % 8 != 0) + return -EINVAL; + if (dst_voices[voice].offset % 8 != 0 || + dst_voices[voice].next % 8 != 0) + return -EINVAL; + } data = (alaw_t *)plugin->extra_data; - if (plugin->src_format.interleave) { - data->func(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(src_voices[voice].addr, - dst_voices[voice].addr, - samples); - } - } + data->func(plugin, src_voices, dst_voices, samples); return samples; } @@ -268,69 +262,43 @@ int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle, snd_pcm_format_t *dst_format, snd_pcm_plugin_t **r_plugin) { - struct alaw_private_data *data; + alaw_t *data; snd_pcm_plugin_t *plugin; - int endian, src_width, dst_width, sign; + snd_pcm_format_t *format; alaw_f func; if (r_plugin == NULL) return -EINVAL; *r_plugin = NULL; - if (src_format->interleave != dst_format->interleave && - src_format->voices > 1) - return -EINVAL; if (src_format->rate != dst_format->rate) return -EINVAL; if (src_format->voices != dst_format->voices) return -EINVAL; - if (dst_format->format == SND_PCM_SFMT_MU_LAW) { - 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 = ((alaw_f(*)[2][2])alaw_functions_encode)[(src_width/8)-1][sign][endian]; - } else if (src_format->format == SND_PCM_SFMT_MU_LAW) { - 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 = ((alaw_f(*)[2][2])alaw_functions_decode)[(dst_width/8)-1][sign][endian]; - } else { - return -EINVAL; + if (dst_format->format == SND_PCM_SFMT_A_LAW) { + format = src_format; + func = alaw_encode; + } + else if (src_format->format == SND_PCM_SFMT_A_LAW) { + format = dst_format; + func = alaw_decode; } + else + return -EINVAL; + if (!snd_pcm_format_linear(format->format)) + return -EINVAL; + plugin = snd_pcm_plugin_build(handle, "A-Law<->linear conversion", src_format, dst_format, - sizeof(struct alaw_private_data)); + sizeof(alaw_t)); if (plugin == NULL) return -ENOMEM; - data = (struct alaw_private_data *)plugin->extra_data; - data->src_byte_width = src_width / 8; - data->dst_byte_width = dst_width / 8; + data = (alaw_t*)plugin->extra_data; data->func = func; + data->conv = getput_index(format->format); plugin->transfer = alaw_transfer; *r_plugin = plugin; return 0; diff --git a/src/pcm/plugin/interleave.c b/src/pcm/plugin/interleave.c deleted file mode 100644 index d13e39cf..00000000 --- a/src/pcm/plugin/interleave.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Interleave / non-interleave conversion Plug-In - * Copyright (c) 2000 by Abramo Bagnara , - * Jaroslav Kysela - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifdef __KERNEL__ -#include "../../include/driver.h" -#include "../../include/pcm.h" -#include "../../include/pcm_plugin.h" -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include "../pcm_local.h" -#endif - -/* - * Basic interleave / non-interleave conversion plugin - */ - -typedef void (*interleave_f)(const snd_pcm_plugin_voice_t *src_voices, - const snd_pcm_plugin_voice_t *dst_voices, - int voices, size_t samples); - -typedef struct interleave_private_data { - interleave_f func; -} interleave_t; - - -#define INTERLEAVE_FUNC(name, type) \ -static void name(const snd_pcm_plugin_voice_t *src_voices, \ - const snd_pcm_plugin_voice_t *dst_voices, \ - int voices, size_t samples) \ -{ \ - type *src, *dst; \ - int voice, sample; \ - for (voice = 0; voice < voices; voice++) { \ - src = (type *)src_voices[voice].addr; \ - dst = (type *)dst_voices[voice].addr + voice; \ - for (sample = 0; sample < samples; sample++) { \ - *dst = *src++; \ - dst += voices; \ - } \ - } \ -} \ - -#define DEINTERLEAVE_FUNC(name, type) \ -static void name(const snd_pcm_plugin_voice_t *src_voices, \ - const snd_pcm_plugin_voice_t *dst_voices, \ - int voices, size_t samples) \ -{ \ - type *src, *dst; \ - int voice, sample; \ - for (voice = 0; voice < voices; voice++) { \ - src = (type *)src_voices[voice].addr + voice; \ - dst = (type *)dst_voices[voice].addr; \ - for (sample = 0; sample < samples; sample++) { \ - *dst++ = *src; \ - src += voices; \ - } \ - } \ -} - -#define FUNCS(name, type) \ -INTERLEAVE_FUNC(int_##name, type); \ -DEINTERLEAVE_FUNC(deint_##name, type); - -FUNCS(1, int8_t); -FUNCS(2, int16_t); -FUNCS(4, int32_t); -FUNCS(8, int64_t); - -static ssize_t interleave_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) -{ - interleave_t *data; - - if (plugin == NULL || src_voices == NULL || src_voices == NULL || samples < 0) - return -EINVAL; - if (samples == 0) - return 0; - data = (interleave_t *)plugin->extra_data; - if (data == NULL) - return -EINVAL; - data->func(src_voices, dst_voices, plugin->src_format.voices, samples); - return samples; -} - -int snd_pcm_plugin_build_interleave(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 interleave_private_data *data; - snd_pcm_plugin_t *plugin; - interleave_f func; - - if (r_plugin == NULL || src_format == NULL || dst_format == NULL) - return -EINVAL; - *r_plugin = NULL; - - if (src_format->interleave == dst_format->interleave) - return -EINVAL; - if (src_format->format != dst_format->format) - return -EINVAL; - if (src_format->rate != dst_format->rate) - return -EINVAL; - if (src_format->voices != dst_format->voices) - return -EINVAL; - if (!src_format->interleave) { - switch (snd_pcm_format_width(src_format->format)) { - case 8: - func = int_1; - break; - case 16: - func = int_2; - break; - case 32: - func = int_4; - break; - case 64: - func = int_8; - break; - default: - return -EINVAL; - } - } else { - switch (snd_pcm_format_width(src_format->format)) { - case 8: - func = deint_1; - break; - case 16: - func = deint_2; - break; - case 32: - func = deint_4; - break; - case 64: - func = deint_8; - break; - default: - return -EINVAL; - } - } - - plugin = snd_pcm_plugin_build(handle, - "interleave conversion", - src_format, dst_format, - sizeof(interleave_t)); - if (plugin == NULL) - return -ENOMEM; - data = (interleave_t *)plugin->extra_data; - data->func = func; - plugin->transfer = interleave_transfer; - *r_plugin = plugin; - return 0; -} diff --git a/src/pcm/plugin/linear.c b/src/pcm/plugin/linear.c index 4f190212..c99c3d98 100644 --- a/src/pcm/plugin/linear.c +++ b/src/pcm/plugin/linear.c @@ -24,8 +24,6 @@ #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 #include @@ -42,261 +40,51 @@ * Basic linear conversion plugin */ -typedef void (*linear_f)(void *src, void *dst, size_t size); - typedef struct linear_private_data { - int src_sample_size, dst_sample_size; - linear_f func; + int copy; } linear_t; -#define LIN_FUNC(name, srctype, dsttype, val) \ -static void lin_##name(void *src_ptr, void *dst_ptr, size_t size) \ -{ \ - srctype *srcp = src_ptr; \ - dsttype *dstp = dst_ptr; \ - while (size--) { \ - srctype src = *srcp++; \ - *dstp++ = val; \ - } \ +static void convert(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define COPY_LABELS +#include "plugin_ops.h" +#undef COPY_LABELS + linear_t *data = (linear_t *)plugin->extra_data; + void *copy = copy_labels[data->copy]; + int voice; + int nvoices = plugin->src_format.voices; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + char *dst; + int src_step, dst_step; + size_t samples1; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + src_step = src_voices[voice].next / 8; + dst_step = dst_voices[voice].next / 8; + samples1 = samples; + while (samples1-- > 0) { + goto *copy; +#define COPY_END after +#include "plugin_ops.h" +#undef COPY_END + after: + src += src_step; + dst += dst_step; + } + } } -LIN_FUNC(8_sign, u_int8_t, u_int8_t, src ^ 0x80) - -LIN_FUNC(8_16, u_int8_t, u_int16_t, (u_int16_t)src << 8) -LIN_FUNC(8_16_end, u_int8_t, u_int16_t, (u_int16_t)src) -LIN_FUNC(8_16_sign, u_int8_t, u_int16_t, (u_int16_t)(src ^ 0x80) << 8) -LIN_FUNC(8_16_sign_end, u_int8_t, u_int16_t, (u_int16_t)src ^ 0x80) - -LIN_FUNC(8_24, u_int8_t, u_int32_t, (u_int32_t)src << 16) -LIN_FUNC(8_24_end, u_int8_t, u_int32_t, (u_int32_t)src << 8) -LIN_FUNC(8_24_sign, u_int8_t, u_int32_t, (u_int32_t)(src ^ 0x80) << 16) -LIN_FUNC(8_24_sign_end, u_int8_t, u_int32_t, (u_int32_t)(src ^ 0x80) << 8) - -LIN_FUNC(8_32, u_int8_t, u_int32_t, (u_int32_t)src << 24) -LIN_FUNC(8_32_end, u_int8_t, u_int32_t, (u_int32_t)src) -LIN_FUNC(8_32_sign, u_int8_t, u_int32_t, (u_int32_t)(src ^ 0x80) << 24) -LIN_FUNC(8_32_sign_end, u_int8_t, u_int32_t, (u_int32_t)src ^ 0x80) - -LIN_FUNC(16_8, u_int16_t, u_int8_t, src >> 8) -LIN_FUNC(16_end_8, u_int16_t, u_int8_t, src) -LIN_FUNC(16_8_sign, u_int16_t, u_int8_t, (src >> 8) ^ 0x80) -LIN_FUNC(16_end_8_sign, u_int16_t, u_int8_t, src ^ 0x80) - -LIN_FUNC(16_sign, u_int16_t, u_int16_t, src ^ 0x8000) -LIN_FUNC(16_end, u_int16_t, u_int16_t, bswap_16(src)) -LIN_FUNC(16_end_sign, u_int16_t, u_int16_t, bswap_16(src) ^ 0x8000) -LIN_FUNC(16_sign_end, u_int16_t, u_int16_t, bswap_16(src ^ 0x8000)) -LIN_FUNC(16_end_sign_end, u_int16_t, u_int16_t, src ^ 0x80) - -LIN_FUNC(16_24, u_int16_t, u_int32_t, (u_int32_t)src << 8) -LIN_FUNC(16_24_sign, u_int16_t, u_int32_t, (u_int32_t)(src ^ 0x8000) << 8) -LIN_FUNC(16_24_end, u_int16_t, u_int32_t, (u_int32_t)bswap_16(src) << 8) -LIN_FUNC(16_24_sign_end, u_int16_t, u_int32_t, (u_int32_t)bswap_16(src ^ 0x8000) << 8) -LIN_FUNC(16_end_24, u_int16_t, u_int32_t, (u_int32_t)bswap_16(src) << 8) -LIN_FUNC(16_end_24_sign, u_int16_t, u_int32_t, (u_int32_t)(bswap_16(src) ^ 0x8000) << 8) -LIN_FUNC(16_end_24_end, u_int16_t, u_int32_t, (u_int32_t)src << 8) -LIN_FUNC(16_end_24_sign_end, u_int16_t, u_int32_t, ((u_int32_t)src ^ 0x80) << 8) - -LIN_FUNC(16_32, u_int16_t, u_int32_t, (u_int32_t)src << 16) -LIN_FUNC(16_32_sign, u_int16_t, u_int32_t, (u_int32_t)(src ^ 0x8000) << 16) -LIN_FUNC(16_32_end, u_int16_t, u_int32_t, (u_int32_t)bswap_16(src)) -LIN_FUNC(16_32_sign_end, u_int16_t, u_int32_t, (u_int32_t)bswap_16(src ^ 0x8000)) -LIN_FUNC(16_end_32, u_int16_t, u_int32_t, (u_int32_t)bswap_16(src) << 16) -LIN_FUNC(16_end_32_sign, u_int16_t, u_int32_t, (u_int32_t)(bswap_16(src) ^ 0x8000) << 16) -LIN_FUNC(16_end_32_end, u_int16_t, u_int32_t, (u_int32_t)src) -LIN_FUNC(16_end_32_sign_end, u_int16_t, u_int32_t, (u_int32_t)src ^ 0x80) - -LIN_FUNC(24_8, u_int32_t, u_int8_t, src >> 16) -LIN_FUNC(24_end_8, u_int32_t, u_int8_t, src >> 8) -LIN_FUNC(24_8_sign, u_int32_t, u_int8_t, (src >> 16) ^ 0x80) -LIN_FUNC(24_end_8_sign, u_int32_t, u_int8_t, (src >> 8) ^ 0x80) - -LIN_FUNC(24_16, u_int32_t, u_int16_t, src >> 8) -LIN_FUNC(24_16_sign, u_int32_t, u_int16_t, (src >> 8) ^ 0x8000) -LIN_FUNC(24_16_end, u_int32_t, u_int16_t, bswap_32(src >> 8)) -LIN_FUNC(24_16_sign_end, u_int32_t, u_int16_t, bswap_32((src >> 8) ^ 0x8000)) -LIN_FUNC(24_end_16, u_int32_t, u_int16_t, bswap_32(src) >> 8) -LIN_FUNC(24_end_16_sign, u_int32_t, u_int16_t, (bswap_32(src) >> 8) ^ 0x8000) -LIN_FUNC(24_end_16_end, u_int32_t, u_int16_t, src >> 8) -LIN_FUNC(24_end_16_sign_end, u_int32_t, u_int16_t, (src >> 8) ^ 0x80) - -LIN_FUNC(24_sign, u_int32_t, u_int32_t, src ^ 0x800000) -LIN_FUNC(24_end, u_int32_t, u_int32_t, bswap_32(src)) -LIN_FUNC(24_end_sign, u_int32_t, u_int32_t, bswap_32(src) ^ 0x800000) -LIN_FUNC(24_sign_end, u_int32_t, u_int32_t, bswap_32(src) ^ 0x80) -LIN_FUNC(24_end_sign_end, u_int32_t, u_int32_t, src ^ 0x80) - -LIN_FUNC(24_32, u_int32_t, u_int32_t, src << 8) -LIN_FUNC(24_32_sign, u_int32_t, u_int32_t, (src << 8) ^ 0x80000000) -LIN_FUNC(24_32_end, u_int32_t, u_int32_t, bswap_32(src << 8)) -LIN_FUNC(24_32_sign_end, u_int32_t, u_int32_t, bswap_32((src << 8) ^ 0x80000000)) -LIN_FUNC(24_end_32, u_int32_t, u_int32_t, bswap_32(src) << 8) -LIN_FUNC(24_end_32_sign, u_int32_t, u_int32_t, (bswap_32(src) << 8) ^ 0x80000000) -LIN_FUNC(24_end_32_end, u_int32_t, u_int32_t, src >> 8) -LIN_FUNC(24_end_32_sign_end, u_int32_t, u_int32_t, (src >> 8) ^ 0x80) - -LIN_FUNC(32_8, u_int32_t, u_int8_t, src >> 24) -LIN_FUNC(32_end_8, u_int32_t, u_int8_t, src) -LIN_FUNC(32_8_sign, u_int32_t, u_int8_t, (src >> 24) ^ 0x80) -LIN_FUNC(32_end_8_sign, u_int32_t, u_int8_t, src ^ 0x80) - -LIN_FUNC(32_16, u_int32_t, u_int16_t, src >> 16) -LIN_FUNC(32_16_sign, u_int32_t, u_int16_t, (src >> 16) ^ 0x8000) -LIN_FUNC(32_16_end, u_int32_t, u_int16_t, bswap_16(src >> 16)) -LIN_FUNC(32_16_sign_end, u_int32_t, u_int16_t, bswap_16((src >> 16) ^ 0x8000)) -LIN_FUNC(32_end_16, u_int32_t, u_int16_t, bswap_16(src)) -LIN_FUNC(32_end_16_sign, u_int32_t, u_int16_t, bswap_16(src) ^ 0x8000) -LIN_FUNC(32_end_16_end, u_int32_t, u_int16_t, src) -LIN_FUNC(32_end_16_sign_end, u_int32_t, u_int16_t, src ^ 0x80) - -LIN_FUNC(32_24, u_int32_t, u_int32_t, src >> 8) -LIN_FUNC(32_24_sign, u_int32_t, u_int32_t, (src >> 8) ^ 0x800000) -LIN_FUNC(32_24_end, u_int32_t, u_int32_t, bswap_32(src >> 8)) -LIN_FUNC(32_24_sign_end, u_int32_t, u_int32_t, bswap_32((src >> 8) ^ 0x800000)) -LIN_FUNC(32_end_24, u_int32_t, u_int32_t, bswap_32(src) >> 8) -LIN_FUNC(32_end_24_sign, u_int32_t, u_int32_t, (bswap_32(src) >> 8) ^ 0x800000) -LIN_FUNC(32_end_24_end, u_int32_t, u_int32_t, src << 8) -LIN_FUNC(32_end_24_sign_end, u_int32_t, u_int32_t, (src << 8) ^ 0x80) - -LIN_FUNC(32_sign, u_int32_t, u_int32_t, src ^ 0x80000000) -LIN_FUNC(32_end, u_int32_t, u_int32_t, bswap_32(src)) -LIN_FUNC(32_end_sign, u_int32_t, u_int32_t, bswap_32(src) ^ 0x80000000) -LIN_FUNC(32_sign_end, u_int32_t, u_int32_t, bswap_32(src) ^ 0x80) -LIN_FUNC(32_end_sign_end, u_int32_t, u_int32_t, src ^ 0x80) - -/* src_wid dst_wid src_endswap, dst_endswap, sign_swap */ -static linear_f linear_functions[4 * 4 * 2 * 2 * 2] = { - NULL, /* 8->8: Nothing to do */ - lin_8_sign, /* 8->8 sign: lin_8_sign */ - NULL, /* 8->8 dst_end: Nothing to do */ - lin_8_sign, /* 8->8 dst_end sign: lin_8_sign */ - NULL, /* 8->8 src_end: Nothing to do */ - lin_8_sign, /* 8->8 src_end sign: lin_8_sign */ - NULL, /* 8->8 src_end dst_end: Nothing to do */ - lin_8_sign, /* 8->8 src_end dst_end sign: lin_8_sign */ - lin_8_16, /* 8->16: lin_8_16 */ - lin_8_16_sign, /* 8->16 sign: lin_8_16_sign */ - lin_8_16_end, /* 8->16 dst_end: lin_8_16_end */ - lin_8_16_sign_end, /* 8->16 dst_end sign: lin_8_16_sign_end */ - lin_8_16, /* 8->16 src_end: lin_8_16 */ - lin_8_16_sign, /* 8->16 src_end sign: lin_8_16_sign */ - lin_8_16_end, /* 8->16 src_end dst_end: lin_8_16_end */ - lin_8_16_sign_end, /* 8->16 src_end dst_end sign: lin_8_16_sign_end */ - lin_8_24, /* 8->24: lin_8_24 */ - lin_8_24_sign, /* 8->24 sign: lin_8_24_sign */ - lin_8_24_end, /* 8->24 dst_end: lin_8_24_end */ - lin_8_24_sign_end, /* 8->24 dst_end sign: lin_8_24_sign_end */ - lin_8_24, /* 8->24 src_end: lin_8_24 */ - lin_8_24_sign, /* 8->24 src_end sign: lin_8_24_sign */ - lin_8_24_end, /* 8->24 src_end dst_end: lin_8_24_end */ - lin_8_24_sign_end, /* 8->24 src_end dst_end sign: lin_8_24_sign_end */ - lin_8_32, /* 8->32: lin_8_32 */ - lin_8_32_sign, /* 8->32 sign: lin_8_32_sign */ - lin_8_32_end, /* 8->32 dst_end: lin_8_32_end */ - lin_8_32_sign_end, /* 8->32 dst_end sign: lin_8_32_sign_end */ - lin_8_32, /* 8->32 src_end: lin_8_32 */ - lin_8_32_sign, /* 8->32 src_end sign: lin_8_32_sign */ - lin_8_32_end, /* 8->32 src_end dst_end: lin_8_32_end */ - lin_8_32_sign_end, /* 8->32 src_end dst_end sign: lin_8_32_sign_end */ - lin_16_8, /* 16->8: lin_16_8 */ - lin_16_8_sign, /* 16->8 sign: lin_16_8_sign */ - lin_16_8, /* 16->8 dst_end: lin_16_8 */ - lin_16_8_sign, /* 16->8 dst_end sign: lin_16_8_sign */ - lin_16_end_8, /* 16->8 src_end: lin_16_end_8 */ - lin_16_end_8_sign, /* 16->8 src_end sign: lin_16_end_8_sign */ - lin_16_end_8, /* 16->8 src_end dst_end: lin_16_end_8 */ - lin_16_end_8_sign, /* 16->8 src_end dst_end sign: lin_16_end_8_sign */ - NULL, /* 16->16: Nothing to do */ - lin_16_sign, /* 16->16 sign: lin_16_sign */ - lin_16_end, /* 16->16 dst_end: lin_16_end */ - lin_16_sign_end, /* 16->16 dst_end sign: lin_16_sign_end */ - lin_16_end, /* 16->16 src_end: lin_16_end */ - lin_16_end_sign, /* 16->16 src_end sign: lin_16_end_sign */ - NULL, /* 16->16 src_end dst_end: Nothing to do */ - lin_16_end_sign_end, /* 16->16 src_end dst_end sign: lin_16_end_sign_end */ - lin_16_24, /* 16->24: lin_16_24 */ - lin_16_24_sign, /* 16->24 sign: lin_16_24_sign */ - lin_16_24_end, /* 16->24 dst_end: lin_16_24_end */ - lin_16_24_sign_end, /* 16->24 dst_end sign: lin_16_24_sign_end */ - lin_16_end_24, /* 16->24 src_end: lin_16_end_24 */ - lin_16_end_24_sign, /* 16->24 src_end sign: lin_16_end_24_sign */ - lin_16_end_24_end, /* 16->24 src_end dst_end: lin_16_end_24_end */ - lin_16_end_24_sign_end,/* 16->24 src_end dst_end sign: lin_16_end_24_sign_end */ - lin_16_32, /* 16->32: lin_16_32 */ - lin_16_32_sign, /* 16->32 sign: lin_16_32_sign */ - lin_16_32_end, /* 16->32 dst_end: lin_16_32_end */ - lin_16_32_sign_end, /* 16->32 dst_end sign: lin_16_32_sign_end */ - lin_16_end_32, /* 16->32 src_end: lin_16_end_32 */ - lin_16_end_32_sign, /* 16->32 src_end sign: lin_16_end_32_sign */ - lin_16_end_32_end, /* 16->32 src_end dst_end: lin_16_end_32_end */ - lin_16_end_32_sign_end,/* 16->32 src_end dst_end sign: lin_16_end_32_sign_end */ - lin_24_8, /* 24->8: lin_24_8 */ - lin_24_8_sign, /* 24->8 sign: lin_24_8_sign */ - lin_24_8, /* 24->8 dst_end: lin_24_8 */ - lin_24_8_sign, /* 24->8 dst_end sign: lin_24_8_sign */ - lin_24_end_8, /* 24->8 src_end: lin_24_end_8 */ - lin_24_end_8_sign, /* 24->8 src_end sign: lin_24_end_8_sign */ - lin_24_end_8, /* 24->8 src_end dst_end: lin_24_end_8 */ - lin_24_end_8_sign, /* 24->8 src_end dst_end sign: lin_24_end_8_sign */ - lin_24_16, /* 24->16: lin_24_16 */ - lin_24_16_sign, /* 24->16 sign: lin_24_16_sign */ - lin_24_16_end, /* 24->16 dst_end: lin_24_16_end */ - lin_24_16_sign_end, /* 24->16 dst_end sign: lin_24_16_sign_end */ - lin_24_end_16, /* 24->16 src_end: lin_24_end_16 */ - lin_24_end_16_sign, /* 24->16 src_end sign: lin_24_end_16_sign */ - lin_24_end_16_end, /* 24->16 src_end dst_end: lin_24_end_16_end */ - lin_24_end_16_sign_end,/* 24->16 src_end dst_end sign: lin_24_end_16_sign_end */ - NULL, /* 24->24: Nothing to do */ - lin_24_sign, /* 24->24 sign: lin_24_sign */ - lin_24_end, /* 24->24 dst_end: lin_24_end */ - lin_24_sign_end, /* 24->24 dst_end sign: lin_24_sign_end */ - lin_24_end, /* 24->24 src_end: lin_24_end */ - lin_24_end_sign, /* 24->24 src_end sign: lin_24_end_sign */ - NULL, /* 24->24 src_end dst_end: Nothing to do */ - lin_24_end_sign_end, /* 24->24 src_end dst_end sign: lin_24_end_sign_end */ - lin_24_32, /* 24->32: lin_24_32 */ - lin_24_32_sign, /* 24->32 sign: lin_24_32_sign */ - lin_24_32_end, /* 24->32 dst_end: lin_24_32_end */ - lin_24_32_sign_end, /* 24->32 dst_end sign: lin_24_32_sign_end */ - lin_24_end_32, /* 24->32 src_end: lin_24_end_32 */ - lin_24_end_32_sign, /* 24->32 src_end sign: lin_24_end_32_sign */ - lin_24_end_32_end, /* 24->32 src_end dst_end: lin_24_end_32_end */ - lin_24_end_32_sign_end,/* 24->32 src_end dst_end sign: lin_24_end_32_sign_end */ - lin_32_8, /* 32->8: lin_32_8 */ - lin_32_8_sign, /* 32->8 sign: lin_32_8_sign */ - lin_32_8, /* 32->8 dst_end: lin_32_8 */ - lin_32_8_sign, /* 32->8 dst_end sign: lin_32_8_sign */ - lin_32_end_8, /* 32->8 src_end: lin_32_end_8 */ - lin_32_end_8_sign, /* 32->8 src_end sign: lin_32_end_8_sign */ - lin_32_end_8, /* 32->8 src_end dst_end: lin_32_end_8 */ - lin_32_end_8_sign, /* 32->8 src_end dst_end sign: lin_32_end_8_sign */ - lin_32_16, /* 32->16: lin_32_16 */ - lin_32_16_sign, /* 32->16 sign: lin_32_16_sign */ - lin_32_16_end, /* 32->16 dst_end: lin_32_16_end */ - lin_32_16_sign_end, /* 32->16 dst_end sign: lin_32_16_sign_end */ - lin_32_end_16, /* 32->16 src_end: lin_32_end_16 */ - lin_32_end_16_sign, /* 32->16 src_end sign: lin_32_end_16_sign */ - lin_32_end_16_end, /* 32->16 src_end dst_end: lin_32_end_16_end */ - lin_32_end_16_sign_end,/* 32->16 src_end dst_end sign: lin_32_end_16_sign_end */ - lin_32_24, /* 32->24: lin_32_24 */ - lin_32_24_sign, /* 32->24 sign: lin_32_24_sign */ - lin_32_24_end, /* 32->24 dst_end: lin_32_24_end */ - lin_32_24_sign_end, /* 32->24 dst_end sign: lin_32_24_sign_end */ - lin_32_end_24, /* 32->24 src_end: lin_32_end_24 */ - lin_32_end_24_sign, /* 32->24 src_end sign: lin_32_end_24_sign */ - lin_32_end_24_end, /* 32->24 src_end dst_end: lin_32_end_24_end */ - lin_32_end_24_sign_end,/* 32->24 src_end dst_end sign: lin_32_end_24_sign_end */ - NULL, /* 32->32: Nothing to do */ - lin_32_sign, /* 32->32 sign: lin_32_sign */ - lin_32_end, /* 32->32 dst_end: lin_32_end */ - lin_32_sign_end, /* 32->32 dst_end sign: lin_32_sign_end */ - lin_32_end, /* 32->32 src_end: lin_32_end */ - lin_32_end_sign, /* 32->32 src_end sign: lin_32_end_sign */ - NULL, /* 32->32 src_end dst_end: Nothing to do */ - lin_32_end_sign_end /* 32->32 src_end dst_end sign: lin_32_end_sign_end */ -}; - - static ssize_t linear_transfer(snd_pcm_plugin_t *plugin, const snd_pcm_plugin_voice_t *src_voices, const snd_pcm_plugin_voice_t *dst_voices, @@ -304,25 +92,56 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin, { linear_t *data; int voice; - ssize_t result; - if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0) + if (plugin == NULL || src_voices == NULL || dst_voices == NULL) + return -EFAULT; + data = (linear_t *)plugin->extra_data; + if (samples < 0) return -EINVAL; if (samples == 0) return 0; - data = (linear_t *)plugin->extra_data; - for (voice = 0, result = 0; voice < plugin->src_format.voices; voice++) { - if (src_voices[voice].addr == NULL) - continue; - if (dst_voices[voice].addr == NULL) + for (voice = 0; voice < plugin->src_format.voices; voice++) { + if (src_voices[voice].addr != NULL && + dst_voices[voice].addr == NULL) + return -EFAULT; + if (src_voices[voice].offset % 8 != 0 || + src_voices[voice].next % 8 != 0) + return -EINVAL; + if (dst_voices[voice].offset % 8 != 0 || + dst_voices[voice].next % 8 != 0) return -EINVAL; - data->func(src_voices[voice].addr, - dst_voices[voice].addr, - samples); } + convert(plugin, src_voices, dst_voices, samples); return samples; } +int copy_index(int src_format, int dst_format) +{ + int src_endian, dst_endian, sign, src_width, dst_width; + + sign = (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)); +#if __BYTE_ORDER == __LITTLE_ENDIAN + src_endian = snd_pcm_format_big_endian(src_format); + dst_endian = snd_pcm_format_big_endian(dst_format); +#elif __BYTE_ORDER == __BIG_ENDIAN + src_endian = snd_pcm_format_little_endian(src_format); + dst_endian = snd_pcm_format_little_endian(dst_format); +#else +#error "Unsupported endian..." +#endif + + if (src_endian < 0) + src_endian = 0; + if (dst_endian < 0) + dst_endian = 0; + + src_width = snd_pcm_format_width(src_format) / 8 - 1; + dst_width = snd_pcm_format_width(dst_format) / 8 - 1; + + return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; +} + int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle, snd_pcm_format_t *src_format, snd_pcm_format_t *dst_format, @@ -330,16 +149,11 @@ int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle, { struct linear_private_data *data; snd_pcm_plugin_t *plugin; - linear_f func; - int src_endian, dst_endian, sign, src_width, dst_width; if (r_plugin == NULL) - return -EINVAL; + return -EFAULT; *r_plugin = NULL; - if (src_format->interleave != dst_format->interleave && - src_format->voices > 1) - return -EINVAL; if (src_format->rate != dst_format->rate) return -EINVAL; if (src_format->voices != dst_format->voices) @@ -348,42 +162,6 @@ int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle, snd_pcm_format_linear(dst_format->format))) return -EINVAL; - 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 - 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 - 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 - - src_width = snd_pcm_format_width(src_format->format); - if (src_width < 0) - return src_width; - src_width /= 8; - src_width--; - - dst_width = snd_pcm_format_width(dst_format->format); - if (dst_width < 0) - return dst_width; - dst_width /= 8; - dst_width--; - - if (src_endian < 0) - src_endian = 0; - if (dst_endian < 0) - dst_endian = 0; - - func = ((linear_f(*)[4][2][2][2])linear_functions)[src_width][dst_width][src_endian][dst_endian][sign]; - - if (func == NULL) - return -EINVAL; - plugin = snd_pcm_plugin_build(handle, "linear format conversion", src_format, @@ -392,9 +170,7 @@ int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle, if (plugin == NULL) return -ENOMEM; data = (linear_t *)plugin->extra_data; - data->func = func; - data->src_sample_size = plugin->src_width / 8; - data->dst_sample_size = plugin->dst_width / 8; + data->copy = copy_index(src_format->format, dst_format->format); plugin->transfer = linear_transfer; *r_plugin = plugin; return 0; diff --git a/src/pcm/plugin/mmap.c b/src/pcm/plugin/mmap.c index 97157ff6..47e42c0c 100644 --- a/src/pcm/plugin/mmap.c +++ b/src/pcm/plugin/mmap.c @@ -214,7 +214,7 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin, if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples)) return -EINVAL; addr = data->buffer + control->fragments[data->frag].addr; - for (voice = 0; voice < plugin->src_format.voices; voice++) { + for (voice = 0; voice < plugin->src_format.voices; voice++, v++) { v->aptr = NULL; v->addr = addr; v->offset = voice * plugin->src_width; @@ -224,7 +224,7 @@ static int mmap_src_voices(snd_pcm_plugin_t *plugin, int frag, voice; if (control->status.frag_size != snd_pcm_plugin_src_samples_to_size(plugin, samples) / plugin->src_format.voices) return -EINVAL; - for (voice = 0; voice < plugin->src_format.voices; voice++) { + for (voice = 0; voice < plugin->src_format.voices; voice++, v++) { frag = data->frag + (voice * data->frags); v->aptr = NULL; v->addr = data->buffer + control->fragments[frag].addr; @@ -260,7 +260,7 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin, if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples)) return -EINVAL; addr = data->buffer + control->fragments[data->frag].addr; - for (voice = 0; voice < plugin->dst_format.voices; voice++) { + for (voice = 0; voice < plugin->dst_format.voices; voice++, v++) { v->addr = addr; v->offset = voice * plugin->src_width; v->next = plugin->dst_format.voices * plugin->dst_width; @@ -269,7 +269,7 @@ static int mmap_dst_voices(snd_pcm_plugin_t *plugin, int frag, voice; if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples) / plugin->dst_format.voices) return -EINVAL; - for (voice = 0; voice < plugin->dst_format.voices; voice++) { + for (voice = 0; voice < plugin->dst_format.voices; voice++, v++) { frag = data->frag + (voice * data->frags); v->addr = data->buffer + control->fragments[frag].addr; v->offset = 0; diff --git a/src/pcm/plugin/mulaw.c b/src/pcm/plugin/mulaw.c index 6dd7ff24..c6b3e9cf 100644 --- a/src/pcm/plugin/mulaw.c +++ b/src/pcm/plugin/mulaw.c @@ -148,108 +148,101 @@ static int ulaw2linear(unsigned char u_val) * Basic Mu-Law plugin */ -typedef void (*mulaw_f)(void *src_ptr, void *dst_ptr, int samples); +typedef void (*mulaw_f)(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples); typedef struct mulaw_private_data { - int src_byte_width; - int dst_byte_width; mulaw_f func; + int conv; } mulaw_t; -#define MULAW_FUNC_DECODE(name, dsttype, val) \ -static void mulaw_decode_##name(void *src_ptr, void *dst_ptr, int samples) \ -{ \ - unsigned char *src = src_ptr; \ - dsttype *dst = dst_ptr; \ - unsigned int s; \ - while (samples--) { \ - s = ulaw2linear(*src++); \ - *dst++ = val; \ - } \ +static void mulaw_decode(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define PUT16_LABELS +#include "plugin_ops.h" +#undef PUT16_LABELS + mulaw_t *data = (mulaw_t *)plugin->extra_data; + void *put = put16_labels[data->conv]; + int voice; + int nvoices = plugin->src_format.voices; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + char *dst; + int src_step, dst_step; + size_t samples1; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + src_step = src_voices[voice].next / 8; + dst_step = dst_voices[voice].next / 8; + samples1 = samples; + while (samples1-- > 0) { + signed short sample = ulaw2linear(*src); + goto *put; +#define PUT16_END after +#include "plugin_ops.h" +#undef PUT16_END + after: + src += src_step; + dst += dst_step; + } + } } -#define MULAW_FUNC_ENCODE(name, srctype, val) \ -static void mulaw_encode_##name(void *src_ptr, void *dst_ptr, int samples) \ -{ \ - srctype *src = src_ptr; \ - unsigned char *dst = dst_ptr; \ - unsigned int s; \ - while (samples--) { \ - s = *src++; \ - *dst++ = linear2ulaw(val); \ - } \ +static void mulaw_encode(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) +{ +#define GET16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS + mulaw_t *data = (mulaw_t *)plugin->extra_data; + void *get = get16_labels[data->conv]; + int voice; + int nvoices = plugin->src_format.voices; + signed short sample = 0; + for (voice = 0; voice < nvoices; ++voice) { + char *src; + char *dst; + int src_step, dst_step; + size_t samples1; + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], samples); + } + continue; + } + src = src_voices[voice].addr + src_voices[voice].offset / 8; + dst = dst_voices[voice].addr + dst_voices[voice].offset / 8; + src_step = src_voices[voice].next / 8; + dst_step = dst_voices[voice].next / 8; + samples1 = samples; + while (samples1-- > 0) { + goto *get; +#define GET16_END after +#include "plugin_ops.h" +#undef GET16_END + after: + *dst = linear2ulaw(sample); + src += src_step; + dst += dst_step; + } + } } -MULAW_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80) -MULAW_FUNC_DECODE(s8, u_int8_t, s >> 8) -MULAW_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000) -MULAW_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000)) -MULAW_FUNC_DECODE(s16n, u_int16_t, s) -MULAW_FUNC_DECODE(s16s, u_int16_t, bswap_16(s)) -MULAW_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000) -MULAW_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000)) -MULAW_FUNC_DECODE(s24n, u_int32_t, s << 8) -MULAW_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8)) -MULAW_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000) -MULAW_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000)) -MULAW_FUNC_DECODE(s32n, u_int32_t, s << 16) -MULAW_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16)) - -MULAW_FUNC_ENCODE(u8, u_int8_t, s << 8) -MULAW_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000) -MULAW_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000) -MULAW_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000)) -MULAW_FUNC_ENCODE(s16n, u_int16_t, s) -MULAW_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s)) -MULAW_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8) -MULAW_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8)) -MULAW_FUNC_ENCODE(s24n, u_int32_t, s >> 8) -MULAW_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8)) -MULAW_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16) -MULAW_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16)) -MULAW_FUNC_ENCODE(s32n, u_int32_t, s >> 16) -MULAW_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16)) - -/* wide, sign, swap endian */ -static mulaw_f mulaw_functions_decode[4 * 4 * 2 * 2] = { - mulaw_decode_u8, /* decode:8-bit:unsigned:none */ - mulaw_decode_u8, /* decode:8-bit:unsigned:swap */ - mulaw_decode_s8, /* decode:8-bit:signed:none */ - mulaw_decode_s8, /* decode:8-bit:signed:swap */ - mulaw_decode_u16n, /* decode:16-bit:unsigned:none */ - mulaw_decode_u16s, /* decode:16-bit:unsigned:swap */ - mulaw_decode_s16n, /* decode:16-bit:signed:none */ - mulaw_decode_s16s, /* decode:16-bit:signed:swap */ - mulaw_decode_u24n, /* decode:24-bit:unsigned:none */ - mulaw_decode_u24s, /* decode:24-bit:unsigned:swap */ - mulaw_decode_s24n, /* decode:24-bit:signed:none */ - mulaw_decode_s24s, /* decode:24-bit:signed:swap */ - mulaw_decode_u32n, /* decode:32-bit:unsigned:none */ - mulaw_decode_u32s, /* decode:32-bit:unsigned:swap */ - mulaw_decode_s32n, /* decode:32-bit:signed:none */ - mulaw_decode_s32s, /* decode:32-bit:signed:swap */ -}; - -/* wide, sign, swap endian */ -static mulaw_f mulaw_functions_encode[4 * 2 * 2] = { - mulaw_encode_u8, /* from:8-bit:unsigned:none */ - mulaw_encode_u8, /* from:8-bit:unsigned:swap */ - mulaw_encode_s8, /* from:8-bit:signed:none */ - mulaw_encode_s8, /* from:8-bit:signed:swap */ - mulaw_encode_u16n, /* from:16-bit:unsigned:none */ - mulaw_encode_u16s, /* from:16-bit:unsigned:swap */ - mulaw_encode_s16n, /* from:16-bit:signed:none */ - mulaw_encode_s16s, /* from:16-bit:signed:swap */ - mulaw_encode_u24n, /* from:24-bit:unsigned:none */ - mulaw_encode_u24s, /* from:24-bit:unsigned:swap */ - mulaw_encode_s24n, /* from:24-bit:signed:none */ - mulaw_encode_s24s, /* from:24-bit:signed:swap */ - mulaw_encode_u32n, /* from:32-bit:unsigned:none */ - mulaw_encode_u32s, /* from:32-bit:unsigned:swap */ - mulaw_encode_s32n, /* from:32-bit:signed:none */ - mulaw_encode_s32s, /* from:32-bit:signed:swap */ -}; - static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin, const snd_pcm_plugin_voice_t *src_voices, const snd_pcm_plugin_voice_t *dst_voices, @@ -258,24 +251,25 @@ static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin, mulaw_t *data; int voice; - if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0) + if (plugin == NULL || src_voices == NULL || dst_voices == NULL) + return -EFAULT; + if (samples < 0) return -EINVAL; if (samples == 0) return 0; - data = (mulaw_t *)plugin->extra_data; - if (plugin->src_format.interleave) { - data->func(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(src_voices[voice].addr, - dst_voices[voice].addr, - samples); - } + for (voice = 0; voice < plugin->src_format.voices; voice++) { + if (src_voices[voice].addr != NULL && + dst_voices[voice].addr == NULL) + return -EFAULT; + if (src_voices[voice].offset % 8 != 0 || + src_voices[voice].next % 8 != 0) + return -EINVAL; + if (dst_voices[voice].offset % 8 != 0 || + dst_voices[voice].next % 8 != 0) + return -EINVAL; } + data = (mulaw_t *)plugin->extra_data; + data->func(plugin, src_voices, dst_voices, samples); return samples; } @@ -284,70 +278,43 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle, snd_pcm_format_t *dst_format, snd_pcm_plugin_t **r_plugin) { - struct mulaw_private_data *data; + mulaw_t *data; snd_pcm_plugin_t *plugin; - int endian, src_width, dst_width, sign; + snd_pcm_format_t *format; mulaw_f func; if (r_plugin == NULL) return -EINVAL; *r_plugin = NULL; - if (src_format->interleave != dst_format->interleave && - src_format->voices > 1) - return -EINVAL; if (src_format->rate != dst_format->rate) return -EINVAL; if (src_format->voices != dst_format->voices) return -EINVAL; - if (dst_format->format == SND_PCM_SFMT_MU_LAW) { - 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 = ((mulaw_f(*)[2][2])mulaw_functions_encode)[(src_width/8)-1][sign][endian]; - } else if (src_format->format == SND_PCM_SFMT_MU_LAW) { - 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 = ((mulaw_f(*)[2][2])mulaw_functions_decode)[(dst_width/8)-1][sign][endian]; - } else { - return -EINVAL; + format = src_format; + func = mulaw_encode; } + else if (src_format->format == SND_PCM_SFMT_MU_LAW) { + format = dst_format; + func = mulaw_decode; + } + else + return -EINVAL; + if (!snd_pcm_format_linear(format->format)) + return -EINVAL; + plugin = snd_pcm_plugin_build(handle, "Mu-Law<->linear conversion", src_format, dst_format, - sizeof(struct mulaw_private_data)); + sizeof(mulaw_t)); if (plugin == NULL) return -ENOMEM; - data = (struct mulaw_private_data *)plugin->extra_data; - data->src_byte_width = src_width / 8; - data->dst_byte_width = dst_width / 8; + data = (mulaw_t*)plugin->extra_data; data->func = func; + data->conv = getput_index(format->format); plugin->transfer = mulaw_transfer; *r_plugin = plugin; return 0; diff --git a/src/pcm/plugin/plugin_ops.h b/src/pcm/plugin/plugin_ops.h new file mode 100644 index 00000000..e5874d50 --- /dev/null +++ b/src/pcm/plugin/plugin_ops.h @@ -0,0 +1,513 @@ +/* + * Plugin sample operators with fast switch + * Copyright (c) 2000 by Jaroslav Kysela + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#define as_u8(ptr) (*(u_int8_t*)(ptr)) +#define as_u16(ptr) (*(u_int16_t*)(ptr)) +#define as_u32(ptr) (*(u_int32_t*)(ptr)) +#define as_s8(ptr) (*(int8_t*)(ptr)) +#define as_s16(ptr) (*(int16_t*)(ptr)) +#define as_s32(ptr) (*(int32_t*)(ptr)) + + +#ifdef COPY_LABELS +/* src_wid src_endswap sign_toggle dst_wid dst_endswap */ +static void *copy_labels[4 * 2 * 2 * 4 * 2] = { + &©_xxx1_xxx1, /* 8h -> 8h */ + &©_xxx1_xxx1, /* 8h -> 8s */ + &©_xxx1_xx10, /* 8h -> 16h */ + &©_xxx1_xx01, /* 8h -> 16s */ + &©_xxx1_x100, /* 8h -> 24h */ + &©_xxx1_001x, /* 8h -> 24s */ + &©_xxx1_1000, /* 8h -> 32h */ + &©_xxx1_0001, /* 8h -> 32s */ + &©_xxx1_xxx9, /* 8h ^> 8h */ + &©_xxx1_xxx9, /* 8h ^> 8s */ + &©_xxx1_xx90, /* 8h ^> 16h */ + &©_xxx1_xx09, /* 8h ^> 16s */ + &©_xxx1_x900, /* 8h ^> 24h */ + &©_xxx1_009x, /* 8h ^> 24s */ + &©_xxx1_9000, /* 8h ^> 32h */ + &©_xxx1_0009, /* 8h ^> 32s */ + &©_xxx1_xxx1, /* 8s -> 8h */ + &©_xxx1_xxx1, /* 8s -> 8s */ + &©_xxx1_xx10, /* 8s -> 16h */ + &©_xxx1_xx01, /* 8s -> 16s */ + &©_xxx1_x100, /* 8s -> 24h */ + &©_xxx1_001x, /* 8s -> 24s */ + &©_xxx1_1000, /* 8s -> 32h */ + &©_xxx1_0001, /* 8s -> 32s */ + &©_xxx1_xxx9, /* 8s ^> 8h */ + &©_xxx1_xxx9, /* 8s ^> 8s */ + &©_xxx1_xx90, /* 8s ^> 16h */ + &©_xxx1_xx09, /* 8s ^> 16s */ + &©_xxx1_x900, /* 8s ^> 24h */ + &©_xxx1_009x, /* 8s ^> 24s */ + &©_xxx1_9000, /* 8s ^> 32h */ + &©_xxx1_0009, /* 8s ^> 32s */ + &©_xx12_xxx1, /* 16h -> 8h */ + &©_xx12_xxx1, /* 16h -> 8s */ + &©_xx12_xx12, /* 16h -> 16h */ + &©_xx12_xx21, /* 16h -> 16s */ + &©_xx12_x120, /* 16h -> 24h */ + &©_xx12_021x, /* 16h -> 24s */ + &©_xx12_1200, /* 16h -> 32h */ + &©_xx12_0021, /* 16h -> 32s */ + &©_xx12_xxx9, /* 16h ^> 8h */ + &©_xx12_xxx9, /* 16h ^> 8s */ + &©_xx12_xx92, /* 16h ^> 16h */ + &©_xx12_xx29, /* 16h ^> 16s */ + &©_xx12_x920, /* 16h ^> 24h */ + &©_xx12_029x, /* 16h ^> 24s */ + &©_xx12_9200, /* 16h ^> 32h */ + &©_xx12_0029, /* 16h ^> 32s */ + &©_xx12_xxx2, /* 16s -> 8h */ + &©_xx12_xxx2, /* 16s -> 8s */ + &©_xx12_xx21, /* 16s -> 16h */ + &©_xx12_xx12, /* 16s -> 16s */ + &©_xx12_x210, /* 16s -> 24h */ + &©_xx12_012x, /* 16s -> 24s */ + &©_xx12_2100, /* 16s -> 32h */ + &©_xx12_0012, /* 16s -> 32s */ + &©_xx12_xxxA, /* 16s ^> 8h */ + &©_xx12_xxxA, /* 16s ^> 8s */ + &©_xx12_xxA1, /* 16s ^> 16h */ + &©_xx12_xx1A, /* 16s ^> 16s */ + &©_xx12_xA10, /* 16s ^> 24h */ + &©_xx12_01Ax, /* 16s ^> 24s */ + &©_xx12_A100, /* 16s ^> 32h */ + &©_xx12_001A, /* 16s ^> 32s */ + &©_x123_xxx1, /* 24h -> 8h */ + &©_x123_xxx1, /* 24h -> 8s */ + &©_x123_xx12, /* 24h -> 16h */ + &©_x123_xx21, /* 24h -> 16s */ + &©_x123_x123, /* 24h -> 24h */ + &©_x123_321x, /* 24h -> 24s */ + &©_x123_1230, /* 24h -> 32h */ + &©_x123_0321, /* 24h -> 32s */ + &©_x123_xxx9, /* 24h ^> 8h */ + &©_x123_xxx9, /* 24h ^> 8s */ + &©_x123_xx92, /* 24h ^> 16h */ + &©_x123_xx29, /* 24h ^> 16s */ + &©_x123_x923, /* 24h ^> 24h */ + &©_x123_329x, /* 24h ^> 24s */ + &©_x123_9230, /* 24h ^> 32h */ + &©_x123_0329, /* 24h ^> 32s */ + &©_123x_xxx3, /* 24s -> 8h */ + &©_123x_xxx3, /* 24s -> 8s */ + &©_123x_xx32, /* 24s -> 16h */ + &©_123x_xx23, /* 24s -> 16s */ + &©_123x_x321, /* 24s -> 24h */ + &©_123x_123x, /* 24s -> 24s */ + &©_123x_3210, /* 24s -> 32h */ + &©_123x_0123, /* 24s -> 32s */ + &©_123x_xxxB, /* 24s ^> 8h */ + &©_123x_xxxB, /* 24s ^> 8s */ + &©_123x_xxB2, /* 24s ^> 16h */ + &©_123x_xx2B, /* 24s ^> 16s */ + &©_123x_xB21, /* 24s ^> 24h */ + &©_123x_12Bx, /* 24s ^> 24s */ + &©_123x_B210, /* 24s ^> 32h */ + &©_123x_012B, /* 24s ^> 32s */ + &©_1234_xxx1, /* 32h -> 8h */ + &©_1234_xxx1, /* 32h -> 8s */ + &©_1234_xx12, /* 32h -> 16h */ + &©_1234_xx21, /* 32h -> 16s */ + &©_1234_x123, /* 32h -> 24h */ + &©_1234_321x, /* 32h -> 24s */ + &©_1234_1234, /* 32h -> 32h */ + &©_1234_4321, /* 32h -> 32s */ + &©_1234_xxx9, /* 32h ^> 8h */ + &©_1234_xxx9, /* 32h ^> 8s */ + &©_1234_xx92, /* 32h ^> 16h */ + &©_1234_xx29, /* 32h ^> 16s */ + &©_1234_x923, /* 32h ^> 24h */ + &©_1234_329x, /* 32h ^> 24s */ + &©_1234_9234, /* 32h ^> 32h */ + &©_1234_4329, /* 32h ^> 32s */ + &©_1234_xxx4, /* 32s -> 8h */ + &©_1234_xxx4, /* 32s -> 8s */ + &©_1234_xx43, /* 32s -> 16h */ + &©_1234_xx34, /* 32s -> 16s */ + &©_1234_x432, /* 32s -> 24h */ + &©_1234_234x, /* 32s -> 24s */ + &©_1234_4321, /* 32s -> 32h */ + &©_1234_1234, /* 32s -> 32s */ + &©_1234_xxxC, /* 32s ^> 8h */ + &©_1234_xxxC, /* 32s ^> 8s */ + &©_1234_xxC3, /* 32s ^> 16h */ + &©_1234_xx3C, /* 32s ^> 16s */ + &©_1234_xC32, /* 32s ^> 24h */ + &©_1234_23Cx, /* 32s ^> 24s */ + &©_1234_C321, /* 32s ^> 32h */ + &©_1234_123C, /* 32s ^> 32s */ +}; +#endif + +#ifdef COPY_END +while(0) { +copy_xxx1_xxx1: as_u8(dst) = as_u8(src); goto COPY_END; +copy_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto COPY_END; +copy_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto COPY_END; +copy_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto COPY_END; +copy_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto COPY_END; +copy_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto COPY_END; +copy_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto COPY_END; +copy_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto COPY_END; +copy_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto COPY_END; +copy_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto COPY_END; +copy_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto COPY_END; +copy_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto COPY_END; +copy_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto COPY_END; +copy_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto COPY_END; +copy_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto COPY_END; +copy_xx12_xx12: as_u16(dst) = as_u16(src); goto COPY_END; +copy_xx12_xx21: as_u16(dst) = bswap_16(as_u16(src)); goto COPY_END; +copy_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto COPY_END; +copy_xx12_021x: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto COPY_END; +copy_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto COPY_END; +copy_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)); goto COPY_END; +copy_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto COPY_END; +copy_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto COPY_END; +copy_xx12_xx29: as_u16(dst) = bswap_16(as_u16(src)) ^ 0x80; goto COPY_END; +copy_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto COPY_END; +copy_xx12_029x: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80) << 8; goto COPY_END; +copy_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto COPY_END; +copy_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80); goto COPY_END; +copy_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto COPY_END; +copy_xx12_x210: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto COPY_END; +copy_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto COPY_END; +copy_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 16; goto COPY_END; +copy_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto COPY_END; +copy_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto COPY_END; +copy_xx12_xxA1: as_u16(dst) = bswap_16(as_u16(src) ^ 0x80); goto COPY_END; +copy_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto COPY_END; +copy_xx12_xA10: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 8; goto COPY_END; +copy_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto COPY_END; +copy_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 16; goto COPY_END; +copy_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto COPY_END; +copy_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto COPY_END; +copy_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto COPY_END; +copy_x123_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto COPY_END; +copy_x123_x123: as_u32(dst) = as_u32(src); goto COPY_END; +copy_x123_321x: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END; +copy_x123_1230: as_u32(dst) = as_u32(src) << 8; goto COPY_END; +copy_x123_0321: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto COPY_END; +copy_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto COPY_END; +copy_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto COPY_END; +copy_x123_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 8) ^ 0x80; goto COPY_END; +copy_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto COPY_END; +copy_x123_329x: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x8000; goto COPY_END; +copy_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto COPY_END; +copy_x123_0329: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x80; goto COPY_END; +copy_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto COPY_END; +copy_123x_xx32: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto COPY_END; +copy_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto COPY_END; +copy_123x_x321: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END; +copy_123x_123x: as_u32(dst) = as_u32(src); goto COPY_END; +copy_123x_3210: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto COPY_END; +copy_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto COPY_END; +copy_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto COPY_END; +copy_123x_xxB2: as_u16(dst) = bswap_16((as_u32(src) >> 8) ^ 0x80); goto COPY_END; +copy_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto COPY_END; +copy_123x_xB21: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x800000; goto COPY_END; +copy_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto COPY_END; +copy_123x_B210: as_u32(dst) = bswap_32(as_u32(src) ^ 0x8000) << 8; goto COPY_END; +copy_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto COPY_END; +copy_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto COPY_END; +copy_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto COPY_END; +copy_1234_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 16); goto COPY_END; +copy_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto COPY_END; +copy_1234_321x: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto COPY_END; +copy_1234_1234: as_u32(dst) = as_u32(src); goto COPY_END; +copy_1234_4321: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END; +copy_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto COPY_END; +copy_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto COPY_END; +copy_1234_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 16) ^ 0x80; goto COPY_END; +copy_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto COPY_END; +copy_1234_329x: as_u32(dst) = (bswap_32(as_u32(src)) ^ 0x80) << 8; goto COPY_END; +copy_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto COPY_END; +copy_1234_4329: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x80; goto COPY_END; +copy_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto COPY_END; +copy_1234_xx43: as_u16(dst) = bswap_16(as_u32(src)); goto COPY_END; +copy_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto COPY_END; +copy_1234_x432: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto COPY_END; +copy_1234_234x: as_u32(dst) = as_u32(src) << 8; goto COPY_END; +copy_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto COPY_END; +copy_1234_xxC3: as_u16(dst) = bswap_16(as_u32(src) ^ 0x80); goto COPY_END; +copy_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto COPY_END; +copy_1234_xC32: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x800000; goto COPY_END; +copy_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto COPY_END; +copy_1234_C321: as_u32(dst) = bswap_32(as_u32(src) ^ 0x80); goto COPY_END; +copy_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto COPY_END; +} +#endif + +#ifdef GET16_LABELS +/* src_wid src_endswap sign_toggle */ +static void *get16_labels[4 * 2 * 2] = { + &&get16_xxx1_xx10, /* 8h -> 16h */ + &&get16_xxx1_xx90, /* 8h ^> 16h */ + &&get16_xxx1_xx10, /* 8s -> 16h */ + &&get16_xxx1_xx90, /* 8s ^> 16h */ + &&get16_xx12_xx12, /* 16h -> 16h */ + &&get16_xx12_xx92, /* 16h ^> 16h */ + &&get16_xx12_xx21, /* 16s -> 16h */ + &&get16_xx12_xxA1, /* 16s ^> 16h */ + &&get16_x123_xx12, /* 24h -> 16h */ + &&get16_x123_xx92, /* 24h ^> 16h */ + &&get16_123x_xx32, /* 24s -> 16h */ + &&get16_123x_xxB2, /* 24s ^> 16h */ + &&get16_1234_xx12, /* 32h -> 16h */ + &&get16_1234_xx92, /* 32h ^> 16h */ + &&get16_1234_xx43, /* 32s -> 16h */ + &&get16_1234_xxC3, /* 32s ^> 16h */ +}; +#endif + +#ifdef GET16_END +while(0) { +get16_xxx1_xx10: sample = (u_int32_t)as_u8(src) << 8; goto GET16_END; +get16_xxx1_xx90: sample = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto GET16_END; +get16_xx12_xx12: sample = as_u16(src); goto GET16_END; +get16_xx12_xx92: sample = as_u16(src) ^ 0x8000; goto GET16_END; +get16_xx12_xx21: sample = bswap_16(as_u16(src)); goto GET16_END; +get16_xx12_xxA1: sample = bswap_16(as_u16(src) ^ 0x80); goto GET16_END; +get16_x123_xx12: sample = as_u32(src) >> 8; goto GET16_END; +get16_x123_xx92: sample = (as_u32(src) >> 8) ^ 0x8000; goto GET16_END; +get16_123x_xx32: sample = bswap_16(as_u32(src) >> 8); goto GET16_END; +get16_123x_xxB2: sample = bswap_16((as_u32(src) >> 8) ^ 0x8000); goto GET16_END; +get16_1234_xx12: sample = as_u32(src) >> 16; goto GET16_END; +get16_1234_xx92: sample = (as_u32(src) >> 16) ^ 0x8000; goto GET16_END; +get16_1234_xx43: sample = bswap_16(as_u32(src)); goto GET16_END; +get16_1234_xxC3: sample = bswap_16(as_u32(src) ^ 0x80); goto GET16_END; +} +#endif + +#ifdef PUT16_LABELS +/* dst_wid dst_endswap sign_toggle*/ +static void *put16_labels[4 * 2 * 2 * 4 * 2] = { + &&put16_xx12_xxx1, /* 16h -> 8h */ + &&put16_xx12_xxx9, /* 16h ^> 8h */ + &&put16_xx12_xxx1, /* 16h -> 8s */ + &&put16_xx12_xxx9, /* 16h ^> 8s */ + &&put16_xx12_xx12, /* 16h -> 16h */ + &&put16_xx12_xx92, /* 16h ^> 16h */ + &&put16_xx12_xx21, /* 16h -> 16s */ + &&put16_xx12_xx29, /* 16h ^> 16s */ + &&put16_xx12_x120, /* 16h -> 24h */ + &&put16_xx12_x920, /* 16h ^> 24h */ + &&put16_xx12_021x, /* 16h -> 24s */ + &&put16_xx12_029x, /* 16h ^> 24s */ + &&put16_xx12_1200, /* 16h -> 32h */ + &&put16_xx12_9200, /* 16h ^> 32h */ + &&put16_xx12_0021, /* 16h -> 32s */ + &&put16_xx12_0029, /* 16h ^> 32s */ +}; +#endif + +#ifdef PUT16_END +while (0) { +put16_xx12_xxx1: as_u8(dst) = sample >> 8; goto PUT16_END; +put16_xx12_xxx9: as_u8(dst) = (sample >> 8) ^ 0x80; goto PUT16_END; +put16_xx12_xx12: as_u16(dst) = sample; goto PUT16_END; +put16_xx12_xx92: as_u16(dst) = sample ^ 0x8000; goto PUT16_END; +put16_xx12_xx21: as_u16(dst) = bswap_16(sample); goto PUT16_END; +put16_xx12_xx29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT16_END; +put16_xx12_x120: as_u32(dst) = (u_int32_t)sample << 8; goto PUT16_END; +put16_xx12_x920: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 8; goto PUT16_END; +put16_xx12_021x: as_u32(dst) = (u_int32_t)bswap_16(sample) << 8; goto PUT16_END; +put16_xx12_029x: as_u32(dst) = (u_int32_t)(bswap_16(sample) ^ 0x80) << 8; goto PUT16_END; +put16_xx12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT16_END; +put16_xx12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT16_END; +put16_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(sample); goto PUT16_END; +put16_xx12_0029: as_u32(dst) = (u_int32_t)bswap_16(sample) ^ 0x80; goto PUT16_END; +} +#endif + +#ifdef GET32_LABELS +/* src_wid src_endswap sign_toggle */ +static void *get32_labels[4 * 2 * 2] = { + &&get32_xxx1_1000, /* 8h -> 32h */ + &&get32_xxx1_9000, /* 8h ^> 32h */ + &&get32_xxx1_1000, /* 8s -> 32h */ + &&get32_xxx1_9000, /* 8s ^> 32h */ + &&get32_xx12_1200, /* 16h -> 32h */ + &&get32_xx12_9200, /* 16h ^> 32h */ + &&get32_xx12_2100, /* 16s -> 32h */ + &&get32_xx12_A100, /* 16s ^> 32h */ + &&get32_x123_1230, /* 24h -> 32h */ + &&get32_x123_9230, /* 24h ^> 32h */ + &&get32_123x_3210, /* 24s -> 32h */ + &&get32_123x_B210, /* 24s ^> 32h */ + &&get32_1234_1234, /* 32h -> 32h */ + &&get32_1234_9234, /* 32h ^> 32h */ + &&get32_1234_4321, /* 32s -> 32h */ + &&get32_1234_C321, /* 32s ^> 32h */ +}; +#endif + +#ifdef GET32_END +while (0) { +get32_xxx1_1000: sample = (u_int32_t)as_u8(src) << 24; goto goto GET32_END; +get32_xxx1_9000: sample = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto goto GET32_END; +get32_xx12_1200: sample = (u_int32_t)as_u16(src) << 16; goto goto GET32_END; +get32_xx12_9200: sample = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto goto GET32_END; +get32_xx12_2100: sample = (u_int32_t)bswap_16(as_u16(src)) << 16; goto goto GET32_END; +get32_xx12_A100: sample = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 16; goto goto GET32_END; +get32_x123_1230: sample = as_u32(src) << 8; goto goto GET32_END; +get32_x123_9230: sample = (as_u32(src) << 8) ^ 0x80000000; goto goto GET32_END; +get32_123x_3210: sample = bswap_32(as_u32(src) >> 8); goto goto GET32_END; +get32_123x_B210: sample = bswap_32((as_u32(src) >> 8) ^ 0x80); goto goto GET32_END; +get32_1234_1234: sample = as_u32(src); goto goto GET32_END; +get32_1234_9234: sample = as_u32(src) ^ 0x80000000; goto goto GET32_END; +get32_1234_4321: sample = bswap_32(as_u32(src)); goto goto GET32_END; +get32_1234_C321: sample = bswap_32(as_u32(src) ^ 0x80); goto goto GET32_END; +} +#endif + +#ifdef PUT32_LABELS +/* dst_wid dst_endswap sign_toggle*/ +static void *put32_labels[4 * 2 * 2] = { + &&put32_1234_xxx1, /* 32h -> 8h */ + &&put32_1234_xxx9, /* 32h ^> 8h */ + &&put32_1234_xxx1, /* 32h -> 8s */ + &&put32_1234_xxx9, /* 32h ^> 8s */ + &&put32_1234_xx12, /* 32h -> 16h */ + &&put32_1234_xx92, /* 32h ^> 16h */ + &&put32_1234_xx21, /* 32h -> 16s */ + &&put32_1234_xx29, /* 32h ^> 16s */ + &&put32_1234_x123, /* 32h -> 24h */ + &&put32_1234_x923, /* 32h ^> 24h */ + &&put32_1234_321x, /* 32h -> 24s */ + &&put32_1234_329x, /* 32h ^> 24s */ + &&put32_1234_1234, /* 32h -> 32h */ + &&put32_1234_9234, /* 32h ^> 32h */ + &&put32_1234_4321, /* 32h -> 32s */ + &&put32_1234_4329, /* 32h ^> 32s */ +}; +#endif + +#ifdef PUT32_END +while (0) { +put32_1234_xxx1: as_u8(dst) = sample >> 24; goto PUT32_END; +put32_1234_xxx9: as_u8(dst) = (sample >> 24) ^ 0x80; goto PUT32_END; +put32_1234_xx12: as_u16(dst) = sample >> 16; goto PUT32_END; +put32_1234_xx92: as_u16(dst) = (sample >> 16) ^ 0x8000; goto PUT32_END; +put32_1234_xx21: as_u16(dst) = bswap_16(sample >> 16); goto PUT32_END; +put32_1234_xx29: as_u16(dst) = bswap_16(sample >> 16) ^ 0x80; goto PUT32_END; +put32_1234_x123: as_u32(dst) = sample >> 8; goto PUT32_END; +put32_1234_x923: as_u32(dst) = (sample >> 8) ^ 0x800000; goto PUT32_END; +put32_1234_321x: as_u32(dst) = bswap_32(sample) << 8; goto PUT32_END; +put32_1234_329x: as_u32(dst) = (bswap_32(sample) ^ 0x80) << 8; goto PUT32_END; +put32_1234_1234: as_u32(dst) = sample; goto PUT32_END; +put32_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT32_END; +put32_1234_4321: as_u32(dst) = bswap_32(sample); goto PUT32_END; +put32_1234_4329: as_u32(dst) = bswap_32(sample) ^ 0x80; goto PUT32_END; +} +#endif + +#ifdef GET_LABELS +/* width endswap sign_toggle*/ +static void *get_labels[4 * 2 * 2] = { + &&get_s8, /* s8 -> s8 */ + &&get_u8, /* u8 -> s8 */ + &&get_s8, /* s8 -> s8 */ + &&get_u8, /* u8 -> s8 */ + &&get_s16h, /* s16h -> s16h */ + &&get_u16h, /* u16h -> s16h */ + &&get_s16s, /* s16s -> s16h */ + &&get_u16s, /* u16s -> s16h */ + &&get_s24h, /* s24h -> s32h */ + &&get_u24h, /* u24h -> s32h */ + &&get_s24s, /* s24s -> s32h */ + &&get_u24s, /* u24s -> s32h */ + &&get_s32h, /* s32h -> s32h */ + &&get_u32h, /* u32h -> s32h */ + &&get_s32s, /* s32s -> s32h */ + &&get_u32s, /* u32s -> s32h */ +}; +#endif + +#ifdef GET_END +while (0) { +get_s8: sample = as_s8(src); goto GET_END; +get_u8: sample = (int8_t)(as_u8(src) ^ 0x80); goto GET_END; +get_s16h: sample = as_s16(src); goto GET_END; +get_u16h: sample = (int16_t)(as_u16(src) ^ 0x8000); goto GET_END; +get_s16s: sample = (int16_t)bswap_16(as_u16(src)); goto GET_END; +get_u16s: sample = (int16_t)(bswap_16(as_u16(src) ^ 0x80)); goto GET_END; +get_s24h: sample = (int32_t)(as_u32(src) << 8) / 256; goto GET_END; +get_u24h: sample = (as_u32(src) ^ 0x80000000); goto GET_END; +get_s24s: sample = (int32_t)(bswap_32(as_u32(src)) << 8) / 256; goto GET_END; +get_u24s: sample = bswap_32(as_u32(src) ^ 0x80); goto GET_END; +get_s32h: sample = as_s32(src); goto GET_END; +get_u32h: sample = as_u32(src) ^ 0x80000000; goto GET_END; +get_s32s: sample = bswap_32(as_u32(src)); goto GET_END; +get_u32s: sample = bswap_32(as_u32(src) ^ 0x80); goto GET_END; +} +#endif + +#ifdef PUT_LABELS +/* width endswap sign_toggle*/ +static void *put_labels[4 * 2 * 2] = { + &&put_s8, /* s8 -> s8 */ + &&put_u8, /* u8 -> s8 */ + &&put_s8, /* s8 -> s8 */ + &&put_u8, /* u8 -> s8 */ + &&put_s16h, /* s16h -> s16h */ + &&put_u16h, /* u16h -> s16h */ + &&put_s16s, /* s16s -> s16h */ + &&put_u16s, /* u16s -> s16h */ + &&put_s24h, /* s24h -> s32h */ + &&put_u24h, /* u24h -> s32h */ + &&put_s24s, /* s24s -> s32h */ + &&put_u24s, /* u24s -> s32h */ + &&put_s32h, /* s32h -> s32h */ + &&put_u32h, /* u32h -> s32h */ + &&put_s32s, /* s32s -> s32h */ + &&put_u32s, /* u32s -> s32h */ +}; +#endif + +#ifdef PUT_END +put_s8: as_s8(dst) = sample; goto PUT_END; +put_u8: as_u8(dst) = sample ^ 0x80; goto PUT_END; +put_s16h: as_s16(dst) = sample; goto PUT_END; +put_u16h: as_u16(dst) = sample ^ 0x8000; goto PUT_END; +put_s16s: as_s16(dst) = bswap_16(sample); goto PUT_END; +put_u16s: as_u16(dst) = bswap_16(sample ^ 0x80); goto PUT_END; +put_s24h: as_s24(dst) = sample & 0xffffff; goto PUT_END; +put_u24h: as_u24(dst) = sample ^ 0x80000000; goto PUT_END; +put_s24s: as_s24(dst) = bswap_32(sample & 0xffffff); goto PUT_END; +put_u24s: as_u24(dst) = bswap_32(sample ^ 0x80); goto PUT_END; +put_s32h: as_s32(dst) = sample; goto PUT_END; +put_u32h: as_u32(dst) = sample ^ 0x80000000; goto PUT_END; +put_s32s: as_s32(dst) = bswap_32(sample); goto PUT_END; +put_u32s: as_u32(dst) = bswap_32(sample ^ 0x80); goto PUT_END; +#endif + +#undef as_u8 +#undef as_u16 +#undef as_u32 +#undef as_s8 +#undef as_s16 +#undef as_s32 diff --git a/src/pcm/plugin/rate.c b/src/pcm/plugin/rate.c index 30d6dfa7..e943e31b 100644 --- a/src/pcm/plugin/rate.c +++ b/src/pcm/plugin/rate.c @@ -42,56 +42,42 @@ * Basic rate conversion plugin */ -#define rate_voices(data) ((rate_voice_t *)((char *)data + sizeof(*data))) - -typedef signed short (*take_sample_f)(void *ptr); -typedef void (*put_sample_f)(void *ptr, signed int val); - typedef struct { signed short last_S1; signed short last_S2; } rate_voice_t; +typedef void (*rate_f)(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + int src_samples, int dst_samples); + typedef struct rate_private_data { - snd_pcm_plugin_t *plugin; - take_sample_f take; - put_sample_f put; unsigned int pitch; unsigned int pos; + rate_f func; + int get, put; ssize_t old_src_samples, old_dst_samples; + rate_voice_t voices[0]; } rate_t; -static void rate_init(snd_pcm_plugin_t *plugin, rate_t *data) +static void rate_init(snd_pcm_plugin_t *plugin) { int voice; - rate_voice_t *rvoices = rate_voices(data); - + rate_t *data = (rate_t *)plugin->extra_data; data->pos = 0; - for (voice = 0; plugin->src_format.voices; voice++) { - rvoices[voice].last_S1 = 0; - rvoices[voice].last_S2 = 0; + for (voice = 0; voice < plugin->src_format.voices; voice++) { + data->voices[voice].last_S1 = 0; + data->voices[voice].last_S2 = 0; } } -#define RATE_TAKE_SAMPLE(name, type, val) \ -static signed short rate_take_sample_##name(void *ptr) \ -{ \ - signed int smp = *(type *)ptr; \ - return val; \ -} - -#define RATE_PUT_SAMPLE(name, type, val) \ -static void rate_put_sample_##name(void *ptr, signed int smp) \ -{ \ - *(type *)ptr = val; \ -} - static void resample_expand(snd_pcm_plugin_t *plugin, const snd_pcm_plugin_voice_t *src_voices, const snd_pcm_plugin_voice_t *dst_voices, int src_samples, int dst_samples) { - unsigned int pos; + unsigned int pos = 0; signed int val; signed short S1, S2; char *src, *dst; @@ -99,24 +85,45 @@ static void resample_expand(snd_pcm_plugin_t *plugin, int src_step, dst_step; int src_samples1, dst_samples1; rate_t *data = (rate_t *)plugin->extra_data; - rate_voice_t *rvoices = rate_voices(data); + rate_voice_t *rvoices = data->voices; + +#define GET16_LABELS +#define PUT16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS +#undef PUT16_LABELS + void *get = get16_labels[data->get]; + void *put = put16_labels[data->put]; + void *get16_end = 0; + signed short sample = 0; +#define GET16_END *get16_end +#include "plugin_ops.h" +#undef GET16_END for (voice = 0; voice < plugin->src_format.voices; voice++, rvoices++) { pos = data->pos; S1 = rvoices->last_S1; S2 = rvoices->last_S2; - if (src_voices[voice].addr == NULL) + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], dst_samples); + } continue; + } src = (char *)src_voices[voice].addr + src_voices[voice].offset / 8; - dst = (char *)dst_voices[voice].addr + src_voices[voice].offset / 8; + dst = (char *)dst_voices[voice].addr + dst_voices[voice].offset / 8; src_step = src_voices[voice].next / 8; dst_step = dst_voices[voice].next / 8; src_samples1 = src_samples; dst_samples1 = dst_samples; if (pos & ~MASK) { + get16_end = &&after_get1; + goto *get; + after_get1: pos &= MASK; S1 = S2; - S2 = data->take(src); + S2 = sample; src += src_step; src_samples--; } @@ -125,7 +132,10 @@ static void resample_expand(snd_pcm_plugin_t *plugin, pos &= MASK; S1 = S2; if (src_samples1-- > 0) { - S2 = data->take(src); + get16_end = &&after_get2; + goto *get; + after_get2: + S2 = sample; src += src_step; } } @@ -134,14 +144,20 @@ static void resample_expand(snd_pcm_plugin_t *plugin, val = -32768; else if (val > 32767) val = 32767; - data->put(dst, val); + sample = val; + goto *put; +#define PUT16_END after_put +#include "plugin_ops.h" +#undef PUT16_END + after_put: dst += dst_step; pos += data->pitch; } rvoices->last_S1 = S1; rvoices->last_S2 = S2; - data->pos = pos; + rvoices++; } + data->pos = pos; } static void resample_shrink(snd_pcm_plugin_t *plugin, @@ -149,7 +165,7 @@ static void resample_shrink(snd_pcm_plugin_t *plugin, const snd_pcm_plugin_voice_t *dst_voices, int src_samples, int dst_samples) { - unsigned int pos; + unsigned int pos = 0; signed int val; signed short S1, S2; char *src, *dst; @@ -157,16 +173,30 @@ static void resample_shrink(snd_pcm_plugin_t *plugin, int src_step, dst_step; int src_samples1, dst_samples1; rate_t *data = (rate_t *)plugin->extra_data; - rate_voice_t *rvoices = rate_voices(data); + rate_voice_t *rvoices = data->voices; +#define GET16_LABELS +#define PUT16_LABELS +#include "plugin_ops.h" +#undef GET16_LABELS +#undef PUT16_LABELS + void *get = get16_labels[data->get]; + void *put = put16_labels[data->put]; + signed short sample = 0; + for (voice = 0; voice < plugin->src_format.voices; ++voice) { pos = data->pos; S1 = rvoices->last_S1; S2 = rvoices->last_S2; - if (src_voices[voice].addr == NULL) + if (src_voices[voice].addr == NULL) { + if (dst_voices[voice].addr != NULL) { +// null_voice(&dst_voices[voice]); + zero_voice(plugin, &dst_voices[voice], dst_samples); + } continue; + } src = (char *)src_voices[voice].addr + src_voices[voice].offset / 8; - dst = (char *)dst_voices[voice].addr + src_voices[voice].offset / 8; + dst = (char *)dst_voices[voice].addr + dst_voices[voice].offset / 8; src_step = src_voices[voice].next / 8; dst_step = dst_voices[voice].next / 8; src_samples1 = src_samples; @@ -174,7 +204,12 @@ static void resample_shrink(snd_pcm_plugin_t *plugin, while (dst_samples1 > 0) { S1 = S2; if (src_samples1-- > 0) { - S2 = data->take(src); + goto *get; +#define GET16_END after_get +#include "plugin_ops.h" +#undef GET16_END + after_get: + S2 = sample; src += src_step; } if (pos & ~MASK) { @@ -184,7 +219,12 @@ static void resample_shrink(snd_pcm_plugin_t *plugin, val = -32768; else if (val > 32767) val = 32767; - data->put(dst, val); + sample = val; + goto *put; +#define PUT16_END after_put +#include "plugin_ops.h" +#undef PUT16_END + after_put: dst += dst_step; dst_samples1--; } @@ -192,8 +232,9 @@ static void resample_shrink(snd_pcm_plugin_t *plugin, } rvoices->last_S1 = S1; rvoices->last_S2 = S2; - data->pos = pos; + rvoices++; } + data->pos = pos; } static ssize_t rate_src_samples(snd_pcm_plugin_t *plugin, size_t samples) @@ -264,17 +305,30 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin, size_t samples) { size_t dst_samples; + int voice; + rate_t *data; - if (plugin == NULL || src_voices == NULL || src_voices == NULL || samples < 0) + if (plugin == NULL || src_voices == NULL || dst_voices == NULL) + return -EFAULT; + if (samples < 0) return -EINVAL; if (samples == 0) return 0; - dst_samples = rate_dst_samples(plugin, samples); - if (plugin->src_format.rate < plugin->dst_format.rate) { - resample_expand(plugin, src_voices, dst_voices, samples, dst_samples); - } else { - resample_shrink(plugin, src_voices, dst_voices, samples, dst_samples); + for (voice = 0; voice < plugin->src_format.voices; voice++) { + if (src_voices[voice].addr != NULL && + dst_voices[voice].addr == NULL) + return -EFAULT; + if (src_voices[voice].offset % 8 != 0 || + src_voices[voice].next % 8 != 0) + return -EINVAL; + if (dst_voices[voice].offset % 8 != 0 || + dst_voices[voice].next % 8 != 0) + return -EINVAL; } + + dst_samples = rate_dst_samples(plugin, samples); + data = (rate_t *)plugin->extra_data; + data->func(plugin, src_voices, dst_voices, samples, dst_samples); return dst_samples; } @@ -282,118 +336,34 @@ static int rate_action(snd_pcm_plugin_t *plugin, snd_pcm_plugin_action_t action, unsigned long udata) { - rate_t *data; - if (plugin == NULL) return -EINVAL; - data = (rate_t *)plugin->extra_data; switch (action) { case INIT: case PREPARE: case DRAIN: case FLUSH: - rate_init(plugin, data); + rate_init(plugin); break; } return 0; /* silenty ignore other actions */ } -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define my_little_swap16(x) (x) -#define my_little_swap32(x) (x) -#define my_big_swap16(x) bswap_16(x) -#define my_big_swap32(x) bswap_32(x) -#else -#define my_little_swap16(x) bswap_16(x) -#define my_little_swap32(x) bswap_32(x) -#define my_big_swap16(x) (x) -#define my_big_swap32(x) (x) -#endif - -RATE_TAKE_SAMPLE(s8, int8_t, smp << 8) -RATE_TAKE_SAMPLE(u8, int8_t, (smp << 8) ^ 0x8000) -RATE_TAKE_SAMPLE(s16_le, int16_t, my_little_swap16(smp)) -RATE_TAKE_SAMPLE(s16_be, int16_t, my_big_swap16(smp)) -RATE_TAKE_SAMPLE(u16_le, int16_t, my_little_swap16(smp) ^ 0x8000) -RATE_TAKE_SAMPLE(u16_be, int16_t, my_big_swap16(smp) ^ 0x8000) -RATE_TAKE_SAMPLE(s24_le, int32_t, my_little_swap32(smp) >> 8) -RATE_TAKE_SAMPLE(s24_be, int32_t, my_big_swap32(smp) >> 8) -RATE_TAKE_SAMPLE(u24_le, int32_t, (my_little_swap32(smp) >> 8) ^ 0x8000) -RATE_TAKE_SAMPLE(u24_be, int32_t, (my_big_swap32(smp) >> 8) ^ 0x8000) -RATE_TAKE_SAMPLE(s32_le, int32_t, my_little_swap32(smp) >> 16) -RATE_TAKE_SAMPLE(s32_be, int32_t, my_big_swap32(smp) >> 16) -RATE_TAKE_SAMPLE(u32_le, int32_t, (my_little_swap32(smp) >> 16) ^ 0x8000) -RATE_TAKE_SAMPLE(u32_be, int32_t, (my_big_swap32(smp) >> 16) ^ 0x8000) - -static take_sample_f rate_take_sample[] = { - [SND_PCM_SFMT_S8] rate_take_sample_s8, - [SND_PCM_SFMT_U8] rate_take_sample_u8, - [SND_PCM_SFMT_S16_LE] rate_take_sample_s16_le, - [SND_PCM_SFMT_S16_BE] rate_take_sample_s16_be, - [SND_PCM_SFMT_U16_LE] rate_take_sample_u16_le, - [SND_PCM_SFMT_U16_BE] rate_take_sample_u16_be, - [SND_PCM_SFMT_S24_LE] rate_take_sample_s24_le, - [SND_PCM_SFMT_S24_BE] rate_take_sample_s24_be, - [SND_PCM_SFMT_U24_LE] rate_take_sample_u24_le, - [SND_PCM_SFMT_U24_BE] rate_take_sample_u24_be, - [SND_PCM_SFMT_S32_LE] rate_take_sample_s32_le, - [SND_PCM_SFMT_S32_BE] rate_take_sample_s32_be, - [SND_PCM_SFMT_U32_LE] rate_take_sample_u32_le, - [SND_PCM_SFMT_U32_BE] rate_take_sample_u32_be -}; - -RATE_PUT_SAMPLE(s8, int8_t, smp >> 8) -RATE_PUT_SAMPLE(u8, int8_t, (smp >> 8) ^ 0x80) -RATE_PUT_SAMPLE(s16_le, int16_t, my_little_swap16(smp)) -RATE_PUT_SAMPLE(s16_be, int16_t, my_big_swap16(smp)) -RATE_PUT_SAMPLE(u16_le, int16_t, my_little_swap16(smp ^ 0x8000)) -RATE_PUT_SAMPLE(u16_be, int16_t, my_big_swap16(smp ^ 0x8000)) -RATE_PUT_SAMPLE(s24_le, int32_t, my_little_swap32(smp << 8)) -RATE_PUT_SAMPLE(s24_be, int32_t, my_big_swap32(smp << 8)) -RATE_PUT_SAMPLE(u24_le, int32_t, my_little_swap32((smp ^ 0x8000) >> 8)) -RATE_PUT_SAMPLE(u24_be, int32_t, my_big_swap32((smp ^ 0x8000) >> 8)) -RATE_PUT_SAMPLE(s32_le, int32_t, my_little_swap32(smp >> 16)) -RATE_PUT_SAMPLE(s32_be, int32_t, my_big_swap32(smp >> 16)) -RATE_PUT_SAMPLE(u32_le, int32_t, my_little_swap32((smp ^ 0x8000) >> 16)) -RATE_PUT_SAMPLE(u32_be, int32_t, my_big_swap32((smp ^ 0x8000) >> 16)) - -static put_sample_f rate_put_sample[] = { - [SND_PCM_SFMT_S8] rate_put_sample_s8, - [SND_PCM_SFMT_U8] rate_put_sample_u8, - [SND_PCM_SFMT_S16_LE] rate_put_sample_s16_le, - [SND_PCM_SFMT_S16_BE] rate_put_sample_s16_be, - [SND_PCM_SFMT_U16_LE] rate_put_sample_u16_le, - [SND_PCM_SFMT_U16_BE] rate_put_sample_u16_be, - [SND_PCM_SFMT_S24_LE] rate_put_sample_s24_le, - [SND_PCM_SFMT_S24_BE] rate_put_sample_s24_be, - [SND_PCM_SFMT_U24_LE] rate_put_sample_u24_le, - [SND_PCM_SFMT_U24_BE] rate_put_sample_u24_be, - [SND_PCM_SFMT_S32_LE] rate_put_sample_s32_le, - [SND_PCM_SFMT_S32_BE] rate_put_sample_s32_be, - [SND_PCM_SFMT_U32_LE] rate_put_sample_u32_le, - [SND_PCM_SFMT_U32_BE] rate_put_sample_u32_be -}; - int snd_pcm_plugin_build_rate(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 rate_private_data *data; + rate_t *data; snd_pcm_plugin_t *plugin; if (r_plugin == NULL) return -EINVAL; *r_plugin = NULL; - if (src_format->interleave != dst_format->interleave && - src_format->voices > 1) - return -EINVAL; - if (!dst_format->interleave) - return -EINVAL; if (src_format->voices != dst_format->voices) return -EINVAL; - if (dst_format->voices < 1) + if (src_format->voices < 1) return -EINVAL; if (snd_pcm_format_linear(src_format->format) <= 0) return -EINVAL; @@ -401,25 +371,27 @@ int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle, return -EINVAL; if (src_format->rate == dst_format->rate) return -EINVAL; + plugin = snd_pcm_plugin_build(handle, "rate conversion", src_format, dst_format, - sizeof(rate_t) + - src_format->voices * sizeof(rate_voice_t)); + sizeof(rate_t) + src_format->voices * sizeof(rate_voice_t)); if (plugin == NULL) return -ENOMEM; data = (rate_t *)plugin->extra_data; - data->plugin = plugin; - data->take = rate_take_sample[src_format->format]; - data->put = rate_put_sample[dst_format->format]; + data->get = getput_index(src_format->format); + data->put = getput_index(dst_format->format); + if (src_format->rate < dst_format->rate) { data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate; + data->func = resample_expand; } else { data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate; + data->func = resample_shrink; } data->pos = 0; - rate_init(plugin, data); + rate_init(plugin); data->old_src_samples = data->old_dst_samples = 0; plugin->transfer = rate_transfer; plugin->src_samples = rate_src_samples; diff --git a/src/pcm/plugin/route.c b/src/pcm/plugin/route.c index f5787dbf..5d08f9df 100644 --- a/src/pcm/plugin/route.c +++ b/src/pcm/plugin/route.c @@ -23,8 +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)) +#define my_calloc(size) snd_kmalloc(size, GFP_KERNEL) +#define my_free(ptr) snd_kfree(ptr) #else #include #include @@ -33,401 +33,576 @@ #include #include #include +#include #include "../pcm_local.h" +#define my_calloc(size) calloc(1, size) +#define my_free(ptr) free(ptr) #endif -#define ROUTE_PLUGIN_RESOLUTION 16 +typedef struct ttable_dst ttable_dst_t; +typedef struct route_private_data route_t; -struct route_private_data; +typedef void (*route_voice_f)(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voice, + ttable_dst_t* ttable, size_t samples); -typedef void (*route_f)(struct route_private_data *data, - void *src_ptr, void *dst_ptr, - size_t src_size, size_t dst_size); +typedef struct { + int voice; + int as_int; +#ifndef __KERNEL + float as_float; +#endif +} ttable_src_t; + +struct ttable_dst { + int att; /* Attenuated */ + int nsrcs; + ttable_src_t* srcs; + route_voice_f func; +}; struct route_private_data { - int sample_size; /* Bytes per sample */ - route_f func; - int interleave; - int format; - int src_voices; - int dst_voices; - int ttable[0]; + enum {INT32=0, INT64=1, FLOAT=2} sum_type; + int get, put; + int copy; + int src_sample_size; + ttable_dst_t ttable[0]; }; -static void route_noop(struct route_private_data *data, - void *src_ptr, void *dst_ptr, - size_t src_size, size_t dst_size) -{ - memcpy(dst_ptr, src_ptr, src_size); -} +typedef union { + int32_t as_int32; + int64_t as_int64; +#ifndef __KERNEL__ + float as_float; +#endif +} sum_t; -static void route_i_silence(struct route_private_data *data, - void *src_ptr, void *dst_ptr, - size_t src_size, size_t dst_size) + +void zero_voice(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *dst_voice, + size_t samples) { - char *src = src_ptr; - char *dst = dst_ptr; - int sil = snd_pcm_format_silence(data->format); - int src_step = data->sample_size * data->src_voices; - int dst_step = data->sample_size * data->dst_voices; - char *end = dst + dst_size; - if (data->src_voices < data->dst_voices) { - while (dst < end) { - int i; - for (i = 0; i < src_step; ++i) - *dst++ = *src++; - for (; i < dst_step; ++i) - *dst++ = sil; + char *dst = dst_voice->addr + dst_voice->offset / 8; + int dst_step = dst_voice->next / 8; + switch (plugin->dst_width) { + case 4: { + int dstbit = dst_voice->offset % 8; + int dstbit_step = dst_voice->next % 8; + while (samples-- > 0) { + if (dstbit) + *dst &= 0x0f; + else + *dst &= 0xf0; + dst += dst_step; + dstbit += dstbit_step; + if (dstbit == 8) { + dst++; + dstbit = 0; + } + } + break; + } + case 8: + while (samples-- > 0) { + *dst = 0; + dst += dst_step; + } + break; + case 16: + while (samples-- > 0) { + *(int16_t*)dst = 0; + dst += dst_step; + } + break; + case 32: + while (samples-- > 0) { + *(int32_t*)dst = 0; + dst += dst_step; } - } else { - while (dst < end) { - int i; - for (i = 0; i < dst_step; ++i) - *dst++ = *src++; - src += src_step - dst_step; + break; + case 64: + while (samples-- > 0) { + *(int64_t*)dst = 0; + dst += dst_step; } + break; } } -static void route_n_silence(struct route_private_data *data, - void *src_ptr, void *dst_ptr, - size_t src_size, size_t dst_size) + +static void route_to_voice_zero(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voice, + ttable_dst_t* ttable, size_t samples) { - if (src_size < dst_size) { - memcpy(dst_ptr, src_ptr, src_size); - memset(dst_ptr + src_size, snd_pcm_format_silence(data->format), dst_size - src_size); - } else { - memcpy(dst_ptr, src_ptr, dst_size); - } +// null_voice(&dst_voices[voice]); + zero_voice(plugin, dst_voice, samples); } -#define ROUTE_I_FUNC(name, type, ttype, toh, hto, mul, div) \ -static void name(struct route_private_data *data, \ - void *src_ptr, void *dst_ptr, \ - size_t src_size, size_t dst_size) \ -{ \ - type *src = src_ptr; \ - type *dst = dst_ptr; \ - int src_voices = data->src_voices; \ - int dst_voices = data->dst_voices; \ - int *ttable = data->ttable; \ - size_t samples = src_size / (src_voices * data->sample_size); \ - while (samples-- > 0) { \ - int dst_voice; \ - int *ttp = ttable; \ - for (dst_voice = 0; dst_voice < dst_voices; ++dst_voice) { \ - int src_voice; \ - type *s = src; \ - ttype t = 0; \ - for (src_voice = 0; src_voice < src_voices; ++src_voice) { \ - ttype v = toh(*s); \ - t += mul(v, *ttp); \ - s++; \ - ttp++; \ - } \ - t = div(t, ROUTE_PLUGIN_RESOLUTION); \ - *dst++ = hto(t); \ - } \ - src += src_voices; \ - } \ -} +static void route_to_voice_one(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voice, + ttable_dst_t* ttable, size_t samples) +{ +#define COPY_LABELS +#include "plugin_ops.h" +#undef COPY_LABELS + route_t *data = (route_t *)plugin->extra_data; + void *copy; + const snd_pcm_plugin_voice_t *src_voice = 0; + int srcidx; + char *src, *dst; + int src_step, dst_step; + for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) { + src_voice = &src_voices[ttable->srcs[srcidx].voice]; + if (src_voice->addr != NULL) + break; + } + if (srcidx == ttable->nsrcs) { + route_to_voice_zero(plugin, src_voices, dst_voice, ttable, samples); + return; + } -#define ROUTE_N_FUNC(name, type, ttype, toh, hto, mul, div) \ -static void name(struct route_private_data *data, \ - void *src_ptr, void *dst_ptr, \ - size_t src_size, size_t dst_size) \ -{ \ - type *src = src_ptr; \ - type *dst = dst_ptr; \ - int src_voices = data->src_voices; \ - int dst_voices = data->dst_voices; \ - int *ttable = data->ttable; \ - size_t samples = src_size / (src_voices * data->sample_size); \ - int dst_voice; \ - for (dst_voice = 0; dst_voice < dst_voices; ++dst_voice) { \ - int *ttp = ttable + dst_voice * src_voices; \ - size_t samples1 = samples; \ - while (samples1-- > 0) { \ - int *ttp1 = ttp; \ - type *s = src; \ - ttype t = 0; \ - int src_voice; \ - for (src_voice = 0; src_voice < src_voices; ++src_voice) { \ - ttype v = toh(*s); \ - t += mul(v, *ttp1); \ - s += samples; \ - ttp1++; \ - } \ - t = div(t, ROUTE_PLUGIN_RESOLUTION); \ - *dst++ = hto(t); \ - src++; \ - } \ - } \ + copy = copy_labels[data->copy]; + src = src_voice->addr + src_voice->offset / 8; + src_step = src_voice->next / 8; + dst = dst_voice->addr + dst_voice->offset / 8; + dst_step = dst_voice->next / 8; + while (samples-- > 0) { + goto *copy; +#define COPY_END after +#include "plugin_ops.h" +#undef COPY_END + after: + src += src_step; + dst += dst_step; + } } -#define none(p) (p) -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define le16toh none -#define htole16 none -#define le32toh none -#define htole32 none -#define be16toh bswap_16 -#define htobe16 bswap_16 -#define be32toh bswap_32 -#define htobe32 bswap_32 -#elif __BYTE_ORDER == __BIG_ENDIAN -#define le16toh bswap_16 -#define htole16 bswap_16 -#define le32toh bswap_32 -#define htole32 bswap_32 -#define be16toh none -#define htobe16 none -#define be32toh none -#define htobe32 none -#else -#error "Unsupported endian..." +static void route_to_voice(snd_pcm_plugin_t *plugin, + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voice, + ttable_dst_t* ttable, size_t samples) +{ +#define GET_LABELS +#define PUT32_LABELS +#include "plugin_ops.h" +#undef GET_LABELS +#undef PUT32_LABELS + static void *zero_labels[3] = { &&zero_int32, &&zero_int64, +#ifndef __KERNEL__ + &&zero_float +#endif + }; + /* sum_type att */ + static void *add_labels[3 * 2] = { &&add_int32_noatt, &&add_int32_att, + &&add_int64_noatt, &&add_int64_att, +#ifndef __KERNEL__ + &&add_float_noatt, &&add_float_att +#endif + }; + /* sum_type att shift */ + static void *norm_labels[3 * 2 * 4] = { 0, + &&norm_int32_8_noatt, + &&norm_int32_16_noatt, + &&norm_int32_24_noatt, + 0, + &&norm_int32_8_att, + &&norm_int32_16_att, + &&norm_int32_24_att, + &&norm_int64_0_noatt, + &&norm_int64_8_noatt, + &&norm_int64_16_noatt, + &&norm_int64_24_noatt, + &&norm_int64_0_att, + &&norm_int64_8_att, + &&norm_int64_16_att, + &&norm_int64_24_att, +#ifndef __KERNEL__ + &&norm_float_0, + &&norm_float_8, + &&norm_float_16, + &&norm_float_24, + &&norm_float_0, + &&norm_float_8, + &&norm_float_16, + &&norm_float_24, #endif + }; + route_t *data = (route_t *)plugin->extra_data; + void *zero, *get, *add, *norm, *put32; + int nsrcs = ttable->nsrcs; + char *dst; + int dst_step; + char *srcs[nsrcs]; + int src_steps[nsrcs]; + ttable_src_t src_tt[nsrcs]; + int32_t sample = 0; + int srcidx, srcidx1 = 0; + for (srcidx = 0; srcidx < nsrcs; ++srcidx) { + const snd_pcm_plugin_voice_t *src_voice = &src_voices[ttable->srcs[srcidx].voice]; + if (src_voice->addr == NULL) + continue; + srcs[srcidx1] = src_voice->addr + src_voices->offset / 8; + src_steps[srcidx1] = src_voice->next / 8; + src_tt[srcidx1] = ttable->srcs[srcidx]; + srcidx1++; + } + nsrcs = srcidx1; + if (nsrcs == 0) { + route_to_voice_zero(plugin, src_voices, dst_voice, ttable, samples); + return; + } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) { + route_to_voice_one(plugin, src_voices, dst_voice, ttable, samples); + return; + } -#define mul(a,b) ((a)*(b)) -#define div(a,b) ((a)/(b)) -#define nmul(a,b) ((b)?(a):0) -#define ndiv(a,b) (a) - -#define FUNCS(name, type, ttype, toh, hto) \ -ROUTE_I_FUNC(aroute_i_##name, type, ttype, toh, hto, mul, div); \ -ROUTE_N_FUNC(aroute_n_##name, type, ttype, toh, hto, mul, div); \ -ROUTE_I_FUNC(nroute_i_##name, type, ttype, toh, hto, nmul, ndiv); \ -ROUTE_N_FUNC(nroute_n_##name, type, ttype, toh, hto, nmul, ndiv); - - -FUNCS(s8, int8_t, int, none, none); -FUNCS(u8, u_int8_t, int, none, none); -FUNCS(s16_le, int16_t, int, le16toh,htole16); -FUNCS(u16_le, u_int16_t, int, le16toh,htole16); -FUNCS(s16_be, int16_t, int, be16toh,htobe16); -FUNCS(u16_be, u_int16_t, int, be16toh,htobe16); -FUNCS(s24_le, int32_t, int, le32toh,htole32); -FUNCS(u24_le, u_int32_t, int, le32toh,htole32); -FUNCS(s24_be, int32_t, int, be32toh,htobe32); -FUNCS(u24_be, u_int32_t, int, be32toh,htobe32); -FUNCS(s32_le, int32_t, int64_t,le32toh,htole32); -FUNCS(u32_le, u_int32_t, int64_t,le32toh,htole32); -FUNCS(s32_be, int32_t, int64_t,be32toh,htobe32); -FUNCS(u32_be, u_int32_t, int64_t,be32toh,htobe32); - - -static route_f aroute_i[] = { - [SND_PCM_SFMT_S8] aroute_i_s8, - [SND_PCM_SFMT_U8] aroute_i_u8, - [SND_PCM_SFMT_S16_LE] aroute_i_s16_le, - [SND_PCM_SFMT_S16_BE] aroute_i_s16_be, - [SND_PCM_SFMT_U16_LE] aroute_i_u16_le, - [SND_PCM_SFMT_U16_BE] aroute_i_u16_be, - [SND_PCM_SFMT_S24_LE] aroute_i_s24_le, - [SND_PCM_SFMT_S24_BE] aroute_i_s24_be, - [SND_PCM_SFMT_U24_LE] aroute_i_u24_le, - [SND_PCM_SFMT_U24_BE] aroute_i_u24_be, - [SND_PCM_SFMT_S32_LE] aroute_i_s32_le, - [SND_PCM_SFMT_S32_BE] aroute_i_s32_be, - [SND_PCM_SFMT_U32_LE] aroute_i_u32_le, - [SND_PCM_SFMT_U32_BE] aroute_i_u32_be -}; + zero = zero_labels[data->sum_type]; + get = get_labels[data->get]; + add = add_labels[data->sum_type * 2 + ttable->att]; + norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size]; + put32 = put32_labels[data->put]; + dst = dst_voice->addr + dst_voice->offset / 8; + dst_step = dst_voice->next / 8; -static route_f aroute_n[] = { - [SND_PCM_SFMT_S8] aroute_n_s8, - [SND_PCM_SFMT_U8] aroute_n_u8, - [SND_PCM_SFMT_S16_LE] aroute_n_s16_le, - [SND_PCM_SFMT_S16_BE] aroute_n_s16_be, - [SND_PCM_SFMT_U16_LE] aroute_n_u16_le, - [SND_PCM_SFMT_U16_BE] aroute_n_u16_be, - [SND_PCM_SFMT_S24_LE] aroute_n_s24_le, - [SND_PCM_SFMT_S24_BE] aroute_n_s24_be, - [SND_PCM_SFMT_U24_LE] aroute_n_u24_le, - [SND_PCM_SFMT_U24_BE] aroute_n_u24_be, - [SND_PCM_SFMT_S32_LE] aroute_n_s32_le, - [SND_PCM_SFMT_S32_BE] aroute_n_s32_be, - [SND_PCM_SFMT_U32_LE] aroute_n_u32_le, - [SND_PCM_SFMT_U32_BE] aroute_n_u32_be -}; + while (samples-- > 0) { + ttable_src_t *ttp = src_tt; + sum_t sum; -static route_f nroute_i[] = { - [SND_PCM_SFMT_S8] nroute_i_s8, - [SND_PCM_SFMT_U8] nroute_i_u8, - [SND_PCM_SFMT_S16_LE] nroute_i_s16_le, - [SND_PCM_SFMT_S16_BE] nroute_i_s16_be, - [SND_PCM_SFMT_U16_LE] nroute_i_u16_le, - [SND_PCM_SFMT_U16_BE] nroute_i_u16_be, - [SND_PCM_SFMT_S24_LE] nroute_i_s24_le, - [SND_PCM_SFMT_S24_BE] nroute_i_s24_be, - [SND_PCM_SFMT_U24_LE] nroute_i_u24_le, - [SND_PCM_SFMT_U24_BE] nroute_i_u24_be, - [SND_PCM_SFMT_S32_LE] nroute_i_s32_le, - [SND_PCM_SFMT_S32_BE] nroute_i_s32_be, - [SND_PCM_SFMT_U32_LE] nroute_i_u32_le, - [SND_PCM_SFMT_U32_BE] nroute_i_u32_be -}; + /* Zero sum */ + goto *zero; + zero_int32: + sum.as_int32 = 0; + goto zero_end; + zero_int64: + sum.as_int64 = 0; + goto zero_end; +#ifndef __KERNEL__ + zero_float: + sum.as_float = 0.0; + goto zero_end; +#endif + zero_end: + for (srcidx = 0; srcidx < nsrcs; ++srcidx) { + char *src = srcs[srcidx]; + + /* Get sample */ + goto *get; +#define GET_END after_get +#include "plugin_ops.h" +#undef GET_END + after_get: -static route_f nroute_n[] = { - [SND_PCM_SFMT_S8] nroute_n_s8, - [SND_PCM_SFMT_U8] nroute_n_u8, - [SND_PCM_SFMT_S16_LE] nroute_n_s16_le, - [SND_PCM_SFMT_S16_BE] nroute_n_s16_be, - [SND_PCM_SFMT_U16_LE] nroute_n_u16_le, - [SND_PCM_SFMT_U16_BE] nroute_n_u16_be, - [SND_PCM_SFMT_S24_LE] nroute_n_s24_le, - [SND_PCM_SFMT_S24_BE] nroute_n_s24_be, - [SND_PCM_SFMT_U24_LE] nroute_n_u24_le, - [SND_PCM_SFMT_U24_BE] nroute_n_u24_be, - [SND_PCM_SFMT_S32_LE] nroute_n_s32_le, - [SND_PCM_SFMT_S32_BE] nroute_n_s32_be, - [SND_PCM_SFMT_U32_LE] nroute_n_u32_le, - [SND_PCM_SFMT_U32_BE] nroute_n_u32_be -}; + /* Sum */ + goto *add; + add_int32_att: + sum.as_int32 += sample * ttp->as_int; + goto after_sum; + add_int32_noatt: + if (ttp->as_int) + sum.as_int32 += sample; + goto after_sum; + add_int64_att: + sum.as_int64 += (int64_t) sample * ttp->as_int; + goto after_sum; + add_int64_noatt: + if (ttp->as_int) + sum.as_int64 += sample; + goto after_sum; +#ifndef __KERNEL__ + add_float_att: + sum.as_float += sample * ttp->as_float; + goto after_sum; + add_float_noatt: + if (ttp->as_int) + sum.as_float += sample; + goto after_sum; +#endif + after_sum: + srcs[srcidx] += src_steps[srcidx]; + ttp++; + } + + /* Normalization */ + goto *norm; + norm_int32_8_att: + sum.as_int64 = sum.as_int32; + sum.as_int64 *= (1 << 8) / ROUTE_PLUGIN_RESOLUTION; + goto after_norm; + norm_int32_16_att: + sum.as_int64 = sum.as_int32; + sum.as_int64 *= (1 << 16) / ROUTE_PLUGIN_RESOLUTION; + goto after_norm; + norm_int32_24_att: + sum.as_int64 = sum.as_int32; + sum.as_int64 *= (1 << 24) / ROUTE_PLUGIN_RESOLUTION; + goto norm_int; + norm_int64_0_att: + sum.as_int64 /= ROUTE_PLUGIN_RESOLUTION; + goto norm_int; + norm_int64_8_att: + sum.as_int64 *= (1 << 8) / ROUTE_PLUGIN_RESOLUTION; + goto norm_int; + norm_int64_16_att: + sum.as_int64 *= (1 << 16) / ROUTE_PLUGIN_RESOLUTION; + goto norm_int; + norm_int64_24_att: + sum.as_int64 *= (1 << 24) / ROUTE_PLUGIN_RESOLUTION; + goto norm_int; + norm_int32_8_noatt: + sum.as_int64 = sum.as_int32; + sum.as_int64 *= (1 << 8); + goto after_norm; + norm_int32_16_noatt: + sum.as_int64 = sum.as_int32; + sum.as_int64 *= (1 << 16); + goto after_norm; + norm_int32_24_noatt: + sum.as_int64 = sum.as_int32; + sum.as_int64 *= (1 << 24); + goto norm_int; + norm_int64_0_noatt: + goto norm_int; + norm_int64_8_noatt: + sum.as_int64 *= (1 << 8); + goto norm_int; + norm_int64_16_noatt: + sum.as_int64 *= (1 << 16); + goto norm_int; + norm_int64_24_noatt: + sum.as_int64 *= (1 << 24); + goto norm_int; + norm_int: + if (sum.as_int64 < (int32_t)0x80000000) + sample = (int32_t)0x80000000; + else if (sum.as_int64 > 0x7fffffffLL) { + sample = 0x7fffffff; + } + else + sample = sum.as_int64; + goto after_norm; +#ifndef __KERNEL__ + norm_float_8: + sum.as_float *= 1 << 8; + goto norm_float; + norm_float_16: + sum.as_float *= 1 << 16; + goto norm_float; + norm_float_24: + sum.as_float *= 1 << 24; + goto norm_float; + norm_float_0: + norm_float: + sum.as_float = floor(sum.as_float + 0.5); + if (sum.as_float < (int32_t)0x80000000) + sample = (int32_t)0x80000000; + else if (sum.as_float > 0x7fffffff) + sample = 0x7fffffff; + else + sample = sum.as_float; + goto after_norm; +#endif + after_norm: + + /* Put sample */ + goto *put32; +#define PUT32_END after_put32 +#include "plugin_ops.h" +#undef PUT32_END + after_put32: + + dst += dst_step; + } +} -static int route_load_ttable(struct route_private_data *data, - const int *src_ttable) +#ifdef __KERNEL__ +#define FULL ROUTE_PLUGIN_RESOLUTION +typedef int src_ttable_entry_t; +#else +#define FULL 1.0 +typedef float src_ttable_entry_t; +#endif + +static void route_free(snd_pcm_plugin_t *plugin, void* private_data) { + route_t *data = (route_t *)plugin->extra_data; + int dst_voice; + for (dst_voice = 0; dst_voice < plugin->dst_format.voices; ++dst_voice) { + if (data->ttable[dst_voice].srcs != NULL) + my_free(data->ttable[dst_voice].srcs); + } +} + +static int route_load_ttable(snd_pcm_plugin_t *plugin, + const src_ttable_entry_t* src_ttable) +{ + route_t *data; int src_voice, dst_voice; - const int *sptr; - int *dptr; - int noop = 1; - int noatt = 1; + const src_ttable_entry_t *sptr; + ttable_dst_t *dptr; if (src_ttable == NULL) return 0; + data = (route_t *)plugin->extra_data; dptr = data->ttable; sptr = src_ttable; - for (dst_voice = 0; dst_voice < data->dst_voices; ++dst_voice) { - int t = 0; - for (src_voice = 0; src_voice < data->src_voices; ++src_voice) { - if (*sptr < 0 || *sptr > ROUTE_PLUGIN_RESOLUTION) + plugin->private_free = route_free; + for (dst_voice = 0; dst_voice < plugin->dst_format.voices; ++dst_voice) { + src_ttable_entry_t t = 0; + int att = 0; + int nsrcs = 0; + ttable_src_t srcs[plugin->src_format.voices]; + for (src_voice = 0; src_voice < plugin->src_format.voices; ++src_voice) { + if (*sptr < 0 || *sptr > FULL) return -EINVAL; - if (*sptr != 0 && *sptr != ROUTE_PLUGIN_RESOLUTION) - noatt = 0; - if (src_voice == dst_voice) { - if (*sptr != ROUTE_PLUGIN_RESOLUTION) - noop = 0; - } - else { - if (*sptr != 0) - noop = 0; + if (*sptr != 0) { + srcs[nsrcs].voice = src_voice; +#ifdef __KERNEL__ + srcs[nsrcs].as_int = *sptr; +#else + /* Also in user space for non attenuated */ + srcs[nsrcs].as_int = (*sptr == FULL ? ROUTE_PLUGIN_RESOLUTION : 0); + srcs[nsrcs].as_float = *sptr; +#endif + if (*sptr != FULL) + att = 1; + t += *sptr; + nsrcs++; } - t += *sptr; - *dptr++ = *sptr++; + sptr++; } #if 0 - if (t > ROUTE_PLUGIN_RESOLUTION) + if (t > FULL) return -EINVAL; #endif - } - if (noop) { - if (data->src_voices == data->dst_voices) - data->func = route_noop; - else if (data->interleave) - data->func = route_i_silence; - else - data->func = route_n_silence; - return 0; - } - if (noatt) { - if (data->interleave) - data->func = nroute_i[data->format]; - else - data->func = nroute_n[data->format]; - } else { - if (data->interleave) - data->func = aroute_i[data->format]; - else - data->func = aroute_n[data->format]; + dptr->att = att; + dptr->nsrcs = nsrcs; + switch (nsrcs) { + case 0: + dptr->func = route_to_voice_zero; + break; + case 1: + dptr->func = route_to_voice_one; + break; + default: + dptr->func = route_to_voice; + break; + } + dptr->srcs = my_calloc(sizeof(*srcs) * nsrcs); + memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs); + dptr++; } return 0; } static ssize_t route_transfer(snd_pcm_plugin_t *plugin, - char *src_ptr, size_t src_size, - char *dst_ptr, size_t dst_size) + const snd_pcm_plugin_voice_t *src_voices, + const snd_pcm_plugin_voice_t *dst_voices, + size_t samples) { - struct route_private_data *data; - if (plugin == NULL || src_ptr == NULL || src_size < 0 || - dst_ptr == NULL || dst_size < 0) + route_t *data; + int src_nvoices, dst_nvoices; + int src_voice, dst_voice; + ttable_dst_t *ttp; + const snd_pcm_plugin_voice_t *dvp; + + if (plugin == NULL || src_voices == NULL || dst_voices == NULL) + return -EFAULT; + if (samples < 0) return -EINVAL; - if (src_size == 0) + if (samples == 0) return 0; - data = (struct route_private_data *)plugin->extra_data; - data->func(data, src_ptr, dst_ptr, src_size, dst_size); - return dst_size; -} + data = (route_t *)plugin->extra_data; -static ssize_t route_src_size(snd_pcm_plugin_t *plugin, size_t size) -{ - struct route_private_data *data; + src_nvoices = plugin->src_format.voices; + for (src_voice = 0; src_voice < src_nvoices; ++src_voice) { + if (src_voices[src_voice].offset % 8 != 0 || + src_voices[src_voice].next % 8 != 0) + return -EINVAL; + } - if (plugin == NULL || size <= 0) - return -EINVAL; - data = (struct route_private_data *)snd_pcm_plugin_extra_data(plugin); - if (!plugin || size <= 0) - return -EINVAL; - return (size * data->src_voices) / data->dst_voices; + dst_nvoices = plugin->dst_format.voices; + for (dst_voice = 0; dst_voice < dst_nvoices; ++dst_voice) { + if (dst_voices[dst_voice].offset % 8 != 0 || + dst_voices[dst_voice].next % 8 != 0) + return -EINVAL; + } + + ttp = data->ttable; + dvp = dst_voices; + for (dst_voice = 0; dst_voice < dst_nvoices; ++dst_voice) { + ttp->func(plugin, src_voices, dvp, ttp, samples); + dvp++; + ttp++; + } + return samples; } -static ssize_t route_dst_size(snd_pcm_plugin_t *plugin, size_t size) +int getput_index(int format) { - struct route_private_data *data; - - if (plugin == NULL || size <= 0) - return -EINVAL; - data = (struct route_private_data *)snd_pcm_plugin_extra_data(plugin); - if (!plugin || size <= 0) - return -EINVAL; - return (size * data->dst_voices) / data->src_voices; + int sign, width, endian; + sign = !snd_pcm_format_signed(format); + width = snd_pcm_format_width(format) / 8 - 1; +#if __BYTE_ORDER == __LITTLE_ENDIAN + endian = snd_pcm_format_big_endian(format); +#elif __BYTE_ORDER == __BIG_ENDIAN + endian = snd_pcm_format_little_endian(format); +#else +#error "Unsupported endian..." +#endif + if (endian < 0) + endian = 0; + return width * 4 + endian * 2 + sign; } -int snd_pcm_plugin_build_route(snd_pcm_format_t *src_format, - snd_pcm_format_t *dst_format, - int *ttable, - snd_pcm_plugin_t **r_plugin) +int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle, + snd_pcm_format_t *src_format, + snd_pcm_format_t *dst_format, + src_ttable_entry_t *ttable, + snd_pcm_plugin_t **r_plugin) { - struct route_private_data *data; + route_t *data; snd_pcm_plugin_t *plugin; - int size; int err; if (!r_plugin) - return -EINVAL; + return -EFAULT; *r_plugin = NULL; - if (src_format->interleave != dst_format->interleave) - return -EINVAL; - if (!dst_format->interleave) - return -EINVAL; - if (src_format->format != dst_format->format) - return -EINVAL; - if (!snd_pcm_format_linear(src_format->format)) - return -EINVAL; if (src_format->rate != dst_format->rate) return -EINVAL; - if (src_format->voices < 1 || dst_format->voices < 1) - return -EINVAL; - size = snd_pcm_format_size(src_format->format, 1); - if (size < 0) + if (!(snd_pcm_format_linear(src_format->format) && + snd_pcm_format_linear(dst_format->format))) return -EINVAL; - plugin = snd_pcm_plugin_build("Volume/balance conversion", - sizeof(struct route_private_data) + - sizeof(data->ttable[0]) * src_format->voices * dst_format->voices); + + plugin = snd_pcm_plugin_build(handle, + "attenuated route conversion", + src_format, + dst_format, + sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->voices); if (plugin == NULL) return -ENOMEM; - data = (struct route_private_data *)plugin->extra_data; - - data->src_voices = src_format->voices; - data->dst_voices = dst_format->voices; - data->format = src_format->format; - data->interleave = src_format->interleave; - data->sample_size = size; - if ((err = route_load_ttable(data, ttable)) < 0) { + + data = (route_t *) plugin->extra_data; + + data->get = getput_index(src_format->format); + data->put = getput_index(dst_format->format); + data->copy = copy_index(src_format->format, dst_format->format); + +#ifdef __KERNEL__ + if (snd_pcm_format_width(src_format->format) == 32) + data->sum_type = INT64; + else + data->sum_type = INT32; +#else + data->sum_type = FLOAT; +#endif + data->src_sample_size = snd_pcm_format_width(src_format->format) / 8; + + if ((err = route_load_ttable(plugin, ttable)) < 0) { snd_pcm_plugin_free(plugin); return err; } plugin->transfer = route_transfer; - plugin->src_size = route_src_size; - plugin->dst_size = route_dst_size; *r_plugin = plugin; return 0; } -- 2.47.1