[PATCH - rate plugin 1/1] Support for float samples in rate converters
Pavel Hofman
pavel.hofman at ivitera.com
Tue Jun 28 08:50:23 CEST 2011
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 70e30e5..9f4ec23 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);
@@ -1409,7 +1516,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_close(pcm);
--
1.7.0.4
--------------000009060503020103050906
Content-Type: text/x-diff;
name="0001-Using-float-instead-of-s16-for-libsamplerate.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename*0="0001-Using-float-instead-of-s16-for-libsamplerate.patch"
More information about the Alsa-devel
mailing list