On Sun, 16 Aug 2015 14:50:12 +0200,
Anssi Hannula wrote:
> 
> 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 causes software using the dB information in
> e.g. volume sliders to have a massive volume difference in 100..102%
> range.
> 
> 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 -53...0 dB.
> 
> Add a quirk for DragonFly to use a custom dB mapping, based on my
> measurements, using a 10-item range TLV (so it still fits 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.
> 
> Signed-off-by: Anssi Hannula <[email protected]>
> Cc: <[email protected]>
> ---
>  sound/usb/mixer_quirks.c | 37 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
> 
> diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
> index 337c317ead6f..39d7f34e44e6 100644
> --- a/sound/usb/mixer_quirks.c
> +++ b/sound/usb/mixer_quirks.c
> @@ -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"
> @@ -1733,6 +1734,38 @@ static int snd_microii_controls_create(struct 
> usb_mixer_interface *mixer)
>       return 0;
>  }
>  
> +static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer)
> +{
> +     struct usb_mixer_elem_list *list;
> +     struct usb_mixer_elem_info *cval;
> +     static const int unit_id = 7;
> +
> +     /* approximation using 10 ranges based on output measurement on hw v1.2 
> */
> +     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),
> +     );
> +
> +     for (list = mixer->id_elems[unit_id]; list; list = list->next_id_elem) {
> +             cval = (struct usb_mixer_elem_info *)list;
> +             if (cval->control == UAC_FU_VOLUME &&
> +                 cval->min == 0 && cval->max == 50) {
> +                     usb_audio_info(mixer->chip, "applying DragonFly dB 
> scale quirk\n");
> +                     list->kctl->tlv.p = scale;
> +                     list->kctl->vd[0].access |=  
> SNDRV_CTL_ELEM_ACCESS_TLV_READ;
> +                     list->kctl->vd[0].access &= 
> ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
> +             }
> +     }

Instead of looking through the list, just hooking at
build_feature_ctl() would be simpler in the end, I think.
E.g. something like:

--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1334,6 +1334,7 @@ static void build_feature_ctl(struct mixer_build *state, 
void *raw_desc,
                                SNDRV_CTL_ELEM_ACCESS_TLV_READ |
                                SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
                }
+               mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl);
        }
 
        range = (cval->max - cval->min) / cval->res;

... and the quirk implementation in mixer_quirks.c like

static void snd_dragonfly_quirk_db_scale(mixer, kctl)
{
        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;
        list->kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;        
}

void mixer_fu_apply_quirk(mixer, cval, unitid, 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;
        }
}


Takashi
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to