[alsa-devel] [PATCH] external plugin for adding delay to channels

Takashi Iwai tiwai at suse.de
Thu Oct 2 11:51:17 CEST 2008


At Tue, 30 Sep 2008 22:51:23 +0200,
Alex wrote:
> 
> This should be interesting for home theater installations, as I was 
> personnally missing a "per channel delay configuration".
> 
> Feel free to tell me what should be modified, I am not really used to proposing 
> a patch.

Thanks for the patch.
Just looking quickly at it, some comments below.


> diff -x libtool -x stamp-h1 -x .vimrc -x rate -x Makefile.in -x Makefile -x .deps -x configure -x config.status -x config.h -x config.log -x a52 -x '*cache*' -x '*aclocal*' -Naur alsa-plugins-1.0.17/configure.in alsa-plugins-1.0.17+delay/configure.in

Maybe it's a good chance to learn git now :)

> --- alsa-plugins-1.0.17/configure.in	2008-07-14 10:57:59.000000000 +0200
> +++ alsa-plugins-1.0.17+delay/configure.in	2008-09-24 10:52:23.000000000 +0200
> @@ -89,6 +89,9 @@
>  fi
>  
>  AM_CONDITIONAL(HAVE_PPH, test "$PPH" = "builtin" -o "$PPH" = "lib")
> +
> +AM_CONDITIONAL(HAVE_DELAY, test x$HAVE_DELAY = xyes)
> +
>  AM_CONDITIONAL(USE_LIBSPEEX, test "$PPH" = "lib")
>  
>  dnl ALSA plugin directory
> @@ -124,6 +127,7 @@
>  	a52/Makefile
>  	rate-lavc/Makefile
>  	maemo/Makefile
> +    delay/Makefile

Try to keep the same indent.

> --- alsa-plugins-1.0.17/delay/pcm_delay.c	1970-01-01 01:00:00.000000000 +0100
> +++ alsa-plugins-1.0.17+delay/delay/pcm_delay.c	2008-09-30 21:57:56.000000000 +0200
(snip)
> +/* Ambient temperature is 20° celsius */

Use ASCII as much as possible.  If inevitably necessary, use UTF-8.

> +typedef struct {
> +    snd_pcm_extplug_t   ext;
> +    
> +    double          *delay_ms;
> +    unsigned int    *delay_sample;
> +
> +    snd_pcm_channel_area_t  *dly_areas;
> +    snd_pcm_uframes_t       *dly_offset;
> +
> +    unsigned int    channels;
> +    unsigned int    mode;
> +} snd_pcm_delay_t;

Could you keep the indent level like other codes?
Not mandatory, but would be better for us...

> +static int  snd_pcm_delay_parse_delay(snd_pcm_delay_t *pcm_delay,
> +                                    snd_config_t    *conf_delay,
> +                                    unsigned char   mode)
> +{
> +    snd_config_iterator_t i, next;
> +    double  *delays;
> +    double  delay = 0.0;
> +    unsigned int    cnt = 0;
> +    unsigned int    channel;
> +    double  val;
> +    
> +    pcm_delay->mode = mode;
> +    if (conf_delay) {
> +        snd_config_for_each(i, next, conf_delay) {
> +            snd_config_t *n = snd_config_iterator_entry(i);
> +            const char *id;
> +            if (snd_config_get_id(n, &id) < 0)
> +                continue;
> +            cnt++;
> +        }

This means cnt includes comments, etc?  Then the number is
inaccurate (although a bigger doesn't matter much).

> +        pcm_delay->delay_ms = delays = calloc(cnt, sizeof(double));
> +        if (delays == NULL)
> +            return -ENOMEM;
> +        pcm_delay->channels = cnt;

Now you have two "channels", one in this definition and another as
pcm_delay->ext.channels.  As far as I see, these are used sometimes
wrongly, possibly resulting in a segfault.

> +static snd_pcm_sframes_t    snd_pcm_delay_transfer(snd_pcm_extplug_t    *ext,
> +                                                const snd_pcm_channel_area_t    *dst_areas,
> +                                                snd_pcm_uframes_t   dst_offset,
> +                                                const snd_pcm_channel_area_t    *src_areas,
> +                                                snd_pcm_uframes_t   src_offset,
> +                                                snd_pcm_uframes_t   size)
> +{
> +    snd_pcm_delay_t *pcm_delay = (snd_pcm_delay_t *)ext;
> +    unsigned int i;
> +    snd_pcm_uframes_t   left;
> +
> +    for (i = 0; i < pcm_delay->ext.channels; i++) {
> +        if (! pcm_delay->delay_sample[i]) {
> +            snd_pcm_area_copy(dst_areas + i, dst_offset,
> +                            src_areas + i, src_offset,
> +                            size, pcm_delay->ext.format);
> +            continue;
> +        }
> +        if (pcm_delay->delay_sample[i] <= size) {
> +            assert(! pcm_delay->dly_offset[i]);

I'm not sure whether this condition is assured...
The size in this callback isn't guaranteed to be a period size.

> +            left = size - pcm_delay->delay_sample[i];
> +            /* delay to dst */
> +            snd_pcm_area_copy(dst_areas + i, dst_offset,
> +                            pcm_delay->dly_areas + i, 0,
> +                            pcm_delay->delay_sample[i], pcm_delay->ext.format);
> +            if (left) {
> +                /* src to dst left */
> +                snd_pcm_area_copy(dst_areas + i, dst_offset + pcm_delay->delay_sample[i],
> +                                src_areas + i, src_offset,
> +                                left, pcm_delay->ext.format);
> +            }
> +            /* src left to delay */
> +            snd_pcm_area_copy(pcm_delay->dly_areas + i, 0,
> +                            src_areas + i, src_offset + left,
> +                            pcm_delay->delay_sample[i], pcm_delay->ext.format);
> +            continue;
> +        }
> +        /* usual (small) delays wont reach this part of the code */
> +        left = pcm_delay->dly_offset[i] + size > pcm_delay->delay_sample[i]
> +            ? (pcm_delay->dly_offset[i] + size) % pcm_delay->delay_sample[i] : 0;
> +        /* copy dly to dst */
> +        snd_pcm_area_copy(dst_areas + i, dst_offset,
> +                pcm_delay->dly_areas + i, pcm_delay->dly_offset[i],
> +                size - left, pcm_delay->ext.format);
> +        /* copy src to dly */
> +        snd_pcm_area_copy(pcm_delay->dly_areas + i, pcm_delay->dly_offset[i],
> +                src_areas + i, src_offset,
> +                size - left, pcm_delay->ext.format);
> +        if (left) {
> +            /* copy dly to dst */
> +            snd_pcm_area_copy(dst_areas + i, dst_offset + size - left,
> +                    pcm_delay->dly_areas + i, 0,
> +                    left, pcm_delay->ext.format);
> +            /* copy src to dly */
> +            snd_pcm_area_copy(pcm_delay->dly_areas + i, 0,
> +                    src_areas + i, src_offset + size - left,
> +                    left, pcm_delay->ext.format);
> +            pcm_delay->dly_offset[i] = left;
> +            continue;
> +        }
> +        pcm_delay->dly_offset[i] += size;

Hmm, the whole copy mechanism is a bit too hard.
I guess this could be simplified more.

> +/*
> + * Main entry point
> + */
> +SND_PCM_PLUGIN_DEFINE_FUNC(delay)
...
> +    snd_pcm_extplug_set_param_minmax(&pcm_delay->ext,
> +                                    SND_PCM_EXTPLUG_HW_CHANNELS,
> +                                    1, 6);
> +    snd_pcm_extplug_set_param_list(&pcm_delay->ext,
> +                                SND_PCM_EXTPLUG_HW_CHANNELS,
> +                                6, chlist);

You don't need both of them.  Both do the same job.

> +    snd_pcm_extplug_set_param(&pcm_delay->ext, SND_PCM_EXTPLUG_HW_FORMAT,
> +                            SND_PCM_FORMAT_S16);
> +    snd_pcm_extplug_set_slave_param(&pcm_delay->ext, SND_PCM_EXTPLUG_HW_FORMAT,
> +                                SND_PCM_FORMAT_S16);

Any reason to restrict to S16?  Just for copying samples, the sample
format doesn't matter much.


thanks,

Takashi


More information about the Alsa-devel mailing list