OSDN Git Service

Enhanced bitmasks in PCM - added support for more formats by Takashi and me
authorJaroslav Kysela <perex@perex.cz>
Wed, 26 Jun 2002 02:04:11 +0000 (02:04 +0000)
committerJaroslav Kysela <perex@perex.cz>
Wed, 26 Jun 2002 02:04:11 +0000 (02:04 +0000)
14 files changed:
include/pcm.h
src/pcm/mask.h
src/pcm/mask_inline.h
src/pcm/pcm.c
src/pcm/pcm_hw.c
src/pcm/pcm_lfloat.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_misc.c
src/pcm/pcm_params.c
src/pcm/pcm_plug.c
src/pcm/pcm_plugin.h
src/pcm/pcm_route.c
src/pcm/plugin_ops.h

index ef28756..670d7c9 100644 (file)
@@ -160,7 +160,31 @@ typedef enum _snd_pcm_format {
        SND_PCM_FORMAT_GSM,
        /** Special */
        SND_PCM_FORMAT_SPECIAL = 31,
-       SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_SPECIAL,
+       /** Signed 24bit Little Endian in 3bytes format */
+       SND_PCM_FORMAT_S24_3LE = 32,
+       /** Signed 24bit Big Endian in 3bytes format */
+       SND_PCM_FORMAT_S24_3BE,
+       /** Unsigned 24bit Little Endian in 3bytes format */
+       SND_PCM_FORMAT_U24_3LE,
+       /** Unsigned 24bit Big Endian in 3bytes format */
+       SND_PCM_FORMAT_U24_3BE,
+       /** Signed 20bit Little Endian in 3bytes format */
+       SND_PCM_FORMAT_S20_3LE,
+       /** Signed 20bit Big Endian in 3bytes format */
+       SND_PCM_FORMAT_S20_3BE,
+       /** Unsigned 20bit Little Endian in 3bytes format */
+       SND_PCM_FORMAT_U20_3LE,
+       /** Unsigned 20bit Big Endian in 3bytes format */
+       SND_PCM_FORMAT_U20_3BE,
+       /** Signed 18bit Little Endian in 3bytes format */
+       SND_PCM_FORMAT_S18_3LE,
+       /** Signed 18bit Big Endian in 3bytes format */
+       SND_PCM_FORMAT_S18_3BE,
+       /** Unsigned 18bit Little Endian in 3bytes format */
+       SND_PCM_FORMAT_U18_3LE,
+       /** Unsigned 18bit Big Endian in 3bytes format */
+       SND_PCM_FORMAT_U18_3BE,
+       SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_U18_3BE,
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
        /** Signed 16 bit CPU endian */
@@ -817,7 +841,7 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format);
 int snd_pcm_format_cpu_endian(snd_pcm_format_t format);
 int snd_pcm_format_width(snd_pcm_format_t format);                     /* in bits */
 int snd_pcm_format_physical_width(snd_pcm_format_t format);            /* in bits */
-snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
+snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian);
 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
 u_int8_t snd_pcm_format_silence(snd_pcm_format_t format);
 u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format);
index 386dc39..ab80f20 100644 (file)
@@ -21,7 +21,7 @@
   
 typedef struct _snd_mask snd_mask_t;
 
-#define SND_MASK_MAX 31
+#define SND_MASK_MAX 64
 
 #ifdef SND_MASK_INLINE
 #include "mask_inline.h"
index 6c33e59..a44be3c 100644 (file)
 
 #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;
 }
index d184ee4..f3a80ea 100644 (file)
@@ -1200,6 +1200,18 @@ static const char *snd_pcm_format_names[] = {
        FORMAT(MPEG),
        FORMAT(GSM),
        FORMAT(SPECIAL),
+       FORMAT(S24_3LE),
+       FORMAT(S24_3BE),
+       FORMAT(U24_3LE),
+       FORMAT(U24_3BE),
+       FORMAT(S20_3LE),
+       FORMAT(S20_3BE),
+       FORMAT(U20_3LE),
+       FORMAT(U20_3BE),
+       FORMAT(S18_3LE),
+       FORMAT(S18_3BE),
+       FORMAT(U18_3LE),
+       FORMAT(U18_3BE),
 };
 
 static const char *snd_pcm_format_descriptions[] = {
@@ -1229,6 +1241,18 @@ static const char *snd_pcm_format_descriptions[] = {
        FORMATD(MPEG, "MPEG"),
        FORMATD(GSM, "GSM"),
        FORMATD(SPECIAL, "Special"),
+       FORMATD(S24_3LE, "Signed 24 bit Little Endian in 3bytes"),
+       FORMATD(S24_3BE, "Signed 24 bit Big Endian in 3bytes"),
+       FORMATD(U24_3LE, "Unsigned 24 bit Little Endian in 3bytes"),
+       FORMATD(U24_3BE, "Unsigned 24 bit Big Endian in 3bytes"),
+       FORMATD(S20_3LE, "Signed 20 bit Little Endian in 3bytes"),
+       FORMATD(S20_3BE, "Signed 20 bit Big Endian in 3bytes"),
+       FORMATD(U20_3LE, "Unsigned 20 bit Little Endian in 3bytes"),
+       FORMATD(U20_3BE, "Unsigned 20 bit Big Endian in 3bytes"),
+       FORMATD(S18_3LE, "Signed 18 bit Little Endian in 3bytes"),
+       FORMATD(S18_3BE, "Signed 18 bit Big Endian in 3bytes"),
+       FORMATD(U18_3LE, "Unsigned 18 bit Little Endian in 3bytes"),
+       FORMATD(U18_3BE, "Unsigned 18 bit Big Endian in 3bytes"),
 };
 
 static const char *snd_pcm_subformat_names[] = {
@@ -2129,6 +2153,13 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_
        return 0;
 }
 
+static void dump_one_param(snd_pcm_hw_params_t *params, unsigned int k, snd_output_t *out)
+{
+       snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(k));
+       snd_pcm_hw_param_dump(params, k, out);
+       snd_output_putc(out, '\n');
+}
+
 /**
  * \brief Dump a PCM hardware configuration space
  * \param params Configuration space
@@ -2138,11 +2169,10 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_
 int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params, snd_output_t *out)
 {
        unsigned int k;
-       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) {
-               snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(k));
-               snd_pcm_hw_param_dump(params, k, out);
-               snd_output_putc(out, '\n');
-       }
+       for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++)
+               dump_one_param(params, k, out);
+       for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
+               dump_one_param(params, k, out);
        return 0;
 }
 
@@ -5433,7 +5463,7 @@ snd_pcm_uframes_t _snd_pcm_boundary(snd_pcm_t *pcm)
        return pcm->boundary;
 }
 
-static const char *names[SND_PCM_HW_PARAM_LAST + 1] = {
+static const char *names[SND_PCM_HW_PARAM_LAST_INTERVAL + 1] = {
        [SND_PCM_HW_PARAM_FORMAT] = "format",
        [SND_PCM_HW_PARAM_CHANNELS] = "channels",
        [SND_PCM_HW_PARAM_RATE] = "rate",
@@ -5498,7 +5528,7 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
                for (k = 0; k < count; ++k) {
                        unsigned int idx = fields[k].index;
                        long v;
-                       assert(idx < SND_PCM_HW_PARAM_LAST);
+                       assert(idx < SND_PCM_HW_PARAM_LAST_INTERVAL);
                        assert(names[idx]);
                        if (strcmp(id, names[idx]) != 0)
                                continue;
index 07e9904..0a602ff 100644 (file)
@@ -54,8 +54,37 @@ const char *_snd_module_pcm_hw = "";
 #define F_SETSIG 10
 #endif
 
+/*
+ *  Compatibility
+ */
+
+struct sndrv_pcm_hw_params_old {
+       unsigned int flags;
+       unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
+                          SNDRV_PCM_HW_PARAM_ACCESS + 1];
+       struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
+                                       SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
+       unsigned int rmask;
+       unsigned int cmask;
+       unsigned int info;
+       unsigned int msbits;
+       unsigned int rate_num;
+       unsigned int rate_den;
+       sndrv_pcm_uframes_t fifo_size;
+       unsigned char reserved[64];
+};
+
+#define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
+#define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
+
 #define SND_PCM_IOCTL_XRUN _IO('A', 0x48)
 
+static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
+
+/*
+ *
+ */
+
 typedef struct {
        int version;
        int fd;
@@ -72,7 +101,7 @@ typedef struct {
 
 #define SNDRV_FILE_PCM_STREAM_PLAYBACK         "/dev/snd/pcmC%iD%ip"
 #define SNDRV_FILE_PCM_STREAM_CAPTURE          "/dev/snd/pcmC%iD%ic"
-#define SNDRV_PCM_VERSION_MAX                  SNDRV_PROTOCOL_VERSION(2, 0, 1)
+#define SNDRV_PCM_VERSION_MAX                  SNDRV_PROTOCOL_VERSION(2, 0, 2)
 
 /* update appl_ptr with driver */
 #define UPDATE_SHADOW_PTR(hw) \
@@ -146,17 +175,25 @@ static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return 0;
 }
 
+static inline int hw_refine_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
+{
+       /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
+       if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
+               return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params);
+       return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_REFINE_OLD, params);
+}
+
 static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_hw_t *hw = pcm->private_data;
-       int fd = hw->fd;
        if (hw->mmap_emulation) {
                int err = 0;
                snd_pcm_access_mask_t oldmask = *snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
-               snd_pcm_access_mask_t mask = { 0 };
+               snd_pcm_access_mask_t mask;
                const snd_mask_t *pmask;
 
-               if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params) < 0)
+               snd_mask_empty(&mask);
+               if (hw_refine_call(hw, params) < 0)
                        err = -errno;
                if (err < 0) {
                        snd_pcm_hw_params_t new = *params;
@@ -170,8 +207,8 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                        if (snd_pcm_access_mask_empty(&mask))
                                return err;
                        pmask = snd_pcm_hw_param_get_mask(&new, SND_PCM_HW_PARAM_ACCESS);
-                       ((snd_mask_t *)pmask)->bits = mask.bits;
-                       if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, &new) < 0)
+                       *(snd_mask_t *)pmask = mask;
+                       if (hw_refine_call(hw, &new) < 0)
                                return -errno;
                        *params = new;
                }
@@ -203,7 +240,7 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                        }
                }
        } else {
-               if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params) < 0) {
+               if (hw_refine_call(hw, params) < 0) {
                        // SYSERR("SNDRV_PCM_IOCTL_HW_REFINE failed");
                        return -errno;
                }
@@ -212,13 +249,20 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
        return 0;
 }
 
+static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
+{
+       /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
+       if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
+               return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
+       return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
+}
+
 static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_hw_t *hw = pcm->private_data;
-       int fd = hw->fd;
        if (hw->mmap_emulation) {
                snd_pcm_hw_params_t old = *params;
-               if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0) {
+               if (hw_params_call(hw, params) < 0) {
                        snd_pcm_access_mask_t oldmask;
                        const snd_mask_t *pmask;
 
@@ -237,13 +281,13 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
                        default:
                                goto _err;
                        }
-                       if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0)
+                       if (hw_params_call(hw, params) < 0)
                                goto _err;
                        hw->mmap_shm = 1;
                        *(snd_pcm_access_mask_t *)pmask = oldmask;
                }
        } else {
-               if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0) {
+               if (hw_params_call(hw, params) < 0) {
                      _err:
                        SYSERR("SNDRV_PCM_IOCTL_HW_PARAMS failed");
                        return -errno;
@@ -964,3 +1008,68 @@ int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
 #ifndef DOC_HIDDEN
 SND_DLSYM_BUILD_VERSION(_snd_pcm_hw_open, SND_PCM_DLSYM_VERSION);
 #endif
+
+/*
+ *  To be removed helpers, but keep binary compatibility at the time
+ */
+
+#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
+#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
+
+static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params,
+                                              struct sndrv_pcm_hw_params_old *oparams)
+{
+       unsigned int i;
+
+       memset(params, 0, sizeof(*params));
+       params->flags = oparams->flags;
+       for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
+               params->masks[i].bits[0] = oparams->masks[i];
+       memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
+       params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
+       params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
+       params->info = oparams->info;
+       params->msbits = oparams->msbits;
+       params->rate_num = oparams->rate_num;
+       params->rate_den = oparams->rate_den;
+       params->fifo_size = oparams->fifo_size;
+}
+
+static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams,
+                                            snd_pcm_hw_params_t *params,
+                                            unsigned int *cmask)
+{
+       unsigned int i, j;
+
+       memset(oparams, 0, sizeof(*oparams));
+       oparams->flags = params->flags;
+       for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++) {
+               oparams->masks[i] = params->masks[i].bits[0];
+               for (j = 1; j < sizeof(params->masks[i].bits) / sizeof(unsigned int); j++)
+                       if (params->masks[i].bits[j]) {
+                               *cmask |= 1 << i;
+                               break;
+                       }
+       }
+       memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
+       oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
+       oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
+       oparams->info = params->info;
+       oparams->msbits = params->msbits;
+       oparams->rate_num = params->rate_num;
+       oparams->rate_den = params->rate_den;
+       oparams->fifo_size = params->fifo_size;
+}
+
+static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params)
+{
+       struct sndrv_pcm_hw_params_old oparams;
+       unsigned int cmask = 0;
+       int res;
+       
+       snd_pcm_hw_convert_to_old_params(&oparams, params, &cmask);
+       res = ioctl(fd, cmd, &oparams);
+       snd_pcm_hw_convert_from_old_params(params, &oparams);
+       params->cmask |= cmask;
+       return res;
+}
index 55aee13..4abc0f9 100644 (file)
@@ -285,11 +285,11 @@ static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                dst_format = snd_pcm_hw_params_get_format(params);
        }
        if (snd_pcm_format_linear(src_format)) {
-               lfloat->int32_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32);
+               lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
                lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format);
                lfloat->func = snd_pcm_lfloat_convert_integer_float;
        } else {
-               lfloat->int32_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format);
+               lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
                lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format);
                lfloat->func = snd_pcm_lfloat_convert_float_integer;
        }
index 74aed8d..6aec4b8 100644 (file)
@@ -39,7 +39,9 @@ const char *_snd_module_pcm_linear = "";
 typedef struct {
        /* This field need to be the first */
        snd_pcm_plugin_t plug;
+       unsigned int use_getput;
        unsigned int conv_idx;
+       unsigned int get_idx, put_idx;
        snd_pcm_format_t sformat;
 } snd_pcm_linear_t;
 #endif
@@ -74,10 +76,9 @@ int snd_pcm_linear_convert_index(snd_pcm_format_t src_format,
 
 int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
 {
-       int sign, width, endian;
+       int sign, width, pwidth, endian;
        sign = (snd_pcm_format_signed(src_format) != 
                snd_pcm_format_signed(dst_format));
-       width = snd_pcm_format_width(src_format) / 8 - 1;
 #ifdef SND_LITTLE_ENDIAN
        endian = snd_pcm_format_big_endian(src_format);
 #else
@@ -85,7 +86,28 @@ int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
 #endif
        if (endian < 0)
                endian = 0;
-       return width * 4 + endian * 2 + sign;
+       pwidth = snd_pcm_format_physical_width(src_format);
+       width = snd_pcm_format_width(src_format);
+       if (pwidth == 24) {
+               switch (width) {
+               case 24:
+                       width = 0; break;
+               case 20:
+                       width = 1; break;
+               case 18:
+               default:
+                       width = 2; break;
+               }
+               return width * 4 + endian * 2 + sign + 16;
+       } else {
+               width = width / 8 - 1;
+               return width * 4 + endian * 2 + sign;
+       }
+}
+
+int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
+{
+       return snd_pcm_linear_get_index(src_format, dst_format);
 }
 
 int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
@@ -104,6 +126,37 @@ int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
        return width * 4 + endian * 2 + sign;
 }
 
+int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
+{
+       int sign, width, pwidth, endian;
+       sign = (snd_pcm_format_signed(src_format) != 
+               snd_pcm_format_signed(dst_format));
+#ifdef SND_LITTLE_ENDIAN
+       endian = snd_pcm_format_big_endian(dst_format);
+#else
+       endian = snd_pcm_format_little_endian(dst_format);
+#endif
+       if (endian < 0)
+               endian = 0;
+       pwidth = snd_pcm_format_physical_width(dst_format);
+       width = snd_pcm_format_width(dst_format);
+       if (pwidth == 24) {
+               switch (width) {
+               case 24:
+                       width = 0; break;
+               case 20:
+                       width = 1; break;
+               case 18:
+               default:
+                       width = 2; break;
+               }
+               return width * 4 + endian * 2 + sign + 16;
+       } else {
+               width = width / 8 - 1;
+               return width * 4 + endian * 2 + sign;
+       }
+}
+
 void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
                            const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
                            unsigned int channels, snd_pcm_uframes_t frames,
@@ -138,6 +191,42 @@ void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_ufr
        }
 }
 
+void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
+                          const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
+                          unsigned int channels, snd_pcm_uframes_t frames,
+                          unsigned int get_idx, unsigned int put_idx)
+{
+#define CONV24_LABELS
+#include "plugin_ops.h"
+#undef CONV24_LABELS
+       void *get = get32_labels[get_idx];
+       void *put = put32_labels[put_idx];
+       unsigned int channel;
+       u_int32_t sample = 0;
+       for (channel = 0; channel < channels; ++channel) {
+               const char *src;
+               char *dst;
+               int src_step, dst_step;
+               snd_pcm_uframes_t frames1;
+               const snd_pcm_channel_area_t *src_area = &src_areas[channel];
+               const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+               src = snd_pcm_channel_area_addr(src_area, src_offset);
+               dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+               src_step = snd_pcm_channel_area_step(src_area);
+               dst_step = snd_pcm_channel_area_step(dst_area);
+               frames1 = frames;
+               while (frames1-- > 0) {
+                       goto *get;
+#define CONV24_END after
+#include "plugin_ops.h"
+#undef CONV24_END
+               after:
+                       src += src_step;
+                       dst += dst_step;
+               }
+       }
+}
+
 #endif /* DOC_HIDDEN */
 
 static int snd_pcm_linear_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
@@ -228,12 +317,24 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                                          snd_pcm_plugin_hw_params_slave);
        if (err < 0)
                return err;
-       if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               linear->conv_idx = snd_pcm_linear_convert_index(snd_pcm_hw_params_get_format(params),
-                                                               linear->sformat);
-       else
-               linear->conv_idx = snd_pcm_linear_convert_index(linear->sformat,
-                                                               snd_pcm_hw_params_get_format(params));
+       linear->use_getput = (snd_pcm_format_physical_width(snd_pcm_hw_params_get_format(params)) == 24 ||
+                             snd_pcm_format_physical_width(linear->sformat) == 24);
+       if (linear->use_getput) {
+               if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+                       linear->get_idx = snd_pcm_linear_get32_index(snd_pcm_hw_params_get_format(params), SND_PCM_FORMAT_S32);
+                       linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, linear->sformat);
+               } else {
+                       linear->get_idx = snd_pcm_linear_get32_index(linear->sformat, SND_PCM_FORMAT_S32);
+                       linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, snd_pcm_hw_params_get_format(params));
+               }
+       } else {
+               if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+                       linear->conv_idx = snd_pcm_linear_convert_index(snd_pcm_hw_params_get_format(params),
+                                                                       linear->sformat);
+               else
+                       linear->conv_idx = snd_pcm_linear_convert_index(linear->sformat,
+                                                                       snd_pcm_hw_params_get_format(params));
+       }
        return 0;
 }
 
@@ -249,9 +350,15 @@ snd_pcm_linear_write_areas(snd_pcm_t *pcm,
        snd_pcm_linear_t *linear = pcm->private_data;
        if (size > *slave_sizep)
                size = *slave_sizep;
-       snd_pcm_linear_convert(slave_areas, slave_offset,
-                              areas, offset, 
-                              pcm->channels, size, linear->conv_idx);
+       if (linear->use_getput)
+               snd_pcm_linear_getput(slave_areas, slave_offset,
+                                     areas, offset, 
+                                     pcm->channels, size,
+                                     linear->get_idx, linear->put_idx);
+       else
+               snd_pcm_linear_convert(slave_areas, slave_offset,
+                                      areas, offset, 
+                                      pcm->channels, size, linear->conv_idx);
        *slave_sizep = size;
        return size;
 }
@@ -268,9 +375,15 @@ snd_pcm_linear_read_areas(snd_pcm_t *pcm,
        snd_pcm_linear_t *linear = pcm->private_data;
        if (size > *slave_sizep)
                size = *slave_sizep;
-       snd_pcm_linear_convert(areas, offset, 
-                              slave_areas, slave_offset,
-                              pcm->channels, size, linear->conv_idx);
+       if (linear->use_getput)
+               snd_pcm_linear_getput(areas, offset, 
+                                     slave_areas, slave_offset,
+                                     pcm->channels, size,
+                                     linear->get_idx, linear->put_idx);
+       else
+               snd_pcm_linear_convert(areas, offset, 
+                                      slave_areas, slave_offset,
+                                      pcm->channels, size, linear->conv_idx);
        *slave_sizep = size;
        return size;
 }
index aaf0a5d..aa2341c 100644 (file)
@@ -25,6 +25,7 @@
 #include <limits.h>
 #include <sys/uio.h>
 
+#define _snd_mask sndrv_mask
 #define _snd_pcm_access_mask _snd_mask
 #define _snd_pcm_format_mask _snd_mask
 #define _snd_pcm_subformat_mask _snd_mask
@@ -57,7 +58,6 @@ typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t;
 #define SND_PCM_HW_PARAM_BUFFER_BYTES SNDRV_PCM_HW_PARAM_BUFFER_BYTES
 #define SND_PCM_HW_PARAM_TICK_TIME SNDRV_PCM_HW_PARAM_TICK_TIME
 #define SND_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_LAST_INTERVAL
-#define SND_PCM_HW_PARAM_LAST SNDRV_PCM_HW_PARAM_LAST
 #define SND_PCM_HW_PARAMS_RUNTIME SNDRV_PCM_HW_PARAMS_RUNTIME
 #define SND_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_LAST_MASK
 #define SND_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_FIRST_MASK
@@ -568,24 +568,24 @@ int snd_pcm_conf_generic_id(const char *id);
 #define SND_PCM_HW_PARBIT_TICK_TIME    (1U << SND_PCM_HW_PARAM_TICK_TIME)
 
 
-#define SND_PCM_ACCBIT_MMAP ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+#define SND_PCM_ACCBIT_MMAP ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
                             (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
-                            (1U << SND_PCM_ACCESS_MMAP_COMPLEX))
-#define SND_PCM_ACCBIT_MMAPI (1U << SND_PCM_ACCESS_MMAP_INTERLEAVED)
-#define SND_PCM_ACCBIT_MMAPN (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
-#define SND_PCM_ACCBIT_MMAPC (1U << SND_PCM_ACCESS_MMAP_COMPLEX)
+                            (1U << SND_PCM_ACCESS_MMAP_COMPLEX)) }
+#define SND_PCM_ACCBIT_MMAPI { (1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) }
+#define SND_PCM_ACCBIT_MMAPN { (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) }
+#define SND_PCM_ACCBIT_MMAPC { (1U << SND_PCM_ACCESS_MMAP_COMPLEX) }
 
-#define SND_PCM_ACCBIT_SHM ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+#define SND_PCM_ACCBIT_SHM ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
                            (1U << SND_PCM_ACCESS_RW_INTERLEAVED) | \
                            (1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
-                           (1U << SND_PCM_ACCESS_RW_NONINTERLEAVED))
-#define SND_PCM_ACCBIT_SHMI ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
-                            (1U << SND_PCM_ACCESS_RW_INTERLEAVED))
-#define SND_PCM_ACCBIT_SHMN ((1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
-                            (1U << SND_PCM_ACCESS_RW_NONINTERLEAVED))
+                           (1U << SND_PCM_ACCESS_RW_NONINTERLEAVED)) }
+#define SND_PCM_ACCBIT_SHMI ((1U << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+                            (1U << SND_PCM_ACCESS_RW_INTERLEAVED)) }
+#define SND_PCM_ACCBIT_SHMN ((1U << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
+                            (1U << SND_PCM_ACCESS_RW_NONINTERLEAVED)) }
 
 #define SND_PCM_FMTBIT_LINEAR \
-       ((1U << SND_PCM_FORMAT_S8) | \
+       ((1U << SND_PCM_FORMAT_S8) | \
         (1U << SND_PCM_FORMAT_U8) | \
         (1U << SND_PCM_FORMAT_S16_LE) | \
         (1U << SND_PCM_FORMAT_S16_BE) | \
@@ -598,10 +598,23 @@ int snd_pcm_conf_generic_id(const char *id);
         (1U << SND_PCM_FORMAT_S32_LE) | \
         (1U << SND_PCM_FORMAT_S32_BE) | \
         (1U << SND_PCM_FORMAT_U32_LE) | \
-        (1U << SND_PCM_FORMAT_U32_BE))
+        (1U << SND_PCM_FORMAT_U32_BE)), \
+       ((1U << (SND_PCM_FORMAT_S24_3LE - 32)) | \
+        (1U << (SND_PCM_FORMAT_U24_3LE - 32)) | \
+        (1U << (SND_PCM_FORMAT_S24_3BE - 32)) | \
+        (1U << (SND_PCM_FORMAT_U24_3BE - 32)) | \
+        (1U << (SND_PCM_FORMAT_S20_3LE - 32)) | \
+        (1U << (SND_PCM_FORMAT_U20_3LE - 32)) | \
+        (1U << (SND_PCM_FORMAT_S20_3BE - 32)) | \
+        (1U << (SND_PCM_FORMAT_U20_3BE - 32)) | \
+        (1U << (SND_PCM_FORMAT_S18_3LE - 32)) | \
+        (1U << (SND_PCM_FORMAT_U18_3LE - 32)) | \
+        (1U << (SND_PCM_FORMAT_S18_3BE - 32)) | \
+        (1U << (SND_PCM_FORMAT_U18_3BE - 32))) }
+       
 
 #define SND_PCM_FMTBIT_FLOAT \
-       ((1U << SND_PCM_FORMAT_FLOAT_LE) | \
+       ((1U << SND_PCM_FORMAT_FLOAT_LE) | \
         (1U << SND_PCM_FORMAT_FLOAT_BE) | \
         (1U << SND_PCM_FORMAT_FLOAT64_LE) | \
-        (1U << SND_PCM_FORMAT_FLOAT64_BE))
+        (1U << SND_PCM_FORMAT_FLOAT64_BE)) }
index 29fbd72..c62e700 100644 (file)
@@ -42,6 +42,12 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_S24_BE:
        case SNDRV_PCM_FORMAT_S32_LE:
        case SNDRV_PCM_FORMAT_S32_BE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
                return 1;
        case SNDRV_PCM_FORMAT_U8:
        case SNDRV_PCM_FORMAT_U16_LE:
@@ -50,6 +56,12 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_U24_BE:
        case SNDRV_PCM_FORMAT_U32_LE:
        case SNDRV_PCM_FORMAT_U32_BE:
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_U24_3BE:
+       case SNDRV_PCM_FORMAT_U20_3LE:
+       case SNDRV_PCM_FORMAT_U20_3BE:
+       case SNDRV_PCM_FORMAT_U18_3LE:
+       case SNDRV_PCM_FORMAT_U18_3BE:
                return 0;
        default:
                return -EINVAL;
@@ -116,6 +128,12 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_FLOAT_LE:
        case SNDRV_PCM_FORMAT_FLOAT64_LE:
        case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_U20_3LE:
+       case SNDRV_PCM_FORMAT_U18_3LE:
                return 1;
        case SNDRV_PCM_FORMAT_S16_BE:
        case SNDRV_PCM_FORMAT_U16_BE:
@@ -126,6 +144,12 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_FLOAT_BE:
        case SNDRV_PCM_FORMAT_FLOAT64_BE:
        case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
+       case SNDRV_PCM_FORMAT_U24_3BE:
+       case SNDRV_PCM_FORMAT_U20_3BE:
+       case SNDRV_PCM_FORMAT_U18_3BE:
                return 0;
        default:
                return -EINVAL;
@@ -177,10 +201,24 @@ int snd_pcm_format_width(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_U16_LE:
        case SNDRV_PCM_FORMAT_U16_BE:
                return 16;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
+       case SNDRV_PCM_FORMAT_U18_3LE:
+       case SNDRV_PCM_FORMAT_U18_3BE:
+               return 18;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+       case SNDRV_PCM_FORMAT_U20_3LE:
+       case SNDRV_PCM_FORMAT_U20_3BE:
+               return 20;
        case SNDRV_PCM_FORMAT_S24_LE:
        case SNDRV_PCM_FORMAT_S24_BE:
        case SNDRV_PCM_FORMAT_U24_LE:
        case SNDRV_PCM_FORMAT_U24_BE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_U24_3BE:
                return 24;
        case SNDRV_PCM_FORMAT_S32_LE:
        case SNDRV_PCM_FORMAT_S32_BE:
@@ -221,6 +259,19 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_U16_LE:
        case SNDRV_PCM_FORMAT_U16_BE:
                return 16;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
+       case SNDRV_PCM_FORMAT_U18_3LE:
+       case SNDRV_PCM_FORMAT_U18_3BE:
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+       case SNDRV_PCM_FORMAT_U20_3LE:
+       case SNDRV_PCM_FORMAT_U20_3BE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_U24_3BE:
+               return 24;
        case SNDRV_PCM_FORMAT_S24_LE:
        case SNDRV_PCM_FORMAT_S24_BE:
        case SNDRV_PCM_FORMAT_U24_LE:
@@ -264,6 +315,19 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
        case SNDRV_PCM_FORMAT_U16_LE:
        case SNDRV_PCM_FORMAT_U16_BE:
                return samples * 2;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
+       case SNDRV_PCM_FORMAT_U18_3LE:
+       case SNDRV_PCM_FORMAT_U18_3BE:
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+       case SNDRV_PCM_FORMAT_U20_3LE:
+       case SNDRV_PCM_FORMAT_U20_3BE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_U24_3BE:
+               return samples * 3;
        case SNDRV_PCM_FORMAT_S24_LE:
        case SNDRV_PCM_FORMAT_S24_BE:
        case SNDRV_PCM_FORMAT_U24_LE:
@@ -309,6 +373,12 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_S24_BE:
        case SNDRV_PCM_FORMAT_S32_LE:
        case SNDRV_PCM_FORMAT_S32_BE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
+       case SNDRV_PCM_FORMAT_S24_3BE:
+       case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
+       case SNDRV_PCM_FORMAT_S18_3LE:
+       case SNDRV_PCM_FORMAT_S18_3BE:
                return 0;
        case SNDRV_PCM_FORMAT_U8:
                return 0x8080808080808080ULL;
@@ -339,6 +409,15 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format)
        case SNDRV_PCM_FORMAT_U32_BE:
                return 0x8000000080000000ULL;
 #endif
+       case SNDRV_PCM_FORMAT_U24_3LE:
+       case SNDRV_PCM_FORMAT_U24_3BE:
+               return 0x0000800000800000ULL;
+       case SNDRV_PCM_FORMAT_U20_3LE:
+       case SNDRV_PCM_FORMAT_U20_3BE:
+               return 0x0000080000080000ULL;
+       case SNDRV_PCM_FORMAT_U18_3LE:
+       case SNDRV_PCM_FORMAT_U18_3BE:
+               return 0x0000020000020000ULL;
        case SNDRV_PCM_FORMAT_FLOAT_LE:
        {
                union {
@@ -470,20 +549,45 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
        }
        case 16: {
                u_int16_t silence = snd_pcm_format_silence_64(format);
-               while (samples-- > 0)
-                       *((u_int16_t *)data)++ = silence;
+               if (! silence)
+                       memset(data, 0, samples * 2);
+               else {
+                       while (samples-- > 0)
+                               *((u_int16_t *)data)++ = silence;
+               }
                break;
        }
+       case 24: {
+               u_int32_t silence = snd_pcm_format_silence_64(format);
+               if (! silence)
+                       memset(data, 0, samples * 3);
+               else {
+                       /* FIXME: rewrite in the more better way.. */
+                       int i;
+                       while (samples-- > 0) {
+                               for (i = 0; i < 3; i++)
+                                       *((u_int8_t *)data)++ = silence >> (i * 8);
+                       }
+               }
+       }
        case 32: {
                u_int32_t silence = snd_pcm_format_silence_64(format);
-               while (samples-- > 0)
-                       *((u_int32_t *)data)++ = silence;
+               if (! silence)
+                       memset(data, 0, samples * 4);
+               else {
+                       while (samples-- > 0)
+                               *((u_int32_t *)data)++ = silence;
+               }
                break;
        }
        case 64: {
                u_int64_t silence = snd_pcm_format_silence_64(format);
-               while (samples-- > 0)
-                       *((u_int64_t *)data)++ = silence;
+               if (! silence)
+                       memset(data, 0, samples * 8);
+               else {
+                       while (samples-- > 0)
+                               *((u_int64_t *)data)++ = silence;
+               }
                break;
        }
        default:
@@ -512,29 +616,62 @@ static int linear_formats[4*2*2] = {
        SNDRV_PCM_FORMAT_U32_BE
 };
 
+static int linear24_formats[3*2*2] = {
+       SNDRV_PCM_FORMAT_S24_3LE,
+       SNDRV_PCM_FORMAT_S24_3BE,
+       SNDRV_PCM_FORMAT_U24_3LE,
+       SNDRV_PCM_FORMAT_U24_3BE,
+       SNDRV_PCM_FORMAT_S20_3LE,
+       SNDRV_PCM_FORMAT_S20_3BE,
+       SNDRV_PCM_FORMAT_U20_3LE,
+       SNDRV_PCM_FORMAT_U20_3BE,
+       SNDRV_PCM_FORMAT_S18_3LE,
+       SNDRV_PCM_FORMAT_S18_3BE,
+       SNDRV_PCM_FORMAT_U18_3LE,
+       SNDRV_PCM_FORMAT_U18_3BE,
+};
+
 /**
  * \brief Compose a PCM sample linear format
  * \param width Nominal bits per sample
+ * \param pwidth Physical bit width of the format
  * \param unsignd Sign: 0 signed, 1 unsigned
  * \return big_endian Endian: 0 little endian, 1 big endian
  */
-snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
+snd_pcm_format_t snd_pcm_build_linear_format(int width, int pwidth, int unsignd, int big_endian)
 {
-       switch (width) {
-       case 8:
-               width = 0;
-               break;
-       case 16:
-               width = 1;
-               break;
-       case 24:
-               width = 2;
-               break;
-       case 32:
-               width = 3;
-               break;
-       default:
-               return SND_PCM_FORMAT_UNKNOWN;
+       if (pwidth == 24) {
+               switch (width) {
+               case 24:
+                       width = 0;
+                       break;
+               case 20:
+                       width = 1;
+                       break;
+               case 18:
+                       width = 2;
+                       break;
+               default:
+                       return SND_PCM_FORMAT_UNKNOWN;
+               }
+               return ((int(*)[2][2])linear24_formats)[width][!!unsignd][!!big_endian];
+       } else {
+               switch (width) {
+               case 8:
+                       width = 0;
+                       break;
+               case 16:
+                       width = 1;
+                       break;
+               case 24:
+                       width = 2;
+                       break;
+               case 32:
+                       width = 3;
+                       break;
+               default:
+                       return SND_PCM_FORMAT_UNKNOWN;
+               }
+               return ((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian];
        }
-       return ((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian];
 }
index c9d9460..2f5acd4 100644 (file)
@@ -91,7 +91,9 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
 {
        unsigned int k;
        memset(params, 0, sizeof(*params));
-       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
+       for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++)
+               _snd_pcm_hw_param_any(params, k);
+       for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
                _snd_pcm_hw_param_any(params, k);
        params->info = ~0U;
 }
@@ -618,7 +620,7 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
                snd_mask_t *m = hw_param_mask(params, var);
                if (val == 0 && dir < 0) {
                        changed = -EINVAL;
-               snd_mask_none(m);
+                       snd_mask_none(m);
                } else {
                        if (dir > 0)
                                val++;
@@ -1144,7 +1146,7 @@ const char *snd_pcm_hw_param_names[] = {
 
 const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param)
 {
-       assert(param <= SND_PCM_HW_PARAM_LAST);
+       assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL);
        return snd_pcm_hw_param_names[param];
 }
 
@@ -1250,7 +1252,7 @@ void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy)
 {
        snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
        int k;
-       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
                if (pars[k].valid && pars[k].free)
                        pars[k].free(&pars[k]);
        }
@@ -1266,7 +1268,7 @@ int snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
        const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
        unsigned int min_choices = UINT_MAX;
        unsigned int min_order = UINT_MAX;
-       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
                const snd_pcm_hw_strategy_simple_t *p = &pars[var];
                unsigned int choices;
                if (!p->valid)
@@ -1306,7 +1308,7 @@ int snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
        snd_pcm_hw_param_t var;
        unsigned int badness = 0;
        const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
-       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
                unsigned int b;
                if (!pars[var].valid)
                        continue;
@@ -1418,7 +1420,7 @@ int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp,
        snd_pcm_hw_strategy_simple_t *data;
        snd_pcm_hw_strategy_t *s;
        assert(strategyp);
-       data = calloc(SND_PCM_HW_PARAM_LAST + 1, sizeof(*data));
+       data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data));
        if (!data)
                return -ENOMEM;
        s = calloc(1, sizeof(*s));
@@ -1446,7 +1448,7 @@ int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy,
        snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
        snd_pcm_hw_strategy_simple_near_t *data;
        assert(strategy);
-       assert(var <= SND_PCM_HW_PARAM_LAST);
+       assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
        assert(!s->valid);
        data = calloc(1, sizeof(*data));
        if (!data)
@@ -1472,7 +1474,7 @@ int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy,
        snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
        snd_pcm_hw_strategy_simple_choices_t *data;
        assert(strategy);
-       assert(var <= SND_PCM_HW_PARAM_LAST);
+       assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
        assert(!s->valid);
        data = calloc(1, sizeof(*data));
        if (!data)
@@ -1499,7 +1501,7 @@ int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
        snd_pcm_hw_params_t i;
        if (depth < 1)
                return -ENOENT;
-       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
                int err;
                i = *success;
                _snd_pcm_hw_param_copy(&i, var, fail);
@@ -1526,7 +1528,7 @@ int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
        snd_pcm_hw_param_t var;
        int done = 0;
        assert(pcm && fail);
-       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
                if (!snd_pcm_hw_param_empty(fail, var))
                        continue;
                snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var));
@@ -1805,16 +1807,16 @@ static snd_pcm_hw_rule_t refine_rules[] = {
 
 static snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = {
        [SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = {
-               bits: 0x1f,
+               bits: { 0x1f },
        },
        [SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
-               bits: 0x81ffffff,
+               bits: { 0x81ffffff, 0xfff},
        },
        [SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
-               bits: 0x1,
+               bits: { 0x1 },
        },
 };
-
+  
 static snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
        [SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
                min: 1, max: UINT_MAX,
@@ -1873,7 +1875,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
        unsigned int k;
        snd_interval_t *i;
        unsigned int rstamps[RULES];
-       unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
+       unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
        unsigned int stamp = 2;
        int changed, again;
 #ifdef RULES_DEBUG
@@ -1885,7 +1887,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
                if (!(params->rmask & (1 << k)))
                        continue;
                changed = snd_mask_refine(hw_param_mask(params, k),
-                                 &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
+                                         &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
                if (changed)
                        params->cmask |= 1 << k;
                if (changed < 0)
@@ -1905,7 +1907,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t
 
        for (k = 0; k < RULES; k++)
                rstamps[k] = 0;
-       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
                vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
        do {
                again = 0;
@@ -1978,7 +1980,7 @@ int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
 {
        int changed, err = 0;
        unsigned int k;
-       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
                if (!(vars & (1 << k)))
                        continue;
                changed = _snd_pcm_hw_param_refine(params, k, src);
index d3fe50f..1553af7 100644 (file)
@@ -145,6 +145,39 @@ static snd_pcm_format_t linear_preferred_formats[] = {
        SND_PCM_FORMAT_S24_LE,
        SND_PCM_FORMAT_U24_LE,
 #endif
+#ifdef SND_LITTLE_ENDIAN
+       SND_PCM_FORMAT_S24_3LE,
+       SND_PCM_FORMAT_U24_3LE,
+       SND_PCM_FORMAT_S24_3BE,
+       SND_PCM_FORMAT_U24_3BE,
+#else
+       SND_PCM_FORMAT_S24_3BE,
+       SND_PCM_FORMAT_U24_3BE,
+       SND_PCM_FORMAT_S24_3LE,
+       SND_PCM_FORMAT_U24_3LE,
+#endif
+#ifdef SND_LITTLE_ENDIAN
+       SND_PCM_FORMAT_S20_3LE,
+       SND_PCM_FORMAT_U20_3LE,
+       SND_PCM_FORMAT_S20_3BE,
+       SND_PCM_FORMAT_U20_3BE,
+#else
+       SND_PCM_FORMAT_S20_3BE,
+       SND_PCM_FORMAT_U20_3BE,
+       SND_PCM_FORMAT_S20_3LE,
+       SND_PCM_FORMAT_U20_3LE,
+#endif
+#ifdef SND_LITTLE_ENDIAN
+       SND_PCM_FORMAT_S18_3LE,
+       SND_PCM_FORMAT_U18_3LE,
+       SND_PCM_FORMAT_S18_3BE,
+       SND_PCM_FORMAT_U18_3BE,
+#else
+       SND_PCM_FORMAT_S18_3BE,
+       SND_PCM_FORMAT_U18_3BE,
+       SND_PCM_FORMAT_S18_3LE,
+       SND_PCM_FORMAT_U18_3LE,
+#endif
 };
 
 static snd_pcm_format_t nonlinear_preferred_formats[] = {
@@ -167,9 +200,39 @@ static snd_pcm_format_t float_preferred_formats[] = {
 #endif
 };
 
+static char linear_format_widths[32] = {
+       0, 0, 0, 0, 0, 0, 0, 1,
+       0, 0, 0, 0, 0, 0, 0, 1,
+       0, 1, 0, 1, 0, 0, 0, 1,
+       0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+static int check_linear_format(const snd_pcm_format_mask_t *format_mask, int wid, int sgn, int ed)
+{
+       int e, s;
+       if (! linear_format_widths[wid - 1])
+               return SND_PCM_FORMAT_UNKNOWN;
+       for (e = 0; e < 2; e++) {
+               for (s = 0; s < 2; s++) {
+                       int pw = ((wid + 7) / 8) * 8;
+                       for (; pw <= 32; pw += 8) {
+                               snd_pcm_format_t f;
+                               f = snd_pcm_build_linear_format(wid, pw, sgn, ed);
+                               if (f != SND_PCM_FORMAT_UNKNOWN &&
+                                   snd_pcm_format_mask_test(format_mask, f))
+                                       return f;
+                       }
+                       sgn = !sgn;
+               }
+               ed = !ed;
+       }
+       return SND_PCM_FORMAT_UNKNOWN;
+}
+
 static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const snd_pcm_format_mask_t *format_mask)
 {
-       int w, u, e, wid, w1, dw;
+       int w, w1, u, e;
+       snd_pcm_format_t f;
        snd_pcm_format_mask_t lin = { SND_PCM_FMTBIT_LINEAR };
        snd_pcm_format_mask_t fl = { SND_PCM_FMTBIT_FLOAT };
        if (snd_pcm_format_mask_test(format_mask, format))
@@ -228,28 +291,15 @@ static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const
                u = snd_pcm_format_unsigned(format);
                e = snd_pcm_format_big_endian(format);
        }
-       w1 = w;
-       dw = 8;
-       for (wid = 0; wid < 4; ++wid) {
-               int end, e1 = e;
-               for (end = 0; end < 2; ++end) {
-                       int sgn, u1 = u;
-                       for (sgn = 0; sgn < 2; ++sgn) {
-                               snd_pcm_format_t f;
-                               f = snd_pcm_build_linear_format(w1, u1, e1);
-                               assert(f != SND_PCM_FORMAT_UNKNOWN);
-                               if (snd_pcm_format_mask_test(format_mask, f))
-                                       return f;
-                               u1 = !u1;
-                       }
-                       e1 = !e1;
-               }
-               if (w1 < 32)
-                       w1 += dw;
-               else {
-                       w1 = w - 8;
-                       dw = -8;
-               }
+       for (w1 = w; w1 <= 32; w1++) {
+               f = check_linear_format(format_mask, w1, u, e);
+               if (f != SND_PCM_FORMAT_UNKNOWN)
+                       return f;
+       }
+       for (w1 = w - 1; w1 > 0; w1--) {
+               f = check_linear_format(format_mask, w1, u, e);
+               if (f != SND_PCM_FORMAT_UNKNOWN)
+                       return f;
        }
        return SND_PCM_FORMAT_UNKNOWN;
 }
index cb48ea8..6e1dc8b 100644 (file)
@@ -105,12 +105,18 @@ snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic
 
 int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
+int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
+int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 
 void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
                            const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
                            unsigned int channels, snd_pcm_uframes_t frames,
                            unsigned int convidx);
+void snd_pcm_linear_getput(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
+                          const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
+                          unsigned int channels, snd_pcm_uframes_t frames,
+                          unsigned int get_idx, unsigned int put_idx);
 void snd_pcm_alaw_decode(const snd_pcm_channel_area_t *dst_areas,
                         snd_pcm_uframes_t dst_offset,
                         const snd_pcm_channel_area_t *src_areas,
index 2c492c3..eed050b 100644 (file)
@@ -62,6 +62,7 @@ typedef struct {
        unsigned int get_idx;
        unsigned int put_idx;
        unsigned int conv_idx;
+       int use_getput;
        unsigned int src_size;
        snd_pcm_format_t dst_sfmt;
        unsigned int ndsts;
@@ -160,6 +161,53 @@ static void snd_pcm_route_convert1_one(const snd_pcm_channel_area_t *dst_area,
        }
 }
 
+static void snd_pcm_route_convert1_one_getput(const snd_pcm_channel_area_t *dst_area,
+                                             snd_pcm_uframes_t dst_offset,
+                                             const snd_pcm_channel_area_t *src_areas,
+                                             snd_pcm_uframes_t src_offset,
+                                             snd_pcm_uframes_t frames,
+                                             const snd_pcm_route_ttable_dst_t* ttable,
+                                             const snd_pcm_route_params_t *params)
+{
+#define CONV24_LABELS
+#include "plugin_ops.h"
+#undef CONV24_LABELS
+       void *get, *put;
+       const snd_pcm_channel_area_t *src_area = 0;
+       unsigned int srcidx;
+       const char *src;
+       char *dst;
+       int src_step, dst_step;
+       u_int32_t sample = 0;
+       for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
+               src_area = &src_areas[ttable->srcs[srcidx].channel];
+               if (src_area->addr != NULL)
+                       break;
+       }
+       if (srcidx == ttable->nsrcs) {
+               snd_pcm_route_convert1_zero(dst_area, dst_offset,
+                                           src_areas, src_offset,
+                                           frames, ttable, params);
+               return;
+       }
+       
+       get = get32_labels[params->get_idx];
+       put = put32_labels[params->put_idx];
+       src = snd_pcm_channel_area_addr(src_area, src_offset);
+       dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+       src_step = snd_pcm_channel_area_step(src_area);
+       dst_step = snd_pcm_channel_area_step(dst_area);
+       while (frames-- > 0) {
+               goto *get;
+#define CONV24_END after
+#include "plugin_ops.h"
+#undef CONV24_END
+       after:
+               src += src_step;
+               dst += dst_step;
+       }
+}
+
 static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
                                        snd_pcm_uframes_t dst_offset,
                                        const snd_pcm_channel_area_t *src_areas,
@@ -239,9 +287,14 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area,
                                            frames, ttable, params);
                return;
        } else if (nsrcs == 1 && src_tt[0].as_int == SND_PCM_PLUGIN_ROUTE_RESOLUTION) {
-               snd_pcm_route_convert1_one(dst_area, dst_offset,
-                                          src_areas, src_offset,
-                                          frames, ttable, params);
+               if (params->use_getput)
+                       snd_pcm_route_convert1_one_getput(dst_area, dst_offset,
+                                                         src_areas, src_offset,
+                                                         frames, ttable, params);
+               else
+                       snd_pcm_route_convert1_one(dst_area, dst_offset,
+                                                  src_areas, src_offset,
+                                                  frames, ttable, params);
                return;
        }
 
@@ -561,8 +614,10 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
                src_format = slave->format;
                dst_format = snd_pcm_hw_params_get_format(params);
        }
+       route->params.use_getput = snd_pcm_format_physical_width(src_format) == 24 ||
+               snd_pcm_format_physical_width(dst_format) == 24;
        route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16);
-       route->params.put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format);
+       route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
        route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format);
        route->params.src_size = snd_pcm_format_width(src_format) / 8;
        route->params.dst_sfmt = dst_format;
@@ -730,9 +785,12 @@ static int route_load_ttable(snd_pcm_route_params_t *params, snd_pcm_stream_t st
                dptr->nsrcs = nsrcs;
                if (nsrcs == 0)
                        dptr->func = snd_pcm_route_convert1_zero;
-               else if (nsrcs == 1 && !att)
-                       dptr->func = snd_pcm_route_convert1_one;
-               else
+               else if (nsrcs == 1 && !att) {
+                       if (params->use_getput)
+                               dptr->func = snd_pcm_route_convert1_one_getput;
+                       else
+                               dptr->func = snd_pcm_route_convert1_one;
+               } else
                        dptr->func = snd_pcm_route_convert1_many;
                if (nsrcs > 0) {
                        dptr->srcs = calloc((unsigned int) nsrcs, sizeof(*srcs));
index bbf177f..1e2b73f 100644 (file)
 
 #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))
 #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
+