All of lore.kernel.org
 help / color / mirror / Atom feed
* Fast Track Ultra mixer - opinions anyone?
@ 2012-04-16 10:38 Felix Homann
  2012-04-16 11:06 ` Aurélien Leblond
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Felix Homann @ 2012-04-16 10:38 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Aurélien Leblond, Grant Diffey, Daniel Mack

[-- Attachment #1: Type: text/plain, Size: 1486 bytes --]

Hi,

over the weekend I tried to prepare a
"set-everything-to-zero-by-default" mixer patch. And failed...
I could get the controls to be defaulted to zero by quirking the
volume range, but then there would not have been any sound at all,
even after adjusting the levels.

So without diving any deeper in this I decided to put some work in the
mixer controls. You can find a patch to play with attached to this
mail. I've left a couple of commented quirks in mixer.c so you can
see, where simple changes can be made.

But working on this patch raised a couple of questions I would like
hear your opinions on:

** Effects **

Essentially, with the attached patch you can control everything but
the effect program. The switch should not be too hard to implement.
But before I put any more work on it I would like to ask wether it
makes sense at all.

IMO, the effect section on the FTUs really sucks. I can't believe that
anybody can really use it in a reasonable way. So should we really add
another 40 controls to the mixer which can cause a lot of pain when
misadjusted (i.e. anything else but 0)?

For those reasons I would prefer not to put effect support in the
kernel. What do you think?

** dB values **

Currently alsamixer does not report any dB changes when you change a
control value. I  don't know how to fix it. Anyone else?

** Naming scheme again **

Once again, is everyone pleased with the current naming scheme?



Looking forward for your suggestions.

Regards,

Felix

[-- Attachment #2: ftu-mixer-effects.diff --]
[-- Type: application/octet-stream, Size: 7622 bytes --]

diff --git a/usb/mixer.c b/usb/mixer.c
index ab23869..d24d657 100644
--- a/usb/mixer.c
+++ b/usb/mixer.c
@@ -770,6 +770,53 @@ 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(strnicmp(kctl->id.name, "AIn", 3) == 0
+			| strnicmp(kctl->id.name, "DIn", 3) == 0) {
+			/* quirking the AIn/DIn controls will result in
+			 * 0 default values. But controls will not have any effect
+			 */
+
+			snd_printk(KERN_INFO
+				"set quirks for FTU AIn/DIn controls\n");
+			//cval->min = 0x0000;
+			//cval->max = 0xffff;
+			//break;
+		}
+		if (strcmp(kctl->id.name, "Effect Duration") == 0) {
+			snd_printk(KERN_INFO
+				"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") == 0) {
+			snd_printk(KERN_INFO
+				"set quirks for FTU Effect Feedback/Volume\n");
+			cval->min = 0x00;
+			cval->max = 0x7f;
+			break;
+		}
+		/* if (strnicmp(kctl->id.name, "Effect Return", 10) == 0) { */
+		/* 	snd_printk(KERN_INFO */
+		/* 		"set quirks for FTU Effect returns\n"); */
+		/* 	printk(KERN_ERR "set quirks for FTU Effect Returns"); */
+		/* 	cval->min = 0xcde7; */
+		/* 	cval->max = 0xffda; */
+		/* 	break; */
+		/* } */
+		/* if (strnicmp(kctl->id.name, "Effect Send", 10) == 0) { */
+		/* 	snd_printk(KERN_INFO */
+		/* 		"set quirks for FTU Effect returns\n"); */
+		/* 	printk(KERN_ERR "set quirks for FTU Effect Returns"); */
+		/* 	cval->min = 0xcde7; */
+		/* 	cval->max = 0xffda; */
+		/* 	break; */
+		/* } */
+
 	case USB_ID(0x0471, 0x0101):
 	case USB_ID(0x0471, 0x0104):
 	case USB_ID(0x0471, 0x0105):
diff --git a/usb/mixer_quirks.c b/usb/mixer_quirks.c
index ab125ee..90f7a32 100644
--- a/usb/mixer_quirks.c
+++ b/usb/mixer_quirks.c
@@ -496,6 +496,12 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 
 /* M-Audio FastTrack Ultra quirks */
 
+/* Note: Some of the FTU controls need volume control quirks
+ * If you change the naming scheme of the controls you need
+ * to change the corresponding names in volume_control_quirks() 
+ * in mixer.c as well
+ */
+
 /* private_free callback */
 static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 {
@@ -503,56 +509,208 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 	kctl->private_data = NULL;
 }
 
+
 static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-				     int in, int out, const char *name)
+					unsigned int id,
+					unsigned int control,
+					unsigned int cmask,
+					int val_type,
+					const char *name)
 {
 	struct usb_mixer_elem_info *cval;
-	struct snd_kcontrol *kctl;
+ 	struct snd_kcontrol *kctl;
 
 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
 	if (!cval)
 		return -ENOMEM;
 
-	cval->id = 5;
+	cval->id = id;
 	cval->mixer = mixer;
-	cval->val_type = USB_MIXER_S16;
+	cval->val_type = val_type;
 	cval->channels = 1;
-	cval->control = out + 1;
-	cval->cmask = 1 << in;
-
+	cval->control = control;
+	cval->cmask = cmask;
+		
+	
+	/* Create control */
 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
 	if (!kctl) {
 		kfree(cval);
 		return -ENOMEM;
 	}
-
+	
+	/* Set name */
 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
 	kctl->private_free = usb_mixer_elem_free;
-	return snd_usb_mixer_add_control(mixer, kctl);
+	
+	/* Add control to mixer */
+	int err = snd_usb_mixer_add_control(mixer, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create a volume control for FTU devices*/
+static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
 	char name[64];
-	int in, out, err;
+	unsigned int id, control, cmask;
+	int in, out, err, val_type;
+
+	id = 5;
+	val_type = USB_MIXER_S16;
 
 	for (out = 0; out < 8; out++) {
+		control = out + 1;
 		for (in = 0; in < 8; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name);
 			if (err < 0)
 				return err;
 		}
-
 		for (in = 8; in < 16; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name);
 			if (err < 0)
 				return err;
 		}
 	}
+	
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 2;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name);
+}
+
+
+static int snd_maudio_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Duration";
+
+	id = 6;
+	val_type = USB_MIXER_S16;
+	control = 3;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name);
+}
+
+static int snd_maudio_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Feedback";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 4;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name);
+}
+
+static int snd_maudio_ftu_create_effects_return_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[16];
+
+	id = 7;
+	val_type = USB_MIXER_S16;
+	control = 2;
+
+	for (ch = 0; ch < 4; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Return %d", ch +1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effects_send_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[16];
+
+	id = 5;
+	val_type = USB_MIXER_S16;
+	control = 9;
+
+	for (ch = 0; ch < 8; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send AIn%d", ch +1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name);
+		if (err < 0)
+			return err;
+	}
+	for (ch = 8; ch < 16; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send DIn%d", ch - 7);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_maudio_ftu_create_volume_ctls(mixer);
+	if (err < 0)
+		return err;
+	
+	err = snd_maudio_ftu_create_effect_volume_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_duration_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_feedback_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_return_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_send_ctls(mixer);
+	if (err < 0)
+		return err;
 
 	return 0;
 }

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-16 10:38 Fast Track Ultra mixer - opinions anyone? Felix Homann
@ 2012-04-16 11:06 ` Aurélien Leblond
  2012-04-16 11:11 ` Grant Diffey
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Aurélien Leblond @ 2012-04-16 11:06 UTC (permalink / raw)
  To: Felix Homann; +Cc: Takashi Iwai, alsa-devel, Grant Diffey, Daniel Mack

> ** Effects **
>
> Essentially, with the attached patch you can control everything but
> the effect program. The switch should not be too hard to implement.
> But before I put any more work on it I would like to ask wether it
> makes sense at all.
>
> IMO, the effect section on the FTUs really sucks. I can't believe that
> anybody can really use it in a reasonable way. So should we really add
> another 40 controls to the mixer which can cause a lot of pain when
> misadjusted (i.e. anything else but 0)?
>
> For those reasons I would prefer not to put effect support in the
> kernel. What do you think?

What if they are activated somehow, and a user would loke to turn them off?

You're completely right, the effects on this soundcard are useless,
but let say they have been turn on in a Windows session, would the FTU
turn them back off at reboot, or would they still be on?

> ** Naming scheme again **
>
> Once again, is everyone pleased with the current naming scheme?
>

The naming scheme is indeed very confusing, but what other solution is
there? I used the FTU mixer under Windows and it is as confusing :)
I'm not sure the problem is with the naming convention though, but
more what the Alsa mixers look like... Gamix used to be perfect for
the FTU with all the controls in a grid, it was very clear how the
levels were setup... Unfortunately it's not maintained anymore, even
in Ubuntu...


So that's my 2 cents...

Aurélien

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-16 10:38 Fast Track Ultra mixer - opinions anyone? Felix Homann
  2012-04-16 11:06 ` Aurélien Leblond
@ 2012-04-16 11:11 ` Grant Diffey
  2012-04-16 12:45   ` Felix Homann
  2012-04-16 13:10 ` Clemens Ladisch
  2012-04-18 11:47 ` Felix Homann
  3 siblings, 1 reply; 8+ messages in thread
From: Grant Diffey @ 2012-04-16 11:11 UTC (permalink / raw)
  To: Felix Homann; +Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Daniel Mack

On Mon, Apr 16, 2012 at 8:38 PM, Felix Homann <linuxaudio@showlabor.de>wrote:

> re-sending to everyone...
>
> [SNIP]
>
> ** Effects **
>
> Essentially, with the attached patch you can control everything but
> the effect program. The switch should not be too hard to implement.
> But before I put any more work on it I would like to ask wether it
> makes sense at all.
>
> IMO, the effect section on the FTUs really sucks. I can't believe that
> anybody can really use it in a reasonable way. So should we really add
> another 40 controls to the mixer which can cause a lot of pain when
> misadjusted (i.e. anything else but 0)?
>
> For those reasons I would prefer not to put effect support in the
> kernel. What do you think?
>

Nope it absolutely should be supported to fully support the device.

They're for monitoring if used as intended... ie: when doing hardware based
monitoring.

>
> ** dB values **
>
> Currently alsamixer does not report any dB changes when you change a
> control value. I  don't know how to fix it. Anyone else?
>
>
What does dB value mean in this context given there's a hardware volume
knob on the device? is it just the db difference or is supposed to be some
sort of dBm absolute output level

the specs say that the output at the rear of the device is +10 dBm balanced
and +1.8dBu unbalanced

and the headphones are 0dBm into 32 ohms


> ** Naming scheme again **
>
> Once again, is everyone pleased with the current naming scheme?
>
>
> I think it's ok. I still think we need some better tools. but with 16*8
controls now and another 4x8 for effects + effect select and misc controls
like clock select I think some better ui is necessary.

>
>
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-16 11:11 ` Grant Diffey
@ 2012-04-16 12:45   ` Felix Homann
  0 siblings, 0 replies; 8+ messages in thread
From: Felix Homann @ 2012-04-16 12:45 UTC (permalink / raw)
  To: Grant Diffey; +Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Daniel Mack

2012/4/16 Grant Diffey <gdiffey@gmail.com>:
>> ** dB values **
>>
>> Currently alsamixer does not report any dB changes when you change a
>> control value. I  don't know how to fix it. Anyone else?
>>
>
> What does dB value mean in this context given there's a hardware volume knob
> on the device? is it just the db difference or is supposed to be some sort
> of dBm absolute output level

What I meant was: At the moment we can just change raw control values
without knowing what they mean. E.g. if we put some control value to
50% do we get linear gain of 50% . Do we have a logarithmic scale or a
"M-Audio-we-work-on-standards-but-dont-support-them" scale?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-16 10:38 Fast Track Ultra mixer - opinions anyone? Felix Homann
  2012-04-16 11:06 ` Aurélien Leblond
  2012-04-16 11:11 ` Grant Diffey
@ 2012-04-16 13:10 ` Clemens Ladisch
  2012-04-18 11:47 ` Felix Homann
  3 siblings, 0 replies; 8+ messages in thread
From: Clemens Ladisch @ 2012-04-16 13:10 UTC (permalink / raw)
  To: Felix Homann
  Cc: Takashi Iwai, Aurélien Leblond, alsa-devel, Grant Diffey,
	Daniel Mack

Felix Homann wrote:
> IMO, the effect section on the FTUs really sucks. I can't believe that
> anybody can really use it in a reasonable way. So should we really add
> another 40 controls to the mixer which can cause a lot of pain when
> misadjusted (i.e. anything else but 0)?
>
> For those reasons I would prefer not to put effect support in the
> kernel. What do you think?

If you want to be able to use these effects at all, there must be _some_
way to access the controls.

Generic mixer programs like alsamixer are not really suitable for
complex devices; you'd need to write a custom mixer.

If you want to prevent the controls from showing up in alsamixer, set
their .iface to SNDRV_CTL_ELEM_IFACE_CARD instead of _MIXER.  (But if
these controls don't show up in alsamixer, you wouldn't be able to reset
them if they are misadjusted ...)

> Currently alsamixer does not report any dB changes when you change a
> control value.

Set the TLV.  For standard controls, the code reads the values from
the USB descriptors, but for control you create by hand, you have to
create these, too.


Regards,
Clemens

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-16 10:38 Fast Track Ultra mixer - opinions anyone? Felix Homann
                   ` (2 preceding siblings ...)
  2012-04-16 13:10 ` Clemens Ladisch
@ 2012-04-18 11:47 ` Felix Homann
  2012-04-18 14:32   ` Felix Homann
  3 siblings, 1 reply; 8+ messages in thread
From: Felix Homann @ 2012-04-18 11:47 UTC (permalink / raw)
  To: alsa-devel; +Cc: Aurélien Leblond, Grant Diffey, Daniel Mack

[-- Attachment #1: Type: text/plain, Size: 561 bytes --]

OK,

I think I've got the mixer essentially done.

* Added Effect section including effect program switch
* Added TLV (dB gain information -> makes huge improvement in usability)

Could you please try the attached patch and give some feedback before
I submit it.

I've already noticed that KMix will crash trying to control the FTU.
It will take the whole KDE session down, too. But since neither
alsamixer, amixer nor qasmixer show similar behaviour I guess it's an
issue within KMix (too many controls?)  - not one of the
patch...hopefully.


Regards,

Felix

[-- Attachment #2: mixer-patch.diff --]
[-- Type: application/octet-stream, Size: 13592 bytes --]

diff --git a/usb/mixer.c b/usb/mixer.c
index ab23869..c2bd4a4 100644
--- a/usb/mixer.c
+++ b/usb/mixer.c
@@ -501,6 +501,11 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 	return 0;
 }
 
+/* This symbol is exported in order to allow the mixer quirks to
+ * reuse it in mixer_quirks.c */
+int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv) = &mixer_vol_tlv;
+
 /*
  * parser routines begin here...
  */
@@ -770,6 +775,53 @@ 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(strnicmp(kctl->id.name, "AIn", 3) == 0
+			| strnicmp(kctl->id.name, "DIn", 3) == 0) {
+			/* quirking the AIn/DIn controls will result in
+			 * 0 default values. But controls will not have any effect
+			 */
+
+			snd_printk(KERN_INFO
+				"set quirks for FTU AIn/DIn controls\n");
+			cval->dBmin = -60;
+			cval->dBmax = 0;
+			//break;
+		}
+		if (strcmp(kctl->id.name, "Effect Duration") == 0) {
+			snd_printk(KERN_INFO
+				"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
+				"set quirks for FTU Effect Feedback/Volume\n");
+			cval->min = 0x00;
+			cval->max = 0x7f;
+			break;
+		}
+		/* if (strnicmp(kctl->id.name, "Effect Return", 10) == 0) { */
+		/* 	snd_printk(KERN_INFO */
+		/* 		"set quirks for FTU Effect returns\n"); */
+		/* 	printk(KERN_ERR "set quirks for FTU Effect Returns"); */
+		/* 	cval->min = 0xcde7; */
+		/* 	cval->max = 0xffda; */
+		/* 	break; */
+		/* } */
+		/* if (strnicmp(kctl->id.name, "Effect Send", 10) == 0) { */
+		/* 	snd_printk(KERN_INFO */
+		/* 		"set quirks for FTU Effect returns\n"); */
+		/* 	printk(KERN_ERR "set quirks for FTU Effect Returns"); */
+		/* 	cval->min = 0xcde7; */
+		/* 	cval->max = 0xffda; */
+		/* 	break; */
+		/* } */
+
 	case USB_ID(0x0471, 0x0101):
 	case USB_ID(0x0471, 0x0104):
 	case USB_ID(0x0471, 0x0105):
diff --git a/usb/mixer_quirks.c b/usb/mixer_quirks.c
index ab125ee..aea842c 100644
--- a/usb/mixer_quirks.c
+++ b/usb/mixer_quirks.c
@@ -34,6 +34,7 @@
 #include <sound/control.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 
 #include "usbaudio.h"
 #include "mixer.h"
@@ -41,6 +42,8 @@
 #include "helper.h"
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+extern int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv);
 
 /*
  * Sound Blaster remote control configuration
@@ -496,6 +499,12 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 
 /* M-Audio FastTrack Ultra quirks */
 
+/* Note: Some of the FTU controls need volume control quirks
+ * If you change the naming scheme of the controls you need
+ * to change the corresponding names in volume_control_quirks() 
+ * in mixer.c as well
+ */
+
 /* private_free callback */
 static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 {
@@ -503,56 +512,406 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 	kctl->private_data = NULL;
 }
 
+static struct snd_maudio_ftu_effect_switch_private_value {
+	struct usb_mixer_interface *mixer;
+	int cached_value;
+	int is_cached;
+};
+
+
+static int snd_maudio_ftu_effect_switch_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	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_maudio_ftu_effect_switch_get(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct usb_mixer_interface *mixer;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+	int err, id, validx, val_len, val_type;
+	unsigned char value[2];
+
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) 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 (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	value[0] = 0x00;
+	value[1] = 0x00;
+
+	val_len = 2;
+
+	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 -1;
+
+	ucontrol->value.enumerated.item[0] = value[0];
+	pval->cached_value = value[0];
+	pval->is_cached = 1;
+
+       	return 0;
+}
+
+static int snd_maudio_ftu_effect_switch_put(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+
+	struct usb_mixer_interface *mixer;
+	int  changed, cur_val, err, id, new_val, validx, val_len, val_type;
+	unsigned char value[2];
+
+	changed = 0;
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	val_len = 2;
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) kctl->private_value; 
+	cur_val = pval->cached_value;
+	new_val = ucontrol->value.enumerated.item[0];
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+	
+	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 -1;
+
+		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 -1;
+		pval->cached_value = new_val;
+		pval->is_cached = 1;
+		changed = 1;
+	}
+
+	return changed;
+}
+
+static int snd_maudio_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+	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_maudio_ftu_effect_switch_info,
+		.get = snd_maudio_ftu_effect_switch_get,
+		.put = snd_maudio_ftu_effect_switch_put
+	};
+	
+	int err;
+	struct snd_kcontrol *kctl;
+	struct snd_maudio_ftu_effect_switch_private_value *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)
+		return -1;
+
+	err = snd_ctl_add(mixer->chip->card, kctl);
+	if (err < 0)
+		return err;
+	
+	return 0;
+}
+
 static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-				     int in, int out, const char *name)
+				unsigned int id,
+				unsigned int control,
+				unsigned int cmask,
+				int val_type,
+				const char *name,
+				snd_kcontrol_tlv_rw_t *tlv_callback)
 {
+	int err;
 	struct usb_mixer_elem_info *cval;
-	struct snd_kcontrol *kctl;
+ 	struct snd_kcontrol *kctl;
 
 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
 	if (!cval)
 		return -ENOMEM;
 
-	cval->id = 5;
+	cval->id = id;
 	cval->mixer = mixer;
-	cval->val_type = USB_MIXER_S16;
+	cval->val_type = val_type;
 	cval->channels = 1;
-	cval->control = out + 1;
-	cval->cmask = 1 << in;
-
+	cval->control = control;
+	cval->cmask = cmask;
+		
+	
+	/* Create control */
 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
 	if (!kctl) {
 		kfree(cval);
 		return -ENOMEM;
 	}
-
+	
+	/* Set name */
 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
 	kctl->private_free = usb_mixer_elem_free;
-	return snd_usb_mixer_add_control(mixer, kctl);
+	
+	/* set TLV */
+	if (tlv_callback != NULL) { 
+		kctl->tlv.c = tlv_callback;
+		kctl->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	}
+	/* Add control to mixer */
+	err = snd_usb_mixer_add_control(mixer, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create a volume control for FTU devices*/
+static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
 	char name[64];
-	int in, out, err;
+	unsigned int id, control, cmask;
+	int in, out, err, val_type;
+
+	id = 5;
+	val_type = USB_MIXER_S16;
 
 	for (out = 0; out < 8; out++) {
+		control = out + 1;
 		for (in = 0; in < 8; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
-
 		for (in = 8; in < 16; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
 	}
+	
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 2;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Duration";
+
+	id = 6;
+	val_type = USB_MIXER_S16;
+	control = 3;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Feedback Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 4;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, NULL);
+}
+
+static int snd_maudio_ftu_create_effects_return_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 7;
+	val_type = USB_MIXER_S16;
+	control = 2;
+
+	for (ch = 0; ch < 4; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Return %d Volume", ch +1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effects_send_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 5;
+	val_type = USB_MIXER_S16;
+	control = 9;
+
+	for (ch = 0; ch < 8; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send AIn%d Volume", ch + 1);
+		err = snd_maudio_ftu_create_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_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_maudio_ftu_create_volume_ctls(mixer);
+	if (err < 0)
+		return err;
+	
+	err = snd_maudio_ftu_create_effect_volume_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_duration_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_feedback_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_return_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_send_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_switch(mixer);
+	if (err < 0)
+		return err;
+
+	/* err = snd_maudio_ftu_create_test_switch(mixer); */
+	/* if (err < 0) */
+	/* 	return err; */
 
 	return 0;
 }

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-18 11:47 ` Felix Homann
@ 2012-04-18 14:32   ` Felix Homann
  2012-04-18 15:02     ` Felix Homann
  0 siblings, 1 reply; 8+ messages in thread
From: Felix Homann @ 2012-04-18 14:32 UTC (permalink / raw)
  To: alsa-devel; +Cc: Aurélien Leblond, Grant Diffey, Daniel Mack

[-- Attachment #1: Type: text/plain, Size: 678 bytes --]

Here's a slightly modified patch to test.

It properly (hopefully) frees some memory if things go wrong. And I
cleaned up some comments etc.

It's against alsa-kmirror so you can test it without recompiling the
whole kernel

(Like this:
git clone git://git.alsa-project.org/alsa-driver.git alsa-driver
git clone git://git.alsa-project.org/alsa-kmirror.git alsa-kmirror

[patch alsa kmirror...]

cd alsa-driver
./gitcompile --with-oss=no --with-pcm-oss-plugins=no --with-debug=full
--enable-dynamic-minors --with-moddir=updates
sudo make install
sudo alsa force-reload

when rebuilding after applying a patch just do

make
sudo make install
alsa force-reload
)


Regards,

Felix

[-- Attachment #2: mixer-patch.diff --]
[-- Type: application/octet-stream, Size: 13592 bytes --]

diff --git a/usb/mixer.c b/usb/mixer.c
index ab23869..c2bd4a4 100644
--- a/usb/mixer.c
+++ b/usb/mixer.c
@@ -501,6 +501,11 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 	return 0;
 }
 
+/* This symbol is exported in order to allow the mixer quirks to
+ * reuse it in mixer_quirks.c */
+int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv) = &mixer_vol_tlv;
+
 /*
  * parser routines begin here...
  */
@@ -770,6 +775,53 @@ 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(strnicmp(kctl->id.name, "AIn", 3) == 0
+			| strnicmp(kctl->id.name, "DIn", 3) == 0) {
+			/* quirking the AIn/DIn controls will result in
+			 * 0 default values. But controls will not have any effect
+			 */
+
+			snd_printk(KERN_INFO
+				"set quirks for FTU AIn/DIn controls\n");
+			cval->dBmin = -60;
+			cval->dBmax = 0;
+			//break;
+		}
+		if (strcmp(kctl->id.name, "Effect Duration") == 0) {
+			snd_printk(KERN_INFO
+				"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
+				"set quirks for FTU Effect Feedback/Volume\n");
+			cval->min = 0x00;
+			cval->max = 0x7f;
+			break;
+		}
+		/* if (strnicmp(kctl->id.name, "Effect Return", 10) == 0) { */
+		/* 	snd_printk(KERN_INFO */
+		/* 		"set quirks for FTU Effect returns\n"); */
+		/* 	printk(KERN_ERR "set quirks for FTU Effect Returns"); */
+		/* 	cval->min = 0xcde7; */
+		/* 	cval->max = 0xffda; */
+		/* 	break; */
+		/* } */
+		/* if (strnicmp(kctl->id.name, "Effect Send", 10) == 0) { */
+		/* 	snd_printk(KERN_INFO */
+		/* 		"set quirks for FTU Effect returns\n"); */
+		/* 	printk(KERN_ERR "set quirks for FTU Effect Returns"); */
+		/* 	cval->min = 0xcde7; */
+		/* 	cval->max = 0xffda; */
+		/* 	break; */
+		/* } */
+
 	case USB_ID(0x0471, 0x0101):
 	case USB_ID(0x0471, 0x0104):
 	case USB_ID(0x0471, 0x0105):
diff --git a/usb/mixer_quirks.c b/usb/mixer_quirks.c
index ab125ee..aea842c 100644
--- a/usb/mixer_quirks.c
+++ b/usb/mixer_quirks.c
@@ -34,6 +34,7 @@
 #include <sound/control.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 
 #include "usbaudio.h"
 #include "mixer.h"
@@ -41,6 +42,8 @@
 #include "helper.h"
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+extern int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv);
 
 /*
  * Sound Blaster remote control configuration
@@ -496,6 +499,12 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 
 /* M-Audio FastTrack Ultra quirks */
 
+/* Note: Some of the FTU controls need volume control quirks
+ * If you change the naming scheme of the controls you need
+ * to change the corresponding names in volume_control_quirks() 
+ * in mixer.c as well
+ */
+
 /* private_free callback */
 static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 {
@@ -503,56 +512,406 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 	kctl->private_data = NULL;
 }
 
+static struct snd_maudio_ftu_effect_switch_private_value {
+	struct usb_mixer_interface *mixer;
+	int cached_value;
+	int is_cached;
+};
+
+
+static int snd_maudio_ftu_effect_switch_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	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_maudio_ftu_effect_switch_get(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct usb_mixer_interface *mixer;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+	int err, id, validx, val_len, val_type;
+	unsigned char value[2];
+
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) 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 (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	value[0] = 0x00;
+	value[1] = 0x00;
+
+	val_len = 2;
+
+	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 -1;
+
+	ucontrol->value.enumerated.item[0] = value[0];
+	pval->cached_value = value[0];
+	pval->is_cached = 1;
+
+       	return 0;
+}
+
+static int snd_maudio_ftu_effect_switch_put(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+
+	struct usb_mixer_interface *mixer;
+	int  changed, cur_val, err, id, new_val, validx, val_len, val_type;
+	unsigned char value[2];
+
+	changed = 0;
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	val_len = 2;
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) kctl->private_value; 
+	cur_val = pval->cached_value;
+	new_val = ucontrol->value.enumerated.item[0];
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+	
+	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 -1;
+
+		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 -1;
+		pval->cached_value = new_val;
+		pval->is_cached = 1;
+		changed = 1;
+	}
+
+	return changed;
+}
+
+static int snd_maudio_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+	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_maudio_ftu_effect_switch_info,
+		.get = snd_maudio_ftu_effect_switch_get,
+		.put = snd_maudio_ftu_effect_switch_put
+	};
+	
+	int err;
+	struct snd_kcontrol *kctl;
+	struct snd_maudio_ftu_effect_switch_private_value *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)
+		return -1;
+
+	err = snd_ctl_add(mixer->chip->card, kctl);
+	if (err < 0)
+		return err;
+	
+	return 0;
+}
+
 static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-				     int in, int out, const char *name)
+				unsigned int id,
+				unsigned int control,
+				unsigned int cmask,
+				int val_type,
+				const char *name,
+				snd_kcontrol_tlv_rw_t *tlv_callback)
 {
+	int err;
 	struct usb_mixer_elem_info *cval;
-	struct snd_kcontrol *kctl;
+ 	struct snd_kcontrol *kctl;
 
 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
 	if (!cval)
 		return -ENOMEM;
 
-	cval->id = 5;
+	cval->id = id;
 	cval->mixer = mixer;
-	cval->val_type = USB_MIXER_S16;
+	cval->val_type = val_type;
 	cval->channels = 1;
-	cval->control = out + 1;
-	cval->cmask = 1 << in;
-
+	cval->control = control;
+	cval->cmask = cmask;
+		
+	
+	/* Create control */
 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
 	if (!kctl) {
 		kfree(cval);
 		return -ENOMEM;
 	}
-
+	
+	/* Set name */
 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
 	kctl->private_free = usb_mixer_elem_free;
-	return snd_usb_mixer_add_control(mixer, kctl);
+	
+	/* set TLV */
+	if (tlv_callback != NULL) { 
+		kctl->tlv.c = tlv_callback;
+		kctl->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	}
+	/* Add control to mixer */
+	err = snd_usb_mixer_add_control(mixer, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create a volume control for FTU devices*/
+static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
 	char name[64];
-	int in, out, err;
+	unsigned int id, control, cmask;
+	int in, out, err, val_type;
+
+	id = 5;
+	val_type = USB_MIXER_S16;
 
 	for (out = 0; out < 8; out++) {
+		control = out + 1;
 		for (in = 0; in < 8; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
-
 		for (in = 8; in < 16; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
 	}
+	
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 2;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Duration";
+
+	id = 6;
+	val_type = USB_MIXER_S16;
+	control = 3;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Feedback Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 4;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, NULL);
+}
+
+static int snd_maudio_ftu_create_effects_return_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 7;
+	val_type = USB_MIXER_S16;
+	control = 2;
+
+	for (ch = 0; ch < 4; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Return %d Volume", ch +1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effects_send_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 5;
+	val_type = USB_MIXER_S16;
+	control = 9;
+
+	for (ch = 0; ch < 8; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send AIn%d Volume", ch + 1);
+		err = snd_maudio_ftu_create_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_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_maudio_ftu_create_volume_ctls(mixer);
+	if (err < 0)
+		return err;
+	
+	err = snd_maudio_ftu_create_effect_volume_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_duration_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_feedback_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_return_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_send_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_switch(mixer);
+	if (err < 0)
+		return err;
+
+	/* err = snd_maudio_ftu_create_test_switch(mixer); */
+	/* if (err < 0) */
+	/* 	return err; */
 
 	return 0;
 }

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: Fast Track Ultra mixer - opinions anyone?
  2012-04-18 14:32   ` Felix Homann
@ 2012-04-18 15:02     ` Felix Homann
  0 siblings, 0 replies; 8+ messages in thread
From: Felix Homann @ 2012-04-18 15:02 UTC (permalink / raw)
  To: alsa-devel; +Cc: Aurélien Leblond, Grant Diffey, Daniel Mack

[-- Attachment #1: Type: text/plain, Size: 124 bytes --]

2012/4/18 Felix Homann <linuxaudio@showlabor.de>:
> Here's a slightly modified patch to test.


Sorry, here it *really* is.

[-- Attachment #2: mixer-patch_v2.diff --]
[-- Type: application/octet-stream, Size: 12747 bytes --]

diff --git a/usb/mixer.c b/usb/mixer.c
index ab23869..8d11dd9 100644
--- a/usb/mixer.c
+++ b/usb/mixer.c
@@ -501,6 +501,11 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 	return 0;
 }
 
+/* This symbol is exported in order to allow the mixer quirks to
+ * reuse it in mixer_quirks.c */
+int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv) = &mixer_vol_tlv;
+
 /*
  * parser routines begin here...
  */
@@ -770,7 +775,25 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
 				  struct snd_kcontrol *kctl)
 {
 	switch (cval->mixer->chip->usb_id) {
-	case USB_ID(0x0471, 0x0101):
+	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
+				"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
+				"set quirks for FTU Effect Feedback/Volume\n");
+			cval->min = 0x00;
+			cval->max = 0x7f;
+			break;
+		}
+       	case USB_ID(0x0471, 0x0101):
 	case USB_ID(0x0471, 0x0104):
 	case USB_ID(0x0471, 0x0105):
 	case USB_ID(0x0672, 0x1041):
diff --git a/usb/mixer_quirks.c b/usb/mixer_quirks.c
index ab125ee..97582ad 100644
--- a/usb/mixer_quirks.c
+++ b/usb/mixer_quirks.c
@@ -34,6 +34,7 @@
 #include <sound/control.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 
 #include "usbaudio.h"
 #include "mixer.h"
@@ -41,6 +42,8 @@
 #include "helper.h"
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+extern int (*snd_usb_mixer_vol_tlv)(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *_tlv);
 
 /*
  * Sound Blaster remote control configuration
@@ -496,6 +499,12 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
 
 /* M-Audio FastTrack Ultra quirks */
 
+/* Note: Some of the FTU controls need volume control quirks
+ * If you change the naming scheme of the controls you need
+ * to change the corresponding names in volume_control_quirks() 
+ * in mixer.c as well
+ */
+
 /* private_free callback */
 static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 {
@@ -503,56 +512,409 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
 	kctl->private_data = NULL;
 }
 
+struct snd_maudio_ftu_effect_switch_private_value {
+	struct usb_mixer_interface *mixer;
+	int cached_value;
+	int is_cached;
+};
+
+
+static int snd_maudio_ftu_effect_switch_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	static 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_maudio_ftu_effect_switch_get(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct usb_mixer_interface *mixer;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+	int err, id, validx, val_len, val_type;
+	unsigned char value[2];
+
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) 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 (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	value[0] = 0x00;
+	value[1] = 0x00;
+
+	val_len = 2;
+
+	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 -1;
+
+	ucontrol->value.enumerated.item[0] = value[0];
+	pval->cached_value = value[0];
+	pval->is_cached = 1;
+
+       	return 0;
+}
+
+static int snd_maudio_ftu_effect_switch_put(struct snd_kcontrol *kctl,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_usb_audio *chip;
+	struct snd_maudio_ftu_effect_switch_private_value *pval;
+
+	struct usb_mixer_interface *mixer;
+	int  changed, cur_val, err, id, new_val, validx, val_len, val_type;
+	unsigned char value[2];
+
+	changed = 0;
+	id = 6;
+	validx = 1;
+	val_type = USB_MIXER_S16;
+
+	val_len = 2;
+	pval = (struct snd_maudio_ftu_effect_switch_private_value *) kctl->private_value; 
+	cur_val = pval->cached_value;
+	new_val = ucontrol->value.enumerated.item[0];
+
+	mixer = (struct usb_mixer_interface *) pval->mixer;
+	if (mixer == NULL) {
+		snd_printd(KERN_ERR "mixer == NULL");
+		return -1;
+	}
+	
+	chip = (struct snd_usb_audio *) mixer->chip;
+	if (chip == NULL) {
+		snd_printd(KERN_ERR "chip == NULL");
+		return -1;
+	}
+	
+	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 -1;
+
+		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 -1;
+
+		pval->cached_value = new_val;
+		pval->is_cached = 1;
+		changed = 1;
+	}
+
+	return changed;
+}
+
+static int snd_maudio_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+	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_maudio_ftu_effect_switch_info,
+		.get = snd_maudio_ftu_effect_switch_get,
+		.put = snd_maudio_ftu_effect_switch_put
+	};
+	
+	int err;
+	struct snd_kcontrol *kctl;
+	struct snd_maudio_ftu_effect_switch_private_value *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;
+}
+
 static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
-				     int in, int out, const char *name)
+				unsigned int id,
+				unsigned int control,
+				unsigned int cmask,
+				int val_type,
+				const char *name,
+				snd_kcontrol_tlv_rw_t *tlv_callback)
 {
+	int err;
 	struct usb_mixer_elem_info *cval;
-	struct snd_kcontrol *kctl;
+ 	struct snd_kcontrol *kctl;
 
 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
 	if (!cval)
 		return -ENOMEM;
 
-	cval->id = 5;
+	cval->id = id;
 	cval->mixer = mixer;
-	cval->val_type = USB_MIXER_S16;
+	cval->val_type = val_type;
 	cval->channels = 1;
-	cval->control = out + 1;
-	cval->cmask = 1 << in;
-
+	cval->control = control;
+	cval->cmask = cmask;
+		
+	
+	/* Create control */
 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
 	if (!kctl) {
 		kfree(cval);
 		return -ENOMEM;
 	}
-
+	
+	/* Set name */
 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
 	kctl->private_free = usb_mixer_elem_free;
-	return snd_usb_mixer_add_control(mixer, kctl);
+	
+	/* set TLV */
+	if (tlv_callback != NULL) { 
+		kctl->tlv.c = tlv_callback;
+		kctl->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	}
+	/* Add control to mixer */
+	err = snd_usb_mixer_add_control(mixer, kctl);
+	if (err < 0)
+		return err;
+
+	return 0;
 }
 
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create a volume control for FTU devices*/
+static int snd_maudio_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
 {
 	char name[64];
-	int in, out, err;
+	unsigned int id, control, cmask;
+	int in, out, err, val_type;
+
+	id = 5;
+	val_type = USB_MIXER_S16;
 
 	for (out = 0; out < 8; out++) {
+		control = out + 1;
 		for (in = 0; in < 8; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "AIn%d - Out%d Capture Volume", in  + 1, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
-
 		for (in = 8; in < 16; in++) {
+			cmask = 1 << in;
 			snprintf(name, sizeof(name),
 				 "DIn%d - Out%d Playback Volume", in - 7, out + 1);
-			err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+			err = snd_maudio_ftu_create_ctl(mixer, id, control,
+							cmask, val_type, name, snd_usb_mixer_vol_tlv);
 			if (err < 0)
 				return err;
 		}
 	}
+	
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 2;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Duration";
+
+	id = 6;
+	val_type = USB_MIXER_S16;
+	control = 3;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+}
+
+static int snd_maudio_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int val_type;
+
+	char name[] ="Effect Feedback Volume";
+
+	id = 6;
+	val_type = USB_MIXER_U8;
+	control = 4;
+	cmask = 0;
+
+	return snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, NULL);
+}
+
+static int snd_maudio_ftu_create_effects_return_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 7;
+	val_type = USB_MIXER_S16;
+	control = 2;
+
+	for (ch = 0; ch < 4; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Return %d Volume", ch +1);
+		err = snd_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_maudio_ftu_create_effects_send_ctls(struct usb_mixer_interface *mixer)
+{
+	unsigned int id, control, cmask;
+	int err, val_type, ch;
+	char name[48];
+
+	id = 5;
+	val_type = USB_MIXER_S16;
+	control = 9;
+
+	for (ch = 0; ch < 8; ++ch) {
+		cmask = 1 << ch;
+		snprintf(name, sizeof(name),
+			"Effect Send AIn%d Volume", ch + 1);
+		err = snd_maudio_ftu_create_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_maudio_ftu_create_ctl(mixer, id, control, cmask, val_type, name, snd_usb_mixer_vol_tlv);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+	int err;
+
+	err = snd_maudio_ftu_create_volume_ctls(mixer);
+	if (err < 0)
+		return err;
+	
+	err = snd_maudio_ftu_create_effect_volume_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_duration_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_feedback_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_return_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effects_send_ctls(mixer);
+	if (err < 0)
+		return err;
+
+	err = snd_maudio_ftu_create_effect_switch(mixer);
+	if (err < 0)
+		return err;
+
+	/* err = snd_maudio_ftu_create_test_switch(mixer); */
+	/* if (err < 0) */
+	/* 	return err; */
 
 	return 0;
 }

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-04-18 15:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-04-16 10:38 Fast Track Ultra mixer - opinions anyone? Felix Homann
2012-04-16 11:06 ` Aurélien Leblond
2012-04-16 11:11 ` Grant Diffey
2012-04-16 12:45   ` Felix Homann
2012-04-16 13:10 ` Clemens Ladisch
2012-04-18 11:47 ` Felix Homann
2012-04-18 14:32   ` Felix Homann
2012-04-18 15:02     ` Felix Homann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.