[PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read()

Volker Rümelin posted 17 patches 3 years ago
Maintainers: Gerd Hoffmann <kraxel@redhat.com>
There is a newer version of this series
[PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read()
Posted by Volker Rümelin 3 years ago
Replace the resampling loop in audio_pcm_sw_read() with the new
function audio_pcm_sw_resample_in(). Unlike the old resample
loop the new function will try to consume input frames even if
the output buffer is full. This is necessary when downsampling
to avoid reading less audio frames than calculated in advance.
The loop was unrolled to avoid complicated loop control conditions
in this case.

Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/audio.c | 59 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index e18b5e98c5..9e9c03a42e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -543,11 +543,43 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
 /*
  * Soft voice (capture)
  */
+static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
+    size_t frames_in_max, size_t frames_out_max,
+    size_t *total_in, size_t *total_out)
+{
+    HWVoiceIn *hw = sw->hw;
+    struct st_sample *src, *dst;
+    size_t live, rpos, frames_in, frames_out;
+
+    live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
+
+    /* resample conv_buf from rpos to end of buffer */
+    src = hw->conv_buf.buffer + rpos;
+    frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
+    dst = sw->resample_buf.buffer;
+    frames_out = frames_out_max;
+    st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
+    rpos += frames_in;
+    *total_in = frames_in;
+    *total_out = frames_out;
+
+    /* resample conv_buf from start of buffer if there are input frames left */
+    if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
+        src = hw->conv_buf.buffer;
+        frames_in = frames_in_max - frames_in;
+        dst += frames_out;
+        frames_out = frames_out_max - frames_out;
+        st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
+        *total_in += frames_in;
+        *total_out += frames_out;
+    }
+}
+
 static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
 {
     HWVoiceIn *hw = sw->hw;
-    size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
-    struct st_sample *src, *dst = sw->resample_buf.buffer;
+    size_t samples, live, ret, swlim, total;
 
     live = hw->total_samples_captured - sw->total_hw_samples_acquired;
     if (!live) {
@@ -558,33 +590,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
         return 0;
     }
 
-    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
-
     samples = size / sw->info.bytes_per_frame;
 
     swlim = (live * sw->ratio) >> 32;
     swlim = MIN (swlim, samples);
 
-    while (swlim) {
-        src = hw->conv_buf.buffer + rpos;
-        if (hw->conv_buf.pos > rpos) {
-            isamp = hw->conv_buf.pos - rpos;
-        } else {
-            isamp = hw->conv_buf.size - rpos;
-        }
-
-        if (!isamp) {
-            break;
-        }
-        osamp = swlim;
-
-        st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
-        swlim -= osamp;
-        rpos = (rpos + isamp) % hw->conv_buf.size;
-        dst += osamp;
-        ret += osamp;
-        total += isamp;
-    }
+    audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
 
     if (!hw->pcm_ops->volume_in) {
         mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
-- 
2.35.3


Re: [PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read()
Posted by Marc-André Lureau 2 years, 11 months ago
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Replace the resampling loop in audio_pcm_sw_read() with the new
> function audio_pcm_sw_resample_in(). Unlike the old resample
> loop the new function will try to consume input frames even if
> the output buffer is full. This is necessary when downsampling
> to avoid reading less audio frames than calculated in advance.
> The loop was unrolled to avoid complicated loop control conditions
> in this case.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>

Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>



> ---
>  audio/audio.c | 59 ++++++++++++++++++++++++++++++---------------------
>  1 file changed, 35 insertions(+), 24 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index e18b5e98c5..9e9c03a42e 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -543,11 +543,43 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
>  /*
>   * Soft voice (capture)
>   */
> +static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
> +    size_t frames_in_max, size_t frames_out_max,
> +    size_t *total_in, size_t *total_out)
> +{
> +    HWVoiceIn *hw = sw->hw;
> +    struct st_sample *src, *dst;
> +    size_t live, rpos, frames_in, frames_out;
> +
> +    live = hw->total_samples_captured - sw->total_hw_samples_acquired;
> +    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
> +
> +    /* resample conv_buf from rpos to end of buffer */
> +    src = hw->conv_buf.buffer + rpos;
> +    frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
> +    dst = sw->resample_buf.buffer;
> +    frames_out = frames_out_max;
> +    st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
> +    rpos += frames_in;
> +    *total_in = frames_in;
> +    *total_out = frames_out;
> +
> +    /* resample conv_buf from start of buffer if there are input frames left */
> +    if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
> +        src = hw->conv_buf.buffer;
> +        frames_in = frames_in_max - frames_in;
> +        dst += frames_out;
> +        frames_out = frames_out_max - frames_out;
> +        st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
> +        *total_in += frames_in;
> +        *total_out += frames_out;
> +    }
> +}
> +
>  static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
>  {
>      HWVoiceIn *hw = sw->hw;
> -    size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
> -    struct st_sample *src, *dst = sw->resample_buf.buffer;
> +    size_t samples, live, ret, swlim, total;
>
>      live = hw->total_samples_captured - sw->total_hw_samples_acquired;
>      if (!live) {
> @@ -558,33 +590,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
>          return 0;
>      }
>
> -    rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
> -
>      samples = size / sw->info.bytes_per_frame;
>
>      swlim = (live * sw->ratio) >> 32;
>      swlim = MIN (swlim, samples);
>
> -    while (swlim) {
> -        src = hw->conv_buf.buffer + rpos;
> -        if (hw->conv_buf.pos > rpos) {
> -            isamp = hw->conv_buf.pos - rpos;
> -        } else {
> -            isamp = hw->conv_buf.size - rpos;
> -        }
> -
> -        if (!isamp) {
> -            break;
> -        }
> -        osamp = swlim;
> -
> -        st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
> -        swlim -= osamp;
> -        rpos = (rpos + isamp) % hw->conv_buf.size;
> -        dst += osamp;
> -        ret += osamp;
> -        total += isamp;
> -    }
> +    audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
>
>      if (!hw->pcm_ops->volume_in) {
>          mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
> --
> 2.35.3
>


--
Marc-André Lureau