audio: split sample conversion and volume mixing

Refactor the volume mixing, so it can be reused for capturing devices.
Additionally, it removes superfluous multiplications with the nominal
volume within the hardware voice code path.

Signed-off-by: Michael Walle <michael@walle.cc>
Signed-off-by: malc <av1474@comtv.ru>
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 727b9f8..4d72014 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -1097,7 +1097,7 @@
                 }
             }
 
-            hw->conv (dst, src, nread, &nominal_volume);
+            hw->conv (dst, src, nread);
 
             src = advance (src, nread << hwshift);
             dst += nread;
diff --git a/audio/audio.c b/audio/audio.c
index 1707446..1729c0b 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -104,7 +104,7 @@
 
 static AudioState glob_audio_state;
 
-struct mixeng_volume nominal_volume = {
+const struct mixeng_volume nominal_volume = {
     .mute = 0,
 #ifdef FLOAT_MIXENG
     .r = 1.0,
@@ -702,13 +702,11 @@
 /*
  * Capture
  */
-static void noop_conv (struct st_sample *dst, const void *src,
-                       int samples, struct mixeng_volume *vol)
+static void noop_conv (struct st_sample *dst, const void *src, int samples)
 {
     (void) src;
     (void) dst;
     (void) samples;
-    (void) vol;
 }
 
 static CaptureVoiceOut *audio_pcm_capture_find_specific (
@@ -956,6 +954,8 @@
         total += isamp;
     }
 
+    mixeng_volume (sw->buf, ret, &sw->vol);
+
     sw->clip (buf, sw->buf, ret);
     sw->total_hw_samples_acquired += total;
     return ret << sw->info.shift;
@@ -1037,7 +1037,8 @@
     swlim = ((int64_t) dead << 32) / sw->ratio;
     swlim = audio_MIN (swlim, samples);
     if (swlim) {
-        sw->conv (sw->buf, buf, swlim, &sw->vol);
+        sw->conv (sw->buf, buf, swlim);
+        mixeng_volume (sw->buf, swlim, &sw->vol);
     }
 
     while (swlim) {
diff --git a/audio/audio_int.h b/audio/audio_int.h
index d66f2c3..2003f8b 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -211,7 +211,7 @@
 extern struct audio_driver pa_audio_driver;
 extern struct audio_driver spice_audio_driver;
 extern struct audio_driver winwave_audio_driver;
-extern struct mixeng_volume nominal_volume;
+extern const struct mixeng_volume nominal_volume;
 
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index e547955..e2d89fd 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -831,11 +831,11 @@
     decr = len1 + len2;
 
     if (p1 && len1) {
-        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+        hw->conv (hw->conv_buf + hw->wpos, p1, len1);
     }
 
     if (p2 && len2) {
-        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+        hw->conv (hw->conv_buf, p2, len2);
     }
 
     dsound_unlock_in (dscb, p1, p2, blen1, blen2);
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
index 9a1f2f8..ff97b39 100644
--- a/audio/esdaudio.c
+++ b/audio/esdaudio.c
@@ -346,8 +346,7 @@
                 break;
             }
 
-            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
-                      &nominal_volume);
+            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
             wpos = (wpos + chunk) % hw->samples;
             to_grab -= chunk;
         }
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index 7f08e14..c34cf53 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -488,10 +488,10 @@
     decr = len1 + len2;
 
     if (p1 && blen1) {
-        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+        hw->conv (hw->conv_buf + hw->wpos, p1, len1);
     }
     if (p2 && len2) {
-        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+        hw->conv (hw->conv_buf, p2, len2);
     }
 
     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 9f1d93f..4a9e8eb 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -333,3 +333,28 @@
 {
     memset (buf, 0, len * sizeof (struct st_sample));
 }
+
+void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol)
+{
+#ifdef CONFIG_MIXEMU
+    if (vol->mute) {
+        mixeng_clear (buf, len);
+        return;
+    }
+
+    while (len--) {
+#ifdef FLOAT_MIXENG
+        buf->l = buf->l * vol->l;
+        buf->r = buf->r * vol->r;
+#else
+        buf->l = (buf->l * vol->l) >> 32;
+        buf->r = (buf->r * vol->r) >> 32;
+#endif
+        buf += 1;
+    }
+#else
+    (void) buf;
+    (void) len;
+    (void) vol;
+#endif
+}
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 4af1dd9..9de443b 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -33,8 +33,7 @@
 struct st_sample { int64_t l; int64_t r; };
 #endif
 
-typedef void (t_sample) (struct st_sample *dst, const void *src,
-                         int samples, struct mixeng_volume *vol);
+typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
 typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
 
 extern t_sample *mixeng_conv[2][2][2][3];
@@ -47,5 +46,6 @@
                        int *isamp, int *osamp);
 void st_rate_stop (void *opaque);
 void mixeng_clear (struct st_sample *buf, int len);
+void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
 
 #endif  /* mixeng.h */
diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h
index 5617705..a2d0ef8 100644
--- a/audio/mixeng_template.h
+++ b/audio/mixeng_template.h
@@ -31,16 +31,6 @@
 #define HALF (IN_MAX >> 1)
 #endif
 
-#ifdef CONFIG_MIXEMU
-#ifdef FLOAT_MIXENG
-#define VOL(a, b) ((a) * (b))
-#else
-#define VOL(a, b) ((a) * (b)) >> 32
-#endif
-#else
-#define VOL(a, b) a
-#endif
-
 #define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
 
 #ifdef FLOAT_MIXENG
@@ -109,40 +99,26 @@
 #endif
 
 static void glue (glue (conv_, ET), _to_stereo)
-    (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
+    (struct st_sample *dst, const void *src, int samples)
 {
     struct st_sample *out = dst;
     IN_T *in = (IN_T *) src;
-#ifdef CONFIG_MIXEMU
-    if (vol->mute) {
-        mixeng_clear (dst, samples);
-        return;
-    }
-#else
-    (void) vol;
-#endif
+
     while (samples--) {
-        out->l = VOL (glue (conv_, ET) (*in++), vol->l);
-        out->r = VOL (glue (conv_, ET) (*in++), vol->r);
+        out->l = glue (conv_, ET) (*in++);
+        out->r = glue (conv_, ET) (*in++);
         out += 1;
     }
 }
 
 static void glue (glue (conv_, ET), _to_mono)
-    (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
+    (struct st_sample *dst, const void *src, int samples)
 {
     struct st_sample *out = dst;
     IN_T *in = (IN_T *) src;
-#ifdef CONFIG_MIXEMU
-    if (vol->mute) {
-        mixeng_clear (dst, samples);
-        return;
-    }
-#else
-    (void) vol;
-#endif
+
     while (samples--) {
-        out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
+        out->l = glue (conv_, ET) (in[0]);
         out->r = out->l;
         out += 1;
         in += 1;
@@ -174,4 +150,3 @@
 
 #undef ET
 #undef HALF
-#undef VOL
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index d7a55e5..b49e102 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -788,8 +788,7 @@
                            hw->info.align + 1);
                 }
                 read_samples += nread >> hwshift;
-                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
-                          &nominal_volume);
+                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
             }
 
             if (bufs[i].len - nread) {
diff --git a/audio/paaudio.c b/audio/paaudio.c
index ff71dac..9cf685d 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -195,7 +195,7 @@
                 return NULL;
             }
 
-            hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
+            hw->conv (hw->conv_buf + wpos, buf, chunk);
             wpos = (wpos + chunk) % hw->samples;
             to_grab -= chunk;
         }
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 373e4c4..a5c0d6b 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -268,11 +268,10 @@
         len[1] = 0;
     }
 
-    hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
+    hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
 
     if (len[1]) {
-        hw->conv (hw->conv_buf, samples + len[0], len[1],
-                  &nominal_volume);
+        hw->conv (hw->conv_buf, samples + len[0], len[1]);
     }
 
     hw->wpos = (hw->wpos + num_samples) % hw->samples;
diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c
index cdf483b..e5ad3c6 100644
--- a/audio/winwaveaudio.c
+++ b/audio/winwaveaudio.c
@@ -581,8 +581,7 @@
         int conv = audio_MIN (left, decr);
         hw->conv (hw->conv_buf + hw->wpos,
                   advance (wave->pcm_buf, wave->rpos << hw->info.shift),
-                  conv,
-                  &nominal_volume);
+                  conv);
 
         wave->rpos = (wave->rpos + conv) % hw->samples;
         hw->wpos = (hw->wpos + conv) % hw->samples;