Discussion:
pcm_rate API question
Rob Sykes
2013-09-27 11:59:33 UTC
Permalink
Hello alsa devs,

There's an ongoing attempt to see if libsoxr-lsr can be used as a plug-in replacement for libsamplerate in pulseaudio and in alsa (libsoxr-lsr is designed with this usage in mind).

With pulseaudio, it seems to 'just work', but with alsa, it looks like there is a buffering problem.  Progress reports for this are here:

http://blog.ivitera.com/pavel/linux-audio/pulseaudio-with-ld_preloading-libsoxr-lsr

http://blog.ivitera.com/pavel/linux-audio/simple-use-of-libsoxr-lsr-in-alsa-using-ld_preload


AFAICT, the problem with alsa relates to the use of this function in pcm_rate.h:

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);

Is there documentation available regarding the use of this function? For example, is the plugin obliged always to consume src_frames and generate dst_frames samples?  If so, how is the plugin expected to comply (say, if it's not been given enough input to generate that amount of output)?

TIA,
Rob
Clemens Ladisch
2013-09-27 12:38:23 UTC
Permalink
Post by Rob Sykes
void (*convert_s16)(void *obj, int16_t *dst, unsigned int dst_frames,
const int16_t *src, unsigned int src_frames);
is the plugin obliged always to consume src_frames and generate dst_frames samples?
Yes. src_frames and dst_frames are the period sizes of the respective
devices; their values will never change, and they define the actual
conversion ratio.


Regards,
Clemens
Rob Sykes
2013-09-28 09:58:40 UTC
Permalink
Sent: Friday, 27 September 2013, 16:28
Subject: Re: [alsa-devel] pcm_rate API  question
Sent: Friday, 27 September 2013, 13:38
Subject: Re: [alsa-devel] pcm_rate API  question
         void
(*convert_s16)(void *obj, int16_t *dst, unsigned int
dst_frames,
                             const int16_t *src, unsigned int src_frames);
  is the plugin obliged always to consume src_frames and generate dst_frames
samples?
Yes.  src_frames and dst_frames are the period sizes of the respective
devices; their values will never change, and they define the actual
conversion ratio.
Q6 : I'm use the SRC_SINC_* converters and up-sampling by a ratio of 2. I reset the converter and put in 1000 samples and I expect to get 2000 samples out, but I'm getting less than that. Why?
The short answer is that there is a transport delay inside the converter itself. Long answer follows.  By way of example, the first time you call src_process() you might only get 1900 samples out.
However, after that first call all subsequent calls will probably get you about 2000 samples out for every 1000 samples you put in.
Also, just noticed that when performing a rate conversion from 44100 -> 48000, the buffer sizes used by alsa are 5512 and 6000, however the actual ratio for the required conversion is 5512.5 to 6000.

If, as you say above, the buffer sizes define the conversion ratio, then this seems to imply that alsa is unable to perform accurate rate conversion for one of the most common uses! — am I missing something here? A pointer to the API documentation, or perhaps some relevant threads, would be very useful. 

Cheers,
Rob
Clemens Ladisch
2013-09-30 08:59:35 UTC
Permalink
Post by Rob Sykes
Typically there is some buffering/delay within a resampler -- how
does the pcm_rate API allow for this?
The API itself does not allow for this. Your code must generate
dst_frames samples.

At startup, prefix the output with zero samples. For example,
rate_samplerate.c in the alsa-plugins package does this:

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);
Post by Rob Sykes
If, as you say above, the buffer sizes
the period sizes
Post by Rob Sykes
define the conversion ratio, then this seems to imply that alsa is
unable to perform accurate rate conversion for one of the most common
uses!
The conversion indeed is not accurate, unless you are using a period
size of an integer multiple of 441 frames. In your example, the
application probably used a buffer of 0.5 s and four periods per buffer;
it should either double the buffer size or halve the number of periods.


Regards,
Clemens
Rob Sykes
2013-09-30 11:15:13 UTC
Permalink
----- Original Message -----
Sent: Monday, 30 September 2013, 9:59
Subject: Re: [alsa-devel] pcm_rate API  question
  Typically there is some buffering/delay within a resampler -- how
  does the pcm_rate API allow for this?
The API itself does not allow for this.  Your code must generate
dst_frames samples.
At startup, prefix the output with zero samples.  For example,
Thanks Clemens. Having to prefix the output with a signal that is unrelated to the input signal doesn't seem great, though I guess this just manifests itself as a delay (variable, dependent on resampler, etc.) and may go unnoticed.  Of more concern is that this situation can apparently occur at any time: "after that first call all subsequent calls will probably get you about 2000 samples out for every 1000 samples you put in" — only "probably", not "always"; occurring after the start, this will likely cause audible distortion.
The conversion indeed is not accurate, unless you are using a period
size of an integer multiple of 441 frames.  In your example, the
application probably used a buffer of 0.5 s and four periods per buffer;
it should either double the buffer size or halve the number of periods.
Oh okay, the application in question was aplay 1.0.25; maybe it's since been fixed, but no matter, it seems that the above buffering issue is the main problem.

Cheers,
Rob
Clemens Ladisch
2013-09-30 14:16:58 UTC
Permalink
Post by Rob Sykes
Post by Clemens Ladisch
Typically there is some buffering/delay within a resampler -- how
does the pcm_rate API allow for this?
The API itself does not allow for this. Your code must generate
dst_frames samples.
At startup, prefix the output with zero samples.
this situation can apparently occur at any time: "after that first
call all subsequent calls will probably get you about 2000 samples out
for every 1000 samples you put in" — only "probably", not "always";
occurring after the start, this will likely cause audible distortion.
You must know your resampling algorithm. If it introduces delays, you
need to buffer more samples.


Regards,
Clemens

Loading...