diff mbox series

[v2,04/17] audio: replace the resampling loop in audio_pcm_sw_write()

Message ID 20230206185237.8358-4-vr_qemu@t-online.de
State New
Headers show
Series audio: improve callback interface for audio frontends | expand

Commit Message

Volker Rümelin Feb. 6, 2023, 6:52 p.m. UTC
Replace the resampling loop in audio_pcm_sw_write() with the new
function audio_pcm_sw_resample_out(). 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 | 63 +++++++++++++++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 27 deletions(-)

Comments

Marc-André Lureau Feb. 22, 2023, 10:49 a.m. UTC | #1
Hi

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_write() with the new
> function audio_pcm_sw_resample_out(). 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>

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



> ---
>  audio/audio.c | 63 +++++++++++++++++++++++++++++----------------------
>  1 file changed, 36 insertions(+), 27 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index a399147486..4412b5fad8 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -673,11 +673,44 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
>  /*
>   * Soft voice (playback)
>   */
> +static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
> +    size_t frames_in_max, size_t frames_out_max,
> +    size_t *total_in, size_t *total_out)
> +{
> +    HWVoiceOut *hw = sw->hw;
> +    struct st_sample *src, *dst;
> +    size_t live, wpos, frames_in, frames_out;
> +
> +    live = sw->total_hw_samples_mixed;
> +    wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
> +
> +    /* write to mix_buf from wpos to end of buffer */
> +    src = sw->resample_buf.buffer;
> +    frames_in = frames_in_max;
> +    dst = hw->mix_buf.buffer + wpos;
> +    frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
> +    st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
> +    wpos += frames_out;
> +    *total_in = frames_in;
> +    *total_out = frames_out;
> +
> +    /* write to mix_buf from start of buffer if there are input frames left */
> +    if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
> +        src += frames_in;
> +        frames_in = frames_in_max - frames_in;
> +        dst = hw->mix_buf.buffer;
> +        frames_out = frames_out_max - frames_out;
> +        st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
> +        *total_in += frames_in;
> +        *total_out += frames_out;
> +    }
> +}
> +
>  static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
>  {
> -    size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
> +    size_t hwsamples, samples, live, dead;
>      size_t hw_free;
> -    size_t ret = 0, pos = 0, total = 0;
> +    size_t ret, total;
>
>      if (!sw) {
>          return size;
> @@ -698,8 +731,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
>          return 0;
>      }
>
> -    wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
> -
>      dead = hwsamples - live;
>      hw_free = audio_pcm_hw_get_free(sw->hw);
>      hw_free = hw_free > live ? hw_free - live : 0;
> @@ -713,29 +744,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
>          }
>      }
>
> -    while (samples) {
> -        dead = hwsamples - live;
> -        left = hwsamples - wpos;
> -        blck = MIN (dead, left);
> -        if (!blck) {
> -            break;
> -        }
> -        isamp = samples;
> -        osamp = blck;
> -        st_rate_flow_mix (
> -            sw->rate,
> -            sw->resample_buf.buffer + pos,
> -            sw->hw->mix_buf.buffer + wpos,
> -            &isamp,
> -            &osamp
> -            );
> -        ret += isamp;
> -        samples -= isamp;
> -        pos += isamp;
> -        live += osamp;
> -        wpos = (wpos + osamp) % hwsamples;
> -        total += osamp;
> -    }
> +    audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
>
>      sw->total_hw_samples_mixed += total;
>      sw->empty = sw->total_hw_samples_mixed == 0;
> --
> 2.35.3
>


--
Marc-André Lureau
diff mbox series

Patch

diff --git a/audio/audio.c b/audio/audio.c
index a399147486..4412b5fad8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -673,11 +673,44 @@  static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
 /*
  * Soft voice (playback)
  */
+static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
+    size_t frames_in_max, size_t frames_out_max,
+    size_t *total_in, size_t *total_out)
+{
+    HWVoiceOut *hw = sw->hw;
+    struct st_sample *src, *dst;
+    size_t live, wpos, frames_in, frames_out;
+
+    live = sw->total_hw_samples_mixed;
+    wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
+
+    /* write to mix_buf from wpos to end of buffer */
+    src = sw->resample_buf.buffer;
+    frames_in = frames_in_max;
+    dst = hw->mix_buf.buffer + wpos;
+    frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
+    st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
+    wpos += frames_out;
+    *total_in = frames_in;
+    *total_out = frames_out;
+
+    /* write to mix_buf from start of buffer if there are input frames left */
+    if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
+        src += frames_in;
+        frames_in = frames_in_max - frames_in;
+        dst = hw->mix_buf.buffer;
+        frames_out = frames_out_max - frames_out;
+        st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
+        *total_in += frames_in;
+        *total_out += frames_out;
+    }
+}
+
 static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
 {
-    size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
+    size_t hwsamples, samples, live, dead;
     size_t hw_free;
-    size_t ret = 0, pos = 0, total = 0;
+    size_t ret, total;
 
     if (!sw) {
         return size;
@@ -698,8 +731,6 @@  static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         return 0;
     }
 
-    wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
-
     dead = hwsamples - live;
     hw_free = audio_pcm_hw_get_free(sw->hw);
     hw_free = hw_free > live ? hw_free - live : 0;
@@ -713,29 +744,7 @@  static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
         }
     }
 
-    while (samples) {
-        dead = hwsamples - live;
-        left = hwsamples - wpos;
-        blck = MIN (dead, left);
-        if (!blck) {
-            break;
-        }
-        isamp = samples;
-        osamp = blck;
-        st_rate_flow_mix (
-            sw->rate,
-            sw->resample_buf.buffer + pos,
-            sw->hw->mix_buf.buffer + wpos,
-            &isamp,
-            &osamp
-            );
-        ret += isamp;
-        samples -= isamp;
-        pos += isamp;
-        live += osamp;
-        wpos = (wpos + osamp) % hwsamples;
-        total += osamp;
-    }
+    audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
 
     sw->total_hw_samples_mixed += total;
     sw->empty = sw->total_hw_samples_mixed == 0;