Skip to content

Commit

Permalink
ALSA: usb-audio: Add a more accurate volume quirk for AudioQuest Drag…
Browse files Browse the repository at this point in the history
…onFly

AudioQuest DragonFly DAC reports a volume control range of 0..50
(0x0000..0x0032) which in USB Audio means a range of 0 .. 0.2dB, which
is obviously incorrect and would cause software using the dB information
in e.g. volume sliders to have a massive volume difference in 100..102%
range.

Commit 2d1cb7f ("ALSA: usb-audio: add dB range mapping for some
devices") added a dB range mapping for it with range 0..50 dB.

However, the actual volume mapping seems to be neither linear volume nor
linear dB scale, but instead quite close to the cubic mapping e.g.
alsamixer uses, with a range of approx. -53...0 dB.

Replace the previous quirk with a custom dB mapping based on some basic
output measurements, using a 10-item range TLV (which will still fit in
alsa-lib MAX_TLV_RANGE_SIZE).

Tested on AudioQuest DragonFly HW v1.2. The quirk is only applied if the
range is 0..50, so if this gets fixed/changed in later HW revisions it
will no longer be applied.

v2: incorporated Takashi Iwai's suggestion for the quirk application
method

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Anssi Hannula authored and Takashi Iwai committed Dec 14, 2015
1 parent 9f9499a commit 42e3121
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 12 deletions.
2 changes: 2 additions & 0 deletions sound/usb/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
}

snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl);

range = (cval->max - cval->min) / cval->res;
/*
* Are there devices with volume range more than 255? I use a bit more
Expand Down
12 changes: 0 additions & 12 deletions sound/usb/mixer_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,13 +348,6 @@ static struct usbmix_name_map bose_companion5_map[] = {
{ 0 } /* terminator */
};

/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */
static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000};
static struct usbmix_name_map dragonfly_1_2_map[] = {
{ 7, NULL, .dB = &dragonfly_1_2_dB },
{ 0 } /* terminator */
};

/*
* Control map entries
*/
Expand Down Expand Up @@ -470,11 +463,6 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x05a7, 0x1020),
.map = bose_companion5_map,
},
{
/* Dragonfly DAC 1.2 */
.id = USB_ID(0x21b4, 0x0081),
.map = dragonfly_1_2_map,
},
{ 0 } /* terminator */
};

37 changes: 37 additions & 0 deletions sound/usb/mixer_quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <sound/control.h>
#include <sound/hwdep.h>
#include <sound/info.h>
#include <sound/tlv.h>

#include "usbaudio.h"
#include "mixer.h"
Expand Down Expand Up @@ -1825,3 +1826,39 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
}
}

static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl)
{
/* Approximation using 10 ranges based on output measurement on hw v1.2.
* This seems close to the cubic mapping e.g. alsamixer uses. */
static const DECLARE_TLV_DB_RANGE(scale,
0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970),
2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160),
6, 7, TLV_DB_MINMAX_ITEM(-3884, -3710),
8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560),
15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324),
17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031),
20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393),
27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032),
32, 40, TLV_DB_MINMAX_ITEM(-968, -490),
41, 50, TLV_DB_MINMAX_ITEM(-441, 0),
);

usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk\n");
kctl->tlv.p = scale;
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
}

void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
struct usb_mixer_elem_info *cval, int unitid,
struct snd_kcontrol *kctl)
{
switch (mixer->chip->usb_id) {
case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
if (unitid == 7 && cval->min == 0 && cval->max == 50)
snd_dragonfly_quirk_db_scale(mixer, kctl);
break;
}
}

4 changes: 4 additions & 0 deletions sound/usb/mixer_quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
int unitid);

void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
struct usb_mixer_elem_info *cval, int unitid,
struct snd_kcontrol *kctl);

#endif /* SND_USB_MIXER_QUIRKS_H */

0 comments on commit 42e3121

Please sign in to comment.