sdlaudio: make it suck less

Signed-off-by: malc <av1474@comtv.ru>
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 8e7e5cb..aa39c33 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -41,8 +41,8 @@
 typedef struct SDLVoiceOut {
     HWVoiceOut hw;
     int live;
-    int rpos;
     int decr;
+    int pending;
 } SDLVoiceOut;
 
 static struct {
@@ -225,6 +225,10 @@
     HWVoiceOut *hw = &sdl->hw;
     int samples = len >> hw->info.shift;
 
+    if (sdl_lock (s, "sdl_callback")) {
+        return;
+    }
+
     if (s->exit) {
         return;
     }
@@ -232,49 +236,34 @@
     while (samples) {
         int to_mix, decr;
 
-        /* dolog ("in callback samples=%d\n", samples); */
-        sdl_wait (s, "sdl_callback");
-        if (s->exit) {
-            return;
+        while (!sdl->pending) {
+            if (sdl_unlock (s, "sdl_callback")) {
+                return;
+            }
+
+            sdl_wait (s, "sdl_callback");
+            if (s->exit) {
+                return;
+            }
+
+            if (sdl_lock (s, "sdl_callback")) {
+                return;
+            }
+            sdl->pending += sdl->live;
+            sdl->live = 0;
         }
 
-        if (sdl_lock (s, "sdl_callback")) {
-            return;
-        }
-
-        if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
-            dolog ("sdl->live=%d hw->samples=%d\n",
-                   sdl->live, hw->samples);
-            return;
-        }
-
-        if (!sdl->live) {
-            goto again;
-        }
-
-        /* dolog ("in callback live=%d\n", live); */
-        to_mix = audio_MIN (samples, sdl->live);
-        decr = to_mix;
-        while (to_mix) {
-            int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
-            struct st_sample *src = hw->mix_buf + hw->rpos;
-
-            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
-            hw->clip (buf, src, chunk);
-            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
-            to_mix -= chunk;
-            buf += chunk << hw->info.shift;
-        }
+        to_mix = audio_MIN (samples, sdl->pending);
+        decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
+        buf += decr << hw->info.shift;
         samples -= decr;
-        sdl->live -= decr;
         sdl->decr += decr;
-
-    again:
-        if (sdl_unlock (s, "sdl_callback")) {
-            return;
-        }
+        sdl->pending -= decr;
     }
-    /* dolog ("done len=%d\n", len); */
+
+    if (sdl_unlock (s, "sdl_callback")) {
+        return;
+    }
 }
 
 static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
@@ -292,18 +281,9 @@
         return 0;
     }
 
-    if (sdl->decr > live) {
-        ldebug ("sdl->decr %d live %d sdl->live %d\n",
-                sdl->decr,
-                live,
-                sdl->live);
-    }
-
-    decr = audio_MIN (sdl->decr, live);
-    sdl->decr -= decr;
-
-    sdl->live = live - decr;
-    hw->rpos = sdl->rpos;
+    sdl->live = live;
+    decr = sdl->decr;
+    sdl->decr = 0;
 
     if (sdl->live > 0) {
         sdl_unlock_and_post (s, "sdl_run_out");