Enhanced bitmasks in PCM - added support for more formats by Takashi and me

This commit is contained in:
Jaroslav Kysela 2002-06-26 02:04:11 +00:00
parent 84730c976f
commit 16b3bf447c
14 changed files with 893 additions and 162 deletions

View file

@ -160,7 +160,31 @@ typedef enum _snd_pcm_format {
SND_PCM_FORMAT_GSM,
/** Special */
SND_PCM_FORMAT_SPECIAL = 31,
SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_SPECIAL,
/** Signed 24bit Little Endian in 3bytes format */
SND_PCM_FORMAT_S24_3LE = 32,
/** Signed 24bit Big Endian in 3bytes format */
SND_PCM_FORMAT_S24_3BE,
/** Unsigned 24bit Little Endian in 3bytes format */
SND_PCM_FORMAT_U24_3LE,
/** Unsigned 24bit Big Endian in 3bytes format */
SND_PCM_FORMAT_U24_3BE,
/** Signed 20bit Little Endian in 3bytes format */
SND_PCM_FORMAT_S20_3LE,
/** Signed 20bit Big Endian in 3bytes format */
SND_PCM_FORMAT_S20_3BE,
/** Unsigned 20bit Little Endian in 3bytes format */
SND_PCM_FORMAT_U20_3LE,
/** Unsigned 20bit Big Endian in 3bytes format */
SND_PCM_FORMAT_U20_3BE,
/** Signed 18bit Little Endian in 3bytes format */
SND_PCM_FORMAT_S18_3LE,
/** Signed 18bit Big Endian in 3bytes format */
SND_PCM_FORMAT_S18_3BE,
/** Unsigned 18bit Little Endian in 3bytes format */
SND_PCM_FORMAT_U18_3LE,
/** Unsigned 18bit Big Endian in 3bytes format */
SND_PCM_FORMAT_U18_3BE,
SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_U18_3BE,
#if __BYTE_ORDER == __LITTLE_ENDIAN
/** Signed 16 bit CPU endian */
@ -817,7 +841,7 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format);
int snd_pcm_format_cpu_endian(snd_pcm_format_t format);
int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */
int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */
snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian);
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
u_int8_t snd_pcm_format_silence(snd_pcm_format_t format);
u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format);

View file

@ -21,7 +21,7 @@
typedef struct _snd_mask snd_mask_t;
#define SND_MASK_MAX 31
#define SND_MASK_MAX 64
#ifdef SND_MASK_INLINE
#include "mask_inline.h"

View file

@ -23,15 +23,11 @@
#define MASK_INLINE static inline
#ifndef MASK_MASK
#define MASK_MAX 31
#endif
#define MASK_MAX SND_MASK_MAX
#define MASK_SIZE (MASK_MAX / 32)
struct _snd_mask {
unsigned int bits;
};
#define snd_mask_bits(mask) ((mask)->bits)
#define MASK_OFS(i) ((i) >> 5)
#define MASK_BIT(i) (1U << ((i) & 31))
MASK_INLINE unsigned int ld2(u_int32_t v)
{
@ -74,106 +70,143 @@ MASK_INLINE size_t snd_mask_sizeof(void)
MASK_INLINE void snd_mask_none(snd_mask_t *mask)
{
snd_mask_bits(mask) = 0;
memset(mask, 0, sizeof(*mask));
}
MASK_INLINE void snd_mask_any(snd_mask_t *mask)
{
snd_mask_bits(mask) = ~0U;
}
MASK_INLINE void snd_mask_load(snd_mask_t *mask, unsigned int msk)
{
snd_mask_bits(mask) = msk;
memset(mask, 0xff, MASK_SIZE * 4);
}
MASK_INLINE int snd_mask_empty(const snd_mask_t *mask)
{
return snd_mask_bits(mask) == 0;
int i;
for (i = 0; i < MASK_SIZE; i++)
if (mask->bits[i])
return 0;
return 1;
}
MASK_INLINE int snd_mask_full(const snd_mask_t *mask)
{
return snd_mask_bits(mask) == ~0U;
int i;
for (i = 0; i < MASK_SIZE; i++)
if (mask->bits[i] != 0xffffffff)
return 0;
return 1;
}
MASK_INLINE unsigned int snd_mask_count(const snd_mask_t *mask)
{
return hweight32(snd_mask_bits(mask));
int i, w = 0;
for (i = 0; i < MASK_SIZE; i++)
w += hweight32(mask->bits[i]);
return w;
}
MASK_INLINE unsigned int snd_mask_min(const snd_mask_t *mask)
{
int i;
assert(!snd_mask_empty(mask));
return ffs(snd_mask_bits(mask)) - 1;
for (i = 0; i < MASK_SIZE; i++) {
if (mask->bits[i])
return ffs(mask->bits[i]) - 1 + (i << 5);
}
return 0;
}
MASK_INLINE unsigned int snd_mask_max(const snd_mask_t *mask)
{
int i;
assert(!snd_mask_empty(mask));
return ld2(snd_mask_bits(mask));
for (i = MASK_SIZE - 1; i >= 0; i--) {
if (mask->bits[i])
return ld2(mask->bits[i]) + (i << 5);
}
return 0;
}
MASK_INLINE void snd_mask_set(snd_mask_t *mask, unsigned int val)
{
assert(val <= SND_MASK_MAX);
snd_mask_bits(mask) |= (1U << val);
mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
}
MASK_INLINE void snd_mask_reset(snd_mask_t *mask, unsigned int val)
{
assert(val <= SND_MASK_MAX);
snd_mask_bits(mask) &= ~(1U << val);
mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
}
MASK_INLINE void snd_mask_set_range(snd_mask_t *mask, unsigned int from, unsigned int to)
{
unsigned int i;
assert(to <= SND_MASK_MAX && from <= to);
snd_mask_bits(mask) |= ((1U << (from - to + 1)) - 1) << from;
for (i = from; i <= to; i++)
mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
}
MASK_INLINE void snd_mask_reset_range(snd_mask_t *mask, unsigned int from, unsigned int to)
{
unsigned int i;
assert(to <= SND_MASK_MAX && from <= to);
snd_mask_bits(mask) &= ~(((1U << (from - to + 1)) - 1) << from);
for (i = from; i <= to; i++)
mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
}
MASK_INLINE void snd_mask_leave(snd_mask_t *mask, unsigned int val)
{
unsigned int v;
assert(val <= SND_MASK_MAX);
snd_mask_bits(mask) &= 1U << val;
v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
snd_mask_none(mask);
mask->bits[MASK_OFS(val)] = v;
}
MASK_INLINE void snd_mask_intersect(snd_mask_t *mask, const snd_mask_t *v)
{
snd_mask_bits(mask) &= snd_mask_bits(v);
int i;
for (i = 0; i < MASK_SIZE; i++)
mask->bits[i] &= v->bits[i];
}
MASK_INLINE void snd_mask_union(snd_mask_t *mask, const snd_mask_t *v)
{
snd_mask_bits(mask) |= snd_mask_bits(v);
int i;
for (i = 0; i < MASK_SIZE; i++)
mask->bits[i] |= v->bits[i];
}
MASK_INLINE int snd_mask_eq(const snd_mask_t *mask, const snd_mask_t *v)
{
return snd_mask_bits(mask) == snd_mask_bits(v);
return ! memcmp(mask, v, MASK_SIZE * 4);
}
MASK_INLINE void snd_mask_copy(snd_mask_t *mask, const snd_mask_t *v)
{
snd_mask_bits(mask) = snd_mask_bits(v);
*mask = *v;
}
MASK_INLINE int snd_mask_test(const snd_mask_t *mask, unsigned int val)
{
assert(val <= SND_MASK_MAX);
return snd_mask_bits(mask) & (1U << val);
return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
}
MASK_INLINE int snd_mask_single(const snd_mask_t *mask)
{
int i, c = 0;
assert(!snd_mask_empty(mask));
return !(snd_mask_bits(mask) & (snd_mask_bits(mask) - 1));
for (i = 0; i < MASK_SIZE; i++) {
if (! mask->bits[i])
continue;
if (mask->bits[i] & (mask->bits[i] - 1))
return 0;
if (c)
return 0;
c++;
}
return 1;
}
MASK_INLINE int snd_mask_refine(snd_mask_t *mask, const snd_mask_t *v)
@ -252,5 +285,9 @@ MASK_INLINE int snd_mask_always_eq(const snd_mask_t *m1, const snd_mask_t *m2)
MASK_INLINE int snd_mask_never_eq(const snd_mask_t *m1, const snd_mask_t *m2)
{
return (snd_mask_bits(m1) & snd_mask_bits(m2)) == 0;
int i;
for (i = 0; i < MASK_SIZE; i++)
if (m1->bits[i] & m2->bits[i])
return 0;
return 1;
}

View file

@ -1200,6 +1200,18 @@ static const char *snd_pcm_format_names[] = {
FORMAT(MPEG),
FORMAT(GSM),
FORMAT(SPECIAL),
FORMAT(S24_3LE),
FORMAT(S24_3BE),
FORMAT(U24_3LE),
FORMAT(U24_3BE),
FORMAT(S20_3LE),
FORMAT(S20_3BE),
FORMAT(U20_3LE),
FORMAT(U20_3BE),
FORMAT(S18_3LE),
FORMAT(S18_3BE),
FORMAT(U18_3LE),
FORMAT(U18_3BE),
};
static const char *snd_pcm_format_descriptions[] = {
@ -1229,6 +1241,18 @@ static const char *snd_pcm_format_descriptions[] = {
FORMATD(MPEG, "MPEG"),
FORMATD(GSM, "GSM"),
FORMATD(SPECIAL, "Special"),
FORMATD(S24_3LE, "Signed 24 bit Little Endian in 3bytes"),
FORMATD(S24_3BE, "Signed 24 bit Big Endian in 3bytes"),
FORMATD(U24_3LE, "Unsigned 24 bit Little Endian in 3bytes"),
FORMATD(U24_3BE, "Unsigned 24 bit Big Endian in 3bytes"),
FORMATD(S20_3LE, "Signed 20 bit Little Endian in 3bytes"),
FORMATD(S20_3BE, "Signed 20 bit Big Endian in 3bytes"),
FORMATD(U20_3LE, "Unsigned 20 bit Little Endian in 3bytes"),
FORMATD(U20_3BE, "Unsigned 20 bit Big Endian in 3bytes"),
FORMATD(S18_3LE, "Signed 18 bit Little Endian in 3bytes"),
FORMATD(S18_3BE, "Signed 18 bit Big Endian in 3bytes"),
FORMATD(U18_3LE, "Unsigned 18 bit Little Endian in 3bytes"),
FORMATD(U18_3BE, "Unsigned 18 bit Big Endian in 3bytes"),
};
static const char *snd_pcm_subformat_names[] = {
@ -2129,6 +2153,13 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_
return 0;
}
static void dump_one_param(snd_pcm_hw_params_t *params, unsigned int k, snd_output_t *out)
{
snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(k));
snd_pcm_hw_param_dump(params, k, out);
snd_output_putc(out, '\n');
}
/**
* \brief Dump a PCM hardware configuration space
* \param params Configuration space
@ -2138,11 +2169,10 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_
int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params, snd_output_t *out)
{
unsigned int k;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) {
snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(k));
snd_pcm_hw_param_dump(params, k, out);
snd_output_putc(out, '\n');
}
for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++)
dump_one_param(params, k, out);
for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
dump_one_param(params, k, out);
return 0;
}
@ -5433,7 +5463,7 @@ snd_pcm_uframes_t _snd_pcm_boundary(snd_pcm_t *pcm)
return pcm->boundary;
}
static const char *names[SND_PCM_HW_PARAM_LAST + 1] = {
static const char *names[SND_PCM_HW_PARAM_LAST_INTERVAL + 1] = {
[SND_PCM_HW_PARAM_FORMAT] = "format",
[SND_PCM_HW_PARAM_CHANNELS] = "channels",
[SND_PCM_HW_PARAM_RATE] = "rate",
@ -5498,7 +5528,7 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
for (k = 0; k < count; ++k) {
unsigned int idx = fields[k].index;
long v;
assert(idx < SND_PCM_HW_PARAM_LAST);
assert(idx < SND_PCM_HW_PARAM_LAST_INTERVAL);
assert(names[idx]);
if (strcmp(id, names[idx]) != 0)
continue;

View file

@ -54,8 +54,37 @@ const char *_snd_module_pcm_hw = "";
#define F_SETSIG 10
#endif
/*
* Compatibility
*/
struct sndrv_pcm_hw_params_old {
unsigned int flags;
unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
SNDRV_PCM_HW_PARAM_ACCESS + 1];
struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
unsigned int rmask;
unsigned int cmask;
unsigned int info;
unsigned int msbits;
unsigned int rate_num;
unsigned int rate_den;
sndrv_pcm_uframes_t fifo_size;
unsigned char reserved[64];
};
#define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
#define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
#define SND_PCM_IOCTL_XRUN _IO('A', 0x48)
static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
/*
*
*/
typedef struct {
int version;
int fd;
@ -72,7 +101,7 @@ typedef struct {
#define SNDRV_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
#define SNDRV_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic"
#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 1)
#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 2)
/* update appl_ptr with driver */
#define UPDATE_SHADOW_PTR(hw) \
@ -146,17 +175,25 @@ static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
return 0;
}
static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
{
/* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params);
return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params);
}
static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_hw_t *hw = pcm->private_data;
int fd = hw->fd;
if (hw->mmap_emulation) {
int err = 0;
snd_pcm_access_mask_t oldmask = *snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
snd_pcm_access_mask_t mask = { 0 };
snd_pcm_access_mask_t mask;
const snd_mask_t *pmask;
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params) < 0)
snd_mask_empty(&mask);
if (hw_refine_call(hw, params) < 0)
err = -errno;
if (err < 0) {
snd_pcm_hw_params_t new = *params;
@ -170,8 +207,8 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
if (snd_pcm_access_mask_empty(&mask))
return err;
pmask = snd_pcm_hw_param_get_mask(&new, SND_PCM_HW_PARAM_ACCESS);
((snd_mask_t *)pmask)->bits = mask.bits;
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, &new) < 0)
*(snd_mask_t *)pmask = mask;
if (hw_refine_call(hw, &new) < 0)
return -errno;
*params = new;
}
@ -203,7 +240,7 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
}
}
} else {
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params) < 0) {
if (hw_refine_call(hw, params) < 0) {
// SYSERR("SNDRV_PCM_IOCTL_HW_REFINE failed");
return -errno;
}
@ -212,13 +249,20 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
return 0;
}
static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
{
/* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
}
static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_hw_t *hw = pcm->private_data;
int fd = hw->fd;
if (hw->mmap_emulation) {
snd_pcm_hw_params_t old = *params;
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0) {
if (hw_params_call(hw, params) < 0) {
snd_pcm_access_mask_t oldmask;
const snd_mask_t *pmask;
@ -237,13 +281,13 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
default:
goto _err;
}
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0)
if (hw_params_call(hw, params) < 0)
goto _err;
hw->mmap_shm = 1;
*(snd_pcm_access_mask_t *)pmask = oldmask;
}
} else {
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0) {
if (hw_params_call(hw, params) < 0) {
_err:
SYSERR("SNDRV_PCM_IOCTL_HW_PARAMS failed");
return -errno;
@ -964,3 +1008,68 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION);
#endif
/*
* To be removed helpers, but keep binary compatibility at the time
*/
#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params,
struct sndrv_pcm_hw_params_old *oparams)
{
unsigned int i;
memset(params, 0, sizeof(*params));
params->flags = oparams->flags;
for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
params->masks[i].bits[0] = oparams->masks[i];
memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
params->info = oparams->info;
params->msbits = oparams->msbits;
params->rate_num = oparams->rate_num;
params->rate_den = oparams->rate_den;
params->fifo_size = oparams->fifo_size;
}
static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams,
snd_pcm_hw_params_t *params,
unsigned int *cmask)
{
unsigned int i, j;
memset(oparams, 0, sizeof(*oparams));
oparams->flags = params->flags;
for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) {
oparams->masks[i] = params->masks[i].bits[0];
for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++)
if (params->masks[i].bits[j]) {
*cmask |= 1 << i;
break;
}
}
memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
oparams->info = params->info;
oparams->msbits = params->msbits;
oparams->rate_num = params->rate_num;
oparams->rate_den = params->rate_den;
oparams->fifo_size = params->fifo_size;
}
static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params)
{
struct sndrv_pcm_hw_params_old oparams;
unsigned int cmask = 0;
int res;
snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask);
res = ioctl(fd, cmd, &oparams);
snd_pcm_hw_convert_from_old_params(params, &oparams);
params->cmask |= cmask;
return res;
}

View file

@ -285,11 +285,11 @@ static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
dst_format = snd_pcm_hw_params_get_format(params);
}
if (snd_pcm_format_linear(src_format)) {
lfloat->int32_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32);
lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format);
lfloat->func = snd_pcm_lfloat_convert_integer_float;
} else {
lfloat->int32_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format);
lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format);
lfloat->func = snd_pcm_lfloat_convert_float_integer;
}

View file

@ -39,7 +39,9 @@ const char *_snd_module_pcm_linear = "";
typedef struct {
/* This field need to be the first */
snd_pcm_plugin_t plug;
unsigned int use_getput;
unsigned int conv_idx;
unsigned int get_idx, put_idx;
snd_pcm_format_t sformat;
} snd_pcm_linear_t;
#endif
@ -74,10 +76,9 @@ int snd_pcm_linear_convert_index(snd_pcm_format_t src_format,
int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
{
int sign, width, endian;
int sign, width, pwidth, endian;
sign = (snd_pcm_format_signed(src_format) !=
snd_pcm_format_signed(dst_format));
width = snd_pcm_format_width(src_format) / 8 - 1;
#ifdef SND_LITTLE_ENDIAN
endian = snd_pcm_format_big_endian(src_format);
#else
@ -85,7 +86,28 @@ int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
#endif
if (endian < 0)
endian = 0;
return width * 4 + endian * 2 + sign;
pwidth = snd_pcm_format_physical_width(src_format);
width = snd_pcm_format_width(src_format);
if (pwidth == 24) {
switch (width) {
case 24:
width = 0; break;
case 20:
width = 1; break;
case 18:
default:
width = 2; break;
}
return width * 4 + endian * 2 + sign + 16;
} else {
width = width / 8 - 1;
return width * 4 + endian * 2 + sign;
}
}
int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
{
return snd_pcm_linear_get_index(src_format, dst_format);
}
int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
@ -104,6 +126,37 @@ int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
return width * 4 + endian * 2 + sign;
}
int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
{
int sign, width, pwidth, endian;
sign = (snd_pcm_format_signed(src_format) !=
snd_pcm_format_signed(dst_format));
#ifdef SND_LITTLE_ENDIAN
endian = snd_pcm_format_big_endian(dst_format);
#else
endian = snd_pcm_format_little_endian(dst_format);
#endif
if (endian < 0)
endian = 0;
pwidth = snd_pcm_format_physical_width(dst_format);
width = snd_pcm_format_width(dst_format);
if (pwidth == 24) {
switch (width) {
case 24:
width = 0; break;
case 20:
width = 1; break;
case 18:
default:
width = 2; break;
}
return width * 4 + endian * 2 + sign + 16;
} else {
width = width / 8 - 1;
return width * 4 + endian * 2 + sign;
}
}
void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
unsigned int channels, snd_pcm_uframes_t frames,
@ -138,6 +191,42 @@ void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_ufr
}
}
void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
unsigned int channels, snd_pcm_uframes_t frames,
unsigned int get_idx, unsigned int put_idx)
{
#define CONV24_LABELS
#include "plugin_ops.h"
#undef CONV24_LABELS
void *get = get32_labels[get_idx];
void *put = put32_labels[put_idx];
unsigned int channel;
u_int32_t sample = 0;
for (channel = 0; channel < channels; ++channel) {
const char *src;
char *dst;
int src_step, dst_step;
snd_pcm_uframes_t frames1;
const snd_pcm_channel_area_t *src_area = &src_areas[channel];
const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
src = snd_pcm_channel_area_addr(src_area, src_offset);
dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
src_step = snd_pcm_channel_area_step(src_area);
dst_step = snd_pcm_channel_area_step(dst_area);
frames1 = frames;
while (frames1-- > 0) {
goto *get;
#define CONV24_END after
#include "plugin_ops.h"
#undef CONV24_END
after:
src += src_step;
dst += dst_step;
}
}
}
#endif /* DOC_HIDDEN */
static int snd_pcm_linear_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
@ -228,12 +317,24 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
snd_pcm_plugin_hw_params_slave);
if (err < 0)
return err;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
linear->conv_idx = snd_pcm_linear_convert_index(snd_pcm_hw_params_get_format(params),
linear->sformat);
else
linear->conv_idx = snd_pcm_linear_convert_index(linear->sformat,
snd_pcm_hw_params_get_format(params));
linear->use_getput = (snd_pcm_format_physical_width(snd_pcm_hw_params_get_format(params)) == 24 ||
snd_pcm_format_physical_width(linear->sformat) == 24);
if (linear->use_getput) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
linear->get_idx = snd_pcm_linear_get32_index(snd_pcm_hw_params_get_format(params), SND_PCM_FORMAT_S32);
linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, linear->sformat);
} else {
linear->get_idx = snd_pcm_linear_get32_index(linear->sformat, SND_PCM_FORMAT_S32);
linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, snd_pcm_hw_params_get_format(params));
}
} else {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
linear->conv_idx = snd_pcm_linear_convert_index(snd_pcm_hw_params_get_format(params),
linear->sformat);
else
linear->conv_idx = snd_pcm_linear_convert_index(linear->sformat,
snd_pcm_hw_params_get_format(params));
}
return 0;
}
@ -249,9 +350,15 @@ snd_pcm_linear_write_areas(snd_pcm_t *pcm,
snd_pcm_linear_t *linear = pcm->private_data;
if (size > *slave_sizep)
size = *slave_sizep;
snd_pcm_linear_convert(slave_areas, slave_offset,
areas, offset,
pcm->channels, size, linear->conv_idx);
if (linear->use_getput)
snd_pcm_linear_getput(slave_areas, slave_offset,
areas, offset,
pcm->channels, size,
linear->get_idx, linear->put_idx);
else
snd_pcm_linear_convert(slave_areas, slave_offset,
areas, offset,
pcm->channels, size, linear->conv_idx);
*slave_sizep = size;
return size;
}
@ -268,9 +375,15 @@ snd_pcm_linear_read_areas(snd_pcm_t *pcm,
snd_pcm_linear_t *linear = pcm->private_data;
if (size > *slave_sizep)
size = *slave_sizep;
snd_pcm_linear_convert(areas, offset,
slave_areas, slave_offset,
pcm->channels, size, linear->conv_idx);
if (linear->use_getput)
snd_pcm_linear_getput(areas, offset,
slave_areas, slave_offset,
pcm->channels, size,
linear->get_idx, linear->put_idx);
else
snd_pcm_linear_convert(areas, offset,
slave_areas, slave_offset,
pcm->channels, size, linear->conv_idx);
*slave_sizep = size;
return size;
}

View file

@ -25,6 +25,7 @@
#include <limits.h>
#include <sys/uio.h>
#define _snd_mask sndrv_mask
#define _snd_pcm_access_mask _snd_mask
#define _snd_pcm_format_mask _snd_mask
#define _snd_pcm_subformat_mask _snd_mask
@ -57,7 +58,6 @@ typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t;
#define SND_PCM_HW_PARAM_BUFFER_BYTES SNDRV_PCM_HW_PARAM_BUFFER_BYTES
#define SND_PCM_HW_PARAM_TICK_TIME SNDRV_PCM_HW_PARAM_TICK_TIME
#define SND_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_LAST_INTERVAL
#define SND_PCM_HW_PARAM_LAST SNDRV_PCM_HW_PARAM_LAST
#define SND_PCM_HW_PARAMS_RUNTIME SNDRV_PCM_HW_PARAMS_RUNTIME
#define SND_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_LAST_MASK
#define SND_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_FIRST_MASK
@ -568,24 +568,24 @@ int snd_pcm_conf_generic_id(const char *id);
#define SND_PCM_HW_PARBIT_TICK_TIME (1U << SND_PCM_HW_PARAM_TICK_TIME)
#define SND_PCM_ACCBIT_MMAP ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
#define SND_PCM_ACCBIT_MMAP { ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
(1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
(1U << SND_PCM_ACCESS_MMAP_COMPLEX))
#define SND_PCM_ACCBIT_MMAPI (1U << SND_PCM_ACCESS_MMAP_INTERLEAVED)
#define SND_PCM_ACCBIT_MMAPN (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
#define SND_PCM_ACCBIT_MMAPC (1U << SND_PCM_ACCESS_MMAP_COMPLEX)
(1U << SND_PCM_ACCESS_MMAP_COMPLEX)) }
#define SND_PCM_ACCBIT_MMAPI { (1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) }
#define SND_PCM_ACCBIT_MMAPN { (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) }
#define SND_PCM_ACCBIT_MMAPC { (1U << SND_PCM_ACCESS_MMAP_COMPLEX) }
#define SND_PCM_ACCBIT_SHM ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
#define SND_PCM_ACCBIT_SHM { ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
(1U << SND_PCM_ACCESS_RW_INTERLEAVED) | \
(1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
(1U << SND_PCM_ACCESS_RW_NONINTERLEAVED))
#define SND_PCM_ACCBIT_SHMI ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
(1U << SND_PCM_ACCESS_RW_INTERLEAVED))
#define SND_PCM_ACCBIT_SHMN ((1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
(1U << SND_PCM_ACCESS_RW_NONINTERLEAVED))
(1U << SND_PCM_ACCESS_RW_NONINTERLEAVED)) }
#define SND_PCM_ACCBIT_SHMI { ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
(1U << SND_PCM_ACCESS_RW_INTERLEAVED)) }
#define SND_PCM_ACCBIT_SHMN { ((1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
(1U << SND_PCM_ACCESS_RW_NONINTERLEAVED)) }
#define SND_PCM_FMTBIT_LINEAR \
((1U << SND_PCM_FORMAT_S8) | \
{ ((1U << SND_PCM_FORMAT_S8) | \
(1U << SND_PCM_FORMAT_U8) | \
(1U << SND_PCM_FORMAT_S16_LE) | \
(1U << SND_PCM_FORMAT_S16_BE) | \
@ -598,10 +598,23 @@ int snd_pcm_conf_generic_id(const char *id);
(1U << SND_PCM_FORMAT_S32_LE) | \
(1U << SND_PCM_FORMAT_S32_BE) | \
(1U << SND_PCM_FORMAT_U32_LE) | \
(1U << SND_PCM_FORMAT_U32_BE))
(1U << SND_PCM_FORMAT_U32_BE)), \
((1U << (SND_PCM_FORMAT_S24_3LE - 32)) | \
(1U << (SND_PCM_FORMAT_U24_3LE - 32)) | \
(1U << (SND_PCM_FORMAT_S24_3BE - 32)) | \
(1U << (SND_PCM_FORMAT_U24_3BE - 32)) | \
(1U << (SND_PCM_FORMAT_S20_3LE - 32)) | \
(1U << (SND_PCM_FORMAT_U20_3LE - 32)) | \
(1U << (SND_PCM_FORMAT_S20_3BE - 32)) | \
(1U << (SND_PCM_FORMAT_U20_3BE - 32)) | \
(1U << (SND_PCM_FORMAT_S18_3LE - 32)) | \
(1U << (SND_PCM_FORMAT_U18_3LE - 32)) | \
(1U << (SND_PCM_FORMAT_S18_3BE - 32)) | \
(1U << (SND_PCM_FORMAT_U18_3BE - 32))) }
#define SND_PCM_FMTBIT_FLOAT \
((1U << SND_PCM_FORMAT_FLOAT_LE) | \
{ ((1U << SND_PCM_FORMAT_FLOAT_LE) | \
(1U << SND_PCM_FORMAT_FLOAT_BE) | \
(1U << SND_PCM_FORMAT_FLOAT64_LE) | \
(1U << SND_PCM_FORMAT_FLOAT64_BE))
(1U << SND_PCM_FORMAT_FLOAT64_BE)) }

View file

@ -42,6 +42,12 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_S24_BE:
case SNDRV_PCM_FORMAT_S32_LE:
case SNDRV_PCM_FORMAT_S32_BE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_3BE:
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S20_3BE:
case SNDRV_PCM_FORMAT_S18_3LE:
case SNDRV_PCM_FORMAT_S18_3BE:
return 1;
case SNDRV_PCM_FORMAT_U8:
case SNDRV_PCM_FORMAT_U16_LE:
@ -50,6 +56,12 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_U24_BE:
case SNDRV_PCM_FORMAT_U32_LE:
case SNDRV_PCM_FORMAT_U32_BE:
case SNDRV_PCM_FORMAT_U24_3LE:
case SNDRV_PCM_FORMAT_U24_3BE:
case SNDRV_PCM_FORMAT_U20_3LE:
case SNDRV_PCM_FORMAT_U20_3BE:
case SNDRV_PCM_FORMAT_U18_3LE:
case SNDRV_PCM_FORMAT_U18_3BE:
return 0;
default:
return -EINVAL;
@ -116,6 +128,12 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_FLOAT_LE:
case SNDRV_PCM_FORMAT_FLOAT64_LE:
case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S18_3LE:
case SNDRV_PCM_FORMAT_U24_3LE:
case SNDRV_PCM_FORMAT_U20_3LE:
case SNDRV_PCM_FORMAT_U18_3LE:
return 1;
case SNDRV_PCM_FORMAT_S16_BE:
case SNDRV_PCM_FORMAT_U16_BE:
@ -126,6 +144,12 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_FLOAT_BE:
case SNDRV_PCM_FORMAT_FLOAT64_BE:
case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
case SNDRV_PCM_FORMAT_S24_3BE:
case SNDRV_PCM_FORMAT_S20_3BE:
case SNDRV_PCM_FORMAT_S18_3BE:
case SNDRV_PCM_FORMAT_U24_3BE:
case SNDRV_PCM_FORMAT_U20_3BE:
case SNDRV_PCM_FORMAT_U18_3BE:
return 0;
default:
return -EINVAL;
@ -177,10 +201,24 @@ int snd_pcm_format_width(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_U16_LE:
case SNDRV_PCM_FORMAT_U16_BE:
return 16;
case SNDRV_PCM_FORMAT_S18_3LE:
case SNDRV_PCM_FORMAT_S18_3BE:
case SNDRV_PCM_FORMAT_U18_3LE:
case SNDRV_PCM_FORMAT_U18_3BE:
return 18;
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S20_3BE:
case SNDRV_PCM_FORMAT_U20_3LE:
case SNDRV_PCM_FORMAT_U20_3BE:
return 20;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_BE:
case SNDRV_PCM_FORMAT_U24_LE:
case SNDRV_PCM_FORMAT_U24_BE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_3BE:
case SNDRV_PCM_FORMAT_U24_3LE:
case SNDRV_PCM_FORMAT_U24_3BE:
return 24;
case SNDRV_PCM_FORMAT_S32_LE:
case SNDRV_PCM_FORMAT_S32_BE:
@ -221,6 +259,19 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_U16_LE:
case SNDRV_PCM_FORMAT_U16_BE:
return 16;
case SNDRV_PCM_FORMAT_S18_3LE:
case SNDRV_PCM_FORMAT_S18_3BE:
case SNDRV_PCM_FORMAT_U18_3LE:
case SNDRV_PCM_FORMAT_U18_3BE:
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S20_3BE:
case SNDRV_PCM_FORMAT_U20_3LE:
case SNDRV_PCM_FORMAT_U20_3BE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_3BE:
case SNDRV_PCM_FORMAT_U24_3LE:
case SNDRV_PCM_FORMAT_U24_3BE:
return 24;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_BE:
case SNDRV_PCM_FORMAT_U24_LE:
@ -264,6 +315,19 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
case SNDRV_PCM_FORMAT_U16_LE:
case SNDRV_PCM_FORMAT_U16_BE:
return samples * 2;
case SNDRV_PCM_FORMAT_S18_3LE:
case SNDRV_PCM_FORMAT_S18_3BE:
case SNDRV_PCM_FORMAT_U18_3LE:
case SNDRV_PCM_FORMAT_U18_3BE:
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S20_3BE:
case SNDRV_PCM_FORMAT_U20_3LE:
case SNDRV_PCM_FORMAT_U20_3BE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_3BE:
case SNDRV_PCM_FORMAT_U24_3LE:
case SNDRV_PCM_FORMAT_U24_3BE:
return samples * 3;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_BE:
case SNDRV_PCM_FORMAT_U24_LE:
@ -309,6 +373,12 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_S24_BE:
case SNDRV_PCM_FORMAT_S32_LE:
case SNDRV_PCM_FORMAT_S32_BE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_3BE:
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S20_3BE:
case SNDRV_PCM_FORMAT_S18_3LE:
case SNDRV_PCM_FORMAT_S18_3BE:
return 0;
case SNDRV_PCM_FORMAT_U8:
return 0x8080808080808080ULL;
@ -339,6 +409,15 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
case SNDRV_PCM_FORMAT_U32_BE:
return 0x8000000080000000ULL;
#endif
case SNDRV_PCM_FORMAT_U24_3LE:
case SNDRV_PCM_FORMAT_U24_3BE:
return 0x0000800000800000ULL;
case SNDRV_PCM_FORMAT_U20_3LE:
case SNDRV_PCM_FORMAT_U20_3BE:
return 0x0000080000080000ULL;
case SNDRV_PCM_FORMAT_U18_3LE:
case SNDRV_PCM_FORMAT_U18_3BE:
return 0x0000020000020000ULL;
case SNDRV_PCM_FORMAT_FLOAT_LE:
{
union {
@ -470,20 +549,45 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
}
case 16: {
u_int16_t silence = snd_pcm_format_silence_64(format);
while (samples-- > 0)
*((u_int16_t *)data)++ = silence;
if (! silence)
memset(data, 0, samples * 2);
else {
while (samples-- > 0)
*((u_int16_t *)data)++ = silence;
}
break;
}
case 24: {
u_int32_t silence = snd_pcm_format_silence_64(format);
if (! silence)
memset(data, 0, samples * 3);
else {
/* FIXME: rewrite in the more better way.. */
int i;
while (samples-- > 0) {
for (i = 0; i < 3; i++)
*((u_int8_t *)data)++ = silence >> (i * 8);
}
}
}
case 32: {
u_int32_t silence = snd_pcm_format_silence_64(format);
while (samples-- > 0)
*((u_int32_t *)data)++ = silence;
if (! silence)
memset(data, 0, samples * 4);
else {
while (samples-- > 0)
*((u_int32_t *)data)++ = silence;
}
break;
}
case 64: {
u_int64_t silence = snd_pcm_format_silence_64(format);
while (samples-- > 0)
*((u_int64_t *)data)++ = silence;
if (! silence)
memset(data, 0, samples * 8);
else {
while (samples-- > 0)
*((u_int64_t *)data)++ = silence;
}
break;
}
default:
@ -512,29 +616,62 @@ static int linear_formats[4*2*2] = {
SNDRV_PCM_FORMAT_U32_BE
};
static int linear24_formats[3*2*2] = {
SNDRV_PCM_FORMAT_S24_3LE,
SNDRV_PCM_FORMAT_S24_3BE,
SNDRV_PCM_FORMAT_U24_3LE,
SNDRV_PCM_FORMAT_U24_3BE,
SNDRV_PCM_FORMAT_S20_3LE,
SNDRV_PCM_FORMAT_S20_3BE,
SNDRV_PCM_FORMAT_U20_3LE,
SNDRV_PCM_FORMAT_U20_3BE,
SNDRV_PCM_FORMAT_S18_3LE,
SNDRV_PCM_FORMAT_S18_3BE,
SNDRV_PCM_FORMAT_U18_3LE,
SNDRV_PCM_FORMAT_U18_3BE,
};
/**
* \brief Compose a PCM sample linear format
* \param width Nominal bits per sample
* \param pwidth Physical bit width of the format
* \param unsignd Sign: 0 signed, 1 unsigned
* \return big_endian Endian: 0 little endian, 1 big endian
*/
snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian)
{
switch (width) {
case 8:
width = 0;
break;
case 16:
width = 1;
break;
case 24:
width = 2;
break;
case 32:
width = 3;
break;
default:
return SND_PCM_FORMAT_UNKNOWN;
if (pwidth == 24) {
switch (width) {
case 24:
width = 0;
break;
case 20:
width = 1;
break;
case 18:
width = 2;
break;
default:
return SND_PCM_FORMAT_UNKNOWN;
}
return ((int(*)[2][2])linear24_formats)[width][!!unsignd][!!big_endian];
} else {
switch (width) {
case 8:
width = 0;
break;
case 16:
width = 1;
break;
case 24:
width = 2;
break;
case 32:
width = 3;
break;
default:
return SND_PCM_FORMAT_UNKNOWN;
}
return ((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian];
}
return ((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian];
}

View file

@ -91,7 +91,9 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
{
unsigned int k;
memset(params, 0, sizeof(*params));
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++)
_snd_pcm_hw_param_any(params, k);
for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
_snd_pcm_hw_param_any(params, k);
params->info = ~0U;
}
@ -618,7 +620,7 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
snd_mask_t *m = hw_param_mask(params, var);
if (val == 0 && dir < 0) {
changed = -EINVAL;
snd_mask_none(m);
snd_mask_none(m);
} else {
if (dir > 0)
val++;
@ -1144,7 +1146,7 @@ const char *snd_pcm_hw_param_names[] = {
const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param)
{
assert(param <= SND_PCM_HW_PARAM_LAST);
assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL);
return snd_pcm_hw_param_names[param];
}
@ -1250,7 +1252,7 @@ void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy)
{
snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
int k;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
if (pars[k].valid && pars[k].free)
pars[k].free(&pars[k]);
}
@ -1266,7 +1268,7 @@ int snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
unsigned int min_choices = UINT_MAX;
unsigned int min_order = UINT_MAX;
for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
const snd_pcm_hw_strategy_simple_t *p = &pars[var];
unsigned int choices;
if (!p->valid)
@ -1306,7 +1308,7 @@ int snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
snd_pcm_hw_param_t var;
unsigned int badness = 0;
const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
unsigned int b;
if (!pars[var].valid)
continue;
@ -1418,7 +1420,7 @@ int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp,
snd_pcm_hw_strategy_simple_t *data;
snd_pcm_hw_strategy_t *s;
assert(strategyp);
data = calloc(SND_PCM_HW_PARAM_LAST + 1, sizeof(*data));
data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data));
if (!data)
return -ENOMEM;
s = calloc(1, sizeof(*s));
@ -1446,7 +1448,7 @@ int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy,
snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
snd_pcm_hw_strategy_simple_near_t *data;
assert(strategy);
assert(var <= SND_PCM_HW_PARAM_LAST);
assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
assert(!s->valid);
data = calloc(1, sizeof(*data));
if (!data)
@ -1472,7 +1474,7 @@ int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy,
snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
snd_pcm_hw_strategy_simple_choices_t *data;
assert(strategy);
assert(var <= SND_PCM_HW_PARAM_LAST);
assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
assert(!s->valid);
data = calloc(1, sizeof(*data));
if (!data)
@ -1499,7 +1501,7 @@ int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
snd_pcm_hw_params_t i;
if (depth < 1)
return -ENOENT;
for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
int err;
i = *success;
_snd_pcm_hw_param_copy(&i, var, fail);
@ -1526,7 +1528,7 @@ int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
snd_pcm_hw_param_t var;
int done = 0;
assert(pcm && fail);
for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
if (!snd_pcm_hw_param_empty(fail, var))
continue;
snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var));
@ -1805,16 +1807,16 @@ static snd_pcm_hw_rule_t refine_rules[] = {
static snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = {
[SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = {
bits: 0x1f,
bits: { 0x1f },
},
[SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
bits: 0x81ffffff,
bits: { 0x81ffffff, 0xfff},
},
[SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
bits: 0x1,
bits: { 0x1 },
},
};
static snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
[SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
min: 1, max: UINT_MAX,
@ -1873,7 +1875,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
unsigned int k;
snd_interval_t *i;
unsigned int rstamps[RULES];
unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp = 2;
int changed, again;
#ifdef RULES_DEBUG
@ -1885,7 +1887,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
if (!(params->rmask & (1 << k)))
continue;
changed = snd_mask_refine(hw_param_mask(params, k),
&refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
&refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
if (changed)
params->cmask |= 1 << k;
if (changed < 0)
@ -1905,7 +1907,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
for (k = 0; k < RULES; k++)
rstamps[k] = 0;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
do {
again = 0;
@ -1978,7 +1980,7 @@ int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
{
int changed, err = 0;
unsigned int k;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
if (!(vars & (1 << k)))
continue;
changed = _snd_pcm_hw_param_refine(params, k, src);

View file

@ -145,6 +145,39 @@ static snd_pcm_format_t linear_preferred_formats[] = {
SND_PCM_FORMAT_S24_LE,
SND_PCM_FORMAT_U24_LE,
#endif
#ifdef SND_LITTLE_ENDIAN
SND_PCM_FORMAT_S24_3LE,
SND_PCM_FORMAT_U24_3LE,
SND_PCM_FORMAT_S24_3BE,
SND_PCM_FORMAT_U24_3BE,
#else
SND_PCM_FORMAT_S24_3BE,
SND_PCM_FORMAT_U24_3BE,
SND_PCM_FORMAT_S24_3LE,
SND_PCM_FORMAT_U24_3LE,
#endif
#ifdef SND_LITTLE_ENDIAN
SND_PCM_FORMAT_S20_3LE,
SND_PCM_FORMAT_U20_3LE,
SND_PCM_FORMAT_S20_3BE,
SND_PCM_FORMAT_U20_3BE,
#else
SND_PCM_FORMAT_S20_3BE,
SND_PCM_FORMAT_U20_3BE,
SND_PCM_FORMAT_S20_3LE,
SND_PCM_FORMAT_U20_3LE,
#endif
#ifdef SND_LITTLE_ENDIAN
SND_PCM_FORMAT_S18_3LE,
SND_PCM_FORMAT_U18_3LE,
SND_PCM_FORMAT_S18_3BE,
SND_PCM_FORMAT_U18_3BE,
#else
SND_PCM_FORMAT_S18_3BE,
SND_PCM_FORMAT_U18_3BE,
SND_PCM_FORMAT_S18_3LE,
SND_PCM_FORMAT_U18_3LE,
#endif
};
static snd_pcm_format_t nonlinear_preferred_formats[] = {
@ -167,9 +200,39 @@ static snd_pcm_format_t float_preferred_formats[] = {
#endif
};
static char linear_format_widths[32] = {
0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1,
0, 1, 0, 1, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 1,
};
static int check_linear_format(const snd_pcm_format_mask_t *format_mask, int wid, int sgn, int ed)
{
int e, s;
if (! linear_format_widths[wid - 1])
return SND_PCM_FORMAT_UNKNOWN;
for (e = 0; e < 2; e++) {
for (s = 0; s < 2; s++) {
int pw = ((wid + 7) / 8) * 8;
for (; pw <= 32; pw += 8) {
snd_pcm_format_t f;
f = snd_pcm_build_linear_format(wid, pw, sgn, ed);
if (f != SND_PCM_FORMAT_UNKNOWN &&
snd_pcm_format_mask_test(format_mask, f))
return f;
}
sgn = !sgn;
}
ed = !ed;
}
return SND_PCM_FORMAT_UNKNOWN;
}
static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const snd_pcm_format_mask_t *format_mask)
{
int w, u, e, wid, w1, dw;
int w, w1, u, e;
snd_pcm_format_t f;
snd_pcm_format_mask_t lin = { SND_PCM_FMTBIT_LINEAR };
snd_pcm_format_mask_t fl = { SND_PCM_FMTBIT_FLOAT };
if (snd_pcm_format_mask_test(format_mask, format))
@ -228,28 +291,15 @@ static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const
u = snd_pcm_format_unsigned(format);
e = snd_pcm_format_big_endian(format);
}
w1 = w;
dw = 8;
for (wid = 0; wid < 4; ++wid) {
int end, e1 = e;
for (end = 0; end < 2; ++end) {
int sgn, u1 = u;
for (sgn = 0; sgn < 2; ++sgn) {
snd_pcm_format_t f;
f = snd_pcm_build_linear_format(w1, u1, e1);
assert(f != SND_PCM_FORMAT_UNKNOWN);
if (snd_pcm_format_mask_test(format_mask, f))
return f;
u1 = !u1;
}
e1 = !e1;
}
if (w1 < 32)
w1 += dw;
else {
w1 = w - 8;
dw = -8;
}
for (w1 = w; w1 <= 32; w1++) {
f = check_linear_format(format_mask, w1, u, e);
if (f != SND_PCM_FORMAT_UNKNOWN)
return f;
}
for (w1 = w - 1; w1 > 0; w1--) {
f = check_linear_format(format_mask, w1, u, e);
if (f != SND_PCM_FORMAT_UNKNOWN)
return f;
}
return SND_PCM_FORMAT_UNKNOWN;
}

View file

@ -105,12 +105,18 @@ snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic
int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
unsigned int channels, snd_pcm_uframes_t frames,
unsigned int convidx);
void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
unsigned int channels, snd_pcm_uframes_t frames,
unsigned int get_idx, unsigned int put_idx);
void snd_pcm_alaw_decode(const snd_pcm_channel_area_t *dst_areas,
snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas,

View file

@ -62,6 +62,7 @@ typedef struct {
unsigned int get_idx;
unsigned int put_idx;
unsigned int conv_idx;
int use_getput;
unsigned int src_size;
snd_pcm_format_t dst_sfmt;
unsigned int ndsts;
@ -160,6 +161,53 @@ static void snd_pcm_route_convert1_one(const snd_pcm_channel_area_t *dst_area,
}
}
static void snd_pcm_route_convert1_one_getput(const snd_pcm_channel_area_t *dst_area,
snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas,
snd_pcm_uframes_t src_offset,
snd_pcm_uframes_t frames,
const snd_pcm_route_ttable_dst_t* ttable,
const snd_pcm_route_params_t *params)
{
#define CONV24_LABELS
#include "plugin_ops.h"
#undef CONV24_LABELS
void *get, *put;
const snd_pcm_channel_area_t *src_area = 0;
unsigned int srcidx;
const char *src;
char *dst;
int src_step, dst_step;
u_int32_t sample = 0;
for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
src_area = &src_areas[ttable->srcs[srcidx].channel];
if (src_area->addr != NULL)
break;
}
if (srcidx == ttable->nsrcs) {
snd_pcm_route_convert1_zero(dst_area, dst_offset,
src_areas, src_offset,
frames, ttable, params);
return;
}
get = get32_labels[params->get_idx];
put = put32_labels[params->put_idx];
src = snd_pcm_channel_area_addr(src_area, src_offset);
dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
src_step = snd_pcm_channel_area_step(src_area);
dst_step = snd_pcm_channel_area_step(dst_area);
while (frames-- > 0) {
goto *get;
#define CONV24_END after
#include "plugin_ops.h"
#undef CONV24_END
after:
src += src_step;
dst += dst_step;
}
}
static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas,
@ -239,9 +287,14 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
frames, ttable, params);
return;
} else if (nsrcs == 1 && src_tt[0].as_int == SND_PCM_PLUGIN_ROUTE_RESOLUTION) {
snd_pcm_route_convert1_one(dst_area, dst_offset,
src_areas, src_offset,
frames, ttable, params);
if (params->use_getput)
snd_pcm_route_convert1_one_getput(dst_area, dst_offset,
src_areas, src_offset,
frames, ttable, params);
else
snd_pcm_route_convert1_one(dst_area, dst_offset,
src_areas, src_offset,
frames, ttable, params);
return;
}
@ -561,8 +614,10 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
src_format = slave->format;
dst_format = snd_pcm_hw_params_get_format(params);
}
route->params.use_getput = snd_pcm_format_physical_width(src_format) == 24 ||
snd_pcm_format_physical_width(dst_format) == 24;
route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16);
route->params.put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format);
route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format);
route->params.src_size = snd_pcm_format_width(src_format) / 8;
route->params.dst_sfmt = dst_format;
@ -730,9 +785,12 @@ static int route_load_ttable(snd_pcm_route_params_t *params, snd_pcm_stream_t st
dptr->nsrcs = nsrcs;
if (nsrcs == 0)
dptr->func = snd_pcm_route_convert1_zero;
else if (nsrcs == 1 && !att)
dptr->func = snd_pcm_route_convert1_one;
else
else if (nsrcs == 1 && !att) {
if (params->use_getput)
dptr->func = snd_pcm_route_convert1_one_getput;
else
dptr->func = snd_pcm_route_convert1_one;
} else
dptr->func = snd_pcm_route_convert1_many;
if (nsrcs > 0) {
dptr->srcs = calloc((unsigned int) nsrcs, sizeof(*srcs));

View file

@ -32,6 +32,13 @@
#define as_u8c(ptr) (*(const u_int8_t*)(ptr))
#define as_u16c(ptr) (*(const u_int16_t*)(ptr))
#ifdef SND_LITTLE_ENDIAN
#define as_u24c(ptr) (u_int32_t)(as_u8(ptr) | as_u8(((char *)ptr) + 1) << 8 | as_u8(((char *)ptr + 2) << 16)
#elif defined(SND_BIG_ENDIAN)
#define as_u24c(ptr) (u_int32_t)(as_u8(ptr) << 16 | as_u8(((char *)ptr) + 1) << 8 | as_u8(((char *)ptr + 2))
#else
#error "Wrong endian..."
#endif
#define as_u32c(ptr) (*(const u_int32_t*)(ptr))
#define as_u64c(ptr) (*(const u_int64_t*)(ptr))
#define as_s8c(ptr) (*(const int8_t*)(ptr))
@ -41,10 +48,45 @@
#define as_floatc(ptr) (*(const float_t*)(ptr))
#define as_doublec(ptr) (*(const double_t*)(ptr))
#ifdef __i386__
#define _get_triple_le(ptr) (*(u_int32_t*)(ptr) & 0xffffff)
#define _get_triple_be(ptr) (bswap_32(*(u_int32_t*)(ptr)) & 0xffffff)
#else
#define _get_triple_le(ptr) (*(u_int8_t*)(ptr) | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | (u_int32_t)*((u_int8_t*)(ptr) + 2) << 16)
#define _get_triple_be(ptr) ((u_int32_t)*(u_int8_t*)(ptr) << 16 | (u_int32_t)*((u_int8_t*)(ptr) + 1) << 8 | *((u_int8_t*)(ptr) + 2))
#endif
#define _put_triple_le(ptr,val) do { \
u_int8_t *_tmp = (u_int8_t *)(ptr); \
u_int32_t _val = (val); \
_tmp[0] = _val; \
_tmp[1] = _val >> 8; \
_tmp[2] = _val >> 16; \
} while(0)
#define _put_triple_be(ptr,val) do { \
u_int8_t *_tmp = (u_int8_t *)(ptr); \
u_int32_t _val = (val); \
_tmp[0] = _val >> 16; \
_tmp[1] = _val >> 8; \
_tmp[2] = _val; \
} while(0)
#ifdef SNDRV_LITTLE_ENDIAN
#define _get_triple(ptr) _get_triple_le(ptr)
#define _get_triple_s(ptr) _get_triple_be(ptr)
#define _put_triple(ptr,val) _put_triple_le(ptr,val)
#define _put_triple_s(ptr,val) _put_triple_be(ptr,val)
#else
#define _get_triple(ptr) _get_triple_be(ptr)
#define _get_triple_s(ptr) _get_triple_le(ptr)
#define _put_triple(ptr,val) _put_triple_be(ptr,val)
#define _put_triple_s(ptr,val) _put_triple_le(ptr,val)
#endif
#ifdef COPY_LABELS
static void *copy_labels[4] = {
static void *copy_labels[5] = {
&&copy_8,
&&copy_16,
&&copy_24
&&copy_32,
&&copy_64
};
@ -54,6 +96,7 @@ static void *copy_labels[4] = {
while(0) {
copy_8: as_s8(dst) = as_s8c(src); goto COPY_END;
copy_16: as_s16(dst) = as_s16c(src); goto COPY_END;
copy_24: memcpy(dst,src,3); goto COPY_END;
copy_32: as_s32(dst) = as_s32c(src); goto COPY_END;
copy_64: as_s64(dst) = as_s64c(src); goto COPY_END;
}
@ -294,7 +337,7 @@ conv_1234_123C: as_u32(dst) = as_u32c(src) ^ 0x80; goto CONV_END;
#ifdef GET16_LABELS
/* src_wid src_endswap sign_toggle */
static void *get16_labels[4 * 2 * 2] = {
static void *get16_labels[4 * 2 * 2 + 4 * 3] = {
&&get16_1_10, /* 8h -> 16h */
&&get16_1_90, /* 8h ^> 16h */
&&get16_1_10, /* 8s -> 16h */
@ -311,6 +354,19 @@ static void *get16_labels[4 * 2 * 2] = {
&&get16_1234_92, /* 32h ^> 16h */
&&get16_1234_43, /* 32s -> 16h */
&&get16_1234_C3, /* 32s ^> 16h */
/* 3bytes format */
&&get16_123_12, /* 24h -> 16h */
&&get16_123_92, /* 24h ^> 16h */
&&get16_123_32, /* 24s -> 16h */
&&get16_123_B2, /* 24s ^> 16h */
&&get16_123_12_20, /* 20h -> 16h */
&&get16_123_92_20, /* 20h ^> 16h */
&&get16_123_32_20, /* 20s -> 16h */
&&get16_123_B2_20, /* 20s ^> 16h */
&&get16_123_12_18, /* 18h -> 16h */
&&get16_123_92_18, /* 18h ^> 16h */
&&get16_123_32_18, /* 18s -> 16h */
&&get16_123_B2_18, /* 18s ^> 16h */
};
#endif
@ -330,6 +386,18 @@ get16_1234_12: sample = as_u32c(src) >> 16; goto GET16_END;
get16_1234_92: sample = (as_u32c(src) >> 16) ^ 0x8000; goto GET16_END;
get16_1234_43: sample = bswap_16(as_u32c(src)); goto GET16_END;
get16_1234_C3: sample = bswap_16(as_u32c(src) ^ 0x80); goto GET16_END;
get16_123_12: sample = _get_triple(src) >> 8; goto GET16_END;
get16_123_92: sample = (_get_triple(src) >> 8) ^ 0x8000; goto GET16_END;
get16_123_32: sample = _get_triple_s(src) >> 8; goto GET16_END;
get16_123_B2: sample = (_get_triple_s(src) >> 8) ^ 0x8000; goto GET16_END;
get16_123_12_20: sample = _get_triple(src) >> 4; goto GET16_END;
get16_123_92_20: sample = (_get_triple(src) >> 4) ^ 0x8000; goto GET16_END;
get16_123_32_20: sample = _get_triple_s(src) >> 4; goto GET16_END;
get16_123_B2_20: sample = (_get_triple_s(src) >> 4) ^ 0x8000; goto GET16_END;
get16_123_12_18: sample = _get_triple(src) >> 2; goto GET16_END;
get16_123_92_18: sample = (_get_triple(src) >> 2) ^ 0x8000; goto GET16_END;
get16_123_32_18: sample = _get_triple_s(src) >> 2; goto GET16_END;
get16_123_B2_18: sample = (_get_triple_s(src) >> 2) ^ 0x8000; goto GET16_END;
}
#endif
@ -374,9 +442,14 @@ put16_12_0029: as_u32(dst) = (u_int32_t)bswap_16(sample) ^ 0x80; goto PUT16_END;
}
#endif
#ifdef CONV24_LABELS
#define GET32_LABELS
#define PUT32_LABELS
#endif
#ifdef GET32_LABELS
/* src_wid src_endswap sign_toggle */
static void *get32_labels[4 * 2 * 2] = {
static void *get32_labels[4 * 2 * 2 + 4 * 3] = {
&&get32_1_1000, /* 8h -> 32h */
&&get32_1_9000, /* 8h ^> 32h */
&&get32_1_1000, /* 8s -> 32h */
@ -393,9 +466,26 @@ static void *get32_labels[4 * 2 * 2] = {
&&get32_1234_9234, /* 32h ^> 32h */
&&get32_1234_4321, /* 32s -> 32h */
&&get32_1234_C321, /* 32s ^> 32h */
/* 3bytes format */
&&get32_123_1230, /* 24h -> 32h */
&&get32_123_9230, /* 24h ^> 32h */
&&get32_123_3210, /* 24s -> 32h */
&&get32_123_B210, /* 24s ^> 32h */
&&get32_123_1230_20, /* 20h -> 32h */
&&get32_123_9230_20, /* 20h ^> 32h */
&&get32_123_3210_20, /* 20s -> 32h */
&&get32_123_B210_20, /* 20s ^> 32h */
&&get32_123_1230_18, /* 18h -> 32h */
&&get32_123_9230_18, /* 18h ^> 32h */
&&get32_123_3210_18, /* 18s -> 32h */
&&get32_123_B210_18, /* 18s ^> 32h */
};
#endif
#ifdef CONV24_END
#define GET32_END __conv24_get
#endif
#ifdef GET32_END
while (0) {
get32_1_1000: sample = (u_int32_t)as_u8c(src) << 24; goto GET32_END;
@ -412,12 +502,29 @@ get32_1234_1234: sample = as_u32c(src); goto GET32_END;
get32_1234_9234: sample = as_u32c(src) ^ 0x80000000; goto GET32_END;
get32_1234_4321: sample = bswap_32(as_u32c(src)); goto GET32_END;
get32_1234_C321: sample = bswap_32(as_u32c(src) ^ 0x80); goto GET32_END;
get32_123_1230: sample = _get_triple(src) << 8; goto GET32_END;
get32_123_9230: sample = (_get_triple(src) << 8) ^ 0x80000000; goto GET32_END;
get32_123_3210: sample = _get_triple_s(src) << 8; goto GET32_END;
get32_123_B210: sample = (_get_triple_s(src) << 8) ^ 0x80000000; goto GET32_END;
get32_123_1230_20: sample = _get_triple(src) << 12; goto GET32_END;
get32_123_9230_20: sample = (_get_triple(src) << 12) ^ 0x80000000; goto GET32_END;
get32_123_3210_20: sample = _get_triple_s(src) << 12; goto GET32_END;
get32_123_B210_20: sample = (_get_triple_s(src) << 12) ^ 0x80000000; goto GET32_END;
get32_123_1230_18: sample = _get_triple(src) << 14; goto GET32_END;
get32_123_9230_18: sample = (_get_triple(src) << 14) ^ 0x80000000; goto GET32_END;
get32_123_3210_18: sample = _get_triple_s(src) << 14; goto GET32_END;
get32_123_B210_18: sample = (_get_triple_s(src) << 14) ^ 0x80000000; goto GET32_END;
}
#endif
#ifdef CONV24_END
__conv24_get: goto *put;
#define PUT32_END CONV24_END
#endif
#ifdef PUT32_LABELS
/* dst_wid dst_endswap sign_toggle */
static void *put32_labels[4 * 2 * 2] = {
static void *put32_labels[4 * 2 * 2 + 4 * 3] = {
&&put32_1234_1, /* 32h -> 8h */
&&put32_1234_9, /* 32h ^> 8h */
&&put32_1234_1, /* 32h -> 8s */
@ -434,9 +541,27 @@ static void *put32_labels[4 * 2 * 2] = {
&&put32_1234_9234, /* 32h ^> 32h */
&&put32_1234_4321, /* 32h -> 32s */
&&put32_1234_4329, /* 32h ^> 32s */
/* 3bytes format */
&&put32_1234_123, /* 32h -> 24h */
&&put32_1234_923, /* 32h ^> 24h */
&&put32_1234_321, /* 32h -> 24s */
&&put32_1234_329, /* 32h ^> 24s */
&&put32_1234_123_20, /* 32h -> 24h */
&&put32_1234_923_20, /* 32h ^> 24h */
&&put32_1234_321_20, /* 32h -> 24s */
&&put32_1234_329_20, /* 32h ^> 24s */
&&put32_1234_123_18, /* 32h -> 24h */
&&put32_1234_923_18, /* 32h ^> 24h */
&&put32_1234_321_18, /* 32h -> 24s */
&&put32_1234_329_18, /* 32h ^> 24s */
};
#endif
#ifdef CONV24_LABELS
#undef GET32_LABELS
#undef PUT32_LABELS
#endif
#ifdef PUT32_END
while (0) {
put32_1234_1: as_u8(dst) = sample >> 24; goto PUT32_END;
@ -453,9 +578,26 @@ 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;
put32_1234_123: _put_triple(dst, sample >> 8); goto PUT32_END;
put32_1234_923: _put_triple(dst, (sample ^ 0x80000000) >> 8); goto PUT32_END;
put32_1234_321: _put_triple_s(dst, sample >> 8); goto PUT32_END;
put32_1234_329: _put_triple_s(dst, (sample ^ 0x80000000) >> 8); goto PUT32_END;
put32_1234_123_20: _put_triple(dst, sample >> 12); goto PUT32_END;
put32_1234_923_20: _put_triple(dst, (sample ^ 0x80000000) >> 12); goto PUT32_END;
put32_1234_321_20: _put_triple_s(dst, sample >> 12); goto PUT32_END;
put32_1234_329_20: _put_triple_s(dst, (sample ^ 0x80000000) >> 12); goto PUT32_END;
put32_1234_123_18: _put_triple(dst, sample >> 14); goto PUT32_END;
put32_1234_923_18: _put_triple(dst, (sample ^ 0x80000000) >> 14); goto PUT32_END;
put32_1234_321_18: _put_triple_s(dst, sample >> 14); goto PUT32_END;
put32_1234_329_18: _put_triple_s(dst, (sample ^ 0x80000000) >> 14); goto PUT32_END;
}
#endif
#ifdef CONV24_END
#undef GET32_END
#undef PUT32_END
#endif
#ifdef GETU_LABELS
/* width endswap sign_toggle */
static void *getu_labels[4 * 2 * 2] = {
@ -924,3 +1066,13 @@ norms_32_s32s: _norms(src, dst, 32, 1, 32, 1); goto NORMS_END;
#undef as_s32c
#undef as_floatc
#undef as_doublec
#undef _get_triple
#undef _get_triple_s
#undef _get_triple_le
#undef _get_triple_be
#undef _put_triple
#undef _put_triple_s
#undef _put_triple_le
#undef _put_triple_be