Skip to content

Commit

Permalink
[ALSA] Support for non-standard rates in USB audio driver
Browse files Browse the repository at this point in the history
There's at least one USB audio chipset out there which supports only one
non-standard rate (ID 0e6a:0310 supports 46875Hz). There's a few other
patches for this card which are unsatisfactory because they attempt to
map this rate to 44.1k leading to sound distortion.
The patch below uses SNDRV_PCM_RATE_KNOT to properly support the
non-standard rates where they are available.

Signed-off-by: Luke Ross <luke@lukeross.name>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
  • Loading branch information
Luke Ross authored and Jaroslav Kysela committed Sep 23, 2006
1 parent 9f458e7 commit a79eee8
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions sound/usb/usbaudio.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ struct audioformat {
unsigned int rate_min, rate_max; /* min/max rates */
unsigned int nr_rates; /* number of rate table entries */
unsigned int *rate_table; /* rate table */
unsigned int needs_knot; /* any unusual rates? */
};

struct snd_usb_substream;
Expand Down Expand Up @@ -1759,6 +1760,9 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
}
channels[f->format] |= (1 << f->channels);
rates[f->format] |= f->rates;
/* needs knot? */
if (f->needs_knot)
goto __out;
}
/* check whether channels and rates match for all formats */
cmaster = rmaster = 0;
Expand Down Expand Up @@ -1799,6 +1803,38 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
return err;
}

/*
* If the device supports unusual bit rates, does the request meet these?
*/
static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
struct snd_usb_substream *subs)
{
struct list_head *p;
struct snd_pcm_hw_constraint_list constraints_rates;
int err;

list_for_each(p, &subs->fmt_list) {
struct audioformat *fp;
fp = list_entry(p, struct audioformat, list);

if (!fp->needs_knot)
continue;

constraints_rates.count = fp->nr_rates;
constraints_rates.list = fp->rate_table;
constraints_rates.mask = 0;

err = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);

if (err < 0)
return err;
}

return 0;
}


/*
* set up the runtime hardware information.
Expand Down Expand Up @@ -1861,6 +1897,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
SNDRV_PCM_HW_PARAM_CHANNELS,
-1)) < 0)
return err;
if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
return err;
}
return 0;
}
Expand Down Expand Up @@ -2406,6 +2444,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
unsigned char *fmt, int offset)
{
int nr_rates = fmt[offset];
int found;
if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
chip->dev->devnum, fp->iface, fp->altsetting);
Expand All @@ -2428,6 +2467,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
return -1;
}

fp->needs_knot = 0;
fp->nr_rates = nr_rates;
fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
Expand All @@ -2436,13 +2476,19 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
fp->rate_min = rate;
else if (rate > fp->rate_max)
fp->rate_max = rate;
found = 0;
for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
if (rate == conv_rates[c]) {
found = 1;
fp->rates |= (1 << c);
break;
}
}
if (!found)
fp->needs_knot = 1;
}
if (fp->needs_knot)
fp->rates |= SNDRV_PCM_RATE_KNOT;
} else {
/* continuous rates */
fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
Expand Down

0 comments on commit a79eee8

Please sign in to comment.