]> git.alsa-project.org Git - alsa-lib.git/commitdiff
New plugin interface with readv/writev support.
authorJaroslav Kysela <perex@perex.cz>
Wed, 29 Mar 2000 20:26:06 +0000 (20:26 +0000)
committerJaroslav Kysela <perex@perex.cz>
Wed, 29 Mar 2000 20:26:06 +0000 (20:26 +0000)
Initial code.

15 files changed:
include/pcm.h
src/pcm/pcm_local.h
src/pcm/pcm_plugin.c
src/pcm/pcm_plugin_build.c
src/pcm/plugin/Makefile.am
src/pcm/plugin/adpcm.c
src/pcm/plugin/alaw.c
src/pcm/plugin/block.c
src/pcm/plugin/interleave.c
src/pcm/plugin/linear.c
src/pcm/plugin/mmap.c
src/pcm/plugin/mulaw.c
src/pcm/plugin/rate.c
src/pcm/plugin/route.c
src/pcm/plugin/stream.c

index 29d717619ec06ddf51f2e97adbcac43f8896d8dd..4bd9a211204d332be5583f75a0c33f39a9258aef 100644 (file)
@@ -65,38 +65,69 @@ const char *snd_pcm_get_format_name(int format);
 #endif
 
 /*
- *  Plug-In interface (ala C++)
+ *  PCM Plug-In interface
  */
 
 typedef struct snd_stru_pcm_plugin snd_pcm_plugin_t;
+#define snd_pcm_plugin_handle_t snd_pcm_t
 
 typedef enum {
        INIT = 0,
        PREPARE = 1,
        DRAIN = 2,
-       FLUSH = 3
+       FLUSH = 3,
 } snd_pcm_plugin_action_t;
 
-#define snd_pcm_plugin_extra_data(plugin) (((char *)plugin) + sizeof(*plugin))
+typedef struct snd_stru_pcm_plugin_voice {
+       void *aptr;                     /* pointer to the allocated area */
+       void *addr;                     /* address to voice samples */
+       unsigned int offset;            /* offset to first voice in bits */
+       unsigned int next;              /* offset to next voice in bits */
+} snd_pcm_plugin_voice_t;
 
 struct snd_stru_pcm_plugin {
-       char *name;                                /* plug-in name */
-       int (*transfer_src_ptr)(snd_pcm_plugin_t *plugin, char **src_ptr, size_t *src_size);
+       char *name;                     /* plug-in name */
+       snd_pcm_format_t src_format;    /* source format */
+       snd_pcm_format_t dst_format;    /* destination format */
+       int src_width;                  /* sample width in bits */
+       int dst_width;                  /* sample width in bits */
+       ssize_t (*src_samples)(snd_pcm_plugin_t *plugin, size_t dst_samples);
+       ssize_t (*dst_samples)(snd_pcm_plugin_t *plugin, size_t src_samples);
+       int (*src_voices)(snd_pcm_plugin_t *plugin,
+                         snd_pcm_plugin_voice_t **voices,
+                         size_t samples,
+                         void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size));
+       int (*dst_voices)(snd_pcm_plugin_t *plugin,
+                         snd_pcm_plugin_voice_t **voices,
+                         size_t samples,
+                         void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size));
        ssize_t (*transfer)(snd_pcm_plugin_t *plugin,
-                           char *src_ptr, size_t src_size,
-                           char *dst_ptr, size_t dst_size);
-       ssize_t (*src_size)(snd_pcm_plugin_t *plugin, size_t dst_size);
-       ssize_t (*dst_size)(snd_pcm_plugin_t *plugin, size_t src_size);
+                           const snd_pcm_plugin_voice_t *src_voices,
+                           const snd_pcm_plugin_voice_t *dst_voices,
+                           size_t samples);
        int (*action)(snd_pcm_plugin_t *plugin,
                      snd_pcm_plugin_action_t action,
                      unsigned long data);
+       int (*parameter_set)(snd_pcm_plugin_t *plugin,
+                            const char *name,
+                            unsigned long value);
+       int (*parameter_get)(snd_pcm_plugin_t *plugin,
+                            const char *name,
+                            unsigned long *value);
        snd_pcm_plugin_t *prev;
        snd_pcm_plugin_t *next;
+       snd_pcm_plugin_handle_t *handle;
        void *private_data;
        void (*private_free)(snd_pcm_plugin_t *plugin, void *private_data);
+       snd_pcm_plugin_voice_t *voices;
+       void *extra_data;
 };
 
-snd_pcm_plugin_t *snd_pcm_plugin_build(const char *name, int extra);
+snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
+                                      const char *name,
+                                      snd_pcm_format_t *src_format,
+                                      snd_pcm_format_t *dst_format,
+                                      int extra);
 int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
 int snd_pcm_plugin_clear(snd_pcm_t *handle, int channel);
 int snd_pcm_plugin_insert(snd_pcm_t *handle, int channel, snd_pcm_plugin_t *plugin);
@@ -105,8 +136,10 @@ int snd_pcm_plugin_remove_to(snd_pcm_t *handle, int channel, snd_pcm_plugin_t *p
 int snd_pcm_plugin_remove_first(snd_pcm_t *handle, int channel);
 snd_pcm_plugin_t *snd_pcm_plugin_first(snd_pcm_t *handle, int channel);
 snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *handle, int channel);
-ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *handle, int channel, size_t drv_size);
-ssize_t snd_pcm_plugin_hardware_size(snd_pcm_t *handle, int channel, size_t trf_size);
+ssize_t snd_pcm_plugin_client_samples(snd_pcm_t *handle, int channel, size_t drv_samples);
+ssize_t snd_pcm_plugin_hardware_samples(snd_pcm_t *handle, int channel, size_t clt_samples);
+ssize_t snd_pcm_plugin_client_size(snd_pcm_t *handle, int channel, size_t drv_size);
+ssize_t snd_pcm_plugin_hardware_size(snd_pcm_t *handle, int channel, size_t clt_size);
 int snd_pcm_plugin_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
 int snd_pcm_plugin_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
 int snd_pcm_plugin_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
@@ -114,41 +147,74 @@ int snd_pcm_plugin_status(snd_pcm_t *handle, snd_pcm_channel_status_t *status);
 int snd_pcm_plugin_prepare(snd_pcm_t *handle, int channel);
 int snd_pcm_plugin_playback_drain(snd_pcm_t *handle);
 int snd_pcm_plugin_flush(snd_pcm_t *handle, int channel);
+ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *handle, int channel);
 int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size);
 ssize_t snd_pcm_plugin_write(snd_pcm_t *handle, const void *buffer, size_t size);
 ssize_t snd_pcm_plugin_read(snd_pcm_t *handle, void *bufer, size_t size);
+int snd_pcm_plugin_pointerv(snd_pcm_t *pcm, int channel, struct iovec **vector, int *count);
+ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
+ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int count);
+ssize_t snd_pcm_plugin_write_continue(snd_pcm_t *pcm);
+
+/*
+ *  Plug-In helpers
+ */
+
+ssize_t snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples);
+ssize_t snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples);
+ssize_t snd_pcm_plugin_src_size_to_samples(snd_pcm_plugin_t *plugin, size_t size);
+ssize_t snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_t *plugin, size_t size);
+int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin,
+                             snd_pcm_plugin_voice_t **voices,
+                             size_t samples);
+int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
+                             snd_pcm_plugin_voice_t **voices,
+                             size_t samples);
 
 /*
  *  Plug-In constructors
  */
 
 /* basic I/O */
-int snd_pcm_plugin_build_stream(snd_pcm_t *handle, int channel, snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_block(snd_pcm_t *handle, int channel, snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mmap(snd_pcm_t *handle, int channel, snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *handle, int channel,
+                               snd_pcm_format_t *format,
+                               snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *handle, int channel,
+                              snd_pcm_format_t *format,
+                              snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle, int channel,
+                             snd_pcm_format_t *format,
+                             snd_pcm_plugin_t **r_plugin);
 /* conversion plugins */
-int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle,
+                                   snd_pcm_format_t *src_format,
                                    snd_pcm_format_t *dst_format,
                                    snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
+                               snd_pcm_format_t *src_format,
                                snd_pcm_format_t *dst_format,
                                snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
+                              snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
                               snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
+                             snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_adpcm(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
+                              snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
                               snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
+                             snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_route(snd_pcm_format_t *src_format,
-                               snd_pcm_format_t *dst_format,
-                               int *ttable,
-                               snd_pcm_plugin_t **r_plugin);
+int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
+                              snd_pcm_format_t *src_format,
+                              snd_pcm_format_t *dst_format,
+                              int *ttable,
+                              snd_pcm_plugin_t **r_plugin);
 
 /*
  *  Loopback interface
index 0ba3089314b5f531126e7f1a004ea4d8b7da3742..f58c54e181c4b1c5beac4ff96bf34a9c5bbd2662 100644 (file)
@@ -39,6 +39,7 @@ struct snd_pcm {
        int plugin_alloc_lock[4];
        void *plugin_alloc_xptr[2];
        long plugin_alloc_xsize[2];
+       int plugin_alloc_xchannel;
 };
 
 unsigned int snd_pcm_plugin_formats(unsigned int formats);
@@ -46,8 +47,8 @@ int snd_pcm_plugin_hwparams(snd_pcm_channel_params_t *params,
                            snd_pcm_channel_info_t *hwinfo,
                            snd_pcm_channel_params_t *hwparams);
 int snd_pcm_plugin_format(snd_pcm_t *pcm,
-                         snd_pcm_channel_params_t *params, 
-                         snd_pcm_channel_params_t *hwparams, 
+                         snd_pcm_channel_params_t *params,
+                         snd_pcm_channel_params_t *hwparams,
                          snd_pcm_channel_info_t *hwinfo);
 
 #if 0
index ef1952ec97180866be161c926f107eb802043546..66ff8e6518752324db415eba412b6c2299dab202 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <math.h>
+#include <sys/uio.h>
 #include "pcm_local.h"
 
-snd_pcm_plugin_t *snd_pcm_plugin_build(const char *name, int extra)
+static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size);
+static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr);
+static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size);
+
+snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
+                                      const char *name,
+                                      snd_pcm_format_t *src_format,
+                                      snd_pcm_format_t *dst_format,
+                                      int extra)
 {
        snd_pcm_plugin_t *plugin;
+       int voices = 0;
        
        if (extra < 0)
                return NULL;
-       plugin = (snd_pcm_plugin_t *)calloc(1, sizeof(*plugin) + extra);
+       if (src_format)
+               voices = src_format->voices;
+       if (dst_format && dst_format->voices > voices)
+               voices = dst_format->voices;
+       plugin = (snd_pcm_plugin_t *)calloc(1, sizeof(*plugin) + voices * sizeof(snd_pcm_plugin_voice_t) + extra);
        if (plugin == NULL)
                return NULL;
        plugin->name = name ? strdup(name) : NULL;
+       if (src_format) {
+               memcpy(&plugin->src_format, src_format, sizeof(snd_pcm_format_t));
+               if ((plugin->src_width = snd_pcm_format_width(src_format->format)) < 0)
+                       return NULL;
+       }
+       if (dst_format) {
+               memcpy(&plugin->dst_format, dst_format, sizeof(snd_pcm_format_t));
+               if ((plugin->dst_width = snd_pcm_format_width(dst_format->format)) < 0)
+                       return NULL;
+       }
+       plugin->handle = handle;
+       plugin->voices = (snd_pcm_plugin_voice_t *)((char *)plugin + sizeof(*plugin));
+       plugin->extra_data = (char *)plugin->voices + voices * sizeof(snd_pcm_plugin_voice_t);
        return plugin;
 }
 
@@ -167,7 +194,7 @@ double snd_pcm_plugin_transfer_ratio(snd_pcm_t *pcm, int channel)
 {
        ssize_t transfer;
 
-       transfer = snd_pcm_plugin_transfer_size(pcm, channel, 1000000);
+       transfer = snd_pcm_plugin_client_size(pcm, channel, 1000000);
        if (transfer < 0)
                return 0;
        return (double)transfer / (double)1000000;
@@ -255,14 +282,14 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
 
        if (params->mode == SND_PCM_MODE_STREAM) {
                pdprintf("params stream plugin\n");
-               err = snd_pcm_plugin_build_stream(pcm, params->channel, &plugin);
+               err = snd_pcm_plugin_build_stream(pcm, params->channel, &hwparams.format, &plugin);
        } else if (params->mode == SND_PCM_MODE_BLOCK) {
                if (hwinfo.flags & SND_PCM_CHNINFO_MMAP) {
                        pdprintf("params mmap plugin\n");
-                       err = snd_pcm_plugin_build_mmap(pcm, params->channel, &plugin);
+                       err = snd_pcm_plugin_build_mmap(pcm, params->channel, &hwparams.format, &plugin);
                } else {
                        pdprintf("params block plugin\n");
-                       err = snd_pcm_plugin_build_block(pcm, params->channel, &plugin);
+                       err = snd_pcm_plugin_build_block(pcm, params->channel, &hwparams.format, &plugin);
                }
        } else {
                return -EINVAL;
@@ -313,11 +340,11 @@ int snd_pcm_plugin_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
                return err;
        if (setup->mode == SND_PCM_MODE_STREAM) {
                pdprintf("params setup: queue_size = %i\n", setup->buf.stream.queue_size);
-               setup->buf.stream.queue_size = snd_pcm_plugin_transfer_size(pcm, setup->channel, setup->buf.stream.queue_size);
+               setup->buf.stream.queue_size = snd_pcm_plugin_client_size(pcm, setup->channel, setup->buf.stream.queue_size);
                pdprintf("params setup: queue_size = %i\n", setup->buf.stream.queue_size);
        } else if (setup->mode == SND_PCM_MODE_BLOCK) {
                pdprintf("params setup: frag_size = %i\n", setup->buf.block.frag_size);
-               setup->buf.block.frag_size = snd_pcm_plugin_transfer_size(pcm, setup->channel, setup->buf.block.frag_size);
+               setup->buf.block.frag_size = snd_pcm_plugin_client_size(pcm, setup->channel, setup->buf.block.frag_size);
                pdprintf("params setup: frag_size = %i\n", setup->buf.block.frag_size);
        } else {
                return -EINVAL;
@@ -338,9 +365,10 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
        ratio = snd_pcm_plugin_transfer_ratio(pcm, status->channel);
        if (ratio <= 0)
                return -EINVAL;
-       status->scount = snd_pcm_plugin_transfer_size(pcm, status->channel, status->scount);
-       status->count = snd_pcm_plugin_transfer_size(pcm, status->channel, status->count);
-       status->free = snd_pcm_plugin_transfer_size(pcm, status->channel, status->free);
+       /* FIXME: scount may overflow */
+       status->scount = snd_pcm_plugin_client_size(pcm, status->channel, status->scount);
+       status->count = snd_pcm_plugin_client_size(pcm, status->channel, status->count);
+       status->free = snd_pcm_plugin_client_size(pcm, status->channel, status->free);
        return 0;       
 }
 
@@ -372,46 +400,298 @@ int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel)
        return snd_pcm_channel_flush(pcm, channel);
 }
 
+ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *pcm, int channel)
+{
+       ssize_t result;
+
+       if ((result = snd_pcm_transfer_size(pcm, channel)) < 0)
+               return result;
+       return snd_pcm_plugin_client_size(pcm, channel, result);
+}
+
 int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size)
 {
-       snd_pcm_plugin_t *plugin;
-       int err;
+       snd_pcm_plugin_t *plugin = NULL;
+       snd_pcm_plugin_voice_t *voices;
+       size_t samples;
+       int width;
 
-       if (!ptr || !size)
+       if (!ptr || !size || *size < 1)
                return -EINVAL;
        *ptr = NULL;
        if (!pcm || channel < 0 || channel > 1)
                return -EINVAL;
-       plugin = pcm->plugin_first[channel];
-       if (!plugin)
-               return -EINVAL;
-       if (plugin->transfer_src_ptr) {
-               err = plugin->transfer_src_ptr(plugin, (char **)ptr, size);
-               if (err >= 0)
-                       return 0;
+       if ((*size = snd_pcm_plugin_transfer_size(pcm, channel)) < 0)
+               return *size;
+       if (channel == SND_PCM_CHANNEL_PLAYBACK && plugin->src_voices) {
+               plugin = pcm->plugin_first[channel];
+               if (!plugin)
+                       goto __skip;
+               if (!plugin->src_format.interleave)
+                       goto __skip;
+               if ((width = snd_pcm_format_width(plugin->src_format.format)) < 0)
+                       return width;
+               samples = *size * width;
+               if ((samples % (plugin->src_format.voices * 8)) != 0)
+                       return -EINVAL;
+               samples /= (plugin->src_format.voices * 8);
+               pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_PLAYBACK;
+               if (plugin->src_voices(plugin, &voices, samples,
+                                      snd_pcm_plugin_ptr_alloc) < 0)
+                       goto __skip;
+               *ptr = voices->addr;
+               return 0;
+       } else if (channel == SND_PCM_CHANNEL_CAPTURE && plugin->dst_voices) {
+               plugin = pcm->plugin_last[channel];
+               if (!plugin)
+                       goto __skip;
+               if (plugin->dst_format.interleave)
+                       goto __skip;
+               if ((width = snd_pcm_format_width(plugin->dst_format.format)) < 0)
+                       return width;
+               samples = *size * width;
+               if ((samples % (plugin->dst_format.voices * 8)) != 0)
+                       return -EINVAL;
+               samples /= (plugin->src_format.voices * 8);
+               pcm->plugin_alloc_xchannel = SND_PCM_CHANNEL_CAPTURE;
+               if (plugin->dst_voices(plugin, &voices, *size,
+                                      snd_pcm_plugin_ptr_alloc) < 0)
+                       goto __skip;
+               *ptr = voices->addr;
+               return 0;
        }
-       if (pcm->plugin_alloc_xptr[channel]) {
-               if (pcm->plugin_alloc_xsize[channel] >= *size) {
-                       *ptr = (char *)pcm->plugin_alloc_xptr[channel];
-                       return 0;
+      __skip:
+       *ptr = snd_pcm_plugin_ptr_alloc(pcm, *size);
+       if (*ptr == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+ssize_t snd_pcm_plugin_write(snd_pcm_t *pcm, const void *buffer, size_t count)
+{
+       snd_pcm_plugin_t *plugin;
+
+       if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
+               return snd_pcm_write(pcm, buffer, count);
+       if (plugin->src_format.interleave) {
+               struct iovec vec;
+               vec.iov_base = (void *)buffer;
+               vec.iov_len = count;
+               return snd_pcm_plugin_writev(pcm, &vec, 1);
+       } else {
+               int idx, voices = plugin->src_format.voices;
+               int size = count / voices;
+               struct iovec vec[voices];
+               for (idx = 0; idx < voices; idx++) {
+                       vec[idx].iov_base = (char *)buffer + (size * idx);
+                       vec[idx].iov_len = size;
                }
-               *ptr = (char *)realloc(pcm->plugin_alloc_xptr[channel], *size);
+               return snd_pcm_plugin_writev(pcm, vec, voices);
+       }
+}
+
+ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count)
+{
+       snd_pcm_plugin_t *plugin;
+
+       if ((plugin = snd_pcm_plugin_last(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
+               return snd_pcm_write(pcm, buffer, count);
+       if (plugin->dst_format.interleave) {
+               struct iovec vec;
+               vec.iov_base = buffer;
+               vec.iov_len = count;
+               return snd_pcm_plugin_readv(pcm, &vec, 1);
        } else {
-               *ptr = (char *)malloc(*size);
-               if (*ptr != NULL)
-                       pcm->plugin_alloc_xsize[channel] = *size;                       
+               int idx, voices = plugin->dst_format.voices;
+               int size = count / voices;
+               struct iovec vec[voices];
+               for (idx = 0; idx < voices; idx++) {
+                       vec[idx].iov_base = (char *)buffer + (size * idx);
+                       vec[idx].iov_len = size;
+               }
+               return snd_pcm_plugin_readv(pcm, vec, voices);
        }
-       if (*ptr == NULL)
-               return -ENOMEM;
-       pcm->plugin_alloc_xptr[channel] = *ptr;
+}
+
+static int snd_pcm_plugin_load_vector(snd_pcm_plugin_t *plugin,
+                                     snd_pcm_plugin_voice_t **voices,
+                                     const struct iovec *vector,
+                                     int count,
+                                     snd_pcm_format_t *format)
+{
+       snd_pcm_plugin_voice_t *v = plugin->voices;
+       int width, cvoices, voice;
+
+       *voices = NULL;
+       if ((width = snd_pcm_format_width(format->format)) < 0)
+               return width;
+       cvoices = format->voices;
+       if (format->interleave) {
+               if (count != 1)
+                       return -EINVAL;
+               for (voice = 0; voice < cvoices; voice++, v++) {
+                       v->aptr = NULL;
+                       if ((v->addr = vector->iov_base) == NULL)
+                               return -EINVAL;
+                       v->offset = voice * width;
+                       v->next = cvoices * width;
+               }
+       } else {
+               if (count != cvoices)
+                       return -EINVAL;
+               for (voice = 0; voice < cvoices; voice++, v++) {
+                       v->aptr = NULL;
+                       v->addr = vector[voice].iov_base;
+                       v->offset = 0;
+                       v->next = width;
+               }               
+       }
+       *voices = plugin->voices;
        return 0;
 }
 
-static void *snd_pcm_plugin_malloc(snd_pcm_t *pcm, long size)
+static inline int snd_pcm_plugin_load_src_vector(snd_pcm_plugin_t *plugin,
+                                         snd_pcm_plugin_voice_t **voices,
+                                         const struct iovec *vector,
+                                         int count)
+{
+       return snd_pcm_plugin_load_vector(plugin, voices, vector, count, &plugin->src_format);
+}
+
+static inline int snd_pcm_plugin_load_dst_vector(snd_pcm_plugin_t *plugin,
+                                         snd_pcm_plugin_voice_t **voices,
+                                         const struct iovec *vector,
+                                         int count)
+{
+       return snd_pcm_plugin_load_vector(plugin, voices, vector, count, &plugin->dst_format);
+}
+
+ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int count)
+{
+       snd_pcm_plugin_t *plugin, *next;
+       snd_pcm_plugin_voice_t *src_voices, *dst_voices;
+       size_t samples;
+       ssize_t size;
+       int idx, err;
+
+       if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
+               return snd_pcm_writev(pcm, vector, count);
+       if ((err = snd_pcm_plugin_load_src_vector(plugin, &src_voices, vector, count)) < 0)
+               return err;
+       size = 0;
+       for (idx = 0; idx < count; idx++)
+               size += vector[idx].iov_len;
+       size = snd_pcm_plugin_src_size_to_samples(plugin, size);
+       if (size < 0)
+               return size;
+       samples = size;
+       while (plugin) {
+               if ((next = plugin->next) != NULL) {
+                       if (next->src_voices) {
+                               if ((err = next->src_voices(next, &dst_voices, samples, snd_pcm_plugin_buf_alloc)) < 0) {
+                                       snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                                       return err;
+                               }
+                       } else {
+                               if ((err = snd_pcm_plugin_src_voices(next, &dst_voices, samples)) < 0) {
+                                       snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                                       return err;
+                               }
+                       }
+               } else {
+                       dst_voices = NULL;
+               }
+               pdprintf("write plugin: %s, %i\n", plugin->name, samples);
+               if ((size = plugin->transfer(plugin, src_voices, dst_voices, samples))<0) {
+                       snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                       if (dst_voices)
+                               snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
+                       return size;
+               }
+               snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+               plugin = plugin->next;
+               src_voices = dst_voices;
+               samples = size;
+       }
+       samples = snd_pcm_plugin_client_samples(pcm, SND_PCM_CHANNEL_PLAYBACK, samples);
+       size = snd_pcm_plugin_src_samples_to_size(pcm->plugin_first[SND_PCM_CHANNEL_PLAYBACK], samples);
+       if (size < 0)
+               return size;
+       pdprintf("writev result = %i\n", size);
+       return size;
+}
+
+ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int count)
+{
+       snd_pcm_plugin_t *plugin, *next;
+       snd_pcm_plugin_voice_t *src_voices = NULL, *dst_voices;
+       size_t samples;
+       ssize_t size;
+       int idx, err;
+
+       if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
+               return snd_pcm_readv(pcm, vector, count);
+       if (vector == NULL)
+               return -EINVAL;
+       size = 0;
+       for (idx = 0; idx < count; idx++)
+               size += vector[idx].iov_len;
+       if (size < 0)
+               return size;
+       samples = snd_pcm_plugin_dst_size_to_samples(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], size);
+       samples = snd_pcm_plugin_hardware_samples(pcm, SND_PCM_CHANNEL_CAPTURE, samples);
+       while (plugin && samples > 0) {
+               if ((next = plugin->next) != NULL) {
+                       if (plugin->dst_voices) {
+                               if ((err = plugin->dst_voices(plugin, &dst_voices, samples, snd_pcm_plugin_buf_alloc)) < 0) {
+                                       if (src_voices)
+                                               snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                                       return err;
+                               }
+                       } else {
+                               if ((err = snd_pcm_plugin_dst_voices(plugin, &dst_voices, samples)) < 0) {
+                                       if (src_voices)
+                                               snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                                       return err;
+                               }
+                       }
+               } else {
+                       if ((err = snd_pcm_plugin_load_dst_vector(plugin, &dst_voices, vector, count)) < 0) {
+                               if (src_voices)
+                                       snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                               return err;
+                       }
+               }
+               pdprintf("read plugin: %s, %i\n", plugin->name, samples);
+               if ((size = plugin->transfer(plugin, src_voices, dst_voices, samples))<0) {
+                       if (src_voices)
+                               snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+                       snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
+                       return size;
+               }
+               if (src_voices)
+                       snd_pcm_plugin_buf_free(pcm, src_voices->aptr);
+               plugin = plugin->next;
+               src_voices = dst_voices;
+               samples = size;
+       }
+       snd_pcm_plugin_buf_free(pcm, dst_voices->aptr);
+       size = snd_pcm_plugin_dst_samples_to_size(pcm->plugin_last[SND_PCM_CHANNEL_CAPTURE], samples);
+       pdprintf("readv result = %i\n", size);
+       return size;
+}
+
+/*
+ *  Plugin helpers
+ */
+
+static void *snd_pcm_plugin_buf_alloc(snd_pcm_t *pcm, size_t size)
 {
        int idx;
        void *ptr;
 
+       if (pcm == NULL || size <= 0)
+               return NULL;
        for (idx = 0; idx < 4; idx++) {
                if (pcm->plugin_alloc_lock[idx])
                        continue;
@@ -447,146 +727,89 @@ static void *snd_pcm_plugin_malloc(snd_pcm_t *pcm, long size)
        return NULL;
 }
 
-static int snd_pcm_plugin_alloc_unlock(snd_pcm_t *pcm, void *ptr)
+static void snd_pcm_plugin_buf_free(snd_pcm_t *pcm, void *ptr)
 {
        int idx;
 
+       if (pcm == NULL || ptr == NULL)
+               return;
        for (idx = 0; idx < 4; idx++) {
                if (pcm->plugin_alloc_ptr[idx] == ptr) {
                        pcm->plugin_alloc_lock[idx] = 0;
-                       return 0;
+                       return;
                }
        }
-       return -ENOENT;
 }
 
-ssize_t snd_pcm_plugin_write(snd_pcm_t *pcm, const void *buffer, size_t count)
+static void *snd_pcm_plugin_ptr_alloc(snd_pcm_t *pcm, size_t size)
 {
-       snd_pcm_plugin_t *plugin, *next;
-       char *dst_ptr, *dst_ptr1 = NULL, *src_ptr, *src_ptr1 = NULL;
-       size_t dst_size, src_size;
-       ssize_t size = 0, result = 0;
-       int err;
+       void *ptr;
+       int channel = pcm->plugin_alloc_xchannel;
 
-       if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_PLAYBACK)) == NULL)
-               return snd_pcm_write(pcm, buffer, count);
-       src_ptr = (char *)buffer;
-       dst_size = src_size = count;
-       while (plugin) {
-               next = plugin->next;
-               if (plugin->dst_size) {
-                       dst_size = plugin->dst_size(plugin, dst_size);
-                       if (dst_size < 0) {
-                               result = dst_size;
-                               goto __free;
-                       }
-               }
-               if (next != NULL) {
-                       if (next->transfer_src_ptr) {
-                               if ((err = next->transfer_src_ptr(next, &dst_ptr, &dst_size)) < 0) {
-                                       if (dst_ptr == NULL)
-                                               goto __alloc;
-                                       result = err;
-                                       goto __free;
-                               }
-                       } else {
-                             __alloc:
-                               dst_ptr = dst_ptr1 = (char *)snd_pcm_plugin_malloc(pcm, dst_size);
-                               if (dst_ptr == NULL) {
-                                       result = -ENOMEM;
-                                       goto __free;
-                               }
-                       }
-               } else {
-                       dst_ptr = src_ptr;
-                       dst_size = src_size;
-               }
-               pdprintf("write plugin: %s, %i, %i\n", plugin->name, src_size, dst_size);
-               if ((size = plugin->transfer(plugin, src_ptr, src_size,
-                                                    dst_ptr, dst_size))<0) {
-                       result = size;
-                       goto __free;
-               }
-               if (src_ptr1)
-                       snd_pcm_plugin_alloc_unlock(pcm, src_ptr1);
-               plugin = next;
-               src_ptr = dst_ptr;
-               src_ptr1 = dst_ptr1;
-               dst_ptr1 = NULL;
-               src_size = dst_size = size;
+       if (pcm->plugin_alloc_xptr[channel]) {
+               if (pcm->plugin_alloc_xsize[channel] >= size)
+                       return pcm->plugin_alloc_xptr[channel];
+               ptr = realloc(pcm->plugin_alloc_xptr[channel], size);
+       } else {
+               ptr = malloc(size);
        }
-       result = snd_pcm_plugin_transfer_size(pcm, SND_PCM_CHANNEL_PLAYBACK, size);
-       pdprintf("size = %i, result = %i, count = %i\n", size, result, count);
-      __free:
-       if (dst_ptr1)
-               snd_pcm_plugin_alloc_unlock(pcm, dst_ptr1);
-       if (src_ptr1)
-               snd_pcm_plugin_alloc_unlock(pcm, src_ptr1);
-       return result;
+       if (ptr == NULL)
+               return NULL;
+       pcm->plugin_alloc_xptr[channel] = (char *)ptr;
+       pcm->plugin_alloc_xsize[channel] = size;                        
+       return ptr;
 }
 
-ssize_t snd_pcm_plugin_read(snd_pcm_t *pcm, void *buffer, size_t count)
+static int snd_pcm_plugin_xvoices(snd_pcm_plugin_t *plugin,
+                                 snd_pcm_plugin_voice_t **voices,
+                                 size_t samples,
+                                 snd_pcm_format_t *format)
 {
-       snd_pcm_plugin_t *plugin, *next;
-       char *dst_ptr, *dst_ptr1 = NULL, *src_ptr, *src_ptr1 = NULL;
-       size_t dst_size, src_size;
-       ssize_t size = 0, result = 0;
-       int err;
-
-       if ((plugin = snd_pcm_plugin_first(pcm, SND_PCM_CHANNEL_CAPTURE)) == NULL)
-               return snd_pcm_read(pcm, buffer, count);
-       src_ptr = NULL;
-       src_size = 0;
-       dst_size = snd_pcm_plugin_hardware_size(pcm, SND_PCM_CHANNEL_CAPTURE, count);
-       if (dst_size < 0)
-               return dst_size;
-       while (plugin) {
-               next = plugin->next;
-               if (plugin->dst_size) {
-                       dst_size = plugin->dst_size(plugin, dst_size);
-                       if (dst_size < 0) {
-                               result = dst_size;
-                               goto __free;
-                       }
-               }
-               if (next != NULL) {
-                       if (next->transfer_src_ptr) {
-                               if ((err = next->transfer_src_ptr(next, &dst_ptr, &dst_size)) < 0) {
-                                       if (dst_ptr == NULL)
-                                               goto __alloc;
-                                       result = err;
-                                       goto __free;
-                               }
-                       } else {
-                             __alloc:
-                               dst_ptr = dst_ptr1 = (char *)snd_pcm_plugin_malloc(pcm, dst_size);
-                               if (dst_ptr == NULL) {
-                                       result = -ENOMEM;
-                                       goto __free;
-                               }
-                       }
+       char *ptr;
+       int width, voice;
+       long size;
+       snd_pcm_plugin_voice_t *v;
+       
+       *voices = NULL;
+       if ((width = snd_pcm_format_width(format->format)) < 0)
+               return width;   
+       size = format->voices * samples * width;
+       if ((size % 8) != 0)
+               return -EINVAL;
+       size /= 8;
+       ptr = (char *)snd_pcm_plugin_buf_alloc(plugin->handle, size);
+       if (ptr == NULL)
+               return -ENOMEM;
+       if ((size % format->voices) != 0)
+               return -EINVAL;
+       size /= format->voices;
+       v = plugin->voices;
+       for (voice = 0; voice < format->voices; voice++, v++) {
+               v->aptr = ptr;
+               if (format->interleave) {
+                       v->addr = ptr;
+                       v->offset = voice * width;
+                       v->next = format->voices * width;
                } else {
-                       dst_ptr = buffer;
-               }
-               pdprintf("read plugin: %s, %i, %i\n", plugin->name, src_size, dst_size);
-               if ((size = plugin->transfer(plugin, src_ptr, src_size,
-                                                    dst_ptr, dst_size))<0) {
-                       result = size;
-                       goto __free;
+                       v->addr = ptr + (voice * size);
+                       v->offset = 0;
+                       v->next = width;
                }
-               if (dst_ptr1)
-                       snd_pcm_plugin_alloc_unlock(pcm, dst_ptr1);
-               plugin = plugin->next;
-               src_ptr = dst_ptr;
-               src_ptr1 = dst_ptr1;
-               dst_ptr1 = NULL;
-               src_size = dst_size = size;
        }
-       result = size;
-      __free:
-       if (dst_ptr1)
-               snd_pcm_plugin_alloc_unlock(pcm, dst_ptr1);
-       if (src_ptr1)
-               snd_pcm_plugin_alloc_unlock(pcm, src_ptr1);
-       return result;
+       *voices = plugin->voices;
+       return 0;
+}
+
+int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin,
+                             snd_pcm_plugin_voice_t **voices,
+                             size_t samples)
+{
+       return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->src_format);
+}
+
+int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
+                             snd_pcm_plugin_voice_t **voices,
+                             size_t samples)
+{
+       return snd_pcm_plugin_xvoices(plugin, voices, samples, &plugin->dst_format);
 }
index 5c008ba008ace5069a8bed29c8074fd6e0f8177e..7da4f2330827967a177a88d5616810b98aabf1ae 100644 (file)
 #endif
 #include "../include/driver.h"
 #include "../include/pcm.h"
-typedef snd_pcm_runtime_t PLUGIN_BASE;
 #define snd_pcm_plugin_first(pb, channel) ((pb)->oss.plugin_first)
 #define snd_pcm_plugin_last(pb, channel) ((pb)->oss.plugin_last)
 #define snd_pcm_plugin_append(pb, channel, plugin) snd_pcm_oss_plugin_append(pb, plugin)
 #define my_calloc(size) snd_kcalloc(size, GFP_KERNEL)
 #define my_free(ptr) snd_kfree(ptr)
+#define my_strdup(str) snd_kmalloc_strdup(str, GFP_KERNEL)
 #else
 #include <malloc.h>
 #include <errno.h>
+#include <stdio.h>
+#include <string.h>
 #include "pcm_local.h"
-typedef snd_pcm_t PLUGIN_BASE;
 #define my_calloc(size) calloc(1, size)
 #define my_free(ptr) free(ptr)
+#define my_strdup(str) strdup(str)
 #endif
 
+ssize_t snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples)
+{
+       ssize_t result;
+
+       if (plugin == NULL)
+               return -EINVAL;
+       result = samples * plugin->src_format.voices * plugin->src_width;
+       if ((result % 8) != 0)
+               return -EINVAL;
+       return result / 8;
+}
+
+ssize_t snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples)
+{
+       ssize_t result;
+
+       if (plugin == NULL)
+               return -EINVAL;
+       result = samples * plugin->dst_format.voices * plugin->dst_width;
+       if ((result % 8) != 0)
+               return -EINVAL;
+       return result / 8;
+}
+
+ssize_t snd_pcm_plugin_src_size_to_samples(snd_pcm_plugin_t *plugin, size_t size)
+{
+       ssize_t result;
+       long tmp;
+
+       if (plugin == NULL)
+               return -EINVAL;
+       result = size * 8;
+       tmp = plugin->src_format.voices * plugin->src_width;
+       if ((result % tmp) != 0)
+               return -EINVAL;
+       return result / tmp;
+}
+
+ssize_t snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_t *plugin, size_t size)
+{
+       ssize_t result;
+       long tmp;
+
+       if (plugin == NULL)
+               return -EINVAL;
+       result = size * 8;
+       tmp = plugin->dst_format.voices * plugin->dst_width;
+       if ((result % tmp) != 0)
+               return -EINVAL;
+       return result / tmp;
+}
 
-ssize_t snd_pcm_plugin_transfer_size(PLUGIN_BASE *pb, int channel, size_t drv_size)
+ssize_t snd_pcm_plugin_client_samples(snd_pcm_plugin_handle_t *pb, int channel, size_t drv_samples)
 {
        snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
        
        if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
-                   channel != SND_PCM_CHANNEL_CAPTURE))
+                          channel != SND_PCM_CHANNEL_CAPTURE))
                return -EINVAL;
-       if (drv_size == 0)
+       if (drv_samples == 0)
                return 0;
-       if (drv_size < 0)
+       if (drv_samples < 0)
                return -EINVAL;
        if (channel == SND_PCM_CHANNEL_PLAYBACK) {
-               plugin = snd_pcm_plugin_last(pb, channel);
-               while (plugin) {
+               plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_PLAYBACK);
+               while (plugin && drv_samples > 0) {
                        plugin_prev = plugin->prev;
-                       if (plugin->src_size)
-                               drv_size = plugin->src_size(plugin, drv_size);
+                       if (plugin->src_samples)
+                               drv_samples = plugin->src_samples(plugin, drv_samples);
                        plugin = plugin_prev;
                }
        } else if (channel == SND_PCM_CHANNEL_CAPTURE) {
-               plugin = snd_pcm_plugin_first(pb, channel);
-               while (plugin) {
+               plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_CAPTURE);
+               while (plugin && drv_samples > 0) {
                        plugin_next = plugin->next;
-                       if (plugin->dst_size)
-                               drv_size = plugin->dst_size(plugin, drv_size);
+                       if (plugin->dst_samples)
+                               drv_samples = plugin->dst_samples(plugin, drv_samples);
                        plugin = plugin_next;
                }
        }
-       return drv_size;
+       return drv_samples;
 }
 
-ssize_t snd_pcm_plugin_hardware_size(PLUGIN_BASE *pb, int channel, size_t trf_size)
+ssize_t snd_pcm_plugin_hardware_samples(snd_pcm_plugin_handle_t *pb, int channel, size_t clt_samples)
 {
        snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
        
        if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
-                    channel != SND_PCM_CHANNEL_CAPTURE))
+                          channel != SND_PCM_CHANNEL_CAPTURE))
                return -EINVAL;
-       if (trf_size == 0)
+       if (clt_samples == 0)
                return 0;
-       if (trf_size < 0)
+       if (clt_samples < 0)
                return -EINVAL;
        if (channel == SND_PCM_CHANNEL_PLAYBACK) {
-               plugin = snd_pcm_plugin_first(pb, channel);
-               while (plugin) {
+               plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_PLAYBACK);
+               while (plugin && clt_samples > 0) {
                        plugin_next = plugin->next;
-                       if (plugin->dst_size)
-                               trf_size = plugin->dst_size(plugin, trf_size);
+                       if (plugin->dst_samples)
+                               clt_samples = plugin->dst_samples(plugin, clt_samples);
                        plugin = plugin_next;
                }
+               if (clt_samples < 0)
+                       return clt_samples;
        } else if (channel == SND_PCM_CHANNEL_CAPTURE) {
-               plugin = snd_pcm_plugin_last(pb, channel);
+               plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_CAPTURE);
                while (plugin) {
                        plugin_prev = plugin->prev;
-                       if (plugin->src_size)
-                               trf_size = plugin->src_size(plugin, trf_size);
+                       if (plugin->src_samples)
+                               clt_samples = plugin->src_samples(plugin, clt_samples);
                        plugin = plugin_prev;
                }
        } 
-       return trf_size;
+       return clt_samples;
+}
+
+ssize_t snd_pcm_plugin_client_size(snd_pcm_plugin_handle_t *pb, int channel, size_t drv_size)
+{
+       snd_pcm_plugin_t *plugin;
+       ssize_t result = 0;
+       
+       if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
+                          channel != SND_PCM_CHANNEL_CAPTURE))
+               return -EINVAL;
+       if (drv_size == 0)
+               return 0;
+       if (drv_size < 0)
+               return -EINVAL;
+       if (channel == SND_PCM_CHANNEL_PLAYBACK) {
+               plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_PLAYBACK);
+               result = snd_pcm_plugin_src_size_to_samples(plugin, drv_size);
+               result = snd_pcm_plugin_client_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+               if (result < 0)
+                       return result;
+               plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_PLAYBACK);
+               result = snd_pcm_plugin_src_samples_to_size(plugin, result);
+       } else if (channel == SND_PCM_CHANNEL_CAPTURE) {
+               plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_CAPTURE);
+               result = snd_pcm_plugin_src_size_to_samples(plugin, drv_size);
+               result = snd_pcm_plugin_client_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+               plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_CAPTURE);
+               result = snd_pcm_plugin_dst_samples_to_size(plugin, result);
+       }
+       return result;
+}
+
+ssize_t snd_pcm_plugin_hardware_size(snd_pcm_plugin_handle_t *pb, int channel, size_t clt_size)
+{
+       snd_pcm_plugin_t *plugin;
+       ssize_t result = 0;
+       
+       if (pb == NULL || (channel != SND_PCM_CHANNEL_PLAYBACK &&
+                          channel != SND_PCM_CHANNEL_CAPTURE))
+               return -EINVAL;
+       if (clt_size == 0)
+               return 0;
+       if (clt_size < 0)
+               return -EINVAL;
+       if (channel == SND_PCM_CHANNEL_PLAYBACK) {
+               plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_PLAYBACK);
+               result = snd_pcm_plugin_src_size_to_samples(plugin, clt_size);
+               result = snd_pcm_plugin_hardware_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+               if (result < 0)
+                       return result;
+               plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_PLAYBACK);
+               result = snd_pcm_plugin_dst_samples_to_size(plugin, result);
+       } else if (channel == SND_PCM_CHANNEL_CAPTURE) {
+               plugin = snd_pcm_plugin_last(pb, SND_PCM_CHANNEL_CAPTURE);
+               result = snd_pcm_plugin_src_size_to_samples(plugin, clt_size);
+               result = snd_pcm_plugin_hardware_samples(pb, SND_PCM_CHANNEL_PLAYBACK, result);
+               if (result < 0)
+                       return result;
+               plugin = snd_pcm_plugin_first(pb, SND_PCM_CHANNEL_CAPTURE);
+               result = snd_pcm_plugin_dst_samples_to_size(plugin, result);
+       } 
+       return result;
 }
 
 
@@ -232,7 +349,7 @@ int snd_pcm_plugin_hwparams(snd_pcm_channel_params_t *params,
 
 #define ROUTE_PLUGIN_RESOLUTION 16
 
-int snd_pcm_plugin_format(PLUGIN_BASE *pb, 
+int snd_pcm_plugin_format(snd_pcm_plugin_handle_t *pb, 
                          snd_pcm_channel_params_t *params, 
                          snd_pcm_channel_params_t *hwparams,
                          snd_pcm_channel_info_t *hwinfo)
@@ -272,6 +389,7 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
 
        /* voices reduction */
        if (srcparams->format.voices > dstparams.format.voices) {
+#if 0
                int sv = srcparams->format.voices;
                int dv = dstparams.format.voices;
                int *ttable = my_calloc(dv*sv*sizeof(*ttable));
@@ -303,6 +421,10 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
                        return err;
                }
                srcparams->format.voices = tmpparams.format.voices;
+#else
+               snd_pcm_plugin_free(plugin);
+               return -EIO;
+#endif
         }
 
        /* Convert to interleaved format if needed */
@@ -310,7 +432,8 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
            srcparams->format.voices > 1 &&
            srcparams->format.rate != dstparams.format.rate) {
                tmpparams.format.interleave = 1;
-               err = snd_pcm_plugin_build_interleave(&srcparams->format,
+               err = snd_pcm_plugin_build_interleave(pb,
+                                                     &srcparams->format,
                                                      &tmpparams.format,
                                                      &plugin);
                pdprintf("params interleave change: src=%i, dst=%i returns %i\n", srcparams->format.interleave, tmpparams.format.interleave, err);
@@ -336,7 +459,8 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
            snd_pcm_format_width(srcparams->format.format) <= 16 &&
            snd_pcm_format_width(srcparams->format.format) >= snd_pcm_format_width(srcparams->format.format)) {
                tmpparams.format.rate = dstparams.format.rate;
-               err = snd_pcm_plugin_build_rate(&srcparams->format,
+               err = snd_pcm_plugin_build_rate(pb,
+                                               &srcparams->format,
                                                &tmpparams.format,
                                                &plugin);
                pdprintf("params rate down resampling: src=%i, dst=%i returns %i\n", srcparams->format.rate, tmpparams.format.rate, err);
@@ -359,18 +483,21 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
                tmpparams.format.format = SND_PCM_SFMT_S16_LE;
                switch (srcparams->format.format) {
                case SND_PCM_SFMT_MU_LAW:
-                       err = snd_pcm_plugin_build_mulaw(&srcparams->format,
+                       err = snd_pcm_plugin_build_mulaw(pb,
+                                                        &srcparams->format,
                                                         &tmpparams.format,
                                                         &plugin);
                        break;
 #ifndef __KERNEL__
                case SND_PCM_SFMT_A_LAW:
-                       err = snd_pcm_plugin_build_alaw(&srcparams->format,
+                       err = snd_pcm_plugin_build_alaw(pb,
+                                                       &srcparams->format,
                                                        &tmpparams.format,
                                                        &plugin);
                        break;
                case SND_PCM_SFMT_IMA_ADPCM:
-                       err = snd_pcm_plugin_build_adpcm(&srcparams->format,
+                       err = snd_pcm_plugin_build_adpcm(pb,
+                                                        &srcparams->format,
                                                         &tmpparams.format,
                                                         &plugin);
                        break;
@@ -394,27 +521,31 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
                tmpparams.format.format = dstparams.format.format;
                if (srcparams->format.format == SND_PCM_SFMT_MU_LAW ||
                    tmpparams.format.format == SND_PCM_SFMT_MU_LAW) {
-                       err = snd_pcm_plugin_build_mulaw(&srcparams->format,
+                       err = snd_pcm_plugin_build_mulaw(pb,
+                                                        &srcparams->format,
                                                         &tmpparams.format,
                                                         &plugin);
                }
 #ifndef __KERNEL__
                else if (srcparams->format.format == SND_PCM_SFMT_A_LAW ||
                         tmpparams.format.format == SND_PCM_SFMT_A_LAW) {
-                       err = snd_pcm_plugin_build_alaw(&srcparams->format,
+                       err = snd_pcm_plugin_build_alaw(pb,
+                                                       &srcparams->format,
                                                        &tmpparams.format,
                                                        &plugin);
                }
                else if (srcparams->format.format == SND_PCM_SFMT_IMA_ADPCM ||
                         tmpparams.format.format == SND_PCM_SFMT_IMA_ADPCM) {
-                       err = snd_pcm_plugin_build_adpcm(&srcparams->format,
+                       err = snd_pcm_plugin_build_adpcm(pb,
+                                                        &srcparams->format,
                                                         &tmpparams.format,
                                                         &plugin);
                }
 #endif
                else if (snd_pcm_format_linear(srcparams->format.format) &&
                         snd_pcm_format_linear(tmpparams.format.format)) {
-                       err = snd_pcm_plugin_build_linear(&srcparams->format,
+                       err = snd_pcm_plugin_build_linear(pb,
+                                                         &srcparams->format,
                                                          &tmpparams.format,
                                                          &plugin);
                }
@@ -434,7 +565,8 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
        /* rate resampling */
         if (srcparams->format.rate != dstparams.format.rate) {
                tmpparams.format.rate = dstparams.format.rate;
-               err = snd_pcm_plugin_build_rate(&srcparams->format,
+               err = snd_pcm_plugin_build_rate(pb,
+                                               &srcparams->format,
                                                &tmpparams.format,
                                                &plugin);
                pdprintf("params rate resampling: src=%i, dst=%i return %i\n", srcparams->format.rate, tmpparams.format.rate, err);
@@ -452,6 +584,7 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
       
        /* voices extension  */
        if (srcparams->format.voices < dstparams.format.voices) {
+#if 0
                int sv = srcparams->format.voices;
                int dv = dstparams.format.voices;
                int *ttable = my_calloc(dv * sv * sizeof(*ttable));
@@ -483,6 +616,10 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
                        return err;
                }
                srcparams->format.voices = tmpparams.format.voices;
+#else
+               snd_pcm_plugin_free(plugin);
+               return -EIO;
+#endif
        }
 
        /* interleave change */
@@ -490,7 +627,8 @@ int snd_pcm_plugin_format(PLUGIN_BASE *pb,
            hwinfo->mode == SND_PCM_MODE_BLOCK &&
            srcparams->format.interleave != dstparams.format.interleave) {
                tmpparams.format.interleave = dstparams.format.interleave;
-               err = snd_pcm_plugin_build_interleave(&srcparams->format,
+               err = snd_pcm_plugin_build_interleave(pb,
+                                                     &srcparams->format,
                                                      &tmpparams.format,
                                                      &plugin);
                pdprintf("params interleave change: src=%i, dst=%i return %i\n", srcparams->format.interleave, tmpparams.format.interleave, err);
index b0189bea15419e195e5b55e07e111543294a99c8..d350e71f164e76b8027e303cd9b5750130cafcfc 100644 (file)
@@ -1,7 +1,8 @@
 EXTRA_LTLIBRARIES = libpcmplugin.la
 
 libpcmplugin_la_SOURCES = block.c mmap.c stream.c linear.c interleave.c \
-                         mulaw.c alaw.c adpcm.c rate.c route.c
+                         mulaw.c alaw.c adpcm.c rate.c
+# route.c
 all: libpcmplugin.la
 
 
index 870691d418b2ad730b7e19b41ac979ecce9fe091..455ff0b4e2946b996412f5151cc47f3f86101b1f 100644 (file)
@@ -86,7 +86,7 @@ static void adpcm_init_state(adpcm_state_t * state_ptr)
        state_ptr->io_shift = 4;
 }
 
-static inline char adpcm_encoder(int sl, adpcm_state_t * state)
+static char adpcm_encoder(int sl, adpcm_state_t * state)
 {
        short diff;             /* Difference between sl and predicted sample */
        short pred_diff;        /* Predicted difference to next sample */
@@ -147,7 +147,7 @@ static inline char adpcm_encoder(int sl, adpcm_state_t * state)
 }
 
 
-static inline int adpcm_decoder(unsigned char code, adpcm_state_t * state)
+static int adpcm_decoder(unsigned char code, adpcm_state_t * state)
 {
        short pred_diff;        /* Predicted difference to next sample */
        short step;             /* holds previous StepSize value */
@@ -197,397 +197,174 @@ static inline int adpcm_decoder(unsigned char code, adpcm_state_t * state)
  *  Basic Ima-ADPCM plugin
  */
 
-typedef enum {
-       _S8_ADPCM,
-       _U8_ADPCM,
-       _S16LE_ADPCM,
-       _U16LE_ADPCM,
-       _S16BE_ADPCM,
-       _U16BE_ADPCM,
-       _ADPCM_S8,
-       _ADPCM_U8,
-       _ADPCM_S16LE,
-       _ADPCM_U16LE,
-       _ADPCM_S16BE,
-       _ADPCM_U16BE
-} combination_t;
-
-struct adpcm_private_data {
-       combination_t cmd;
-       adpcm_state_t state;
-};
-
-static void adpcm_conv_u8bit_adpcm(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       unsigned int pcm;
-
-       while (size-- > 0) {
-               pcm = ((*src_ptr++) ^ 0x80) << 8;
-
-               state_ptr->io_buffer |= adpcm_encoder((signed short)(pcm), state_ptr) << state_ptr->io_shift;
-               if (!(state_ptr->io_shift)) {
-                       *dst_ptr++ = state_ptr->io_buffer & 0xff;
-                       state_ptr->io_buffer = 0;
-               }
-               state_ptr->io_shift ^= 4;
-       }
-       if (!(state_ptr->io_shift)) {
-               *dst_ptr = state_ptr->io_buffer & 0xf0;
-       }
-}
-
-static void adpcm_conv_s8bit_adpcm(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       unsigned int pcm;
-
-       while (size-- > 0) {
-               pcm = *src_ptr++ << 8;
-
-               state_ptr->io_buffer |= adpcm_encoder((signed short)(pcm), state_ptr) << state_ptr->io_shift;
-               if (!(state_ptr->io_shift)) {
-                       *dst_ptr++ = state_ptr->io_buffer & 0xff;
-                       state_ptr->io_buffer = 0;
-               }
-               state_ptr->io_shift ^= 4;
-       }
-       if (!(state_ptr->io_shift)) {
-               *dst_ptr = state_ptr->io_buffer & 0xf0;
-       }
-}
-
-static void adpcm_conv_s16bit_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               state_ptr->io_buffer |= adpcm_encoder((signed short)(*src_ptr++), state_ptr) << state_ptr->io_shift;
-               if (!(state_ptr->io_shift)) {
-                       *dst_ptr++ = state_ptr->io_buffer & 0xff;
-                       state_ptr->io_buffer = 0;
-               }
-               state_ptr->io_shift ^= 4;
-       }
-       if (!(state_ptr->io_shift)) {
-               *dst_ptr = state_ptr->io_buffer & 0xf0;
-       }
-}
-
-static void adpcm_conv_s16bit_swap_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               state_ptr->io_buffer |= adpcm_encoder((signed short)(bswap_16(*src_ptr++)), state_ptr) << state_ptr->io_shift;
-               if (!(state_ptr->io_shift)) {
-                       *dst_ptr++ = state_ptr->io_buffer & 0xff;
-                       state_ptr->io_buffer = 0;
-               }
-               state_ptr->io_shift ^= 4;
-       }
-       if (!(state_ptr->io_shift)) {
-               *dst_ptr = state_ptr->io_buffer & 0xf0;
-       }
-}
-
-static void adpcm_conv_u16bit_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               state_ptr->io_buffer |= adpcm_encoder((signed short)((*src_ptr++) ^ 0x8000), state_ptr) << state_ptr->io_shift;
-               if (!(state_ptr->io_shift)) {
-                       *dst_ptr++ = state_ptr->io_buffer & 0xff;
-                       state_ptr->io_buffer = 0;
-               }
-               state_ptr->io_shift ^= 4;
-       }
-       if (!(state_ptr->io_shift)) {
-               *dst_ptr = state_ptr->io_buffer & 0xf0;
-       }
-}
+typedef void (*adpcm_f)(adpcm_state_t *state, void *src_ptr, void *dst_ptr, int samples);
 
-static void adpcm_conv_u16bit_swap_adpcm(adpcm_state_t * state_ptr, unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               state_ptr->io_buffer |= adpcm_encoder((signed short)(bswap_16(*src_ptr++) ^ 0x8000), state_ptr) << state_ptr->io_shift;
-               if (!(state_ptr->io_shift)) {
-                       *dst_ptr++ = state_ptr->io_buffer & 0xff;
-                       state_ptr->io_buffer = 0;
-               }
-               state_ptr->io_shift ^= 4;
-       }
-       if (!(state_ptr->io_shift)) {
-               *dst_ptr = state_ptr->io_buffer & 0xf0;
-       }
-}
-
-static void adpcm_conv_adpcm_u8bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               if (state_ptr->io_shift) {
-                       state_ptr->io_buffer = *src_ptr++;
-               }
-               *dst_ptr++ = (adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) >> 8) ^ 0x80;
-               state_ptr->io_shift ^= 4;
-       }
-}
-
-static void adpcm_conv_adpcm_s8bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               if (state_ptr->io_shift) {
-                       state_ptr->io_buffer = *src_ptr++;
-               }
-               *dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) >> 8;
-               state_ptr->io_shift ^= 4;
-       }
-}
-
-static void adpcm_conv_adpcm_s16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               if (state_ptr->io_shift) {
-                       state_ptr->io_buffer = *src_ptr++;
-               }
-               *dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr);
-               state_ptr->io_shift ^= 4;
-       }
+typedef struct adpcm_private_data {
+       adpcm_f func;
+       adpcm_state_t state;
+} adpcm_t;
+
+#define ADPCM_FUNC_DECODE(name, dsttype, val) \
+static void adpcm_decode_##name(adpcm_state_t *state, \
+                               void *src_ptr, void *dst_ptr, int samples) \
+{ \
+       unsigned char *src = src_ptr; \
+       dsttype *dst = dst_ptr; \
+       unsigned int s; \
+       samples <<= 1; \
+       while (samples--) { \
+               if (state->io_shift) \
+                       state->io_buffer = *src++; \
+               s = adpcm_decoder((state->io_buffer >> state->io_shift) & 0x0f, state); \
+               *dst++ = val; \
+               state->io_shift ^= 4; \
+       } \
 }
 
-static void adpcm_conv_adpcm_swap_s16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               if (state_ptr->io_shift) {
-                       state_ptr->io_buffer = *src_ptr++;
-               }
-               *dst_ptr++ = bswap_16(adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr));
-               state_ptr->io_shift ^= 4;
-       }
+#define ADPCM_FUNC_ENCODE(name, srctype, val) \
+static void adpcm_encode_##name(adpcm_state_t *state, \
+                               void *src_ptr, void *dst_ptr, int samples) \
+{ \
+       srctype *src = src_ptr; \
+       unsigned char *dst = dst_ptr; \
+       unsigned int s; \
+       samples <<= 1; \
+       while (samples--) { \
+               s = *src++; \
+               state->io_buffer |= adpcm_encoder((signed short)(val), state) << state->io_shift; \
+               if (state->io_shift == 0) { \
+                       *dst++ = state->io_buffer & 0xff; \
+                       state->io_buffer = 0; \
+               } \
+               state->io_shift ^= 4; \
+       } \
 }
 
-static void adpcm_conv_adpcm_u16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               if (state_ptr->io_shift) {
-                       state_ptr->io_buffer = *src_ptr++;
-               }
-               *dst_ptr++ = adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) ^ 0x8000;
-               state_ptr->io_shift ^= 4;
-       }
-}
+ADPCM_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
+ADPCM_FUNC_DECODE(s8, u_int8_t, s >> 8)
+ADPCM_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
+ADPCM_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ADPCM_FUNC_DECODE(s16n, u_int16_t, s)
+ADPCM_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
+ADPCM_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
+ADPCM_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
+ADPCM_FUNC_DECODE(s24n, u_int32_t, s << 8)
+ADPCM_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
+ADPCM_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
+ADPCM_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
+ADPCM_FUNC_DECODE(s32n, u_int32_t, s << 16)
+ADPCM_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
+
+ADPCM_FUNC_ENCODE(u8, u_int8_t, s << 8)
+ADPCM_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
+ADPCM_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
+ADPCM_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ADPCM_FUNC_ENCODE(s16n, u_int16_t, s)
+ADPCM_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
+ADPCM_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
+ADPCM_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
+ADPCM_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
+ADPCM_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
+ADPCM_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
+ADPCM_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
+ADPCM_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
+ADPCM_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
+
+/* wide, sign, swap endian */
+static adpcm_f adpcm_functions_decode[4 * 4 * 2 * 2] = {
+       adpcm_decode_u8,        /* decode:8-bit:unsigned:none */
+       adpcm_decode_u8,        /* decode:8-bit:unsigned:swap */
+       adpcm_decode_s8,        /* decode:8-bit:signed:none */
+       adpcm_decode_s8,        /* decode:8-bit:signed:swap */
+       adpcm_decode_u16n,      /* decode:16-bit:unsigned:none */
+       adpcm_decode_u16s,      /* decode:16-bit:unsigned:swap */
+       adpcm_decode_s16n,      /* decode:16-bit:signed:none */
+       adpcm_decode_s16s,      /* decode:16-bit:signed:swap */
+       adpcm_decode_u24n,      /* decode:24-bit:unsigned:none */
+       adpcm_decode_u24s,      /* decode:24-bit:unsigned:swap */
+       adpcm_decode_s24n,      /* decode:24-bit:signed:none */
+       adpcm_decode_s24s,      /* decode:24-bit:signed:swap */
+       adpcm_decode_u32n,      /* decode:32-bit:unsigned:none */
+       adpcm_decode_u32s,      /* decode:32-bit:unsigned:swap */
+       adpcm_decode_s32n,      /* decode:32-bit:signed:none */
+       adpcm_decode_s32s,      /* decode:32-bit:signed:swap */
+};
 
-static void adpcm_conv_adpcm_swap_u16bit(adpcm_state_t * state_ptr, unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0) {
-               if (state_ptr->io_shift) {
-                       state_ptr->io_buffer = *src_ptr++;
-               }
-               *dst_ptr++ = bswap_16(adpcm_decoder((state_ptr->io_buffer >> state_ptr->io_shift) & 0xf, state_ptr) ^ 0x8000);
-               state_ptr->io_shift ^= 4;
-       }
-}
+/* wide, sign, swap endian */
+static adpcm_f adpcm_functions_encode[4 * 2 * 2] = {
+       adpcm_encode_u8,        /* encode:8-bit:unsigned:none */
+       adpcm_encode_u8,        /* encode:8-bit:unsigned:swap */
+       adpcm_encode_s8,        /* encode:8-bit:signed:none */
+       adpcm_encode_s8,        /* encode:8-bit:signed:swap */
+       adpcm_encode_u16n,      /* encode:16-bit:unsigned:none */
+       adpcm_encode_u16s,      /* encode:16-bit:unsigned:swap */
+       adpcm_encode_s16n,      /* encode:16-bit:signed:none */
+       adpcm_encode_s16s,      /* encode:16-bit:signed:swap */
+       adpcm_encode_u24n,      /* encode:24-bit:unsigned:none */
+       adpcm_encode_u24s,      /* encode:24-bit:unsigned:swap */
+       adpcm_encode_s24n,      /* encode:24-bit:signed:none */
+       adpcm_encode_s24s,      /* encode:24-bit:signed:swap */
+       adpcm_encode_u32n,      /* encode:32-bit:unsigned:none */
+       adpcm_encode_u32s,      /* encode:32-bit:unsigned:swap */
+       adpcm_encode_s32n,      /* encode:32-bit:signed:none */
+       adpcm_encode_s32s,      /* encode:32-bit:signed:swap */
+};
 
-static ssize_t adpcm_transfer(snd_pcm_plugin_t * plugin,
-                             char *src_ptr, size_t src_size,
-                             char *dst_ptr, size_t dst_size)
+static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
+                             const snd_pcm_plugin_voice_t *src_voices,
+                             const snd_pcm_plugin_voice_t *dst_voices,
+                             size_t samples)
 {
-       struct adpcm_private_data *data;
+       adpcm_t *data;
+       int voice;
 
-       if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
-                             dst_ptr == NULL || dst_size < 0)
+       if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
                return -EINVAL;
-       if (src_size == 0)
+       if (samples == 0)
                return 0;
-       data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       switch (data->cmd) {
-       case _U8_ADPCM:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-               adpcm_conv_u8bit_adpcm(&data->state, src_ptr, dst_ptr, src_size);
-               return src_size >> 1;
-       case _S8_ADPCM:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-               adpcm_conv_s8bit_adpcm(&data->state, src_ptr, dst_ptr, src_size);
-               return src_size >> 1;
-       case _S16LE_ADPCM:
-               if ((dst_size << 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_s16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_s16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 2;
-       case _U16LE_ADPCM:
-               if ((dst_size << 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_u16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_u16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 2;
-       case _S16BE_ADPCM:
-               if ((dst_size << 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_s16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_s16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 2;
-       case _U16BE_ADPCM:
-               if ((dst_size << 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_u16bit_swap_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_u16bit_adpcm(&data->state, (short *) src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 2;
-       case _ADPCM_U8:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-               adpcm_conv_adpcm_u8bit(&data->state, src_ptr, dst_ptr, src_size << 1);
-               return src_size << 1;
-       case _ADPCM_S8:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-               adpcm_conv_adpcm_s8bit(&data->state, src_ptr, dst_ptr, src_size << 1);
-               return src_size << 1;
-       case _ADPCM_S16LE:
-               if ((dst_size >> 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_adpcm_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_adpcm_swap_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 2;
-       case _ADPCM_U16LE:
-               if ((dst_size >> 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_adpcm_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_adpcm_swap_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 2;
-       case _ADPCM_S16BE:
-               if ((dst_size >> 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_adpcm_swap_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_adpcm_s16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 2;
-       case _ADPCM_U16BE:
-               if ((dst_size << 2) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               adpcm_conv_adpcm_swap_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               adpcm_conv_adpcm_u16bit(&data->state, src_ptr, (short *) dst_ptr, src_size << 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 2;
-       default:
-               return -EIO;
+       data = (adpcm_t *)plugin->extra_data;
+       /* FIXME */
+       if (plugin->src_format.interleave) {
+               data->func(&data->state,
+                          src_voices[0].addr,
+                          dst_voices[0].addr,
+                          samples * plugin->src_format.voices);
+       } else {
+               for (voice = 0; voice < plugin->src_format.voices; voice++) {
+                       if (src_voices[voice].addr == NULL)
+                               continue;
+                       data->func(&data->state,
+                                  src_voices[voice].addr,
+                                  dst_voices[voice].addr,
+                                  samples);
+               }
        }
+       return samples;
 }
 
 static int adpcm_action(snd_pcm_plugin_t * plugin,
                        snd_pcm_plugin_action_t action,
                        unsigned long udata)
 {
-       struct adpcm_private_data *data;
+       adpcm_t *data;
 
        if (plugin == NULL)
                return -EINVAL;
-       data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (adpcm_t *)plugin->extra_data;
        if (action == PREPARE)
                adpcm_init_state(&data->state);
        return 0;               /* silenty ignore other actions */
 }
 
-static ssize_t adpcm_src_size(snd_pcm_plugin_t * plugin, size_t size)
-{
-       struct adpcm_private_data *data;
-
-       if (!plugin || size <= 0)
-               return -EINVAL;
-       data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
-       switch (data->cmd) {
-       case _U8_ADPCM:
-       case _S8_ADPCM:
-               return size * 2;
-       case _ADPCM_U8:
-       case _ADPCM_S8:
-               return size / 2;
-       case _U16LE_ADPCM:
-       case _S16LE_ADPCM:
-       case _U16BE_ADPCM:
-       case _S16BE_ADPCM:
-               return size * 4;
-       case _ADPCM_U16LE:
-       case _ADPCM_S16LE:
-       case _ADPCM_U16BE:
-       case _ADPCM_S16BE:
-               return size / 4;
-       default:
-               return -EIO;
-       }
-}
-
-static ssize_t adpcm_dst_size(snd_pcm_plugin_t * plugin, size_t size)
-{
-       struct adpcm_private_data *data;
-
-       if (!plugin || size <= 0)
-               return -EINVAL;
-       data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
-       switch (data->cmd) {
-       case _U8_ADPCM:
-       case _S8_ADPCM:
-               return size / 2;
-       case _ADPCM_U8:
-       case _ADPCM_S8:
-               return size * 2;
-       case _U16LE_ADPCM:
-       case _S16LE_ADPCM:
-       case _U16BE_ADPCM:
-       case _S16BE_ADPCM:
-               return size / 4;
-       case _ADPCM_U16LE:
-       case _ADPCM_S16LE:
-       case _ADPCM_U16BE:
-       case _ADPCM_S16BE:
-               return size * 4;
-       default:
-               return -EIO;
-       }
-}
-
-int snd_pcm_plugin_build_adpcm(snd_pcm_format_t * src_format,
-                              snd_pcm_format_t * dst_format,
-                              snd_pcm_plugin_t ** r_plugin)
+int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
+                              snd_pcm_format_t *src_format,
+                              snd_pcm_format_t *dst_format,
+                              snd_pcm_plugin_t **r_plugin)
 {
        struct adpcm_private_data *data;
        snd_pcm_plugin_t *plugin;
-       combination_t cmd;
+       int endian, src_width, dst_width, sign;
+       adpcm_f func;
 
        if (!r_plugin || !src_format || !dst_format)
                return -EINVAL;
@@ -602,39 +379,49 @@ int snd_pcm_plugin_build_adpcm(snd_pcm_format_t * src_format,
                return -EINVAL;
 
        if (dst_format->format == SND_PCM_SFMT_IMA_ADPCM) {
-               switch (src_format->format) {
-               case SND_PCM_SFMT_U8:           cmd = _U8_ADPCM;        break;
-               case SND_PCM_SFMT_S8:           cmd = _S8_ADPCM;        break;
-               case SND_PCM_SFMT_U16_LE:       cmd = _U16LE_ADPCM;     break;
-               case SND_PCM_SFMT_S16_LE:       cmd = _S16LE_ADPCM;     break;
-               case SND_PCM_SFMT_U16_BE:       cmd = _U16BE_ADPCM;     break;
-               case SND_PCM_SFMT_S16_BE:       cmd = _S16BE_ADPCM;     break;
-               default:
+               if (!snd_pcm_format_linear(src_format->format))
                        return -EINVAL;
-               }
+               sign = snd_pcm_format_signed(src_format->format);
+               src_width = snd_pcm_format_width(src_format->format);
+               if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
+                       return -EINVAL;
+               dst_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               endian = snd_pcm_format_big_endian(src_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+               endian = snd_pcm_format_little_endian(src_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+               func = ((adpcm_f(*)[2][2])adpcm_functions_encode)[src_width/8][sign][endian];
        } else if (src_format->format == SND_PCM_SFMT_IMA_ADPCM) {
-               switch (dst_format->format) {
-               case SND_PCM_SFMT_U8:           cmd = _ADPCM_U8;        break;
-               case SND_PCM_SFMT_S8:           cmd = _ADPCM_S8;        break;
-               case SND_PCM_SFMT_U16_LE:       cmd = _ADPCM_U16LE;     break;
-               case SND_PCM_SFMT_S16_LE:       cmd = _ADPCM_S16LE;     break;
-               case SND_PCM_SFMT_U16_BE:       cmd = _ADPCM_U16BE;     break;
-               case SND_PCM_SFMT_S16_BE:       cmd = _ADPCM_S16BE;     break;
-               default:
+               if (!snd_pcm_format_linear(dst_format->format))
                        return -EINVAL;
-               }
+               sign = snd_pcm_format_signed(dst_format->format);
+               dst_width = snd_pcm_format_width(dst_format->format);
+               if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
+                       return -EINVAL;
+               src_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               endian = snd_pcm_format_big_endian(dst_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+               endian = snd_pcm_format_little_endian(dst_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+               func = ((adpcm_f(*)[2][2])adpcm_functions_decode)[dst_width/8][sign][endian];
        } else {
                return -EINVAL;
        }
-       plugin = snd_pcm_plugin_build("Ima-ADPCM<->linear conversion",
+       plugin = snd_pcm_plugin_build(handle,
+                                     "Ima-ADPCM<->linear conversion",
+                                     src_format,
+                                     dst_format,
                                      sizeof(struct adpcm_private_data));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct adpcm_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->cmd = cmd;
+       data = (adpcm_t *)plugin->extra_data;
        plugin->transfer = adpcm_transfer;
-       plugin->src_size = adpcm_src_size;
-       plugin->dst_size = adpcm_dst_size;
        plugin->action = adpcm_action;
        *r_plugin = plugin;
        return 0;
index 86d73637222412041892a9822edaf54c81a9b07f..5cfcf2c40f0f82aa8c807fa58e7706f1655cab1e 100644 (file)
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include <endian.h>
 #include <byteswap.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 
 #define        SIGN_BIT        (0x80)          /* Sign bit for a A-law byte. */
@@ -69,7 +70,7 @@ static inline int search(int val, short *table, int size)
  * For further information see John C. Bellamy's Digital Telephony, 1982,
  * John Wiley & Sons, pps 98-111 and 472-476.
  */
-static inline unsigned char linear2alaw(int pcm_val)   /* 2's complement (16-bit range) */
+static unsigned char linear2alaw(int pcm_val)  /* 2's complement (16-bit range) */
 {
        int             mask;
        int             seg;
@@ -103,7 +104,7 @@ static inline unsigned char linear2alaw(int pcm_val)        /* 2's complement (16-bit r
  * alaw2linear() - Convert an A-law value to 16-bit linear PCM
  *
  */
-static inline int alaw2linear(unsigned char a_val)
+static int alaw2linear(unsigned char a_val)
 {
        int             t;
        int             seg;
@@ -131,298 +132,148 @@ static inline int alaw2linear(unsigned char a_val)
  *  Basic A-Law plugin
  */
 
-typedef enum {
-       _S8_ALAW,
-       _U8_ALAW,
-       _S16LE_ALAW,
-       _U16LE_ALAW,
-       _S16BE_ALAW,
-       _U16BE_ALAW,
-       _ALAW_S8,
-       _ALAW_U8,
-       _ALAW_S16LE,
-       _ALAW_U16LE,
-       _ALAW_S16BE,
-       _ALAW_U16BE
-} combination_t; 
-struct alaw_private_data {
-       combination_t cmd;
-};
-
-static void alaw_conv_u8bit_alaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       unsigned int pcm;
-
-       while (size-- > 0) {
-               pcm = ((*src_ptr++) ^ 0x80) << 8;
-               *dst_ptr++ = linear2alaw((signed short)(pcm));
-       }
+typedef void (*alaw_f)(void *src_ptr, void *dst_ptr, int samples);
+
+typedef struct alaw_private_data {
+       int src_byte_width;
+       int dst_byte_width;
+       alaw_f func;
+} alaw_t;
+
+#define ALAW_FUNC_DECODE(name, dsttype, val) \
+static void alaw_decode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+       unsigned char *src = src_ptr; \
+       dsttype *dst = dst_ptr; \
+       unsigned int s; \
+       while (samples--) { \
+               s = alaw2linear(*src++); \
+               *dst++ = val; \
+       } \
 }
 
-static void alaw_conv_s8bit_alaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       unsigned int pcm;
-
-       while (size-- > 0) {
-               pcm = *src_ptr++ << 8;
-               *dst_ptr++ = linear2alaw((signed short)(pcm));
-       }
-}
-
-static void alaw_conv_s16bit_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2alaw((signed short)(*src_ptr++));
-}
-
-static void alaw_conv_s16bit_swap_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2alaw((signed short)(bswap_16(*src_ptr++)));
-}
-
-static void alaw_conv_u16bit_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2alaw((signed short)((*src_ptr++) ^ 0x8000));
-}
-
-static void alaw_conv_u16bit_swap_alaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2alaw((signed short)(bswap_16(*src_ptr++) ^ 0x8000));
-}
-
-static void alaw_conv_alaw_u8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = (alaw2linear(*src_ptr++) >> 8) ^ 0x80;
-}
-
-static void alaw_conv_alaw_s8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = alaw2linear(*src_ptr++) >> 8;
-}
-
-static void alaw_conv_alaw_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = alaw2linear(*src_ptr++);
+#define ALAW_FUNC_ENCODE(name, srctype, val) \
+static void alaw_encode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+       srctype *src = src_ptr; \
+       unsigned char *dst = dst_ptr; \
+       unsigned int s; \
+       while (samples--) { \
+               s = *src++; \
+               *dst++ = linear2alaw(val); \
+       } \
 }
 
-static void alaw_conv_alaw_swap_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = bswap_16(alaw2linear(*src_ptr++));
-}
-
-static void alaw_conv_alaw_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = alaw2linear(*src_ptr++) ^ 0x8000;
-}
+ALAW_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
+ALAW_FUNC_DECODE(s8, u_int8_t, s >> 8)
+ALAW_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
+ALAW_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ALAW_FUNC_DECODE(s16n, u_int16_t, s)
+ALAW_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
+ALAW_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
+ALAW_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
+ALAW_FUNC_DECODE(s24n, u_int32_t, s << 8)
+ALAW_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
+ALAW_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
+ALAW_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
+ALAW_FUNC_DECODE(s32n, u_int32_t, s << 16)
+ALAW_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
+
+ALAW_FUNC_ENCODE(u8, u_int8_t, s << 8)
+ALAW_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
+ALAW_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
+ALAW_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+ALAW_FUNC_ENCODE(s16n, u_int16_t, s)
+ALAW_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
+ALAW_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
+ALAW_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
+ALAW_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
+ALAW_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
+ALAW_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
+ALAW_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
+ALAW_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
+ALAW_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
+
+/* wide, sign, swap endian */
+static alaw_f alaw_functions_decode[4 * 2 * 2] = {
+       alaw_decode_u8,         /* decode:8-bit:unsigned:none */
+       alaw_decode_u8,         /* decode:8-bit:unsigned:swap */
+       alaw_decode_s8,         /* decode:8-bit:signed:none */
+       alaw_decode_s8,         /* decode:8-bit:signed:swap */
+       alaw_decode_u16n,       /* decode:16-bit:unsigned:none */
+       alaw_decode_u16s,       /* decode:16-bit:unsigned:swap */
+       alaw_decode_s16n,       /* decode:16-bit:signed:none */
+       alaw_decode_s16s,       /* decode:16-bit:signed:swap */
+       alaw_decode_u24n,       /* decode:24-bit:unsigned:none */
+       alaw_decode_u24s,       /* decode:24-bit:unsigned:swap */
+       alaw_decode_s24n,       /* decode:24-bit:signed:none */
+       alaw_decode_s24s,       /* decode:24-bit:signed:swap */
+       alaw_decode_u32n,       /* decode:32-bit:unsigned:none */
+       alaw_decode_u32s,       /* decode:32-bit:unsigned:swap */
+       alaw_decode_s32n,       /* decode:32-bit:signed:none */
+       alaw_decode_s32s,       /* decode:32-bit:signed:swap */
+};
 
-static void alaw_conv_alaw_swap_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = bswap_16(alaw2linear(*src_ptr++) ^ 0x8000);
-}
+/* wide, sign, swap endian */
+static alaw_f alaw_functions_encode[4 * 2 * 2] = {
+       alaw_encode_u8,         /* encode:8-bit:unsigned:none */
+       alaw_encode_u8,         /* encode:8-bit:unsigned:swap */
+       alaw_encode_s8,         /* encode:8-bit:signed:none */
+       alaw_encode_s8,         /* encode:8-bit:signed:swap */
+       alaw_encode_u16n,       /* encode:16-bit:unsigned:none */
+       alaw_encode_u16s,       /* encode:16-bit:unsigned:swap */
+       alaw_encode_s16n,       /* encode:16-bit:signed:none */
+       alaw_encode_s16s,       /* encode:16-bit:signed:swap */
+       alaw_encode_u24n,       /* encode:24-bit:unsigned:none */
+       alaw_encode_u24s,       /* encode:24-bit:unsigned:swap */
+       alaw_encode_s24n,       /* encode:24-bit:signed:none */
+       alaw_encode_s24s,       /* encode:24-bit:signed:swap */
+       alaw_encode_u32n,       /* encode:32-bit:unsigned:none */
+       alaw_encode_u32s,       /* encode:32-bit:unsigned:swap */
+       alaw_encode_s32n,       /* encode:32-bit:signed:none */
+       alaw_encode_s32s,       /* encode:32-bit:signed:swap */
+};
 
 static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
-                             char *src_ptr, size_t src_size,
-                             char *dst_ptr, size_t dst_size)
+                            const snd_pcm_plugin_voice_t *src_voices,
+                            const snd_pcm_plugin_voice_t *dst_voices,
+                            size_t samples)
 {
-       struct alaw_private_data *data;
+       alaw_t *data;
+       int voice;
 
-       if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
-                             dst_ptr == NULL || dst_size < 0)
+       if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
                return -EINVAL;
-       if (src_size == 0)
+       if (samples == 0)
                return 0;
-       data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       switch (data->cmd) {
-       case _U8_ALAW:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               alaw_conv_u8bit_alaw(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _S8_ALAW:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               alaw_conv_s8bit_alaw(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _S16LE_ALAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_s16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_s16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _U16LE_ALAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_u16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_u16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _S16BE_ALAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_s16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_s16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _U16BE_ALAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_u16bit_swap_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_u16bit_alaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _ALAW_U8:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               alaw_conv_alaw_u8bit(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _ALAW_S8:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               alaw_conv_alaw_s8bit(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _ALAW_S16LE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_alaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_alaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       case _ALAW_U16LE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_alaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_alaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       case _ALAW_S16BE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_alaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_alaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       case _ALAW_U16BE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               alaw_conv_alaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               alaw_conv_alaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       default:
-               return -EIO;
-       }
-}
-
-static ssize_t alaw_src_size(snd_pcm_plugin_t *plugin, size_t size)
-{
-       struct alaw_private_data *data;
-
-       if (!plugin || size <= 0)
-               return -EINVAL;
-       data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       switch (data->cmd) {
-       case _U8_ALAW:
-       case _S8_ALAW:
-       case _ALAW_U8:
-       case _ALAW_S8:
-               return size;
-       case _U16LE_ALAW:
-       case _S16LE_ALAW:
-       case _U16BE_ALAW:
-       case _S16BE_ALAW:
-               return size * 2;
-       case _ALAW_U16LE:
-       case _ALAW_S16LE:
-       case _ALAW_U16BE:
-       case _ALAW_S16BE:
-               return size / 2;
-       default:
-               return -EIO;
-       }
+       data = (alaw_t *)plugin->extra_data;
+       if (plugin->src_format.interleave) {
+               data->func(src_voices[0].addr,
+                          dst_voices[0].addr,
+                          samples * plugin->src_format.voices);
+        } else {
+               for (voice = 0; voice < plugin->src_format.voices; voice++) {
+                       if (src_voices[voice].addr == NULL)
+                               continue;
+                       data->func(src_voices[voice].addr,
+                                  dst_voices[voice].addr,
+                                  samples);
+               }
+        }
+        return samples;
 }
 
-static ssize_t alaw_dst_size(snd_pcm_plugin_t *plugin, size_t size)
-{
-       struct alaw_private_data *data;
-
-       if (!plugin || size <= 0)
-               return -EINVAL;
-       data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       switch (data->cmd) {
-       case _U8_ALAW:
-       case _S8_ALAW:
-       case _ALAW_U8:
-       case _ALAW_S8:
-               return size;
-       case _U16LE_ALAW:
-       case _S16LE_ALAW:
-       case _U16BE_ALAW:
-       case _S16BE_ALAW:
-               return size / 2;
-       case _ALAW_U16LE:
-       case _ALAW_S16LE:
-       case _ALAW_U16BE:
-       case _ALAW_S16BE:
-               return size * 2;
-       default:
-               return -EIO;
-       }
-}
-int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
+                             snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin)
 {
        struct alaw_private_data *data;
        snd_pcm_plugin_t *plugin;
-       combination_t cmd;
+       int endian, src_width, dst_width, sign;
+       alaw_f func;
 
-       if (!r_plugin)
+       if (r_plugin == NULL)
                return -EINVAL;
        *r_plugin = NULL;
 
@@ -434,40 +285,53 @@ int snd_pcm_plugin_build_alaw(snd_pcm_format_t *src_format,
        if (src_format->voices != dst_format->voices)
                return -EINVAL;
 
-       if (dst_format->format == SND_PCM_SFMT_A_LAW) {
-               switch (src_format->format) {
-               case SND_PCM_SFMT_U8:           cmd = _U8_ALAW;         break;
-               case SND_PCM_SFMT_S8:           cmd = _S8_ALAW;         break;
-               case SND_PCM_SFMT_U16_LE:       cmd = _U16LE_ALAW;      break;
-               case SND_PCM_SFMT_S16_LE:       cmd = _S16LE_ALAW;      break;
-               case SND_PCM_SFMT_U16_BE:       cmd = _U16BE_ALAW;      break;
-               case SND_PCM_SFMT_S16_BE:       cmd = _S16BE_ALAW;      break;
-               default:
+       if (dst_format->format == SND_PCM_SFMT_MU_LAW) {
+               if (!snd_pcm_format_linear(src_format->format))
                        return -EINVAL;
-               }
-       } else if (src_format->format == SND_PCM_SFMT_A_LAW) {
-               switch (dst_format->format) {
-               case SND_PCM_SFMT_U8:           cmd = _ALAW_U8;         break;
-               case SND_PCM_SFMT_S8:           cmd = _ALAW_S8;         break;
-               case SND_PCM_SFMT_U16_LE:       cmd = _ALAW_U16LE;      break;
-               case SND_PCM_SFMT_S16_LE:       cmd = _ALAW_S16LE;      break;
-               case SND_PCM_SFMT_U16_BE:       cmd = _ALAW_U16BE;      break;
-               case SND_PCM_SFMT_S16_BE:       cmd = _ALAW_S16BE;      break;
-               default:
+               sign = snd_pcm_format_signed(src_format->format);
+               src_width = snd_pcm_format_width(src_format->format);
+               if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
                        return -EINVAL;
-               }
+               dst_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               endian = snd_pcm_format_big_endian(src_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+               endian = snd_pcm_format_little_endian(src_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+               func = ((alaw_f(*)[2][2])alaw_functions_encode)[(src_width/8)-1][sign][endian];
+       } else if (src_format->format == SND_PCM_SFMT_MU_LAW) {
+               if (!snd_pcm_format_linear(dst_format->format))
+                       return -EINVAL;
+               sign = snd_pcm_format_signed(dst_format->format);
+               dst_width = snd_pcm_format_width(dst_format->format);
+               if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
+                       return -EINVAL;
+               src_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               endian = snd_pcm_format_big_endian(dst_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+               endian = snd_pcm_format_little_endian(dst_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+               func = ((alaw_f(*)[2][2])alaw_functions_decode)[(dst_width/8)-1][sign][endian];
        } else {
                return -EINVAL;
        }
-       plugin = snd_pcm_plugin_build("A-Law<->linear conversion",
+       plugin = snd_pcm_plugin_build(handle,
+                                     "A-Law<->linear conversion",
+                                     src_format,
+                                     dst_format,
                                      sizeof(struct alaw_private_data));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct alaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->cmd = cmd;
+       data = (struct alaw_private_data *)plugin->extra_data;
+       data->src_byte_width = src_width / 8;
+       data->dst_byte_width = dst_width / 8;
+       data->func = func;
        plugin->transfer = alaw_transfer;
-       plugin->src_size = alaw_src_size;
-       plugin->dst_size = alaw_dst_size;
        *r_plugin = plugin;
        return 0;
 }
index 195b4683519f5ec61329d53983ab1eab0fd2ae44..6c0e609ec3723d62a5a89b231ece0a6ef0185e30 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 
 /*
  *  Basic block plugin
  */
  
-struct block_private_data {
-       snd_pcm_t *pcm;
+typedef struct block_private_data {
        int channel;
-};
+} block_t;
 
 static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
-                             char *src_ptr, size_t src_size,
-                             char *dst_ptr, size_t dst_size)
+                             const snd_pcm_plugin_voice_t *src_voices,
+                             const snd_pcm_plugin_voice_t *dst_voices,
+                             size_t samples)
 {
-       struct block_private_data *data;
+       block_t *data;
+       ssize_t result;
+       struct iovec *vec;
+       int count, voice;
 
-       if (plugin == NULL || dst_ptr == NULL || dst_size <= 0)
-                       return -EINVAL;
-       data = (struct block_private_data *)snd_pcm_plugin_extra_data(plugin);
+       if (plugin == NULL)
+               return -EINVAL;
+       data = (block_t *)plugin->extra_data;
        if (data == NULL)
                return -EINVAL;
+       vec = (struct iovec *)((char *)data + sizeof(*data));
        if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
-               return snd_pcm_write(data->pcm, dst_ptr, dst_size);
+               if (src_voices == NULL)
+                       return -EINVAL;
+               if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
+                       return result;
+               if (plugin->src_format.interleave) {
+                       vec->iov_base = src_voices->addr;
+                       vec->iov_len = result;
+                       count = 1;
+               } else {
+                       count = plugin->src_format.voices;
+                       result /= count;
+                       for (voice = 0; voice < count; voice++) {
+                               vec[voice].iov_base = src_voices[voice].addr;
+                               vec[voice].iov_len = result;
+                       }
+               }
+               result = snd_pcm_writev(plugin->handle, vec, count);
+               if (result < 0)
+                       return result;
+               return snd_pcm_plugin_src_size_to_samples(plugin, result);
        } else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
-               return snd_pcm_read(data->pcm, dst_ptr, dst_size);
+               if (dst_voices == NULL)
+                       return -EINVAL;
+               if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
+                       return result;
+               if (plugin->dst_format.interleave) {
+                       vec->iov_base = dst_voices->addr;
+                       vec->iov_len = result;
+                       count = 1;
+               } else {
+                       count = plugin->dst_format.voices;
+                       result /= count;
+                       for (voice = 0; voice < count; voice++) {
+                               vec[voice].iov_base = dst_voices[voice].addr;
+                               vec[voice].iov_len = result;
+                       }
+               }
+               result = snd_pcm_readv(plugin->handle, vec, count);
+               return snd_pcm_plugin_dst_size_to_samples(plugin, result);
        } else {
                return -EINVAL;
        }
 }
  
-int snd_pcm_plugin_build_block(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_block(snd_pcm_t *pcm, int channel,
+                              snd_pcm_format_t *format,
+                              snd_pcm_plugin_t **r_plugin)
 {
-       struct block_private_data *data;
+       block_t *data;
        snd_pcm_plugin_t *plugin;
 
        if (r_plugin == NULL)
                return -EINVAL;
        *r_plugin = NULL;
-       if (!pcm || channel < 0 || channel > 1)
+       if (pcm == NULL || channel < 0 || channel > 1 || format == NULL)
                return -EINVAL;
-       plugin = snd_pcm_plugin_build(channel == SND_PCM_CHANNEL_PLAYBACK ?
+       plugin = snd_pcm_plugin_build(pcm,
+                                     channel == SND_PCM_CHANNEL_PLAYBACK ?
                                                "I/O block playback" :
                                                "I/O block capture",
-                                               sizeof(struct block_private_data));
+                                     format, format,
+                                     sizeof(block_t) + sizeof(struct iovec) * format->voices);
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct block_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->pcm = pcm;
+       data = (block_t *)plugin->extra_data;
        data->channel = channel;
        plugin->transfer = block_transfer;
        *r_plugin = plugin;
index 5dedda3618cff4afd6c1d8013a188a96eb1ac8f5..d13e39cf2e15b05827e5aefd15360b828ea4656b 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  Interleave / non-interleave conversion Plug-In
- *  Copyright (c) 2000 by Abramo Bagnara <abbagnara@racine.ra.it>
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>,
+ *                       Jaroslav Kysela <perex@suse.cz>
  *
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -31,6 +32,7 @@
 #include <errno.h>
 #include <endian.h>
 #include <byteswap.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 #endif
 
  *  Basic interleave / non-interleave conversion plugin
  */
  
-typedef void (*interleave_f)(void* src_ptr, void* dst_ptr,
+typedef void (*interleave_f)(const snd_pcm_plugin_voice_t *src_voices,
+                            const snd_pcm_plugin_voice_t *dst_voices,
                             int voices, size_t samples);
 
-struct interleave_private_data {
-       int sample_size;
-       int voices;
+typedef struct interleave_private_data {
        interleave_f func;
-};
+} interleave_t;
 
 
 #define INTERLEAVE_FUNC(name, type) \
-static void name(void* src_ptr, void* dst_ptr, \
-                      int voices, size_t samples) \
+static void name(const snd_pcm_plugin_voice_t *src_voices, \
+                const snd_pcm_plugin_voice_t *dst_voices, \
+                int voices, size_t samples) \
 { \
-       type* src = src_ptr; \
-       int voice; \
-       for (voice = 0; voice < voices; ++voice) { \
-               type *dst = (type*)dst_ptr + voice; \
-               int s; \
-               for (s = 0; s < samples; ++s) { \
-                       *dst = *src; \
-                       src++; \
+       type *src, *dst; \
+       int voice, sample; \
+       for (voice = 0; voice < voices; voice++) { \
+               src = (type *)src_voices[voice].addr; \
+               dst = (type *)dst_voices[voice].addr + voice; \
+               for (sample = 0; sample < samples; sample++) { \
+                       *dst = *src++; \
                        dst += voices; \
                } \
        } \
 } \
 
 #define DEINTERLEAVE_FUNC(name, type) \
-static void name(void* src_ptr, void* dst_ptr, \
-                        int voices, size_t samples) \
+static void name(const snd_pcm_plugin_voice_t *src_voices, \
+                const snd_pcm_plugin_voice_t *dst_voices, \
+                int voices, size_t samples) \
 { \
-       type* dst = dst_ptr; \
-       int voice; \
-       for (voice = 0; voice < voices; ++voice) { \
-               type *src = (type*)src_ptr + voice; \
-               int s; \
-               for (s = 0; s < samples; ++s) { \
-                       *dst = *src; \
-                       dst++; \
+       type *src, *dst; \
+       int voice, sample; \
+       for (voice = 0; voice < voices; voice++) { \
+               src = (type *)src_voices[voice].addr + voice; \
+               dst = (type *)dst_voices[voice].addr; \
+               for (sample = 0; sample < samples; sample++) { \
+                       *dst++ = *src; \
                        src += voices; \
                } \
        } \
@@ -92,36 +93,33 @@ FUNCS(4, int32_t);
 FUNCS(8, int64_t);
 
 static ssize_t interleave_transfer(snd_pcm_plugin_t *plugin,
-                                  char *src_ptr, size_t src_size,
-                                  char *dst_ptr, size_t dst_size)
+                                  const snd_pcm_plugin_voice_t *src_voices,
+                                  const snd_pcm_plugin_voice_t *dst_voices,
+                                  size_t samples)
 {
-       struct interleave_private_data *data;
+       interleave_t *data;
 
-       if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
-                             dst_ptr == NULL || dst_size < 0)
+       if (plugin == NULL || src_voices == NULL || src_voices == NULL || samples < 0)
                return -EINVAL;
-       if (src_size == 0)
+       if (samples == 0)
                return 0;
-       if (src_size != dst_size)
-               return -EINVAL;
-       data = (struct interleave_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (interleave_t *)plugin->extra_data;
        if (data == NULL)
                return -EINVAL;
-       data->func(src_ptr, dst_ptr, data->voices,
-                  src_size / (data->voices * data->sample_size));
-       return src_size;
+       data->func(src_voices, dst_voices, plugin->src_format.voices, samples);
+       return samples;
 }
 
-int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle,
+                                   snd_pcm_format_t *src_format,
                                    snd_pcm_format_t *dst_format,
                                    snd_pcm_plugin_t **r_plugin)
 {
        struct interleave_private_data *data;
        snd_pcm_plugin_t *plugin;
        interleave_f func;
-       int size;
 
-       if (r_plugin == NULL)
+       if (r_plugin == NULL || src_format == NULL || dst_format == NULL)
                return -EINVAL;
        *r_plugin = NULL;
 
@@ -133,36 +131,35 @@ int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format,
                return -EINVAL;
        if (src_format->voices != dst_format->voices)
                return -EINVAL;
-       size = snd_pcm_format_size(dst_format->format, 1);
-       if (dst_format->interleave) {
-               switch (size) {
-               case 1:
+       if (!src_format->interleave) {
+               switch (snd_pcm_format_width(src_format->format)) {
+               case 8:
                        func = int_1;
                        break;
-               case 2:
+               case 16:
                        func = int_2;
                        break;
-               case 4:
+               case 32:
                        func = int_4;
                        break;
-               case 8:
+               case 64:
                        func = int_8;
                        break;
                default:
                        return -EINVAL;
                }
        } else {
-               switch (size) {
-               case 1:
+               switch (snd_pcm_format_width(src_format->format)) {
+               case 8:
                        func = deint_1;
                        break;
-               case 2:
+               case 16:
                        func = deint_2;
                        break;
-               case 4:
+               case 32:
                        func = deint_4;
                        break;
-               case 8:
+               case 64:
                        func = deint_8;
                        break;
                default:
@@ -170,13 +167,13 @@ int snd_pcm_plugin_build_interleave(snd_pcm_format_t *src_format,
                }
        }
 
-       plugin = snd_pcm_plugin_build("interleave conversion",
-                                     sizeof(struct interleave_private_data));
+       plugin = snd_pcm_plugin_build(handle,
+                                     "interleave conversion",
+                                     src_format, dst_format,
+                                     sizeof(interleave_t));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct interleave_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->sample_size = size;
-       data->voices = src_format->voices;
+       data = (interleave_t *)plugin->extra_data;
        data->func = func;
        plugin->transfer = interleave_transfer;
        *r_plugin = plugin;
index 7bc5bb511ebd8a6b5b4e25e581f7752f6999f6f0..4f1902120153c68b2996f623243c0bfe48aa2308 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  Linear conversion Plug-In
- *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>,
+ *                       Abramo Bagnara <abramo@alsa-project.org>
  *
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -33,6 +34,7 @@
 #include <errno.h>
 #include <endian.h>
 #include <byteswap.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 #endif
 
  
 typedef void (*linear_f)(void *src, void *dst, size_t size);
 
-struct linear_private_data {
+typedef struct linear_private_data {
        int src_sample_size, dst_sample_size;
        linear_f func;
-};
+} linear_t;
 
 #define LIN_FUNC(name, srctype, dsttype, val) \
 static void lin_##name(void *src_ptr, void *dst_ptr, size_t size) \
@@ -163,7 +165,7 @@ LIN_FUNC(32_sign_end, u_int32_t, u_int32_t, bswap_32(src) ^ 0x80)
 LIN_FUNC(32_end_sign_end, u_int32_t, u_int32_t, src ^ 0x80)
 
 /* src_wid dst_wid src_endswap, dst_endswap, sign_swap */
-linear_f linear_functions[4 * 4 * 2 * 2 * 2] = {
+static linear_f linear_functions[4 * 4 * 2 * 2 * 2] = {
        NULL,                   /* 8->8: Nothing to do */
        lin_8_sign,             /* 8->8 sign: lin_8_sign */
        NULL,                   /* 8->8 dst_end: Nothing to do */
@@ -296,52 +298,33 @@ linear_f linear_functions[4 * 4 * 2 * 2 * 2] = {
 
 
 static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
-                              char *src_ptr, size_t src_size,
-                              char *dst_ptr, size_t dst_size)
+                              const snd_pcm_plugin_voice_t *src_voices,
+                              const snd_pcm_plugin_voice_t *dst_voices,
+                              size_t samples)
 {
-       struct linear_private_data *data;
+       linear_t *data;
+       int voice;
+       ssize_t result;
 
-       if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
-                             dst_ptr == NULL || dst_size < 0)
+       if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
                return -EINVAL;
-       if (src_size == 0)
+       if (samples == 0)
                return 0;
-       data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       if (src_size % data->src_sample_size != 0)
-               return -EINVAL;
-       if (dst_size < src_size*data->dst_sample_size/data->src_sample_size)
-               return -EINVAL;
-       data->func(src_ptr, dst_ptr, src_size / data->src_sample_size);
-       return src_size*data->dst_sample_size/data->src_sample_size;
-}
-
-static ssize_t linear_src_size(snd_pcm_plugin_t *plugin, size_t size)
-{
-       struct linear_private_data *data;
-
-       if (plugin == NULL || size <= 0)
-               return -EINVAL;
-       data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       return size*data->src_sample_size/data->dst_sample_size;
-}
-
-static ssize_t linear_dst_size(snd_pcm_plugin_t *plugin, size_t size)
-{
-       struct linear_private_data *data;
-
-       if (plugin == NULL || size <= 0)
-               return -EINVAL;
-       data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       return size*data->dst_sample_size/data->src_sample_size;
+       data = (linear_t *)plugin->extra_data;
+       for (voice = 0, result = 0; voice < plugin->src_format.voices; voice++) {
+               if (src_voices[voice].addr == NULL)
+                       continue;
+               if (dst_voices[voice].addr == NULL)
+                       return -EINVAL;
+               data->func(src_voices[voice].addr,
+                          dst_voices[voice].addr,
+                          samples);
+       }
+       return samples;
 }
 
-int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
+                               snd_pcm_format_t *src_format,
                                snd_pcm_format_t *dst_format,
                                snd_pcm_plugin_t **r_plugin)
 {
@@ -349,7 +332,6 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
        snd_pcm_plugin_t *plugin;
        linear_f func;
        int src_endian, dst_endian, sign, src_width, dst_width;
-       int src_sample_size, dst_sample_size;
 
        if (r_plugin == NULL)
                return -EINVAL;
@@ -380,46 +362,17 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
 #error "Unsupported endian..."
 #endif
 
-       switch (src_width) {
-       case 8:
-               src_width = 0;
-               src_sample_size = 1;
-               break;
-       case 16:
-               src_width = 1;
-               src_sample_size = 2;
-               break;
-       case 24:
-               src_width = 2;
-               src_sample_size = 4;
-               break;
-       case 32:
-               src_width = 3;
-               src_sample_size = 4;
-               break;
-       default:
-               return -EINVAL;
-       }
-       switch (dst_width) {
-       case 8:
-               dst_width = 0;
-               dst_sample_size = 1;
-               break;
-       case 16:
-               dst_width = 1;
-               dst_sample_size = 2;
-               break;
-       case 24:
-               dst_width = 2;
-               dst_sample_size = 4;
-               break;
-       case 32:
-               dst_width = 3;
-               dst_sample_size = 4;
-               break;
-       default:
-               return -EINVAL;
-       }
+       src_width = snd_pcm_format_width(src_format->format);
+       if (src_width < 0)
+               return src_width;
+       src_width /= 8;
+       src_width--;
+
+       dst_width = snd_pcm_format_width(dst_format->format);
+       if (dst_width < 0)
+               return dst_width;
+       dst_width /= 8;
+       dst_width--;
 
        if (src_endian < 0)
                src_endian = 0;
@@ -431,18 +384,18 @@ int snd_pcm_plugin_build_linear(snd_pcm_format_t *src_format,
        if (func == NULL)
                return -EINVAL;
 
-       plugin = snd_pcm_plugin_build("linear format conversion",
-                                     sizeof(struct linear_private_data));
+       plugin = snd_pcm_plugin_build(handle,
+                                     "linear format conversion",
+                                     src_format,
+                                     dst_format,
+                                     sizeof(linear_t));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct linear_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (linear_t *)plugin->extra_data;
        data->func = func;
-       data->src_sample_size = src_sample_size;
-       data->dst_sample_size = dst_sample_size;
-
+       data->src_sample_size = plugin->src_width / 8;
+       data->dst_sample_size = plugin->dst_width / 8;
        plugin->transfer = linear_transfer;
-       plugin->src_size = linear_src_size;
-       plugin->dst_size = linear_dst_size;
        *r_plugin = plugin;
        return 0;
 }
index 91f56c4a2b88b68c5cc7b38d16ae88690624abf8..97157ff64fbea7ecf41cf698defa85e934a880fc 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <sys/poll.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 
 /*
  *  Basic mmap plugin
  */
  
-struct mmap_private_data {
-       snd_pcm_t *pcm;
+typedef struct mmap_private_data {
        int channel;
        snd_pcm_mmap_control_t *control;
        char *buffer;
@@ -41,10 +41,13 @@ struct mmap_private_data {
        int frags, frags_used;
        int frags_min, frags_max;
        unsigned int lastblock;
-};
+       struct iovec *vector;
+       int vector_count;
+} mmap_t;
 
-static int playback_ok(struct mmap_private_data *data)
+static int playback_ok(snd_pcm_plugin_t *plugin)
 {
+       mmap_t *data = (mmap_t *)plugin->extra_data;
        snd_pcm_mmap_control_t *control = data->control;
        int delta = control->status.block;
        
@@ -79,8 +82,9 @@ static int poll_playback(snd_pcm_t *pcm)
        return err < 0 ? err : 0;
 }
 
-static int query_playback(struct mmap_private_data *data, int not_use_poll)
+static int query_playback(snd_pcm_plugin_t *plugin, int not_use_poll)
 {
+       mmap_t *data = (mmap_t *)plugin->extra_data;
        snd_pcm_mmap_control_t *control = data->control;
        int err;
 
@@ -89,10 +93,10 @@ static int query_playback(struct mmap_private_data *data, int not_use_poll)
                if (data->start_mode == SND_PCM_START_GO)
                        return -EAGAIN;
                if ((data->start_mode == SND_PCM_START_DATA &&
-                    playback_ok(data)) ||
+                    playback_ok(plugin)) ||
                    (data->start_mode == SND_PCM_START_FULL &&
                     data->frags_used == data->frags)) {
-                       err = snd_pcm_channel_go(data->pcm, data->channel);
+                       err = snd_pcm_channel_go(plugin->handle, data->channel);
                        if (err < 0)
                                return err;
                }
@@ -100,7 +104,7 @@ static int query_playback(struct mmap_private_data *data, int not_use_poll)
        case SND_PCM_STATUS_RUNNING:
                if (!not_use_poll) {
                        control->status.expblock = control->status.block + 1;
-                       err = poll_playback(data->pcm);
+                       err = poll_playback(plugin->handle);
                        if (err < 0)
                                return err;
                }
@@ -113,8 +117,9 @@ static int query_playback(struct mmap_private_data *data, int not_use_poll)
        return 0;
 }
 
-static int capture_ok(struct mmap_private_data *data)
+static int capture_ok(snd_pcm_plugin_t *plugin)
 {
+       mmap_t *data = (mmap_t *)plugin->extra_data;
        snd_pcm_mmap_control_t *control = data->control;
        int delta = control->status.block;
        
@@ -148,8 +153,9 @@ static int poll_capture(snd_pcm_t *pcm)
        return err < 0 ? err : 0;
 }
 
-static int query_capture(struct mmap_private_data *data, int not_use_poll)
+static int query_capture(snd_pcm_plugin_t *plugin, int not_use_poll)
 {
+       mmap_t *data = (mmap_t *)plugin->extra_data;    
        snd_pcm_mmap_control_t *control = data->control;
        int err;
 
@@ -157,14 +163,14 @@ static int query_capture(struct mmap_private_data *data, int not_use_poll)
        case SND_PCM_STATUS_PREPARED:
                if (data->start_mode != SND_PCM_START_DATA)
                        return -EAGAIN;
-               err = snd_pcm_channel_go(data->pcm, data->channel);
+               err = snd_pcm_channel_go(plugin->handle, data->channel);
                if (err < 0)
                        return err;
                break;
        case SND_PCM_STATUS_RUNNING:
                if (!not_use_poll) {
                        control->status.expblock = control->status.block + data->frags_min;
-                       err = poll_capture(data->pcm);
+                       err = poll_capture(plugin->handle);
                        if (err < 0)
                                return err;
                }
@@ -177,131 +183,206 @@ static int query_capture(struct mmap_private_data *data, int not_use_poll)
        return 0;
 }
 
-static int mmap_transfer_src_ptr(snd_pcm_plugin_t *plugin, char **buffer, size_t *size)
+static int mmap_src_voices(snd_pcm_plugin_t *plugin,
+                          snd_pcm_plugin_voice_t **voices,
+                          size_t samples,
+                          void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size))
 {
-       struct mmap_private_data *data;
+       mmap_t *data;
        snd_pcm_mmap_control_t *control;
-       int interleave, err;
+       snd_pcm_plugin_voice_t *v;
+       int err;
 
-       if (plugin == NULL || buffer == NULL || size == NULL)
+       if (plugin == NULL || voices == NULL)
+               return -EINVAL;
+       *voices = NULL;
+       data = (mmap_t *)plugin->extra_data;
+       if (data->channel != SND_PCM_CHANNEL_PLAYBACK)
+               return -EINVAL;
+       if ((control = data->control) == NULL)
+               return -EBADFD;
+       /* wait until the block is not free */
+       while (!playback_ok(plugin)) {
+               err = query_playback(plugin, 0);
+               if (err < 0)
+                       return err;
+       }       
+       v = plugin->voices;
+       if (plugin->src_format.interleave) {
+               void *addr;
+               int voice;
+               if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples))
+                       return -EINVAL;
+               addr = data->buffer + control->fragments[data->frag].addr;
+               for (voice = 0; voice < plugin->src_format.voices; voice++) {
+                       v->aptr = NULL;
+                       v->addr = addr;
+                       v->offset = voice * plugin->src_width;
+                       v->next = plugin->src_format.voices * plugin->src_width;
+               }
+       } else {
+               int frag, voice;
+               if (control->status.frag_size != snd_pcm_plugin_src_samples_to_size(plugin, samples) / plugin->src_format.voices)
                        return -EINVAL;
-       data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
+               for (voice = 0; voice < plugin->src_format.voices; voice++) {
+                       frag = data->frag + (voice * data->frags);
+                       v->aptr = NULL;
+                       v->addr = data->buffer + control->fragments[frag].addr;
+                       v->offset = 0;
+                       v->next = plugin->src_width;
+               }
+       }
+       *voices = plugin->voices;
+       return 0;
+}
+
+static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
+                          snd_pcm_plugin_voice_t **voices,
+                          size_t samples,
+                          void *(*plugin_alloc)(snd_pcm_plugin_handle_t *handle, size_t size))
+{
+       mmap_t *data;
+       snd_pcm_mmap_control_t *control;
+       snd_pcm_plugin_voice_t *v;
+
+       if (plugin == NULL || voices == NULL)
                return -EINVAL;
-       control = data->control;
-       if (control == NULL)
+       *voices = NULL;
+       data = (mmap_t *)plugin->extra_data;
+       if (data->channel != SND_PCM_CHANNEL_CAPTURE)
                return -EINVAL;
-       interleave = control->status.voices < 0;
-       if (interleave) {
-               *buffer = data->buffer + control->fragments[data->frag].addr;
-               if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
-                       /* wait until the block is not free */
-                       while (!playback_ok(data)) {
-                               err = query_playback(data, 0);
-                               if (err < 0)
-                                       return err;
-                       }
+       if ((control = data->control) == NULL)
+               return -EBADFD;
+       v = plugin->voices;
+       if (plugin->dst_format.interleave) {
+               void *addr;
+               int voice;
+               if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples))
+                       return -EINVAL;
+               addr = data->buffer + control->fragments[data->frag].addr;
+               for (voice = 0; voice < plugin->dst_format.voices; voice++) {
+                       v->addr = addr;
+                       v->offset = voice * plugin->src_width;
+                       v->next = plugin->dst_format.voices * plugin->dst_width;
                }
-               *size = control->status.frag_size;
        } else {
-               *buffer = NULL; /* use another buffer */
+               int frag, voice;
+               if (control->status.frag_size != snd_pcm_plugin_dst_samples_to_size(plugin, samples) / plugin->dst_format.voices)
+                       return -EINVAL;
+               for (voice = 0; voice < plugin->dst_format.voices; voice++) {
+                       frag = data->frag + (voice * data->frags);
+                       v->addr = data->buffer + control->fragments[frag].addr;
+                       v->offset = 0;
+                       v->next = plugin->dst_width;
+               }
        }
+       *voices = plugin->voices;
        return 0;
 }
 
 static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
-                             char *src_ptr, size_t src_size,
-                             char *dst_ptr, size_t dst_size)
+                            const snd_pcm_plugin_voice_t *src_voices,
+                            const snd_pcm_plugin_voice_t *dst_voices,
+                            size_t samples)
 {
-       struct mmap_private_data *data;
+       mmap_t *data;
        snd_pcm_mmap_control_t *control;
-       int interleave, voice, err;
+       ssize_t size;
+       int voice, err;
        char *addr;
 
-       if (plugin == NULL || dst_ptr == NULL || dst_size <= 0)
-                       return -EINVAL;
-       data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
+       if (plugin == NULL)
                return -EINVAL;
+       data = (mmap_t *)plugin->extra_data;
        control = data->control;
        if (control == NULL)
                return -EINVAL;
-       interleave = control->status.voices < 0;
-       if (interleave) {
-               if (dst_size != control->status.frag_size)
-                       return -EINVAL;
-       } else {
-               if (dst_size != control->status.frag_size * control->status.voices)
-                       return -EINVAL;
-       }
        if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
-               while (!playback_ok(data)) {
-                       err = query_playback(data, 0);
+               if (src_voices == NULL)
+                       return -EINVAL;
+               while (!playback_ok(plugin)) {
+                       err = query_playback(plugin, 0);
                        if (err < 0)
                                return err;
                }
-               if (interleave) {
+               size = snd_pcm_plugin_src_samples_to_size(plugin, samples);
+               if (size < 0)
+                       return size;
+               if (plugin->src_format.interleave) {
+                       if (size != control->status.frag_size)
+                               return -EINVAL;
                        addr = data->buffer + control->fragments[data->frag].addr;
-                       if (dst_ptr != addr)
-                               memcpy(addr, dst_ptr, dst_size);
+                       if (src_voices->addr != addr)
+                               memcpy(addr, src_voices->addr, size);
                        control->fragments[data->frag++].data = 1;
                        data->frag %= control->status.frags;
                        data->frags_used++;
+                       return samples;
                } else {
                        int frag;
 
-                       for (voice = 0; voice < control->status.voices; voice++) {
+                       if ((size / plugin->src_format.voices) != control->status.frag_size)
+                               return -EINVAL;
+                       for (voice = 0; voice < plugin->src_format.voices; voice++) {
                                frag = data->frag + (voice * data->frags);
                                while (control->fragments[frag].data) {
-                                       err = query_playback(data, 1);
+                                       err = query_playback(plugin, 1);
                                        if (err < 0)
                                                return err;
                                }
                                addr = data->buffer + control->fragments[frag].addr;
-                               if (dst_ptr != addr)
-                                       memcpy(addr, dst_ptr, control->status.frag_size);
+                               if (src_voices[voice].addr != addr)
+                                       memcpy(addr, src_voices[voice].addr, control->status.frag_size);
                                control->fragments[frag].data = 1;
-                               dst_ptr += control->status.frag_size;
                        }
                        data->frag++;
                        data->frag %= data->frags;
                        data->frags_used++;
+                       return samples;
                }
-               return dst_size;
        } else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
-               while (!capture_ok(data)) {
-                       err = query_capture(data, 0);
+               if (dst_voices == NULL)
+                       return -EINVAL;
+               while (!capture_ok(plugin)) {
+                       err = query_capture(plugin, 0);
                        if (err < 0)
                                return err;
                }
-               if (interleave) {
+               size = snd_pcm_plugin_dst_samples_to_size(plugin, samples);
+               if (size < 0)
+                       return size;
+               if (plugin->dst_format.interleave) {
+                       if (size != control->status.frag_size)
+                               return -EINVAL;
                        addr = data->buffer + control->fragments[data->frag].addr;
-                       if (dst_ptr != addr)
-                               memcpy(dst_ptr, addr, dst_size);
+                       if (dst_voices->addr != addr)
+                               memcpy(dst_voices->addr, addr, size);
                        control->fragments[data->frag++].data = 0;
                        data->frag %= control->status.frags;
                        data->frags_used--;
+                       return samples;
                } else {
                        int frag;
 
-                       for (voice = 0; voice < control->status.voices; voice++) {
+                       if ((size / plugin->dst_format.voices) != control->status.frag_size)
+                               return -EINVAL;
+                       for (voice = 0; voice < plugin->dst_format.voices; voice++) {
                                frag = data->frag + (voice * data->frags);
                                while (!control->fragments[data->frag].data) {
-                                       err = query_capture(data, 1);
+                                       err = query_capture(plugin, 1);
                                        if (err < 0)
                                                return err;
                                }
                                addr = data->buffer + control->fragments[frag].addr;
-                               if (dst_ptr != addr)
-                                       memcpy(dst_ptr, addr, control->status.frag_size);
+                               if (dst_voices[voice].addr != addr)
+                                       memcpy(dst_voices[voice].addr, addr, control->status.frag_size);
                                control->fragments[frag].data = 0;
-                               dst_ptr += control->status.frag_size;
                        }
                        data->frag++;
                        data->frag %= data->frags;
                        data->frags_used--;
+                       return samples;
                }
-               return dst_size;
        } else {
                return -EINVAL;
        }
@@ -315,15 +396,15 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
 
        if (plugin == NULL)
                return -EINVAL;
-       data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (mmap_t *)plugin->extra_data;
        if (action == INIT) {
                snd_pcm_channel_params_t *params;
                snd_pcm_channel_setup_t setup;
-               int result, frags;
+               int result;
 
                if (data->control)
-                       snd_pcm_munmap(data->pcm, data->channel);
-               result = snd_pcm_mmap(data->pcm, data->channel, &data->control, (void **)&data->buffer);
+                       snd_pcm_munmap(plugin->handle, data->channel);
+               result = snd_pcm_mmap(plugin->handle, data->channel, &data->control, (void **)&data->buffer);
                if (result < 0)
                        return result;
                params = (snd_pcm_channel_params_t *)udata;
@@ -331,7 +412,7 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
                data->stop_mode = params->stop_mode;
                memset(&setup, 0, sizeof(setup));
                setup.channel = data->channel;
-               if ((result = snd_pcm_channel_setup(data->pcm, &setup)) < 0)
+               if ((result = snd_pcm_channel_setup(plugin->handle, &setup)) < 0)
                        return result;
                data->frags = setup.buf.block.frags;
                data->frags_min = setup.buf.block.frags_min;
@@ -368,14 +449,16 @@ static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data)
 
        if (plugin == NULL)
                return;
-       data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (mmap_t *)plugin->extra_data;
        if (data->control)
-               snd_pcm_munmap(data->pcm, data->channel);
+               snd_pcm_munmap(plugin->handle, data->channel);
 }
  
-int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel,
+                             snd_pcm_format_t *format,
+                             snd_pcm_plugin_t **r_plugin)
 {
-       struct mmap_private_data *data;
+       mmap_t *data;
        snd_pcm_plugin_t *plugin;
 
        if (r_plugin == NULL)
@@ -383,16 +466,18 @@ int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_
        *r_plugin = NULL;
        if (!pcm || channel < 0 || channel > 1)
                return -EINVAL;
-       plugin = snd_pcm_plugin_build(channel == SND_PCM_CHANNEL_PLAYBACK ?
+       plugin = snd_pcm_plugin_build(pcm,
+                                     channel == SND_PCM_CHANNEL_PLAYBACK ?
                                                "I/O mmap playback" :
                                                "I/O mmap capture",
-                                               sizeof(struct mmap_private_data));
+                                     format, format,
+                                     sizeof(mmap_t));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->pcm = pcm;
+       data = (mmap_t *)plugin->extra_data;
        data->channel = channel;
-       plugin->transfer_src_ptr = mmap_transfer_src_ptr;
+       plugin->src_voices = mmap_src_voices;
+       plugin->dst_voices = mmap_dst_voices;
        plugin->transfer = mmap_transfer;
        plugin->action = mmap_action;
        plugin->private_free = mmap_free;
index 337c1787af5bf1a3e3018acc4fab3d7e46df626a..6dd7ff2485a4f44728eed7d7e19a3e044b80faac 100644 (file)
@@ -23,8 +23,8 @@
   
 #ifdef __KERNEL__
 #include "../../include/driver.h"
+#include "../../include/pcm.h"
 #include "../../include/pcm_plugin.h"
-#define bswap_16(x) __swab16((x))
 #else
 #include <stdio.h>
 #include <stdlib.h>
@@ -33,6 +33,7 @@
 #include <errno.h>
 #include <endian.h>
 #include <byteswap.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 #endif
 
@@ -87,7 +88,7 @@ static inline int search(int val, short *table, int size)
  * For further information see John C. Bellamy's Digital Telephony, 1982,
  * John Wiley & Sons, pps 98-111 and 472-476.
  */
-static inline unsigned char linear2ulaw(int pcm_val)   /* 2's complement (16-bit range) */
+static unsigned char linear2ulaw(int pcm_val)  /* 2's complement (16-bit range) */
 {
        int mask;
        int seg;
@@ -126,7 +127,7 @@ static inline unsigned char linear2ulaw(int pcm_val)        /* 2's complement (16-bit r
  * Note that this function expects to be passed the complement of the
  * original code word. This is in keeping with ISDN conventions.
  */
-static inline int ulaw2linear(unsigned char u_val)
+static int ulaw2linear(unsigned char u_val)
 {
        int t;
 
@@ -147,296 +148,146 @@ static inline int ulaw2linear(unsigned char u_val)
  *  Basic Mu-Law plugin
  */
 
-typedef enum {
-       _S8_MULAW,
-       _U8_MULAW,
-       _S16LE_MULAW,
-       _U16LE_MULAW,
-       _S16BE_MULAW,
-       _U16BE_MULAW,
-       _MULAW_S8,
-       _MULAW_U8,
-       _MULAW_S16LE,
-       _MULAW_U16LE,
-       _MULAW_S16BE,
-       _MULAW_U16BE
-} combination_t; 
-struct mulaw_private_data {
-       combination_t cmd;
-};
-
-static void mulaw_conv_u8bit_mulaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       unsigned int pcm;
-
-       while (size-- > 0) {
-               pcm = ((*src_ptr++) ^ 0x80) << 8;
-               *dst_ptr++ = linear2ulaw((signed short)(pcm));
-       }
-}
-
-static void mulaw_conv_s8bit_mulaw(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       unsigned int pcm;
-
-       while (size-- > 0) {
-               pcm = *src_ptr++ << 8;
-               *dst_ptr++ = linear2ulaw((signed short)(pcm));
-       }
-}
-
-static void mulaw_conv_s16bit_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2ulaw((signed short)(*src_ptr++));
-}
-
-static void mulaw_conv_s16bit_swap_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2ulaw((signed short)(bswap_16(*src_ptr++)));
-}
-
-static void mulaw_conv_u16bit_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2ulaw((signed short)((*src_ptr++) ^ 0x8000));
-}
-
-static void mulaw_conv_u16bit_swap_mulaw(unsigned short *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = linear2ulaw((signed short)(bswap_16(*src_ptr++) ^ 0x8000));
-}
-
-static void mulaw_conv_mulaw_u8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = (ulaw2linear(*src_ptr++) >> 8) ^ 0x80;
-}
-
-static void mulaw_conv_mulaw_s8bit(unsigned char *src_ptr, unsigned char *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = ulaw2linear(*src_ptr++) >> 8;
+typedef void (*mulaw_f)(void *src_ptr, void *dst_ptr, int samples);
+
+typedef struct mulaw_private_data {
+       int src_byte_width;
+       int dst_byte_width;
+       mulaw_f func;
+} mulaw_t;
+
+#define MULAW_FUNC_DECODE(name, dsttype, val) \
+static void mulaw_decode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+       unsigned char *src = src_ptr; \
+       dsttype *dst = dst_ptr; \
+       unsigned int s; \
+       while (samples--) { \
+               s = ulaw2linear(*src++); \
+               *dst++ = val; \
+       } \
 }
 
-static void mulaw_conv_mulaw_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = ulaw2linear(*src_ptr++);
-}
-
-static void mulaw_conv_mulaw_swap_s16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = bswap_16(ulaw2linear(*src_ptr++));
+#define MULAW_FUNC_ENCODE(name, srctype, val) \
+static void mulaw_encode_##name(void *src_ptr, void *dst_ptr, int samples) \
+{ \
+       srctype *src = src_ptr; \
+       unsigned char *dst = dst_ptr; \
+       unsigned int s; \
+       while (samples--) { \
+               s = *src++; \
+               *dst++ = linear2ulaw(val); \
+       } \
 }
 
-static void mulaw_conv_mulaw_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = ulaw2linear(*src_ptr++) ^ 0x8000;
-}
+MULAW_FUNC_DECODE(u8, u_int8_t, (s >> 8) ^ 0x80)
+MULAW_FUNC_DECODE(s8, u_int8_t, s >> 8)
+MULAW_FUNC_DECODE(u16n, u_int16_t, s ^ 0x8000)
+MULAW_FUNC_DECODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+MULAW_FUNC_DECODE(s16n, u_int16_t, s)
+MULAW_FUNC_DECODE(s16s, u_int16_t, bswap_16(s))
+MULAW_FUNC_DECODE(u24n, u_int32_t, (s << 8) ^ 0x800000)
+MULAW_FUNC_DECODE(u24s, u_int32_t, bswap_32((s << 8) ^ 0x800000))
+MULAW_FUNC_DECODE(s24n, u_int32_t, s << 8)
+MULAW_FUNC_DECODE(s24s, u_int32_t, bswap_32(s << 8))
+MULAW_FUNC_DECODE(u32n, u_int32_t, (s << 16) ^ 0x80000000)
+MULAW_FUNC_DECODE(u32s, u_int32_t, bswap_32((s << 16) ^ 0x80000000))
+MULAW_FUNC_DECODE(s32n, u_int32_t, s << 16)
+MULAW_FUNC_DECODE(s32s, u_int32_t, bswap_32(s << 16))
+
+MULAW_FUNC_ENCODE(u8, u_int8_t, s << 8)
+MULAW_FUNC_ENCODE(s8, u_int8_t, (s << 8) ^ 0x8000)
+MULAW_FUNC_ENCODE(u16n, u_int16_t, s ^ 0x8000)
+MULAW_FUNC_ENCODE(u16s, u_int16_t, bswap_16(s ^ 0x8000))
+MULAW_FUNC_ENCODE(s16n, u_int16_t, s)
+MULAW_FUNC_ENCODE(s16s, u_int16_t, bswap_16(s))
+MULAW_FUNC_ENCODE(u24n, u_int32_t, (s ^ 0x800000) >> 8)
+MULAW_FUNC_ENCODE(u24s, u_int32_t, bswap_32((s ^ 0x800000) >> 8))
+MULAW_FUNC_ENCODE(s24n, u_int32_t, s >> 8)
+MULAW_FUNC_ENCODE(s24s, u_int32_t, bswap_32(s >> 8))
+MULAW_FUNC_ENCODE(u32n, u_int32_t, (s ^ 0x80000000) >> 16)
+MULAW_FUNC_ENCODE(u32s, u_int32_t, bswap_32((s ^ 0x80000000) >> 16))
+MULAW_FUNC_ENCODE(s32n, u_int32_t, s >> 16)
+MULAW_FUNC_ENCODE(s32s, u_int32_t, bswap_32(s >> 16))
+
+/* wide, sign, swap endian */
+static mulaw_f mulaw_functions_decode[4 * 4 * 2 * 2] = {
+       mulaw_decode_u8,        /* decode:8-bit:unsigned:none */
+       mulaw_decode_u8,        /* decode:8-bit:unsigned:swap */
+       mulaw_decode_s8,        /* decode:8-bit:signed:none */
+       mulaw_decode_s8,        /* decode:8-bit:signed:swap */
+       mulaw_decode_u16n,      /* decode:16-bit:unsigned:none */
+       mulaw_decode_u16s,      /* decode:16-bit:unsigned:swap */
+       mulaw_decode_s16n,      /* decode:16-bit:signed:none */
+       mulaw_decode_s16s,      /* decode:16-bit:signed:swap */
+       mulaw_decode_u24n,      /* decode:24-bit:unsigned:none */
+       mulaw_decode_u24s,      /* decode:24-bit:unsigned:swap */
+       mulaw_decode_s24n,      /* decode:24-bit:signed:none */
+       mulaw_decode_s24s,      /* decode:24-bit:signed:swap */
+       mulaw_decode_u32n,      /* decode:32-bit:unsigned:none */
+       mulaw_decode_u32s,      /* decode:32-bit:unsigned:swap */
+       mulaw_decode_s32n,      /* decode:32-bit:signed:none */
+       mulaw_decode_s32s,      /* decode:32-bit:signed:swap */
+};
 
-static void mulaw_conv_mulaw_swap_u16bit(unsigned char *src_ptr, unsigned short *dst_ptr, size_t size)
-{
-       while (size-- > 0)
-               *dst_ptr++ = bswap_16(ulaw2linear(*src_ptr++) ^ 0x8000);
-}
+/* wide, sign, swap endian */
+static mulaw_f mulaw_functions_encode[4 * 2 * 2] = {
+       mulaw_encode_u8,        /* from:8-bit:unsigned:none */
+       mulaw_encode_u8,        /* from:8-bit:unsigned:swap */
+       mulaw_encode_s8,        /* from:8-bit:signed:none */
+       mulaw_encode_s8,        /* from:8-bit:signed:swap */
+       mulaw_encode_u16n,      /* from:16-bit:unsigned:none */
+       mulaw_encode_u16s,      /* from:16-bit:unsigned:swap */
+       mulaw_encode_s16n,      /* from:16-bit:signed:none */
+       mulaw_encode_s16s,      /* from:16-bit:signed:swap */
+       mulaw_encode_u24n,      /* from:24-bit:unsigned:none */
+       mulaw_encode_u24s,      /* from:24-bit:unsigned:swap */
+       mulaw_encode_s24n,      /* from:24-bit:signed:none */
+       mulaw_encode_s24s,      /* from:24-bit:signed:swap */
+       mulaw_encode_u32n,      /* from:32-bit:unsigned:none */
+       mulaw_encode_u32s,      /* from:32-bit:unsigned:swap */
+       mulaw_encode_s32n,      /* from:32-bit:signed:none */
+       mulaw_encode_s32s,      /* from:32-bit:signed:swap */
+};
 
 static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
-                          char *src_ptr, size_t src_size,
-                          char *dst_ptr, size_t dst_size)
+                             const snd_pcm_plugin_voice_t *src_voices,
+                             const snd_pcm_plugin_voice_t *dst_voices,
+                             size_t samples)
 {
-       struct mulaw_private_data *data;
+       mulaw_t *data;
+       int voice;
 
-       if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
-                             dst_ptr == NULL || dst_size < 0)
+       if (plugin == NULL || src_voices == NULL || dst_voices == NULL || samples < 0)
                return -EINVAL;
-       if (src_size == 0)
+       if (samples == 0)
                return 0;
-       data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       switch (data->cmd) {
-       case _U8_MULAW:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               mulaw_conv_u8bit_mulaw(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _S8_MULAW:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               mulaw_conv_s8bit_mulaw(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _S16LE_MULAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_s16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_s16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _U16LE_MULAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_u16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_u16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _S16BE_MULAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_s16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_s16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _U16BE_MULAW:
-               if ((dst_size << 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_u16bit_swap_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_u16bit_mulaw((short *)src_ptr, dst_ptr, src_size >> 1);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size >> 1;
-       case _MULAW_U8:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               mulaw_conv_mulaw_u8bit(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _MULAW_S8:
-               if (dst_size < src_size)
-                       return -EINVAL;
-               mulaw_conv_mulaw_s8bit(src_ptr, dst_ptr, src_size);
-               return src_size;
-       case _MULAW_S16LE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_mulaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_mulaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       case _MULAW_U16LE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_mulaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_mulaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       case _MULAW_S16BE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_mulaw_swap_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_mulaw_s16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       case _MULAW_U16BE:
-               if ((dst_size >> 1) < src_size)
-                       return -EINVAL;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               mulaw_conv_mulaw_swap_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#elif __BYTE_ORDER == __BIG_ENDIAN
-               mulaw_conv_mulaw_u16bit(src_ptr, (short *)dst_ptr, src_size);
-#else
-#error "Have to be coded..."
-#endif
-               return src_size << 1;
-       default:
-               return -EIO;
-       }
-}
-
-static ssize_t mulaw_src_size(snd_pcm_plugin_t *plugin, size_t size)
-{
-       struct mulaw_private_data *data;
-
-       if (plugin == NULL || size <= 0)
-               return -EINVAL;
-       data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       switch (data->cmd) {
-       case _U8_MULAW:
-       case _S8_MULAW:
-       case _MULAW_U8:
-       case _MULAW_S8:
-               return size;
-       case _U16LE_MULAW:
-       case _S16LE_MULAW:
-       case _U16BE_MULAW:
-       case _S16BE_MULAW:
-               return size * 2;
-       case _MULAW_U16LE:
-       case _MULAW_S16LE:
-       case _MULAW_U16BE:
-       case _MULAW_S16BE:
-               return size / 2;
-       default:
-               return -EIO;
+       data = (mulaw_t *)plugin->extra_data;
+       if (plugin->src_format.interleave) {
+               data->func(src_voices[0].addr,
+                          dst_voices[0].addr,
+                          samples * plugin->src_format.voices);
+       } else {
+               for (voice = 0; voice < plugin->src_format.voices; voice++) {
+                       if (src_voices[voice].addr == NULL)
+                               continue;
+                       data->func(src_voices[voice].addr,
+                                  dst_voices[voice].addr,
+                                  samples);
+               }
        }
+       return samples;
 }
 
-static ssize_t mulaw_dst_size(snd_pcm_plugin_t *plugin, size_t size)
-{
-       struct mulaw_private_data *data;
-
-       if (plugin == NULL || size <= 0)
-               return -EINVAL;
-       data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       switch (data->cmd) {
-       case _U8_MULAW:
-       case _S8_MULAW:
-       case _MULAW_U8:
-       case _MULAW_S8:
-               return size;
-       case _U16LE_MULAW:
-       case _S16LE_MULAW:
-       case _U16BE_MULAW:
-       case _S16BE_MULAW:
-               return size / 2;
-       case _MULAW_U16LE:
-       case _MULAW_S16LE:
-       case _MULAW_U16BE:
-       case _MULAW_S16BE:
-               return size * 2;
-       default:
-               return -EIO;
-       }
-}
-int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format,
+int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
+                              snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
                               snd_pcm_plugin_t **r_plugin)
 {
        struct mulaw_private_data *data;
        snd_pcm_plugin_t *plugin;
-       combination_t cmd;
+       int endian, src_width, dst_width, sign;
+       mulaw_f func;
 
        if (r_plugin == NULL)
                return -EINVAL;
@@ -450,40 +301,54 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_format_t *src_format,
        if (src_format->voices != dst_format->voices)
                return -EINVAL;
 
+
        if (dst_format->format == SND_PCM_SFMT_MU_LAW) {
-               switch (src_format->format) {
-               case SND_PCM_SFMT_U8:           cmd = _U8_MULAW;        break;
-               case SND_PCM_SFMT_S8:           cmd = _S8_MULAW;        break;
-               case SND_PCM_SFMT_U16_LE:       cmd = _U16LE_MULAW;     break;
-               case SND_PCM_SFMT_S16_LE:       cmd = _S16LE_MULAW;     break;
-               case SND_PCM_SFMT_U16_BE:       cmd = _U16BE_MULAW;     break;
-               case SND_PCM_SFMT_S16_BE:       cmd = _S16BE_MULAW;     break;
-               default:
+               if (!snd_pcm_format_linear(src_format->format))
                        return -EINVAL;
-               }
+               sign = snd_pcm_format_signed(src_format->format);
+               src_width = snd_pcm_format_width(src_format->format);
+               if ((src_width % 8) != 0 || src_width < 8 || src_width > 32)
+                       return -EINVAL;
+               dst_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               endian = snd_pcm_format_big_endian(src_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+               endian = snd_pcm_format_little_endian(src_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+               func = ((mulaw_f(*)[2][2])mulaw_functions_encode)[(src_width/8)-1][sign][endian];
        } else if (src_format->format == SND_PCM_SFMT_MU_LAW) {
-               switch (dst_format->format) {
-               case SND_PCM_SFMT_U8:           cmd = _MULAW_U8;        break;
-               case SND_PCM_SFMT_S8:           cmd = _MULAW_S8;        break;
-               case SND_PCM_SFMT_U16_LE:       cmd = _MULAW_U16LE;     break;
-               case SND_PCM_SFMT_S16_LE:       cmd = _MULAW_S16LE;     break;
-               case SND_PCM_SFMT_U16_BE:       cmd = _MULAW_U16BE;     break;
-               case SND_PCM_SFMT_S16_BE:       cmd = _MULAW_S16BE;     break;
-               default:
+               if (!snd_pcm_format_linear(dst_format->format))
                        return -EINVAL;
-               }
+               sign = snd_pcm_format_signed(dst_format->format);
+               dst_width = snd_pcm_format_width(dst_format->format);
+               if ((dst_width % 8) != 0 || dst_width < 8 || dst_width > 32)
+                       return -EINVAL;
+               src_width = 8;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               endian = snd_pcm_format_big_endian(dst_format->format);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+               endian = snd_pcm_format_little_endian(dst_format->format);
+#else
+#error "Unsupported endian..."
+#endif
+               func = ((mulaw_f(*)[2][2])mulaw_functions_decode)[(dst_width/8)-1][sign][endian];
        } else {
                return -EINVAL;
        }
-       plugin = snd_pcm_plugin_build("Mu-Law<->linear conversion",
+       plugin = snd_pcm_plugin_build(handle,
+                                     "Mu-Law<->linear conversion",
+                                     src_format,
+                                     dst_format,
                                      sizeof(struct mulaw_private_data));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct mulaw_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->cmd = cmd;
+       data = (struct mulaw_private_data *)plugin->extra_data;
+       data->src_byte_width = src_width / 8;
+       data->dst_byte_width = dst_width / 8;
+       data->func = func;
        plugin->transfer = mulaw_transfer;
-       plugin->src_size = mulaw_src_size;
-       plugin->dst_size = mulaw_dst_size;
        *r_plugin = plugin;
        return 0;
 }
index 6cfe29b3d8f6ae86c6894930c47086241ac21821..30d6dfa7e20a8eca6e39c455a344fe208c645437 100644 (file)
@@ -21,6 +21,7 @@
   
 #ifdef __KERNEL__
 #include "../../include/driver.h"
+#include "../../include/pcm.h"
 #include "../../include/pcm_plugin.h"
 #else
 #include <stdio.h>
 #define SHIFT  11
 #define BITS   (1<<SHIFT)
 #define MASK   (BITS-1)
-#define MAX_VOICES 6
 
 /*
  *  Basic rate conversion plugin
  */
+
+#define rate_voices(data) ((rate_voice_t *)((char *)data + sizeof(*data)))
+
+typedef signed short (*take_sample_f)(void *ptr);
+typedef void (*put_sample_f)(void *ptr, signed int val);
+typedef struct {
+       signed short last_S1;
+       signed short last_S2;
+} rate_voice_t;
  
-struct rate_private_data {
-       int src_voices;
-       int dst_voices;
-       int src_rate;
-       int dst_rate;
-       int sample_size;
-       int expand: 1;
+typedef struct rate_private_data {
+       snd_pcm_plugin_t *plugin;
+       take_sample_f take;
+       put_sample_f put;
        unsigned int pitch;
        unsigned int pos;
-       signed short last_S1[MAX_VOICES];
-       signed short last_S2[MAX_VOICES];
-       ssize_t old_src_size, old_dst_size;
-};
+       ssize_t old_src_samples, old_dst_samples;
+} rate_t;
 
-static void resample16_expand(struct rate_private_data *data, int voices,
-                             signed short *src_ptr, int src_size,
-                             signed short *dst_ptr, int dst_size)
+static void rate_init(snd_pcm_plugin_t *plugin, rate_t *data)
 {
-       unsigned int pos;
-       signed int val;
-       signed short S1, S2;
        int voice;
-       signed short *src, *dst;
-       int size;
-       
-       for (voice = 0; voice < voices; ++voice) {
-               pos = data->pos;
-               S1 = data->last_S1[voice];
-               S2 = data->last_S2[voice];
-               src = src_ptr + voice;
-               dst = dst_ptr + voice;
-               size = dst_size;
-               if (pos >> SHIFT) {
-                       pos &= MASK;
-                       S1 = S2;
-                       S2 = *src;
-               }
-               while (size-- > 0) {
-                       if (pos >> SHIFT) {
-                               src += voices;
-                               pos &= MASK;
-                               S1 = S2;
-                               if ((src - src_ptr) < src_size * voices)
-                                       S2 = *src;
-                       }
-                       val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
-                       if (val < -32768)
-                               val = -32768;
-                       else if (val > 32767)
-                               val = 32767;
-                       *dst = val;
-                       dst += voices;
-                       pos += data->pitch;
-               }
-               data->last_S1[voice] = S1;
-               data->last_S2[voice] = S2;
-               data->pos = pos;
+       rate_voice_t *rvoices = rate_voices(data);
+
+       data->pos = 0;
+       for (voice = 0; plugin->src_format.voices; voice++) {
+               rvoices[voice].last_S1 = 0;
+               rvoices[voice].last_S2 = 0;
        }
 }
 
-static void resample16_shrink(struct rate_private_data *data, int voices,
-                             signed short *src_ptr, int src_size,
-                             signed short *dst_ptr, int dst_size)
-{
-       unsigned int pos;
-       signed int val;
-       signed short S1, S2;
-       int voice;
-       signed short *src, *dst;
-       int size;
-       
-       for (voice = 0; voice < voices; ++voice) {
-               pos = data->pos;
-               S1 = data->last_S1[voice];
-               S2 = data->last_S2[voice];
-               src = src_ptr + voice;
-               dst = dst_ptr + voice;
-               size = dst_size;
-               while (size > 0) {
-                       S1 = S2;
-                       if ((src - src_ptr) < (src_size * voices)) {
-                               S2 = *src;
-                               src += voices;
-                       }
-                       if (pos >> SHIFT) {
-                               pos &= MASK;
-                               val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
-                               if (val < -32768)
-                                       val = -32768;
-                               else if (val > 32767)
-                                       val = 32767;
-                               *dst = val;
-                               dst += voices;
-                               size--;
-                       }
-                       pos += data->pitch;
-               }
-               data->last_S1[voice] = S1;
-               data->last_S2[voice] = S2;
-               data->pos = pos;
-       }
+#define RATE_TAKE_SAMPLE(name, type, val) \
+static signed short rate_take_sample_##name(void *ptr) \
+{ \
+       signed int smp = *(type *)ptr; \
+       return val; \
+}
+
+#define RATE_PUT_SAMPLE(name, type, val) \
+static void rate_put_sample_##name(void *ptr, signed int smp) \
+{ \
+       *(type *)ptr = val; \
 }
 
-static void resample8_expand(struct rate_private_data *data, int voices,
-                            unsigned char *src_ptr, int src_size,
-                            unsigned char *dst_ptr, int dst_size)
+static void resample_expand(snd_pcm_plugin_t *plugin,
+                           const snd_pcm_plugin_voice_t *src_voices,
+                           const snd_pcm_plugin_voice_t *dst_voices,
+                           int src_samples, int dst_samples)
 {
        unsigned int pos;
        signed int val;
        signed short S1, S2;
+       char *src, *dst;
        int voice;
-       unsigned char *src, *dst;
-       int size;
+       int src_step, dst_step;
+       int src_samples1, dst_samples1;
+       rate_t *data = (rate_t *)plugin->extra_data;
+       rate_voice_t *rvoices = rate_voices(data);
        
-       for (voice = 0; voice < voices; ++voice) {
+       for (voice = 0; voice < plugin->src_format.voices; voice++, rvoices++) {
                pos = data->pos;
-               S1 = data->last_S1[voice];
-               S2 = data->last_S2[voice];
-               src = src_ptr + voice;
-               dst = dst_ptr + voice;
-               size = dst_size;
-               if (pos >> SHIFT) {
+               S1 = rvoices->last_S1;
+               S2 = rvoices->last_S2;
+               if (src_voices[voice].addr == NULL)
+                       continue;
+               src = (char *)src_voices[voice].addr + src_voices[voice].offset / 8;
+               dst = (char *)dst_voices[voice].addr + src_voices[voice].offset / 8;
+               src_step = src_voices[voice].next / 8;
+               dst_step = dst_voices[voice].next / 8;
+               src_samples1 = src_samples;
+               dst_samples1 = dst_samples;
+               if (pos & ~MASK) {
                        pos &= MASK;
                        S1 = S2;
-                       S2 = (*src << 8) ^ 0x8000;
+                       S2 = data->take(src);
+                       src += src_step;
+                       src_samples--;
                }
-               while (size-- > 0) {
-                       if (pos >> SHIFT) {
-                               src += voices;
+               while (dst_samples1-- > 0) {
+                       if (pos & ~MASK) {
                                pos &= MASK;
                                S1 = S2;
-                               if ((src - src_ptr) < src_size * voices)
-                                       S2 = (*src << 8) ^ 0x8000;
+                               if (src_samples1-- > 0) {
+                                       S2 = data->take(src);
+                                       src += src_step;
+                               }
                        }
                        val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
                        if (val < -32768)
                                val = -32768;
                        else if (val > 32767)
                                val = 32767;
-                       *dst = (val >> 8) ^ 0x0080;
-                       dst += voices;
+                       data->put(dst, val);
+                       dst += dst_step;
                        pos += data->pitch;
                }
-               data->last_S1[voice] = S1;
-               data->last_S2[voice] = S2;
+               rvoices->last_S1 = S1;
+               rvoices->last_S2 = S2;
                data->pos = pos;
        }
 }
 
-static void resample8_shrink(struct rate_private_data *data, int voices,
-                            unsigned char *src_ptr, int src_size,
-                            unsigned char *dst_ptr, int dst_size)
+static void resample_shrink(snd_pcm_plugin_t *plugin,
+                           const snd_pcm_plugin_voice_t *src_voices,
+                           const snd_pcm_plugin_voice_t *dst_voices,
+                           int src_samples, int dst_samples)
 {
        unsigned int pos;
        signed int val;
        signed short S1, S2;
+       char *src, *dst;
        int voice;
-       unsigned char *src, *dst;
-       int size;
+       int src_step, dst_step;
+       int src_samples1, dst_samples1;
+       rate_t *data = (rate_t *)plugin->extra_data;
+       rate_voice_t *rvoices = rate_voices(data);
        
-       for (voice = 0; voice < voices; ++voice) {
+       for (voice = 0; voice < plugin->src_format.voices; ++voice) {
                pos = data->pos;
-               S1 = data->last_S1[voice];
-               S2 = data->last_S2[voice];
-               src = src_ptr + voice;
-               dst = dst_ptr + voice;
-               size = dst_size;
-               while (size > 0) {
+               S1 = rvoices->last_S1;
+               S2 = rvoices->last_S2;
+               if (src_voices[voice].addr == NULL)
+                       continue;
+               src = (char *)src_voices[voice].addr + src_voices[voice].offset / 8;
+               dst = (char *)dst_voices[voice].addr + src_voices[voice].offset / 8;
+               src_step = src_voices[voice].next / 8;
+               dst_step = dst_voices[voice].next / 8;
+               src_samples1 = src_samples;
+               dst_samples1 = dst_samples;
+               while (dst_samples1 > 0) {
                        S1 = S2;
-                       if ((src - src_ptr) < (src_size * voices)) {
-                               S2 = (*src << 8) ^ 0x8000;
-                               src += voices;
+                       if (src_samples1-- > 0) {
+                               S2 = data->take(src);
+                               src += src_step;
                        }
-                       if (pos >> SHIFT) {
+                       if (pos & ~MASK) {
                                pos &= MASK;
                                val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
                                if (val < -32768)
                                        val = -32768;
                                else if (val > 32767)
                                        val = 32767;
-                               *dst = (val >> 8) ^ 0x0080;
-                               dst += voices;
-                               size--;
+                               data->put(dst, val);
+                               dst += dst_step;
+                               dst_samples1--;
                        }
                        pos += data->pitch;
                }
-               data->last_S1[voice] = S1;
-               data->last_S2[voice] = S2;
+               rvoices->last_S1 = S1;
+               rvoices->last_S2 = S2;
                data->pos = pos;
        }
 }
 
-static ssize_t rate_src_size(snd_pcm_plugin_t *plugin, size_t size)
+static ssize_t rate_src_samples(snd_pcm_plugin_t *plugin, size_t samples)
 {
-       struct rate_private_data *data;
+       rate_t *data;
        ssize_t res;
 
-       if (plugin == NULL || size <= 0)
+       if (plugin == NULL || samples <= 0)
                return -EINVAL;
-       data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data->expand) {
-               res = (((size * data->pitch) + (BITS/2)) >> SHIFT);
+       data = (rate_t *)plugin->extra_data;
+       if (plugin->src_format.rate < plugin->dst_format.rate) {
+               res = (((samples * data->pitch) + (BITS/2)) >> SHIFT);
        } else {
-               res = (((size << SHIFT) + (data->pitch / 2)) / data->pitch);            
+               res = (((samples << SHIFT) + (data->pitch / 2)) / data->pitch);         
        }
-       res = res / (data->src_voices*data->sample_size) * (data->src_voices*data->sample_size);
-       if (data->old_src_size > 0) {
-               ssize_t size1 = size, res1 = data->old_dst_size;
-               while (data->old_src_size < size1) {
-                       size1 >>= 1;
+       if (data->old_src_samples > 0) {
+               ssize_t samples1 = samples, res1 = data->old_dst_samples;
+               while (data->old_src_samples < samples1) {
+                       samples1 >>= 1;
                        res1 <<= 1;
                }
-               while (data->old_src_size > size1) {
-                       size1 <<= 1;
+               while (data->old_src_samples > samples1) {
+                       samples1 <<= 1;
                        res1 >>= 1;
                }
-               if (data->old_src_size == size1)
+               if (data->old_src_samples == samples1)
                        return res1;
        }
-       data->old_src_size = size;
-       data->old_dst_size = res;
+       data->old_src_samples = samples;
+       data->old_dst_samples = res;
        return res;
 }
 
-static ssize_t rate_dst_size(snd_pcm_plugin_t *plugin, size_t size)
+static ssize_t rate_dst_samples(snd_pcm_plugin_t *plugin, size_t samples)
 {
-       struct rate_private_data *data;
+       rate_t *data;
        ssize_t res;
 
-       if (plugin == NULL || size <= 0)
+       if (plugin == NULL || samples <= 0)
                return -EINVAL;
-       data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data->expand) {
-               res = (((size << SHIFT) + (data->pitch / 2)) / data->pitch);
+       data = (rate_t *)plugin->extra_data;
+       if (plugin->src_format.rate < plugin->dst_format.rate) {
+               res = (((samples << SHIFT) + (data->pitch / 2)) / data->pitch);
        } else {
-               res = (((size * data->pitch) + (BITS/2)) >> SHIFT);
+               res = (((samples * data->pitch) + (BITS/2)) >> SHIFT);
        }
-       res = res / (data->dst_voices*data->sample_size) * (data->dst_voices*data->sample_size);
-       if (data->old_dst_size > 0) {
-               ssize_t size1 = size, res1 = data->old_src_size;
-               while (data->old_dst_size < size1) {
-                       size1 >>= 1;
+       if (data->old_dst_samples > 0) {
+               ssize_t samples1 = samples, res1 = data->old_src_samples;
+               while (data->old_dst_samples < samples1) {
+                       samples1 >>= 1;
                        res1 <<= 1;
                }
-               while (data->old_dst_size > size1) {
-                       size1 <<= 1;
+               while (data->old_dst_samples > samples1) {
+                       samples1 <<= 1;
                        res1 >>= 1;
                }
-               if (data->old_dst_size == size1)
+               if (data->old_dst_samples == samples1)
                        return res1;
        }
-       data->old_dst_size = size;
-       data->old_src_size = res;
+       data->old_dst_samples = samples;
+       data->old_src_samples = res;
        return res;
 }
 
 static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
-                            char *src_ptr, size_t src_size,
-                            char *dst_ptr, size_t dst_size)
+                            const snd_pcm_plugin_voice_t *src_voices,
+                            const snd_pcm_plugin_voice_t *dst_voices,
+                            size_t samples)
 {
-       struct rate_private_data *data;
+       size_t dst_samples;
 
-       if (plugin == NULL || src_ptr == NULL || src_size < 0 ||
-                             dst_ptr == NULL || dst_size < 0)
+       if (plugin == NULL || src_voices == NULL || src_voices == NULL || samples < 0)
                return -EINVAL;
-       if (src_size == 0)
+       if (samples == 0)
                return 0;
-       data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
-       if (data == NULL)
-               return -EINVAL;
-       if (data->sample_size == 2) {
-               if (data->src_rate < data->dst_rate) {
-                       resample16_expand(data, data->src_voices,
-                                    (signed short *)src_ptr, src_size / (data->src_voices * 2),
-                                    (signed short *)dst_ptr, dst_size / (data->dst_voices * 2));
-               } else {
-                       resample16_shrink(data, data->src_voices,
-                                    (signed short *)src_ptr, src_size / (data->src_voices * 2),
-                                    (signed short *)dst_ptr, dst_size / (data->dst_voices * 2));
-               }
+       dst_samples = rate_dst_samples(plugin, samples);
+       if (plugin->src_format.rate < plugin->dst_format.rate) {
+               resample_expand(plugin, src_voices, dst_voices, samples, dst_samples);
        } else {
-               if (data->src_rate < data->dst_rate) {
-                       resample8_expand(data, data->src_voices,
-                                   src_ptr, src_size / data->src_voices,
-                                   dst_ptr, dst_size / data->dst_voices);
-               } else {
-                       resample8_shrink(data, data->src_voices,
-                                   src_ptr, src_size / data->src_voices,
-                                   dst_ptr, dst_size / data->dst_voices);
-               }
+               resample_shrink(plugin, src_voices, dst_voices, samples, dst_samples);
        }
-       return rate_dst_size(plugin, src_size);
+       return dst_samples;
 }
 
 static int rate_action(snd_pcm_plugin_t *plugin,
                       snd_pcm_plugin_action_t action,
                       unsigned long udata)
 {
-       struct rate_private_data *data;
-       int voice;
+       rate_t *data;
 
        if (plugin == NULL)
                return -EINVAL;
-       data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (rate_t *)plugin->extra_data;
        switch (action) {
        case INIT:
        case PREPARE:
        case DRAIN:
        case FLUSH:
-               data->pos = 0;
-               for (voice = 0; voice < data->src_voices; ++voice) {
-                       data->last_S1[voice] = data->last_S2[voice] = 0;
-               }
+               rate_init(plugin, data);
                break;
        }
        return 0;       /* silenty ignore other actions */
 }
 
-int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format,
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define my_little_swap16(x) (x)
+#define my_little_swap32(x) (x)
+#define my_big_swap16(x) bswap_16(x)
+#define my_big_swap32(x) bswap_32(x)
+#else
+#define my_little_swap16(x) bswap_16(x)
+#define my_little_swap32(x) bswap_32(x)
+#define my_big_swap16(x) (x)
+#define my_big_swap32(x) (x)
+#endif
+
+RATE_TAKE_SAMPLE(s8, int8_t, smp << 8)
+RATE_TAKE_SAMPLE(u8, int8_t, (smp << 8) ^ 0x8000)
+RATE_TAKE_SAMPLE(s16_le, int16_t, my_little_swap16(smp))
+RATE_TAKE_SAMPLE(s16_be, int16_t, my_big_swap16(smp))
+RATE_TAKE_SAMPLE(u16_le, int16_t, my_little_swap16(smp) ^ 0x8000)
+RATE_TAKE_SAMPLE(u16_be, int16_t, my_big_swap16(smp) ^ 0x8000)
+RATE_TAKE_SAMPLE(s24_le, int32_t, my_little_swap32(smp) >> 8)
+RATE_TAKE_SAMPLE(s24_be, int32_t, my_big_swap32(smp) >> 8)
+RATE_TAKE_SAMPLE(u24_le, int32_t, (my_little_swap32(smp) >> 8) ^ 0x8000)
+RATE_TAKE_SAMPLE(u24_be, int32_t, (my_big_swap32(smp) >> 8) ^ 0x8000)
+RATE_TAKE_SAMPLE(s32_le, int32_t, my_little_swap32(smp) >> 16)
+RATE_TAKE_SAMPLE(s32_be, int32_t, my_big_swap32(smp) >> 16)
+RATE_TAKE_SAMPLE(u32_le, int32_t, (my_little_swap32(smp) >> 16) ^ 0x8000)
+RATE_TAKE_SAMPLE(u32_be, int32_t, (my_big_swap32(smp) >> 16) ^ 0x8000)
+
+static take_sample_f rate_take_sample[] = {
+       [SND_PCM_SFMT_S8]       rate_take_sample_s8,
+       [SND_PCM_SFMT_U8]       rate_take_sample_u8,
+       [SND_PCM_SFMT_S16_LE]   rate_take_sample_s16_le,
+       [SND_PCM_SFMT_S16_BE]   rate_take_sample_s16_be,
+       [SND_PCM_SFMT_U16_LE]   rate_take_sample_u16_le,
+       [SND_PCM_SFMT_U16_BE]   rate_take_sample_u16_be,
+       [SND_PCM_SFMT_S24_LE]   rate_take_sample_s24_le,
+       [SND_PCM_SFMT_S24_BE]   rate_take_sample_s24_be,
+       [SND_PCM_SFMT_U24_LE]   rate_take_sample_u24_le,
+       [SND_PCM_SFMT_U24_BE]   rate_take_sample_u24_be,
+       [SND_PCM_SFMT_S32_LE]   rate_take_sample_s32_le,
+       [SND_PCM_SFMT_S32_BE]   rate_take_sample_s32_be,
+       [SND_PCM_SFMT_U32_LE]   rate_take_sample_u32_le,
+       [SND_PCM_SFMT_U32_BE]   rate_take_sample_u32_be
+};
+
+RATE_PUT_SAMPLE(s8, int8_t, smp >> 8)
+RATE_PUT_SAMPLE(u8, int8_t, (smp >> 8) ^ 0x80)
+RATE_PUT_SAMPLE(s16_le, int16_t, my_little_swap16(smp))
+RATE_PUT_SAMPLE(s16_be, int16_t, my_big_swap16(smp))
+RATE_PUT_SAMPLE(u16_le, int16_t, my_little_swap16(smp ^ 0x8000))
+RATE_PUT_SAMPLE(u16_be, int16_t, my_big_swap16(smp ^ 0x8000))
+RATE_PUT_SAMPLE(s24_le, int32_t, my_little_swap32(smp << 8))
+RATE_PUT_SAMPLE(s24_be, int32_t, my_big_swap32(smp << 8))
+RATE_PUT_SAMPLE(u24_le, int32_t, my_little_swap32((smp ^ 0x8000) >> 8))
+RATE_PUT_SAMPLE(u24_be, int32_t, my_big_swap32((smp ^ 0x8000) >> 8))
+RATE_PUT_SAMPLE(s32_le, int32_t, my_little_swap32(smp >> 16))
+RATE_PUT_SAMPLE(s32_be, int32_t, my_big_swap32(smp >> 16))
+RATE_PUT_SAMPLE(u32_le, int32_t, my_little_swap32((smp ^ 0x8000) >> 16))
+RATE_PUT_SAMPLE(u32_be, int32_t, my_big_swap32((smp ^ 0x8000) >> 16))
+
+static put_sample_f rate_put_sample[] = {
+       [SND_PCM_SFMT_S8]       rate_put_sample_s8,
+       [SND_PCM_SFMT_U8]       rate_put_sample_u8,
+       [SND_PCM_SFMT_S16_LE]   rate_put_sample_s16_le,
+       [SND_PCM_SFMT_S16_BE]   rate_put_sample_s16_be,
+       [SND_PCM_SFMT_U16_LE]   rate_put_sample_u16_le,
+       [SND_PCM_SFMT_U16_BE]   rate_put_sample_u16_be,
+       [SND_PCM_SFMT_S24_LE]   rate_put_sample_s24_le,
+       [SND_PCM_SFMT_S24_BE]   rate_put_sample_s24_be,
+       [SND_PCM_SFMT_U24_LE]   rate_put_sample_u24_le,
+       [SND_PCM_SFMT_U24_BE]   rate_put_sample_u24_be,
+       [SND_PCM_SFMT_S32_LE]   rate_put_sample_s32_le,
+       [SND_PCM_SFMT_S32_BE]   rate_put_sample_s32_be,
+       [SND_PCM_SFMT_U32_LE]   rate_put_sample_u32_le,
+       [SND_PCM_SFMT_U32_BE]   rate_put_sample_u32_be
+};
+
+int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
+                             snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin)
 {
        struct rate_private_data *data;
        snd_pcm_plugin_t *plugin;
-       int voice;
 
        if (r_plugin == NULL)
                return -EINVAL;
@@ -375,45 +389,41 @@ int snd_pcm_plugin_build_rate(snd_pcm_format_t *src_format,
        if (src_format->interleave != dst_format->interleave && 
            src_format->voices > 1)
                return -EINVAL;
-       if (src_format->format != dst_format->format)
-               return -EINVAL;
        if (!dst_format->interleave)
                return -EINVAL;
        if (src_format->voices != dst_format->voices)
                return -EINVAL;
-       if (dst_format->voices < 1 || dst_format->voices > MAX_VOICES)
+       if (dst_format->voices < 1)
                return -EINVAL;
-
-       if (src_format->format != SND_PCM_SFMT_S16_LE &&
-           src_format->format != SND_PCM_SFMT_U8)
+       if (snd_pcm_format_linear(src_format->format) <= 0)
+               return -EINVAL;
+       if (snd_pcm_format_linear(dst_format->format) <= 0)
                return -EINVAL;
        if (src_format->rate == dst_format->rate)
                return -EINVAL;
-       plugin = snd_pcm_plugin_build("rate conversion",
-                                     sizeof(struct rate_private_data));
+       plugin = snd_pcm_plugin_build(handle,
+                                     "rate conversion",
+                                     src_format,
+                                     dst_format,
+                                     sizeof(rate_t) +
+                                       src_format->voices * sizeof(rate_voice_t));
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct rate_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->sample_size = src_format->format == SND_PCM_SFMT_S16_LE ? 2 : 1;
-       data->src_voices = src_format->voices;
-       data->dst_voices = dst_format->voices;
-       data->src_rate = src_format->rate;
-       data->dst_rate = dst_format->rate;
+       data = (rate_t *)plugin->extra_data;
+       data->plugin = plugin;
+       data->take = rate_take_sample[src_format->format];
+       data->put = rate_put_sample[dst_format->format];
        if (src_format->rate < dst_format->rate) {
-               data->expand = 1;
                data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
        } else {
-               data->expand = 0;
                data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate;
        }
        data->pos = 0;
-       for (voice = 0; voice < data->src_voices; ++voice) {
-               data->last_S1[voice] = data->last_S2[voice] = 0;
-       }
-       data->old_src_size = data->old_dst_size = 0;
+       rate_init(plugin, data);
+       data->old_src_samples = data->old_dst_samples = 0;
        plugin->transfer = rate_transfer;
-       plugin->src_size = rate_src_size;
-       plugin->dst_size = rate_dst_size;
+       plugin->src_samples = rate_src_samples;
+       plugin->dst_samples = rate_dst_samples;
        plugin->action = rate_action;
        *r_plugin = plugin;
        return 0;
index ca818b7c66e6643a032cfc735923c89723d63cbb..f5787dbf92184e2499abf76b0a480b2a6d655be5 100644 (file)
@@ -352,7 +352,7 @@ static ssize_t route_transfer(snd_pcm_plugin_t *plugin,
                return -EINVAL;
        if (src_size == 0)
                return 0;
-       data = (struct route_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (struct route_private_data *)plugin->extra_data;
        data->func(data, src_ptr, dst_ptr, src_size, dst_size);
        return dst_size;
 }
@@ -414,7 +414,7 @@ int snd_pcm_plugin_build_route(snd_pcm_format_t *src_format,
                                      sizeof(data->ttable[0]) * src_format->voices * dst_format->voices);
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct route_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (struct route_private_data *)plugin->extra_data;
 
        data->src_voices = src_format->voices;
        data->dst_voices = dst_format->voices;
index 3324221caa7d4b0bc051a8885bd758b391835dcb..963a6973bf1aa8ab27e3dadfe32739c603c51ec1 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/uio.h>
 #include "../pcm_local.h"
 
 /*
  *  Basic stream plugin
  */
  
-struct stream_private_data {
-       snd_pcm_t *pcm;
+typedef struct stream_private_data {
        int channel;
-};
+} stream_t;
 
 static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
-                              char *src_ptr, size_t src_size,
-                              char *dst_ptr, size_t dst_size)
+                              const snd_pcm_plugin_voice_t *src_voices,
+                              const snd_pcm_plugin_voice_t *dst_voices,
+                              size_t samples)
 {
-       struct stream_private_data *data;
+       stream_t *data;
+       ssize_t result;
+       struct iovec *vec;
+       int count, voice;
 
-       if (plugin == NULL || dst_ptr == NULL || dst_size <= 0)
+       if (plugin == NULL)
                return -EINVAL;
-       data = (struct stream_private_data *)snd_pcm_plugin_extra_data(plugin);
+       data = (stream_t *)plugin->extra_data;
        if (data == NULL)
                return -EINVAL;
+       vec = (struct iovec *)((char *)data + sizeof(*data));
        if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
-               return snd_pcm_write(data->pcm, dst_ptr, dst_size);
+               if (src_voices == NULL)
+                       return -EINVAL;
+               if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
+                       return result;
+               if (plugin->src_format.interleave) {
+                       vec->iov_base = src_voices->addr;
+                       vec->iov_len = result;
+                       count = 1;
+               } else {
+                       count = plugin->src_format.voices;
+                       result /= count;
+                       for (voice = 0; voice < count; voice++) {
+                               vec[voice].iov_base = src_voices[voice].addr;
+                               vec[voice].iov_len = result;
+                       }
+               }
+               result = snd_pcm_writev(plugin->handle, vec, count);
+               if (result < 0)
+                       return result;
+               return snd_pcm_plugin_src_size_to_samples(plugin, result);
        } else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
-               return snd_pcm_read(data->pcm, dst_ptr, dst_size);
+               if (dst_voices == NULL)
+                       return -EINVAL;
+               if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
+                       return result;
+               if (plugin->dst_format.interleave) {
+                       vec->iov_base = dst_voices->addr;
+                       vec->iov_len = result;
+                       count = 1;
+               } else {
+                       count = plugin->dst_format.voices;
+                       result /= count;
+                       for (voice = 0; voice < count; voice++) {
+                               vec[voice].iov_base = dst_voices[voice].addr;
+                               vec[voice].iov_len = result;
+                       }
+               }
+               result = snd_pcm_readv(plugin->handle, vec, count);
+               return snd_pcm_plugin_dst_size_to_samples(plugin, result);
        } else {
                return -EINVAL;
        }
 }
  
-int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **r_plugin)
+int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel,
+                               snd_pcm_format_t *format,
+                               snd_pcm_plugin_t **r_plugin)
 {
-       struct stream_private_data *data;
+       stream_t *data;
        snd_pcm_plugin_t *plugin;
 
        if (!r_plugin)
@@ -65,14 +108,15 @@ int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel, snd_pcm_plugin_t **
        *r_plugin = NULL;
        if (!pcm || channel < 0 || channel > 1)
                return -EINVAL;
-       plugin = snd_pcm_plugin_build(channel == SND_PCM_CHANNEL_PLAYBACK ?
+       plugin = snd_pcm_plugin_build(pcm,
+                                     channel == SND_PCM_CHANNEL_PLAYBACK ?
                                                "I/O stream playback" :
                                                "I/O stream capture",
-                                               sizeof(struct stream_private_data));
+                                     format, format,
+                                     sizeof(stream_t) + sizeof(struct iovec) * format->voices);
        if (plugin == NULL)
                return -ENOMEM;
-       data = (struct stream_private_data *)snd_pcm_plugin_extra_data(plugin);
-       data->pcm = pcm;
+       data = (stream_t *)plugin->extra_data;
        data->channel = channel;
        plugin->transfer = stream_transfer;
        *r_plugin = plugin;