diff mbox

Conversion to int16_t and resolution loss with rate converter plugins

Message ID 3a7d4f82-07af-cffb-a757-a258242b0199@ivitera.com (mailing list archive)
State New, archived
Headers show

Commit Message

Pavel Hofman April 5, 2018, 6:17 a.m. UTC
Dne 5.4.2018 v 05:05 Flavio Protasio Ribeiro napsal(a):
> Hi Folks,
> 
> 
> 
> The libsamplerate and speex rate converter plugins only implement the
> convert_s16 callback from snd_pcm_rate_ops_t. This has ALSA convert
> the buffer to int16_t before handing it over to the plugin for
> resampling. On devices with more than 16 effective bits, this implies
> words gets truncated and bits are lost.
> 
> 
> 
> Specifically for libsamplerate, the resampling is internally
> implemented with floats, so truncating to 16 bits does not offer a
> computational benefit.
> 
> 
> 
> I get why only convert_s16 is implemented for plugins that aren't
> part of the main alsa-lib package. The more generic convert callback
> comes with the burden having the plugin support conversion from/to
> any of the ALSA data types (or alternatively, having the plugin
> source include plugin_ops.h and its dependencies). So here's what I
> propose: replace convert_s16 with a convert_s32 callback which uses
> int32_t instead of int16_t. This would preserve all bits from the
> device and keep the plugin interface simple. Of course this means
> plugins have to be updated to use convert_s32 and rebuilt.
> 
> 

Hi,

Many years ago I tried to extend the rate API to float, the native 
formats of libsamplerate and speex.

I go stuck on float support of all platforms, perhaps you can get 
something from the discussion and patches.

http://mailman.alsa-project.org/pipermail/alsa-devel/2011-June/041059.html

http://mailman.alsa-project.org/pipermail/alsa-devel/2011-July/041503.html

If we succeed in adding >16 bit API to the rate plugin, perhaps 
supporting libsoxr would be the next step which would bring great value 
(performance vs. CPU load) to alsa-lib. Unfortunately that is not just 
about conversion, there are other quirks to iron out...

Anyway, thanks a lot and good luck to your very useful endeavour.

Best regards,

Pavel.

Comments

Flavio Protasio Ribeiro April 5, 2018, 9:21 p.m. UTC | #1
Hi Pavel,

Thanks for the reference to your previous discussion and the patches. They were super helpful. As you can see from my reply to Takashi, I'm proposing adding a convert_s32 method that doesn't impose dependency on a HW FPU on alsa-lib. The convert_s32 method would operate on an array of int32's.

From the point of view of the plugin developer, the change from convert_s16 to convert_s32 is pretty trivial. The plugins that I personally care about operate internally with floats. The plugin would remain responsible for converting between int32 and float.

I agree that a libsoxr plugin would be great. Getting higher quality real-time resampling is my ultimate goal :)

Thanks,
Flavio

-----Original Message-----
From: Pavel Hofman <pavel.hofman@ivitera.com> 
Sent: Wednesday, April 4, 2018 11:17 PM
To: Flavio Protasio Ribeiro <flaviopr@microsoft.com>; alsa-devel@alsa-project.org
Subject: Re: [alsa-devel] Conversion to int16_t and resolution loss with rate converter plugins



Dne 5.4.2018 v 05:05 Flavio Protasio Ribeiro napsal(a):
> Hi Folks,
> 
> 
> 
> The libsamplerate and speex rate converter plugins only implement the
> convert_s16 callback from snd_pcm_rate_ops_t. This has ALSA convert 
> the buffer to int16_t before handing it over to the plugin for 
> resampling. On devices with more than 16 effective bits, this implies 
> words gets truncated and bits are lost.
> 
> 
> 
> Specifically for libsamplerate, the resampling is internally 
> implemented with floats, so truncating to 16 bits does not offer a 
> computational benefit.
> 
> 
> 
> I get why only convert_s16 is implemented for plugins that aren't part 
> of the main alsa-lib package. The more generic convert callback comes 
> with the burden having the plugin support conversion from/to any of 
> the ALSA data types (or alternatively, having the plugin source 
> include plugin_ops.h and its dependencies). So here's what I
> propose: replace convert_s16 with a convert_s32 callback which uses 
> int32_t instead of int16_t. This would preserve all bits from the 
> device and keep the plugin interface simple. Of course this means 
> plugins have to be updated to use convert_s32 and rebuilt.
> 
> 

Hi,

Many years ago I tried to extend the rate API to float, the native formats of libsamplerate and speex.

I go stuck on float support of all platforms, perhaps you can get something from the discussion and patches.

https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmailman.alsa-project.org%2Fpipermail%2Falsa-devel%2F2011-June%2F041059.html&data=02%7C01%7Cflaviopr%40microsoft.com%7C1a39272ef41948b9e0e508d59abce88d%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C1%7C636585058520946316&sdata=y3iBvFGetAKtrkVO%2FUlHUUHSKpXSyko8pJme6NSlpQA%3D&reserved=0

https://na01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmailman.alsa-project.org%2Fpipermail%2Falsa-devel%2F2011-July%2F041503.html&data=02%7C01%7Cflaviopr%40microsoft.com%7C1a39272ef41948b9e0e508d59abce88d%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C1%7C636585058520946316&sdata=4%2F%2BIryERoT4btWN%2FGzYQmLH2Q86IPGr7odNuSAxJIVM%3D&reserved=0

If we succeed in adding >16 bit API to the rate plugin, perhaps supporting libsoxr would be the next step which would bring great value (performance vs. CPU load) to alsa-lib. Unfortunately that is not just about conversion, there are other quirks to iron out...

Anyway, thanks a lot and good luck to your very useful endeavour.

Best regards,

Pavel.
Pavel Hofman April 6, 2018, 6:32 a.m. UTC | #2
Dne 5.4.2018 v 23:21 Flavio Protasio Ribeiro napsal(a):
> Hi Pavel,
> 
> Thanks for the reference to your previous discussion and the patches.
> They were super helpful. As you can see from my reply to Takashi, I'm
> proposing adding a convert_s32 method that doesn't impose dependency
> on a HW FPU on alsa-lib. The convert_s32 method would operate on an
> array of int32's.
> 
> From the point of view of the plugin developer, the change from
> convert_s16 to convert_s32 is pretty trivial. The plugins that I
> personally care about operate internally with floats. The plugin
> would remain responsible for converting between int32 and float.

Sounds much better than my attempt at float API.
> 
> I agree that a libsoxr plugin would be great. Getting higher quality
> real-time resampling is my ultimate goal :)

If you make it work, you will be praised by countless users :-)

But the existing rate API will have to be modified since libsoxr behaves 
a bit different to speex or libresample - see the library author 
discussing the issues 
http://mailman.alsa-project.org/pipermail/alsa-devel/2013-September/066764.html

Thanks,

Pavel.
diff mbox

Patch

From 34fb26dc0a95f7d1950abe2582cf79219d1876a9 Mon Sep 17 00:00:00 2001
From: Pavel Hofman <pavel.hofman@ivitera.com>
Date: Tue, 28 Jun 2011 08:55:08 +0200
Subject: [PATCH - resample 1/1] Using float instead of s16 for libsamplerate

Natively libsamplerate operates in floats. Using the new convert_float API instead of dropping resoluton in convert_s16.

Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>

diff --git a/rate/rate_samplerate.c b/rate/rate_samplerate.c
index 53a0627..c612983 100644
--- a/rate/rate_samplerate.c
+++ b/rate/rate_samplerate.c
@@ -23,12 +23,12 @@ 
 #include <alsa/asoundlib.h>
 #include <alsa/pcm_rate.h>
 
+typedef float float_t;
+
 struct rate_src {
 	double ratio;
 	int converter;
 	unsigned int channels;
-	float *src_buf;
-	float *dst_buf;
 	SRC_STATE *state;
 	SRC_DATA data;
 };
@@ -53,9 +53,6 @@  static void pcm_src_free(void *obj)
 {
 	struct rate_src *rate = obj;
 
-	free(rate->src_buf);
-	free(rate->dst_buf);
-	rate->src_buf = rate->dst_buf = NULL;
 
 	if (rate->state) {
 		src_delete(rate->state);
@@ -79,17 +76,6 @@  static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
 
 	rate->ratio = (double)info->out.rate / (double)info->in.rate;
 
-	free(rate->src_buf);
-	rate->src_buf = malloc(sizeof(float) * rate->channels * info->in.period_size);
-	free(rate->dst_buf);
-	rate->dst_buf = malloc(sizeof(float) * rate->channels * info->out.period_size);
-	if (! rate->src_buf || ! rate->dst_buf) {
-		pcm_src_free(rate);
-		return -ENOMEM;
-	}
-
-	rate->data.data_in = rate->src_buf;
-	rate->data.data_out = rate->dst_buf;
 	rate->data.src_ratio = rate->ratio;
 	rate->data.end_of_input = 0;
 
@@ -112,8 +98,8 @@  static void pcm_src_reset(void *obj)
 	src_reset(rate->state);
 }
 
-static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int dst_frames,
-				const int16_t *src, unsigned int src_frames)
+static void pcm_src_convert_float(void *obj, float_t *dst, unsigned int dst_frames,
+				const float_t *src, unsigned int src_frames)
 {
 	struct rate_src *rate = obj;
 	unsigned int ofs;
@@ -121,15 +107,17 @@  static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int dst_frames
 	rate->data.input_frames = src_frames;
 	rate->data.output_frames = dst_frames;
 	rate->data.end_of_input = 0;
+	rate->data.data_in = src;
+	rate->data.data_out = dst;
+
 	
-	src_short_to_float_array(src, rate->src_buf, src_frames * rate->channels);
 	src_process(rate->state, &rate->data);
 	if (rate->data.output_frames_gen < dst_frames)
 		ofs = dst_frames - rate->data.output_frames_gen;
 	else
 		ofs = 0;
-	src_float_to_short_array(rate->dst_buf, dst + ofs * rate->channels,
-				 rate->data.output_frames_gen * rate->channels);
+	/*src_float_to_short_array(rate->dst_buf, dst + ofs * rate->channels,
+				 rate->data.output_frames_gen * rate->channels); */
 }
 
 static void pcm_src_close(void *obj)
@@ -157,7 +145,7 @@  static snd_pcm_rate_ops_t pcm_src_ops = {
 	.free = pcm_src_free,
 	.reset = pcm_src_reset,
 	.adjust_pitch = pcm_src_adjust_pitch,
-	.convert_s16 = pcm_src_convert_s16,
+	.convert_float = pcm_src_convert_float,
 	.input_frames = input_frames,
 	.output_frames = output_frames,
 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
-- 
1.7.0.4