qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@web.de>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] wm8750: Soft-volume control for OUT2
Date: Sat, 19 Apr 2008 21:59:35 +0200	[thread overview]
Message-ID: <480A4F27.70708@web.de> (raw)

This adds basic soft-volume control to the Wolfson 8750. Only OUT2 is
considered so far. The critical path of the calculation is built on
scaled math, thus should be fairly efficient (though, given the low
sound data rates, one will have a hard time to notice this on todays
hardware :)). I twisted my brain several times, but I can't guarantee I
got endianness right (if you are on big endian, be warned, keep your
volume low :)).

Note that I ported the volume mapping from the MusicPal patch. For that
device, the mapping allows to play with the volume while being able to
hear an effect even if the host volume is not at its limit. Please check
if this is not due to some MusicPal properties, in which case the
mapping should become tunable. Avoiding positive gains should
unconditionally make sense, though.

Signed-off-by: Jan Kiszka <jan.kiszka@web.de> 
---
 hw/wm8750.c |   33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

Index: b/hw/wm8750.c
===================================================================
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -7,6 +7,8 @@
  * This file is licensed under GNU GPL.
  */
 
+#include <math.h>
+
 #include "hw.h"
 #include "i2c.h"
 #include "audio/audio.h"
@@ -34,6 +36,7 @@ struct wm8750_s {
 
     SWVoiceOut **out[2];
     uint8_t outvol[7], outmute[2];
+    int out2vol_mult[2];
     SWVoiceIn **in[2];
     uint8_t invol[4], inmute[2];
 
@@ -166,11 +169,11 @@ static void wm8750_set_format(struct wm8
                     CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
 
     /* Setup output */
-    out_fmt.endianness = 0;
+    out_fmt.endianness = AUDIO_HOST_ENDIANNESS;
     out_fmt.nchannels = 2;
     out_fmt.freq = s->rate->dac_hz;
     out_fmt.fmt = AUD_FMT_S16;
-    monoout_fmt.endianness = 0;
+    monoout_fmt.endianness = AUDIO_HOST_ENDIANNESS;
     monoout_fmt.nchannels = 1;
     monoout_fmt.freq = s->rate->dac_hz;
     monoout_fmt.fmt = AUD_FMT_S16;
@@ -314,6 +317,7 @@ static int wm8750_tx(i2c_slave *i2c, uin
     struct wm8750_s *s = (struct wm8750_s *) i2c;
     uint8_t cmd;
     uint16_t value;
+    int vol;
 
     if (s->i2c_len >= 2) {
         printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
@@ -440,7 +444,12 @@ static int wm8750_tx(i2c_slave *i2c, uin
         break;
 
     case WM8750_LOUT2V:	/* LOUT2 Volume */
-        s->outvol[4] = value & 0x7f;		/* LOUT2VOL */
+        s->outvol[4] = vol = value & 0x7f;	/* LOUT2VOL */
+        /* Map volume:
+         *  - no positive gain (avoid clipping)
+         *  - smaller range */
+        vol = (vol - 0x7F) / 3;
+        s->out2vol_mult[0] = pow(10.0, vol/20.0) * 65536.0;
         break;
 
     case WM8750_ROUT1V:	/* ROUT1 Volume */
@@ -448,7 +457,12 @@ static int wm8750_tx(i2c_slave *i2c, uin
         break;
 
     case WM8750_ROUT2V:	/* ROUT2 Volume */
-        s->outvol[5] = value & 0x7f;		/* ROUT2VOL */
+        s->outvol[5] = vol = value & 0x7f;	/* ROUT2VOL */
+        /* Map volume:
+         *  - no positive gain (avoid clipping)
+         *  - smaller range */
+        vol = (vol - 0x7F) / 3;
+        s->out2vol_mult[1] = pow(10.0, vol/20.0) * 65536.0;
         break;
 
     case WM8750_MOUTV:	/* MONOOUT Volume */
@@ -616,8 +630,15 @@ void wm8750_data_req_set(i2c_slave *i2c,
 void wm8750_dac_dat(void *opaque, uint32_t sample)
 {
     struct wm8750_s *s = (struct wm8750_s *) opaque;
-    uint32_t *data = (uint32_t *) &s->data_out[s->idx_out];
-    *data = sample & s->outmask;
+    uint16_t *data = (uint16_t *) &s->data_out[s->idx_out];
+    int32_t tmp;
+
+    tmp = ((int16_t)le16_to_cpu((sample & s->outmask) & 0xFFFF) *
+            s->out2vol_mult[1]) >> 16;
+    *data++ = tmp;
+    tmp = ((int16_t)le16_to_cpu((sample & s->outmask) >> 16) *
+            s->out2vol_mult[0]) >> 16;
+    *data = tmp;
     s->req_out -= 4;
     s->idx_out += 4;
     if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)

                 reply	other threads:[~2008-04-19 19:59 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=480A4F27.70708@web.de \
    --to=jan.kiszka@web.de \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).