Skip to contentSkip to conversation

Allow hw/audio drivers to pass raw DB values to audio/ drivers

PATCH In review Yaroslav Isakov 3 participants 7 messages Dec 21, 2018 – Jan 7, 2019

lore
Share & tools
lore
#0 lore raw

cover Allow hw/audio drivers to pass raw DB values to audio/ drivers

This patch series introduces the ability for virtual audio drivers to pass information about guest-chosen DB values to backend audio drivers.

For now, supported virtual driver is hda-codec, and backend is pulseaudio, as they both support DB values.

Without these patches, emulated Windows has a very short range of hearable sound, as range in the guest is much smaller than in Pulseaudio.

Yaroslav Isakov (3):
Allow audio driver to pass DB value to underlying drivers Pass raw DB values from hda-codec.c to audio driver If raw DB values are known, use them in paaudio

 audio/audio.c               | 15 +++++++++++++--
 audio/audio.h               |  6 ++++--
 audio/mixeng.h              |  6 ++++--
 audio/paaudio.c             |  9 +++++++--
 hw/audio/ac97.c             |  4 ++--
 hw/audio/hda-codec-common.h |  2 +-
 hw/audio/hda-codec.c        | 12 ++++++++++--
 hw/audio/lm4549.c           |  2 +-
 hw/audio/wm8750.c           | 18 ++++++++++++------
 hw/display/xlnx_dp.c        |  3 ++-
 hw/usb/dev-audio.c          |  6 ++++--
 11 files changed, 60 insertions(+), 23 deletions(-)
Signature · 1 line
2.18.1
#1 lore raw

PATCH 1/3 Allow audio driver to pass DB value to underlying drivers

---
 audio/audio.c               | 15 +++++++++++++--
 audio/audio.h               |  6 ++++--
 audio/mixeng.h              |  6 ++++--
 hw/audio/ac97.c             |  4 ++--
 hw/audio/hda-codec-common.h |  2 +-
 hw/audio/hda-codec.c        |  8 ++++++--
 hw/audio/lm4549.c           |  2 +-
 hw/audio/wm8750.c           | 18 ++++++++++++------
 hw/display/xlnx_dp.c        |  3 ++-
 hw/usb/dev-audio.c          |  6 ++++--
 10 files changed, 49 insertions(+), 21 deletions(-)
audio/audio.c +13 -2
index 1ace47f510..939958d154 100644
@@ -146,6 +146,9 @@ const struct mixeng_volume nominal_volume = {
     .r = 1ULL << 32,
     .l = 1ULL << 32,
 #endif
+    .db_known = false,
+    .r_db = 0,
+    .l_db = 0
 };
 
 #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
@@ -2089,7 +2092,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
     }
 }
 
-void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
+void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol,
+                         bool db_known, double lvol_db, double rvol_db)
 {
     if (sw) {
         HWVoiceOut *hw = sw->hw;
@@ -2097,6 +2101,9 @@ void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
         sw->vol.mute = mute;
         sw->vol.l = nominal_volume.l * lvol / 255;
         sw->vol.r = nominal_volume.r * rvol / 255;
+        sw->vol.db_known = db_known;
+        sw->vol.l_db = lvol_db;
+        sw->vol.r_db = rvol_db;
 
         if (hw->pcm_ops->ctl_out) {
             hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw);
@@ -2104,7 +2111,8 @@ 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)
+void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol,
+                        bool db_known, double lvol_db, double rvol_db)
 {
     if (sw) {
         HWVoiceIn *hw = sw->hw;
@@ -2112,6 +2120,9 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
         sw->vol.mute = mute;
         sw->vol.l = nominal_volume.l * lvol / 255;
         sw->vol.r = nominal_volume.r * rvol / 255;
+        sw->vol.db_known = db_known;
+        sw->vol.l_db = lvol_db;
+        sw->vol.r_db = rvol_db;
 
         if (hw->pcm_ops->ctl_in) {
             hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw);
audio/audio.h +4 -2
index f4339a185e..5fe3841a74 100644
@@ -117,8 +117,10 @@ int  AUD_is_active_out (SWVoiceOut *sw);
 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);
+void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol,
+                         bool db_known, double lvol_db, double rvol_db);
+void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol,
+                        bool db_known, double lvol_db, double rvol_db);
 
 SWVoiceIn *AUD_open_in (
     QEMUSoundCard *card,
audio/mixeng.h +4 -2
index b53a5ef99a..e66f6c0e0a 100644
@@ -27,10 +27,12 @@
 
 #ifdef FLOAT_MIXENG
 typedef float mixeng_real;
-struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; };
+struct mixeng_volume { int mute; mixeng_real r; mixeng_real l;
+                       bool db_known; double r_db; double l_db; };
 struct st_sample { mixeng_real l; mixeng_real r; };
 #else
-struct mixeng_volume { int mute; int64_t r; int64_t l; };
+struct mixeng_volume { int mute; int64_t r; int64_t l;
+                       bool db_known; double r_db; double l_db;};
 struct st_sample { int64_t l; int64_t r; };
 #endif
 
hw/audio/ac97.c +2 -2
index d799533aa9..051f62acd9 100644
@@ -470,7 +470,7 @@ static void update_combined_volume_out (AC97LinkState *s)
     lvol = (lvol * plvol) / 255;
     rvol = (rvol * prvol) / 255;
 
-    AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
+    AUD_set_volume_out (s->voice_po, mute, lvol, rvol, false, 0, 0);
 }
 
 static void update_volume_in (AC97LinkState *s)
@@ -481,7 +481,7 @@ static void update_volume_in (AC97LinkState *s)
     get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0,
                 &mute, &lvol, &rvol);
 
-    AUD_set_volume_in (s->voice_pi, mute, lvol, rvol);
+    AUD_set_volume_in (s->voice_pi, mute, lvol, rvol, false, 0, 0);
 }
 
 static void set_volume (AC97LinkState *s, int index, uint32_t val)
hw/audio/hda-codec-common.h +1 -1
index b4fdb51e8b..59cbb7224e 100644
@@ -32,7 +32,7 @@
     (AC_AMPCAP_MUTE |                                                   \
      (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)    |                \
      (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |                \
-     (3                  << AC_AMPCAP_STEP_SIZE_SHIFT))
+     (QEMU_HDA_AMP_STEP_SIZE << AC_AMPCAP_STEP_SIZE_SHIFT))
 #else
 #define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
 #define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
hw/audio/hda-codec.c +6 -2
index 617a1c1016..09f9da344b 100644
@@ -119,6 +119,8 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
                               0x1fc /* 16 -> 96 kHz */)
 #define QEMU_HDA_AMP_NONE    (0)
 #define QEMU_HDA_AMP_STEPS   0x4a
+#define QEMU_HDA_AMP_STEP_SIZE 3
+#define QEMU_HDA_AMP_DB_OF_STEP ((QEMU_HDA_AMP_STEP_SIZE + 1) * 0.25)
 
 #define   PARAM mixemu
 #define   HDA_MIXER
@@ -451,9 +453,11 @@ static void hda_audio_set_amp(HDAAudioStream *st)
         return;
     }
     if (st->output) {
-        AUD_set_volume_out(st->voice.out, muted, left, right);
+        AUD_set_volume_out(st->voice.out, muted, left, right,
+                           false, 0, 0);
     } else {
-        AUD_set_volume_in(st->voice.in, muted, left, right);
+        AUD_set_volume_in(st->voice.in, muted, left, right,
+                          false, 0, 0);
     }
 }
 
hw/audio/lm4549.c +1 -1
index a46f2301af..6f0d0328c5 100644
@@ -304,7 +304,7 @@ void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
         &as
     );
 
-    AUD_set_volume_out(s->voice, 0, 255, 255);
+    AUD_set_volume_out(s->voice, 0, 255, 255, false, 0, 0);
 
     s->voice_is_active = 0;
 
hw/audio/wm8750.c +12 -6
index f4aa838f62..8127e3d440 100644
@@ -144,30 +144,36 @@ static void wm8750_vol_update(WM8750State *s)
 
     AUD_set_volume_in(s->adc_voice[0], s->mute,
                     s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
-                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]),
+                    false, 0, 0);
     AUD_set_volume_in(s->adc_voice[1], s->mute,
                     s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
-                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]),
+                    false, 0, 0);
     AUD_set_volume_in(s->adc_voice[2], s->mute,
                     s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
-                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]),
+                    false, 0, 0);
 
     /* 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_OUTVOL_TRANSFORM(s->outvol[4]),
-                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]),
+                    false, 0, 0);
 
     /* Headphone: LOUT1VOL ROUT1VOL */
     AUD_set_volume_out(s->dac_voice[1], s->mute,
                     s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
-                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]),
+                    false, 0, 0);
 
     /* MONOOUT: MONOVOL MONOVOL */
     AUD_set_volume_out(s->dac_voice[2], s->mute,
                     s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
-                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
+                    false, 0, 0);
 }
 
 static void wm8750_set_format(WM8750State *s)
hw/display/xlnx_dp.c +2 -1
index cc0f9bc9cc..948e05810b 100644
@@ -1271,7 +1271,8 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
                                            s,
                                            xlnx_dp_audio_callback,
                                            &as);
-    AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255);
+    AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255,
+                       false, 0, 0);
     xlnx_dp_audio_activate(s);
 }
 
hw/usb/dev-audio.c +4 -2
index ee43e4914d..355205f554 100644
@@ -500,7 +500,8 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
                     s->out.mute, s->out.vol[0], s->out.vol[1]);
         }
         AUD_set_volume_out(s->out.voice, s->out.mute,
-                           s->out.vol[0], s->out.vol[1]);
+                           s->out.vol[0], s->out.vol[1],
+                           false, 0, 0);
     }
 
     return ret;
@@ -653,7 +654,8 @@ static void usb_audio_realize(USBDevice *dev, Error **errp)
 
     s->out.voice = AUD_open_out(&s->card, s->out.voice, TYPE_USB_AUDIO,
                                 s, output_callback, &s->out.as);
-    AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
+    AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1],
+                       false, 0, 0);
     AUD_set_active_out(s->out.voice, 0);
 }
 
Signature · 1 line
2.18.1
#2 lore raw

PATCH 2/3 Pass raw DB values from hda-codec.c to audio driver

In reply to Yaroslav Isakov
---
 hw/audio/hda-codec.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
hw/audio/hda-codec.c +6 -2
index 09f9da344b..d160e86d2a 100644
@@ -437,6 +437,7 @@ static void hda_audio_set_amp(HDAAudioStream *st)
 {
     bool muted;
     uint32_t left, right;
+    double left_db, right_db;
 
     if (st->node == NULL) {
         return;
@@ -446,6 +447,9 @@ static void hda_audio_set_amp(HDAAudioStream *st)
     left  = st->mute_left  ? 0 : st->gain_left;
     right = st->mute_right ? 0 : st->gain_right;
 
+    left_db = ((int64_t)left - QEMU_HDA_AMP_STEPS) * QEMU_HDA_AMP_DB_OF_STEP;
+    right_db = ((int64_t)right - QEMU_HDA_AMP_STEPS) * QEMU_HDA_AMP_DB_OF_STEP;
+
     left = left * 255 / QEMU_HDA_AMP_STEPS;
     right = right * 255 / QEMU_HDA_AMP_STEPS;
 
@@ -454,10 +458,10 @@ static void hda_audio_set_amp(HDAAudioStream *st)
     }
     if (st->output) {
         AUD_set_volume_out(st->voice.out, muted, left, right,
-                           false, 0, 0);
+                           true, left_db, right_db);
     } else {
         AUD_set_volume_in(st->voice.in, muted, left, right,
-                          false, 0, 0);
+                          true, left_db, right_db);
     }
 }
 
Signature · 1 line
2.18.1
#3 lore raw

PATCH 3/3 If raw DB values are known, use them in paaudio

In reply to Yaroslav Isakov
---
 audio/paaudio.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
audio/paaudio.c +7 -2
index 4c100bc318..d25df102ab 100644
@@ -724,8 +724,13 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
             va_end (ap);
 
             v.channels = 2;
-            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
-            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
+            if (sw->vol.db_known) {
+                v.values[0] = pa_sw_volume_from_dB(sw->vol.l_db);
+                v.values[1] = pa_sw_volume_from_dB(sw->vol.r_db);
+            } else {
+                v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
+                v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
+            }
 
             pa_threaded_mainloop_lock (g->mainloop);
 
Signature · 1 line
2.18.1
#4 lore raw
In reply to Yaroslav Isakov

Sorry for a mess, forgot to add maintainer. Gerd, please, take a look at these patches.

пт, 21 дек. 2018 г. в 22:40, Yaroslav Isakov <[email protected]>:

Quoted 31 lines

This patch series introduces the ability for virtual audio drivers to pass information about guest-chosen DB values to backend audio drivers.

For now, supported virtual driver is hda-codec, and backend is pulseaudio, as they both support DB values.

Without these patches, emulated Windows has a very short range of hearable sound, as range in the guest is much smaller than in Pulseaudio.

Yaroslav Isakov (3):
Allow audio driver to pass DB value to underlying drivers Pass raw DB values from hda-codec.c to audio driver If raw DB values are known, use them in paaudio

 audio/audio.c               | 15 +++++++++++++--
 audio/audio.h               |  6 ++++--
 audio/mixeng.h              |  6 ++++--
 audio/paaudio.c             |  9 +++++++--
 hw/audio/ac97.c             |  4 ++--
 hw/audio/hda-codec-common.h |  2 +-
 hw/audio/hda-codec.c        | 12 ++++++++++--
 hw/audio/lm4549.c           |  2 +-
 hw/audio/wm8750.c           | 18 ++++++++++++------
 hw/display/xlnx_dp.c        |  3 ++-
 hw/usb/dev-audio.c          |  6 ++++--
 11 files changed, 60 insertions(+), 23 deletions(-)

--
2.18.1

#5 lore raw
In reply to Yaroslav Isakov
Patchew URL: https://patchew.org/QEMU/[email protected]/

Patchew URL: https://patchew.org/QEMU/[email protected]/

Hi,

This series seems to have some coding style problems. See output below for more information:

Message-id: [email protected]
Type: series
Subject: [Qemu-devel] [PATCH 0/3] Allow hw/audio drivers to pass raw DB values to audio/ drivers

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram

commits="$(git log --format=%H --reverse $BASE..)" for c in $commits; do

    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))

done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 Switched to a new branch 'test'
8eb6105 If raw DB values are known, use them in paaudio 5d986ae Pass raw DB values from hda-codec.c to audio driver 80db359 Allow audio driver to pass DB value to underlying drivers

=== OUTPUT BEGIN ===
Checking PATCH 1/3: Allow audio driver to pass DB value to underlying drivers...
ERROR: space required after that ';' (ctx:VxV)
#95: FILE: audio/mixeng.h:35:

+                       bool db_known; double r_db; double l_db;};
                                                               ^

total: 1 errors, 0 warnings, 193 lines checked

Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS.

Checking PATCH 2/3: Pass raw DB values from hda-codec.c to audio driver... Checking PATCH 3/3: If raw DB values are known, use them in paaudio...
ERROR: line over 90 characters
#23: FILE: audio/paaudio.c:731:
+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;

ERROR: line over 90 characters
#24: FILE: audio/paaudio.c:732:
+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;

total: 2 errors, 0 warnings, 15 lines checked

Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS.

=== OUTPUT END ===

Test command exited with code: 1

The full log is available at
http://patchew.org/logs/[email protected]/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to [email protected]

#6 lore raw
In reply to Yaroslav Isakov
Quoted 8 lines · Yaroslav Isakov

This patch series introduces the ability for virtual audio drivers to pass information about guest-chosen DB values to backend audio drivers.

For now, supported virtual driver is hda-codec, and backend is pulseaudio, as they both support DB values.

Without these patches, emulated Windows has a very short range of hearable sound, as range in the guest is much smaller than in Pulseaudio.

It's more useful to add support for converting db values to linear values, so it'll work properly with all backends not only pulse.

cheers,
Gerd