From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JnJDn-0002xN-Mt for qemu-devel@nongnu.org; Sat, 19 Apr 2008 15:59:39 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JnJDl-0002xB-Ag for qemu-devel@nongnu.org; Sat, 19 Apr 2008 15:59:38 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JnJDl-0002x8-4a for qemu-devel@nongnu.org; Sat, 19 Apr 2008 15:59:37 -0400 Received: from fmmailgate01.web.de ([217.72.192.221]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1JnJDk-0003EK-FJ for qemu-devel@nongnu.org; Sat, 19 Apr 2008 15:59:36 -0400 Received: from smtp07.web.de (fmsmtp07.dlan.cinetic.de [172.20.5.215]) by fmmailgate01.web.de (Postfix) with ESMTP id BBD89DBEFD83 for ; Sat, 19 Apr 2008 21:59:35 +0200 (CEST) Received: from [88.64.18.144] (helo=[192.168.1.198]) by smtp07.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.109 #226) id 1JnJDj-00029Q-00 for qemu-devel@nongnu.org; Sat, 19 Apr 2008 21:59:35 +0200 Message-ID: <480A4F27.70708@web.de> Date: Sat, 19 Apr 2008 21:59:35 +0200 From: Jan Kiszka MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-15 Sender: jan.kiszka@web.de Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH] wm8750: Soft-volume control for OUT2 Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 =20 --- hw/wm8750.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) Index: b/hw/wm8750.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -7,6 +7,8 @@ * This file is licensed under GNU GPL. */ =20 +#include + #include "hw.h" #include "i2c.h" #include "audio/audio.h" @@ -34,6 +36,7 @@ struct wm8750_s { =20 SWVoiceOut **out[2]; uint8_t outvol[7], outmute[2]; + int out2vol_mult[2]; SWVoiceIn **in[2]; uint8_t invol[4], inmute[2]; =20 @@ -166,11 +169,11 @@ static void wm8750_set_format(struct wm8 CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt); =20 /* Setup output */ - out_fmt.endianness =3D 0; + out_fmt.endianness =3D AUDIO_HOST_ENDIANNESS; out_fmt.nchannels =3D 2; out_fmt.freq =3D s->rate->dac_hz; out_fmt.fmt =3D AUD_FMT_S16; - monoout_fmt.endianness =3D 0; + monoout_fmt.endianness =3D AUDIO_HOST_ENDIANNESS; monoout_fmt.nchannels =3D 1; monoout_fmt.freq =3D s->rate->dac_hz; monoout_fmt.fmt =3D AUD_FMT_S16; @@ -314,6 +317,7 @@ static int wm8750_tx(i2c_slave *i2c, uin struct wm8750_s *s =3D (struct wm8750_s *) i2c; uint8_t cmd; uint16_t value; + int vol; =20 if (s->i2c_len >=3D 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; =20 case WM8750_LOUT2V: /* LOUT2 Volume */ - s->outvol[4] =3D value & 0x7f; /* LOUT2VOL */ + s->outvol[4] =3D vol =3D value & 0x7f; /* LOUT2VOL */ + /* Map volume: + * - no positive gain (avoid clipping) + * - smaller range */ + vol =3D (vol - 0x7F) / 3; + s->out2vol_mult[0] =3D pow(10.0, vol/20.0) * 65536.0; break; =20 case WM8750_ROUT1V: /* ROUT1 Volume */ @@ -448,7 +457,12 @@ static int wm8750_tx(i2c_slave *i2c, uin break; =20 case WM8750_ROUT2V: /* ROUT2 Volume */ - s->outvol[5] =3D value & 0x7f; /* ROUT2VOL */ + s->outvol[5] =3D vol =3D value & 0x7f; /* ROUT2VOL */ + /* Map volume: + * - no positive gain (avoid clipping) + * - smaller range */ + vol =3D (vol - 0x7F) / 3; + s->out2vol_mult[1] =3D pow(10.0, vol/20.0) * 65536.0; break; =20 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 =3D (struct wm8750_s *) opaque; - uint32_t *data =3D (uint32_t *) &s->data_out[s->idx_out]; - *data =3D sample & s->outmask; + uint16_t *data =3D (uint16_t *) &s->data_out[s->idx_out]; + int32_t tmp; + + tmp =3D ((int16_t)le16_to_cpu((sample & s->outmask) & 0xFFFF) * + s->out2vol_mult[1]) >> 16; + *data++ =3D tmp; + tmp =3D ((int16_t)le16_to_cpu((sample & s->outmask) >> 16) * + s->out2vol_mult[0]) >> 16; + *data =3D tmp; s->req_out -=3D 4; s->idx_out +=3D 4; if (s->idx_out >=3D sizeof(s->data_out) || s->req_out <=3D 0)