* [Qemu-devel] [PATCH] wm8750: Soft-volume control for OUT2
@ 2008-04-19 19:59 Jan Kiszka
0 siblings, 0 replies; only message in thread
From: Jan Kiszka @ 2008-04-19 19:59 UTC (permalink / raw)
To: qemu-devel
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)
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2008-04-19 19:59 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-19 19:59 [Qemu-devel] [PATCH] wm8750: Soft-volume control for OUT2 Jan Kiszka
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).