Skip to content

Commit

Permalink
ALSA: usb-audio: M-Audio Fast Track Ultra: Add effect controls
Browse files Browse the repository at this point in the history
This adds controls for the effects section on the FTU devices.
Some of these controls need volume quirks. They are added to
mixer.c.

[fixed missing break by tiwai]

Signed-off-by: Felix Homann <linuxaudio@showlabor.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Felix Homann authored and Takashi Iwai committed Apr 24, 2012
1 parent cfe8f97 commit d34bf14
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 0 deletions.
20 changes: 20 additions & 0 deletions sound/usb/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,26 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
struct snd_kcontrol *kctl)
{
switch (cval->mixer->chip->usb_id) {
case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
if (strcmp(kctl->id.name, "Effect Duration") == 0) {
snd_printk(KERN_INFO
"usb-audio: set quirk for FTU Effect Duration\n");
cval->min = 0x0000;
cval->max = 0x7f00;
cval->res = 0x0100;
break;
}
if (strcmp(kctl->id.name, "Effect Volume") == 0 ||
strcmp(kctl->id.name, "Effect Feedback Volume") == 0) {
snd_printk(KERN_INFO
"usb-audio: set quirks for FTU Effect Feedback/Volume\n");
cval->min = 0x00;
cval->max = 0x7f;
break;
}
break;

case USB_ID(0x0471, 0x0101):
case USB_ID(0x0471, 0x0104):
case USB_ID(0x0471, 0x0105):
Expand Down
299 changes: 299 additions & 0 deletions sound/usb/mixer_quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,186 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
}

/* M-Audio FastTrack Ultra quirks */
/* FTU Effect switch */
struct snd_ftu_eff_switch_priv_val {
struct usb_mixer_interface *mixer;
int cached_value;
int is_cached;
};

static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
static const char *texts[8] = {"Room 1",
"Room 2",
"Room 3",
"Hall 1",
"Hall 2",
"Plate",
"Delay",
"Echo"
};

uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 8;
if (uinfo->value.enumerated.item > 7)
uinfo->value.enumerated.item = 7;
strcpy(uinfo->value.enumerated.name,
texts[uinfo->value.enumerated.item]);

return 0;
}

static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_usb_audio *chip;
struct usb_mixer_interface *mixer;
struct snd_ftu_eff_switch_priv_val *pval;
int err;
unsigned char value[2];

const int id = 6;
const int validx = 1;
const int val_len = 2;

value[0] = 0x00;
value[1] = 0x00;

pval = (struct snd_ftu_eff_switch_priv_val *)
kctl->private_value;

if (pval->is_cached) {
ucontrol->value.enumerated.item[0] = pval->cached_value;
return 0;
}

mixer = (struct usb_mixer_interface *) pval->mixer;
if (snd_BUG_ON(!mixer))
return -EINVAL;

chip = (struct snd_usb_audio *) mixer->chip;
if (snd_BUG_ON(!chip))
return -EINVAL;


err = snd_usb_ctl_msg(chip->dev,
usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
value, val_len);
if (err < 0)
return err;

ucontrol->value.enumerated.item[0] = value[0];
pval->cached_value = value[0];
pval->is_cached = 1;

return 0;
}

static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_usb_audio *chip;
struct snd_ftu_eff_switch_priv_val *pval;

struct usb_mixer_interface *mixer;
int changed, cur_val, err, new_val;
unsigned char value[2];


const int id = 6;
const int validx = 1;
const int val_len = 2;

changed = 0;

pval = (struct snd_ftu_eff_switch_priv_val *)
kctl->private_value;
cur_val = pval->cached_value;
new_val = ucontrol->value.enumerated.item[0];

mixer = (struct usb_mixer_interface *) pval->mixer;
if (snd_BUG_ON(!mixer))
return -EINVAL;

chip = (struct snd_usb_audio *) mixer->chip;
if (snd_BUG_ON(!chip))
return -EINVAL;

if (!pval->is_cached) {
/* Read current value */
err = snd_usb_ctl_msg(chip->dev,
usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
value, val_len);
if (err < 0)
return err;

cur_val = value[0];
pval->cached_value = cur_val;
pval->is_cached = 1;
}
/* update value if needed */
if (cur_val != new_val) {
value[0] = new_val;
value[1] = 0;
err = snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
value, val_len);
if (err < 0)
return err;

pval->cached_value = new_val;
pval->is_cached = 1;
changed = 1;
}

return changed;
}

static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
{
static struct snd_kcontrol_new template = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Effect Program Switch",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_ftu_eff_switch_info,
.get = snd_ftu_eff_switch_get,
.put = snd_ftu_eff_switch_put
};

int err;
struct snd_kcontrol *kctl;
struct snd_ftu_eff_switch_priv_val *pval;

pval = kzalloc(sizeof(*pval), GFP_KERNEL);
if (!pval)
return -ENOMEM;

pval->cached_value = 0;
pval->is_cached = 0;
pval->mixer = mixer;

template.private_value = (unsigned long) pval;
kctl = snd_ctl_new1(&template, mixer->chip);
if (!kctl) {
kfree(pval);
return -ENOMEM;
}

err = snd_ctl_add(mixer->chip->card, kctl);
if (err < 0)
return err;

return 0;
}

/* Create volume controls for FTU devices*/
static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
Expand Down Expand Up @@ -614,6 +794,102 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
return 0;
}

/* This control needs a volume quirk, see mixer.c */
static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
{
static const char name[] = "Effect Volume";
const unsigned int id = 6;
const int val_type = USB_MIXER_U8;
const unsigned int control = 2;
const unsigned int cmask = 0;

return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
name, snd_usb_mixer_vol_tlv);
}

/* This control needs a volume quirk, see mixer.c */
static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
{
static const char name[] = "Effect Duration";
const unsigned int id = 6;
const int val_type = USB_MIXER_S16;
const unsigned int control = 3;
const unsigned int cmask = 0;

return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
name, snd_usb_mixer_vol_tlv);
}

/* This control needs a volume quirk, see mixer.c */
static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
{
static const char name[] = "Effect Feedback Volume";
const unsigned int id = 6;
const int val_type = USB_MIXER_U8;
const unsigned int control = 4;
const unsigned int cmask = 0;

return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
name, NULL);
}

static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
{
unsigned int cmask;
int err, ch;
char name[48];

const unsigned int id = 7;
const int val_type = USB_MIXER_S16;
const unsigned int control = 7;

for (ch = 0; ch < 4; ++ch) {
cmask = 1 << ch;
snprintf(name, sizeof(name),
"Effect Return %d Volume", ch + 1);
err = snd_create_std_mono_ctl(mixer, id, control,
cmask, val_type, name,
snd_usb_mixer_vol_tlv);
if (err < 0)
return err;
}

return 0;
}

static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
{
unsigned int cmask;
int err, ch;
char name[48];

const unsigned int id = 5;
const int val_type = USB_MIXER_S16;
const unsigned int control = 9;

for (ch = 0; ch < 8; ++ch) {
cmask = 1 << ch;
snprintf(name, sizeof(name),
"Effect Send AIn%d Volume", ch + 1);
err = snd_create_std_mono_ctl(mixer, id, control, cmask,
val_type, name,
snd_usb_mixer_vol_tlv);
if (err < 0)
return err;
}
for (ch = 8; ch < 16; ++ch) {
cmask = 1 << ch;
snprintf(name, sizeof(name),
"Effect Send DIn%d Volume", ch - 7);
err = snd_create_std_mono_ctl(mixer, id, control, cmask,
val_type, name,
snd_usb_mixer_vol_tlv);
if (err < 0)
return err;
}
return 0;
}

static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
{
int err;
Expand All @@ -622,6 +898,29 @@ static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
if (err < 0)
return err;

err = snd_ftu_create_effect_switch(mixer);
if (err < 0)
return err;
err = snd_ftu_create_effect_volume_ctl(mixer);
if (err < 0)
return err;

err = snd_ftu_create_effect_duration_ctl(mixer);
if (err < 0)
return err;

err = snd_ftu_create_effect_feedback_ctl(mixer);
if (err < 0)
return err;

err = snd_ftu_create_effect_return_ctls(mixer);
if (err < 0)
return err;

err = snd_ftu_create_effect_send_ctls(mixer);
if (err < 0)
return err;

return 0;
}

Expand Down

0 comments on commit d34bf14

Please sign in to comment.