qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Andrzej Zaborowski <balrogg@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [4321] First cut at WM8750 volume control (Jan Kiszka).
Date: Sun, 04 May 2008 10:21:05 +0000	[thread overview]
Message-ID: <E1JsbL7-0001en-7L@cvs.savannah.gnu.org> (raw)

Revision: 4321
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4321
Author:   balrog
Date:     2008-05-04 10:21:03 +0000 (Sun, 04 May 2008)

Log Message:
-----------
First cut at WM8750 volume control (Jan Kiszka).

Modified Paths:
--------------
    trunk/audio/audio.c
    trunk/audio/audio.h
    trunk/hw/wm8750.c

Modified: trunk/audio/audio.c
===================================================================
--- trunk/audio/audio.c	2008-05-04 08:16:10 UTC (rev 4320)
+++ trunk/audio/audio.c	2008-05-04 10:21:03 UTC (rev 4321)
@@ -117,8 +117,8 @@
     1.0,
     1.0
 #else
-    UINT_MAX,
-    UINT_MAX
+    1ULL << 32,
+    1ULL << 32
 #endif
 };
 
@@ -1955,3 +1955,21 @@
         }
     }
 }
+
+void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
+{
+    if (sw) {
+        sw->vol.mute = mute;
+        sw->vol.l = nominal_volume.l * lvol / 255;
+        sw->vol.r = nominal_volume.r * rvol / 255;
+    }
+}
+
+void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
+{
+    if (sw) {
+        sw->vol.mute = mute;
+        sw->vol.l = nominal_volume.l * lvol / 255;
+        sw->vol.r = nominal_volume.r * rvol / 255;
+    }
+}

Modified: trunk/audio/audio.h
===================================================================
--- trunk/audio/audio.h	2008-05-04 08:16:10 UTC (rev 4320)
+++ trunk/audio/audio.h	2008-05-04 10:21:03 UTC (rev 4321)
@@ -124,6 +124,9 @@
 void     AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
 uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
 
+void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol);
+void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol);
+
 SWVoiceIn *AUD_open_in (
     QEMUSoundCard *card,
     SWVoiceIn *sw,

Modified: trunk/hw/wm8750.c
===================================================================
--- trunk/hw/wm8750.c	2008-05-04 08:16:10 UTC (rev 4320)
+++ trunk/hw/wm8750.c	2008-05-04 10:21:03 UTC (rev 4321)
@@ -39,10 +39,18 @@
 
     uint8_t diff[2], pol, ds, monomix[2], alc, mute;
     uint8_t path[4], mpath[2], power, format;
-    uint32_t inmask, outmask;
     const struct wm_rate_s *rate;
 };
 
+/* pow(10.0, -i / 20.0), i = 0..42 */
+static const uint8_t wm8750_vol_db_table[] = {
+    255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
+    40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
+    4, 4, 3, 3, 3, 2, 2
+};
+
+#define WM8750_VOL_TRANSFORM(x)	wm8750_vol_db_table[(0x7f - x) / 3]
+
 static inline void wm8750_in_load(struct wm8750_s *s)
 {
     int acquired;
@@ -125,6 +133,32 @@
     {  192, 88200,  192, 88200 },	/* SR: 11111 */
 };
 
+static void wm8750_vol_update(struct wm8750_s *s)
+{
+    /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
+
+    AUD_set_volume_in(*s->in[0], s->mute,
+                    s->inmute[0] ? 0 : 0xff,
+                    s->inmute[1] ? 0 : 0xff);
+
+    /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
+
+    /* Speaker: LOUT2VOL ROUT2VOL */
+    AUD_set_volume_out(s->dac_voice[0], s->mute,
+                    s->outmute[0] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[4]),
+                    s->outmute[1] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[5]));
+
+    /* Headphone: LOUT2VOL ROUT2VOL */
+    AUD_set_volume_out(s->dac_voice[1], s->mute,
+                    s->outmute[0] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[2]),
+                    s->outmute[1] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[3]));
+
+    /* MONOOUT: MONOVOL MONOVOL */
+    AUD_set_volume_out(s->dac_voice[2], s->mute,
+                    s->outmute[0] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[6]),
+                    s->outmute[1] ? 0 : WM8750_VOL_TRANSFORM(s->outvol[6]));
+}
+
 static void wm8750_set_format(struct wm8750_s *s)
 {
     int i;
@@ -185,6 +219,8 @@
                     CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
     /* no sense emulating OUT3 which is a mix of other outputs */
 
+    wm8750_vol_update(s);
+
     /* We should connect the left and right channels to their
      * respective inputs/outputs but we have completely no need
      * for mixing or combining paths to different ports, so we
@@ -195,22 +231,6 @@
         AUD_set_active_out(*s->out[0], 1);
 }
 
-static void inline wm8750_mask_update(struct wm8750_s *s)
-{
-#define R_ONLY	0x0000ffff
-#define L_ONLY	0xffff0000
-#define BOTH	(R_ONLY | L_ONLY)
-#define NONE	(R_ONLY & L_ONLY)
-    s->inmask =
-            (s->inmute[0] ? R_ONLY : BOTH) &
-            (s->inmute[1] ? L_ONLY : BOTH) &
-            (s->mute ? NONE : BOTH);
-    s->outmask =
-            (s->outmute[0] ? R_ONLY : BOTH) &
-            (s->outmute[1] ? L_ONLY : BOTH) &
-            (s->mute ? NONE : BOTH);
-}
-
 void wm8750_reset(i2c_slave *i2c)
 {
     struct wm8750_s *s = (struct wm8750_s *) i2c;
@@ -249,7 +269,7 @@
     s->req_in = 0;
     s->idx_out = 0;
     s->req_out = 0;
-    wm8750_mask_update(s);
+    wm8750_vol_update(s);
     s->i2c_len = 0;
 }
 
@@ -367,19 +387,19 @@
     case WM8750_LINVOL:	/* Left Channel PGA */
         s->invol[0] = value & 0x3f;		/* LINVOL */
         s->inmute[0] = (value >> 7) & 1;	/* LINMUTE */
-        wm8750_mask_update(s);
+        wm8750_vol_update(s);
         break;
 
     case WM8750_RINVOL:	/* Right Channel PGA */
         s->invol[1] = value & 0x3f;		/* RINVOL */
         s->inmute[1] = (value >> 7) & 1;	/* RINMUTE */
-        wm8750_mask_update(s);
+        wm8750_vol_update(s);
         break;
 
     case WM8750_ADCDAC:	/* ADC and DAC Control */
         s->pol = (value >> 5) & 3;		/* ADCPOL */
         s->mute = (value >> 3) & 1;		/* DACMU */
-        wm8750_mask_update(s);
+        wm8750_vol_update(s);
         break;
 
     case WM8750_ADCTL3:	/* Additional Control (3) */
@@ -437,19 +457,21 @@
         break;
 
     case WM8750_LOUT1V:	/* LOUT1 Volume */
-        s->outvol[2] = value & 0x7f;		/* LOUT2VOL */
+        s->outvol[2] = value & 0x7f;		/* LOUT1VOL */
         break;
 
     case WM8750_LOUT2V:	/* LOUT2 Volume */
         s->outvol[4] = value & 0x7f;		/* LOUT2VOL */
+        wm8750_vol_update(s);
         break;
 
     case WM8750_ROUT1V:	/* ROUT1 Volume */
-        s->outvol[3] = value & 0x7f;		/* ROUT2VOL */
+        s->outvol[3] = value & 0x7f;		/* ROUT1VOL */
         break;
 
     case WM8750_ROUT2V:	/* ROUT2 Volume */
         s->outvol[5] = value & 0x7f;		/* ROUT2VOL */
+        wm8750_vol_update(s);
         break;
 
     case WM8750_MOUTV:	/* MONOOUT Volume */
@@ -531,8 +553,6 @@
         qemu_put_8s(f, &s->mpath[i]);
     qemu_put_8s(f, &s->format);
     qemu_put_8s(f, &s->power);
-    qemu_put_be32s(f, &s->inmask);
-    qemu_put_be32s(f, &s->outmask);
     qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
     i2c_slave_save(f, &s->i2c);
 }
@@ -573,8 +593,6 @@
         qemu_get_8s(f, &s->mpath[i]);
     qemu_get_8s(f, &s->format);
     qemu_get_8s(f, &s->power);
-    qemu_get_be32s(f, &s->inmask);
-    qemu_get_be32s(f, &s->outmask);
     s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
     i2c_slave_load(f, &s->i2c);
     return 0;
@@ -619,8 +637,7 @@
 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;
+    *(uint32_t *) &s->data_out[s->idx_out] = sample;
     s->req_out -= 4;
     s->idx_out += 4;
     if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
@@ -654,5 +671,5 @@
     data = (uint32_t *) &s->data_in[s->idx_in];
     s->req_in -= 4;
     s->idx_in += 4;
-    return *data & s->inmask;
+    return *data;
 }

             reply	other threads:[~2008-05-04 10:21 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-04 10:21 Andrzej Zaborowski [this message]
2008-05-04 10:47 ` [Qemu-devel] [4321] First cut at WM8750 volume control (Jan Kiszka) Jan Kiszka
2008-05-04 12:31   ` andrzej zaborowski
2008-05-04 15:49     ` andrzej zaborowski
2008-05-04 17:31       ` Jan Kiszka
2008-05-04 17:31     ` Jan Kiszka
2008-05-04 23:59       ` andrzej zaborowski
2008-05-05 18:43         ` [Qemu-devel] [PATCH] Enable volume control globally (was: First cut at WM8750 volume control) Jan Kiszka
2008-05-04 21:33     ` [Qemu-devel] [PATCH] musicpal: doc fragment Jan Kiszka

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=E1JsbL7-0001en-7L@cvs.savannah.gnu.org \
    --to=balrogg@gmail.com \
    --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).