[alsa-devel] [PATCH] Bugfix: Fix resampling when client and slave both use format float

Takashi Iwai tiwai at suse.de
Mon Feb 24 14:38:28 CET 2014


At Mon, 24 Feb 2014 13:57:24 +0100,
Pavel Hofman wrote:
> 
> On 24.2.2014 13:13, Maarten Baert wrote:
> > On 24/02/14 10:17, Takashi Iwai wrote:
> >> Can S32 work instead of S16?  Then we won't lose the accuracy so much.
> >> Of course, handling float directly would be the best option.
> > The samplerate and speexrate plugins currently take S16 (see
> > pcm_src_convert_s16 in alsa-plugins/rate/rate_samplerate.c and
> > alsa-plugins/rate/rate_speexrate.c), so just using S32 will not improve
> > the accuracy. It would be easy to replace those functions with
> > pcm_src_convert_float (both resampler libraries have functions that take
> > float directly), but that will break the plugin ABI. Is that acceptable?
> 
> Here is my older patch for the convertor, I know it needs a bit of work
> before accepting (originally discussed at
> http://mailman.alsa-project.org/pipermail/alsa-devel/2011-June/041368.html )
> 
> If this project gets done, there is a CPU-efficient libsoxr convertor
> plugin in the pipeline too.

Yeah, we'll need some change like this, but need the version checks
and process the new process_float ops only for the new protocol
version for keeping the backward compatibility, too.


thanks,

Takashi

> 
> Thanks a lot,
> 
> Pavel.
> >From 628930dabaa8b8e3f79a03a092a63ee44bfdb98e Mon Sep 17 00:00:00 2001
> From: Pavel Hofman <pavel.hofman at ivitera.com>
> Date: Tue, 28 Jun 2011 08:50:23 +0200
> Subject: [ALSA-LIB 1/1] Support for float samples in rate converter plugins
> 
> Some rate converters have native float resolution, no need
> to loose information by converting to s16.
> 
> Signed-off-by: Pavel Hofman <pavel.hofman at ivitera.com>
> 
> diff --git a/include/pcm_rate.h b/include/pcm_rate.h
> index 4d70df2..e92900b 100644
> --- a/include/pcm_rate.h
> +++ b/include/pcm_rate.h
> @@ -91,6 +91,11 @@ typedef struct snd_pcm_rate_ops {
>  	void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames,
>  			    const int16_t *src, unsigned int src_frames);
>  	/**
> +	 * convert a float interleaved-data array; exclusive with convert
> +	 */
> +	void (*convert_float)(void *obj, float *dst, unsigned int dst_frames,
> +			    const float *src, unsigned int src_frames);
> +	/**
>  	 * compute the frame size for input
>  	 */
>  	snd_pcm_uframes_t (*input_frames)(void *obj, snd_pcm_uframes_t frames);
> diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
> index 54a3e67..2831f23 100644
> --- a/src/pcm/pcm_rate.c
> +++ b/src/pcm/pcm_rate.c
> @@ -35,7 +35,7 @@
>  #include "iatomic.h"
>  
>  #include "plugin_ops.h"
> -
> +typedef float float_t;
>  #if 0
>  #define DEBUG_REFINE
>  #endif
> @@ -66,8 +66,8 @@ struct _snd_pcm_rate {
>  	snd_pcm_rate_ops_t ops;
>  	unsigned int get_idx;
>  	unsigned int put_idx;
> -	int16_t *src_buf;
> -	int16_t *dst_buf;
> +	void *src_buf;
> +	void *dst_buf;
>  	int start_pending; /* start is triggered but not commited to slave */
>  	snd_htimestamp_t trigger_tstamp;
>  	unsigned int plugin_version;
> @@ -310,13 +310,23 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
>  		rate->sareas[chn].step = swidth;
>  	}
>  
> -	if (rate->ops.convert_s16) {
> +	if (rate->ops.convert_float) {
> +		rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S32);
> +		rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, rate->info.out.format);
> +		free(rate->src_buf);
> +		rate->src_buf = (float_t *) malloc(channels * rate->info.in.period_size * sizeof(float_t));
> +		free(rate->dst_buf);
> +		rate->dst_buf = (float_t *) malloc(channels * rate->info.out.period_size * sizeof(float_t));
> +		if (! rate->src_buf || ! rate->dst_buf)
> +			goto error;
> +	}
> +	else if (rate->ops.convert_s16) {
>  		rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S16);
>  		rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, rate->info.out.format);
>  		free(rate->src_buf);
> -		rate->src_buf = malloc(channels * rate->info.in.period_size * 2);
> +		rate->src_buf = (int16_t *) malloc(channels * rate->info.in.period_size * 2);
>  		free(rate->dst_buf);
> -		rate->dst_buf = malloc(channels * rate->info.out.period_size * 2);
> +		rate->dst_buf = (int16_t *) malloc(channels * rate->info.out.period_size * 2);
>  		if (! rate->src_buf || ! rate->dst_buf)
>  			goto error;
>  	}
> @@ -503,6 +513,85 @@ static void convert_from_s16(snd_pcm_rate_t *rate, const int16_t *buf,
>  		}
>  	}
>  }
> +static void convert_to_float(snd_pcm_rate_t *rate, float_t *buf,
> +			   const snd_pcm_channel_area_t *areas,
> +			   snd_pcm_uframes_t offset, unsigned int frames,
> +			   unsigned int channels)
> +{
> +#ifndef DOC_HIDDEN
> +#define GET32_LABELS
> +#include "plugin_ops.h"
> +#undef GET32_LABELS
> +#endif /* DOC_HIDDEN */
> +	void *get32 = get32_labels[rate->get_idx];
> +	const char *src;
> +	int32_t sample;
> +	const char *srcs[channels];
> +	int src_step[channels];
> +	unsigned int c;
> +
> +	for (c = 0; c < channels; c++) {
> +		srcs[c] = snd_pcm_channel_area_addr(areas + c, offset);
> +		src_step[c] = snd_pcm_channel_area_step(areas + c);
> +	}
> +
> +	while (frames--) {
> +		for (c = 0; c < channels; c++) {
> +			src = srcs[c];
> +			// converting the source format to int32 first
> +			goto *get32;
> +#ifndef DOC_HIDDEN
> +#define GET32_END after_get
> +#include "plugin_ops.h"
> +#undef GET32_END
> +#endif /* DOC_HIDDEN */
> +		after_get:
> +			// converting to float for the plugin
> +			*buf++ = (float_t) sample;
> +			srcs[c] += src_step[c];
> +		}
> +	}
> +}
> +
> +static void convert_from_float(snd_pcm_rate_t *rate, const float_t *buf,
> +			     const snd_pcm_channel_area_t *areas,
> +			     snd_pcm_uframes_t offset, unsigned int frames,
> +			     unsigned int channels)
> +{
> +#ifndef DOC_HIDDEN
> +#define PUT32_LABELS
> +#include "plugin_ops.h"
> +#undef PUT32_LABELS
> +#endif /* DOC_HIDDEN */
> +	void *put32 = put32_labels[rate->put_idx];
> +	char *dst;
> +	int32_t sample;
> +	char *dsts[channels];
> +	int dst_step[channels];
> +	unsigned int c;
> +
> +	for (c = 0; c < channels; c++) {
> +		dsts[c] = snd_pcm_channel_area_addr(areas + c, offset);
> +		dst_step[c] = snd_pcm_channel_area_step(areas + c);
> +	}
> +
> +	while (frames--) {
> +		for (c = 0; c < channels; c++) {
> +			dst = dsts[c];
> +			// plugin returned float, converting to int32 first
> +			sample = (int32_t) *buf++;
> +			// converting int32 to the destination format
> +			goto *put32;
> +#ifndef DOC_HIDDEN
> +#define PUT32_END after_put
> +#include "plugin_ops.h"
> +#undef PUT32_END
> +#endif /* DOC_HIDDEN */
> +		after_put:
> +			dsts[c] += dst_step[c];
> +		}
> +	}
> +}
>  
>  static void do_convert(const snd_pcm_channel_area_t *dst_areas,
>  		       snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
> @@ -511,18 +600,36 @@ static void do_convert(const snd_pcm_channel_area_t *dst_areas,
>  		       unsigned int channels,
>  		       snd_pcm_rate_t *rate)
>  {
> -	if (rate->ops.convert_s16) {
> +	if (rate->ops.convert_float) {
> +		const float_t *src;
> +		float_t *dst;
> +		if (! rate->src_buf)
> +			src = src_areas->addr + src_offset * sizeof(float_t) * channels;
> +		else {
> +			convert_to_float(rate, rate->src_buf, src_areas, src_offset,
> +				       src_frames, channels);
> +			src = rate->src_buf;
> +		}
> +		if (! rate->dst_buf)
> +			dst = dst_areas->addr + dst_offset * sizeof(float_t) * channels;
> +		else
> +			dst = rate->dst_buf;
> +		rate->ops.convert_float(rate->obj, dst, dst_frames, src, src_frames);
> +		if (dst == rate->dst_buf)
> +			convert_from_float(rate, rate->dst_buf, dst_areas, dst_offset,
> +					 dst_frames, channels);
> +	} else if (rate->ops.convert_s16) {
>  		const int16_t *src;
>  		int16_t *dst;
>  		if (! rate->src_buf)
> -			src = src_areas->addr + src_offset * 2 * channels;
> +			src = src_areas->addr + src_offset * sizeof(int16_t) * channels;
>  		else {
>  			convert_to_s16(rate, rate->src_buf, src_areas, src_offset,
>  				       src_frames, channels);
>  			src = rate->src_buf;
>  		}
>  		if (! rate->dst_buf)
> -			dst = dst_areas->addr + dst_offset * 2 * channels;
> +			dst = dst_areas->addr + dst_offset * sizeof(int16_t) * channels;
>  		else
>  			dst = rate->dst_buf;
>  		rate->ops.convert_s16(rate->obj, dst, dst_frames, src, src_frames);
> @@ -1416,7 +1523,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
>  	}
>  #endif
>  
> -	if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16) ||
> +	if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16 || rate->ops.convert_float) ||
>  	    ! rate->ops.input_frames || ! rate->ops.output_frames) {
>  		SNDERR("Inproper rate plugin %s initialization", type);
>  		snd_pcm_free(pcm);
> -- 
> 1.7.1
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


More information about the Alsa-devel mailing list