diff options
author | Jaroslav Kysela <perex@perex.cz> | 2002-06-26 02:04:11 +0000 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2002-06-26 02:04:11 +0000 |
commit | 16b3bf447c280ae0009e5c07b8ad4474073a9363 (patch) | |
tree | f2d1811c5a7eea9be3520f84ad3ce2ca2a7a700f | |
parent | 84730c976f7f5d51b32f80964e252a43e477e198 (diff) |
Enhanced bitmasks in PCM - added support for more formats by Takashi and me
-rw-r--r-- | include/pcm.h | 28 | ||||
-rw-r--r-- | src/pcm/mask.h | 2 | ||||
-rw-r--r-- | src/pcm/mask_inline.h | 101 | ||||
-rw-r--r-- | src/pcm/pcm.c | 44 | ||||
-rw-r--r-- | src/pcm/pcm_hw.c | 131 | ||||
-rw-r--r-- | src/pcm/pcm_lfloat.c | 4 | ||||
-rw-r--r-- | src/pcm/pcm_linear.c | 143 | ||||
-rw-r--r-- | src/pcm/pcm_local.h | 45 | ||||
-rw-r--r-- | src/pcm/pcm_misc.c | 183 | ||||
-rw-r--r-- | src/pcm/pcm_params.c | 40 | ||||
-rw-r--r-- | src/pcm/pcm_plug.c | 96 | ||||
-rw-r--r-- | src/pcm/pcm_plugin.h | 6 | ||||
-rw-r--r-- | src/pcm/pcm_route.c | 72 | ||||
-rw-r--r-- | src/pcm/plugin_ops.h | 160 |
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] = { &©_8, &©_16, + &©_24 &©_32, &©_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 + |