summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2002-06-26 02:04:11 +0000
committerJaroslav Kysela <perex@perex.cz>2002-06-26 02:04:11 +0000
commit16b3bf447c280ae0009e5c07b8ad4474073a9363 (patch)
treef2d1811c5a7eea9be3520f84ad3ce2ca2a7a700f
parent84730c976f7f5d51b32f80964e252a43e477e198 (diff)
Enhanced bitmasks in PCM - added support for more formats by Takashi and me
-rw-r--r--include/pcm.h28
-rw-r--r--src/pcm/mask.h2
-rw-r--r--src/pcm/mask_inline.h101
-rw-r--r--src/pcm/pcm.c44
-rw-r--r--src/pcm/pcm_hw.c131
-rw-r--r--src/pcm/pcm_lfloat.c4
-rw-r--r--src/pcm/pcm_linear.c143
-rw-r--r--src/pcm/pcm_local.h45
-rw-r--r--src/pcm/pcm_misc.c183
-rw-r--r--src/pcm/pcm_params.c40
-rw-r--r--src/pcm/pcm_plug.c96
-rw-r--r--src/pcm/pcm_plugin.h6
-rw-r--r--src/pcm/pcm_route.c72
-rw-r--r--src/pcm/plugin_ops.h160
14 files changed, 893 insertions, 162 deletions
diff --git a/include/pcm.h b/include/pcm.h
index ef287567..670d7c97 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -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);
diff --git a/src/pcm/mask.h b/src/pcm/mask.h
index 386dc395..ab80f208 100644
--- a/src/pcm/mask.h
+++ b/src/pcm/mask.h
@@ -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"
diff --git a/src/pcm/mask_inline.h b/src/pcm/mask_inline.h
index 6c33e594..a44be3c4 100644
--- a/src/pcm/mask_inline.h
+++ b/src/pcm/mask_inline.h
@@ -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;
}
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index d184ee4c..f3a80ea6 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -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;
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index 07e9904f..0a602fff 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -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;
+}
diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c
index 55aee134..4abc0f9f 100644
--- a/src/pcm/pcm_lfloat.c
+++ b/src/pcm/pcm_lfloat.c
@@ -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;
}
diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c
index 74aed8dc..6aec4b8e 100644
--- a/src/pcm/pcm_linear.c
+++ b/src/pcm/pcm_linear.c
@@ -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;
}
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index aaf0a5de..aa2341cd 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -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)) }
diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index 29fbd72b..c62e700c 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -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];
}
diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c
index c9d9460f..2f5acd44 100644
--- a/src/pcm/pcm_params.c
+++ b/src/pcm/pcm_params.c
@@ -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);
diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c
index d3fe50fb..1553af76 100644
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -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;
}
diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h
index cb48ea83..6e1dc8b2 100644
--- a/src/pcm/pcm_plugin.h
+++ b/src/pcm/pcm_plugin.h
@@ -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,
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 2c492c31..eed050b7 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -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));
diff --git a/src/pcm/plugin_ops.h b/src/pcm/plugin_ops.h
index bbf177f1..1e2b73f1 100644
--- a/src/pcm/plugin_ops.h
+++ b/src/pcm/plugin_ops.h
@@ -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
+