mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
ALSA: emu10k1: enable bit-exact playback, part 1: DSP attenuation
Fractional multiplication with the maximal value 2^31-1 causes some tiny distortion. Instead, we want to multiply with the full 2^31. The catch is of course that this cannot be represented in the DSP's signed 32 bit registers. One way to deal with this is to encode 1.0 as a negative number and special-case it. As a matter of fact, the SbLive! code path already contained such code, though the controls never actually exercised it. A more efficient approach is to use negative values, which actually extend to -2^31. Accordingly, for all the volume adjustments we now use the MAC1 instruction which negates the X operand. The range of the controls in highres mode is extended downwards, so -1 is the new zero/mute. At maximal excursion, real zero is not mute any more, but I don't think anyone will notice this behavior change. ;-) That also required making the min/max/values in the control structs signed. This technically changes the user space interface, but it seems implausible that someone would notice - the numbers were actually treated as if they were signed anyway (and in the actual mixer iface they _are_). And without this change, the min value didn't even make sense in the first place (and no-one noticed, because it was always 0). Tested-by: Jonathan Dowland <jon@dow.land> Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Link: https://lore.kernel.org/r/20230514170323.3408834-7-oswald.buddenhagen@gmx.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
de0dc31070
commit
1298bc978a
3 changed files with 64 additions and 69 deletions
|
@ -1508,9 +1508,9 @@ struct snd_emu10k1_fx8010_ctl {
|
||||||
unsigned int vcount;
|
unsigned int vcount;
|
||||||
unsigned int count; /* count of GPR (1..16) */
|
unsigned int count; /* count of GPR (1..16) */
|
||||||
unsigned short gpr[32]; /* GPR number(s) */
|
unsigned short gpr[32]; /* GPR number(s) */
|
||||||
unsigned int value[32];
|
int value[32];
|
||||||
unsigned int min; /* minimum range */
|
int min; /* minimum range */
|
||||||
unsigned int max; /* maximum range */
|
int max; /* maximum range */
|
||||||
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
||||||
struct snd_kcontrol *kcontrol;
|
struct snd_kcontrol *kcontrol;
|
||||||
};
|
};
|
||||||
|
|
|
@ -308,6 +308,8 @@ struct snd_emu10k1_fx8010_info {
|
||||||
#define EMU10K1_GPR_TRANSLATION_BASS 2
|
#define EMU10K1_GPR_TRANSLATION_BASS 2
|
||||||
#define EMU10K1_GPR_TRANSLATION_TREBLE 3
|
#define EMU10K1_GPR_TRANSLATION_TREBLE 3
|
||||||
#define EMU10K1_GPR_TRANSLATION_ONOFF 4
|
#define EMU10K1_GPR_TRANSLATION_ONOFF 4
|
||||||
|
#define EMU10K1_GPR_TRANSLATION_NEGATE 5
|
||||||
|
#define EMU10K1_GPR_TRANSLATION_NEG_TABLE100 6
|
||||||
|
|
||||||
enum emu10k1_ctl_elem_iface {
|
enum emu10k1_ctl_elem_iface {
|
||||||
EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */
|
EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */
|
||||||
|
@ -328,9 +330,9 @@ struct snd_emu10k1_fx8010_control_gpr {
|
||||||
unsigned int vcount; /* visible count */
|
unsigned int vcount; /* visible count */
|
||||||
unsigned int count; /* count of GPR (1..16) */
|
unsigned int count; /* count of GPR (1..16) */
|
||||||
unsigned short gpr[32]; /* GPR number(s) */
|
unsigned short gpr[32]; /* GPR number(s) */
|
||||||
unsigned int value[32]; /* initial values */
|
int value[32]; /* initial values */
|
||||||
unsigned int min; /* minimum range */
|
int min; /* minimum range */
|
||||||
unsigned int max; /* maximum range */
|
int max; /* maximum range */
|
||||||
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */
|
||||||
const unsigned int *tlv;
|
const unsigned int *tlv;
|
||||||
};
|
};
|
||||||
|
|
|
@ -332,7 +332,7 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl
|
||||||
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
|
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
|
||||||
struct snd_emu10k1_fx8010_ctl *ctl =
|
struct snd_emu10k1_fx8010_ctl *ctl =
|
||||||
(struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
|
(struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
|
||||||
unsigned int nval, val;
|
int nval, val;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
int change = 0;
|
int change = 0;
|
||||||
|
|
||||||
|
@ -349,9 +349,16 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl
|
||||||
case EMU10K1_GPR_TRANSLATION_NONE:
|
case EMU10K1_GPR_TRANSLATION_NONE:
|
||||||
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
|
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
|
||||||
break;
|
break;
|
||||||
|
case EMU10K1_GPR_TRANSLATION_NEGATE:
|
||||||
|
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, ~val);
|
||||||
|
break;
|
||||||
case EMU10K1_GPR_TRANSLATION_TABLE100:
|
case EMU10K1_GPR_TRANSLATION_TABLE100:
|
||||||
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
|
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
|
||||||
break;
|
break;
|
||||||
|
case EMU10K1_GPR_TRANSLATION_NEG_TABLE100:
|
||||||
|
snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0,
|
||||||
|
val == 100 ? 0x80000000 : -(int)db_table[val]);
|
||||||
|
break;
|
||||||
case EMU10K1_GPR_TRANSLATION_BASS:
|
case EMU10K1_GPR_TRANSLATION_BASS:
|
||||||
if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
|
if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
|
||||||
change = -EIO;
|
change = -EIO;
|
||||||
|
@ -771,8 +778,10 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
|
||||||
}
|
}
|
||||||
switch (gctl->translation) {
|
switch (gctl->translation) {
|
||||||
case EMU10K1_GPR_TRANSLATION_NONE:
|
case EMU10K1_GPR_TRANSLATION_NONE:
|
||||||
|
case EMU10K1_GPR_TRANSLATION_NEGATE:
|
||||||
break;
|
break;
|
||||||
case EMU10K1_GPR_TRANSLATION_TABLE100:
|
case EMU10K1_GPR_TRANSLATION_TABLE100:
|
||||||
|
case EMU10K1_GPR_TRANSLATION_NEG_TABLE100:
|
||||||
if (gctl->min != 0 || gctl->max != 100) {
|
if (gctl->min != 0 || gctl->max != 100) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto __error;
|
goto __error;
|
||||||
|
@ -1143,16 +1152,16 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
|
||||||
strcpy(ctl->id.name, name);
|
strcpy(ctl->id.name, name);
|
||||||
ctl->vcount = ctl->count = 1;
|
ctl->vcount = ctl->count = 1;
|
||||||
if (high_res_gpr_volume) {
|
if (high_res_gpr_volume) {
|
||||||
ctl->min = 0;
|
ctl->min = -1;
|
||||||
ctl->max = 0x7fffffff;
|
ctl->max = 0x7fffffff;
|
||||||
ctl->tlv = snd_emu10k1_db_linear;
|
ctl->tlv = snd_emu10k1_db_linear;
|
||||||
ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
|
ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE;
|
||||||
defval = defval * 0x7fffffffLL / 100;
|
defval = defval * 0x80000000LL / 100 - 1;
|
||||||
} else {
|
} else {
|
||||||
ctl->min = 0;
|
ctl->min = 0;
|
||||||
ctl->max = 100;
|
ctl->max = 100;
|
||||||
ctl->tlv = snd_emu10k1_db_scale1;
|
ctl->tlv = snd_emu10k1_db_scale1;
|
||||||
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
|
ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100;
|
||||||
}
|
}
|
||||||
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
|
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
|
||||||
}
|
}
|
||||||
|
@ -1165,16 +1174,16 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
|
||||||
strcpy(ctl->id.name, name);
|
strcpy(ctl->id.name, name);
|
||||||
ctl->vcount = ctl->count = 2;
|
ctl->vcount = ctl->count = 2;
|
||||||
if (high_res_gpr_volume) {
|
if (high_res_gpr_volume) {
|
||||||
ctl->min = 0;
|
ctl->min = -1;
|
||||||
ctl->max = 0x7fffffff;
|
ctl->max = 0x7fffffff;
|
||||||
ctl->tlv = snd_emu10k1_db_linear;
|
ctl->tlv = snd_emu10k1_db_linear;
|
||||||
ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
|
ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE;
|
||||||
defval = defval * 0x7fffffffLL / 100;
|
defval = defval * 0x80000000LL / 100 - 1;
|
||||||
} else {
|
} else {
|
||||||
ctl->min = 0;
|
ctl->min = 0;
|
||||||
ctl->max = 100;
|
ctl->max = 100;
|
||||||
ctl->tlv = snd_emu10k1_db_scale1;
|
ctl->tlv = snd_emu10k1_db_scale1;
|
||||||
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
|
ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100;
|
||||||
}
|
}
|
||||||
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
|
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
|
||||||
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
|
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
|
||||||
|
@ -1293,36 +1302,36 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
/* PCM front Playback Volume (independent from stereo mix)
|
/* PCM front Playback Volume (independent from stereo mix)
|
||||||
* playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
|
* playback = -gpr * FXBUS_PCM_LEFT_FRONT >> 31
|
||||||
* where gpr contains attenuation from corresponding mixer control
|
* where gpr contains negated attenuation from corresponding mixer control
|
||||||
* (snd_emu10k1_init_stereo_control)
|
* (snd_emu10k1_init_stereo_control)
|
||||||
*/
|
*/
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* PCM Surround Playback (independent from stereo mix) */
|
/* PCM Surround Playback (independent from stereo mix) */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* PCM Side Playback (independent from stereo mix) */
|
/* PCM Side Playback (independent from stereo mix) */
|
||||||
if (emu->card_capabilities->spk71) {
|
if (emu->card_capabilities->spk71) {
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PCM Center Playback (independent from stereo mix) */
|
/* PCM Center Playback (independent from stereo mix) */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
|
||||||
snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
|
snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
|
||||||
gpr++;
|
gpr++;
|
||||||
|
|
||||||
/* PCM LFE Playback (independent from stereo mix) */
|
/* PCM LFE Playback (independent from stereo mix) */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
|
||||||
snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
|
snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
|
||||||
gpr++;
|
gpr++;
|
||||||
|
|
||||||
|
@ -1330,26 +1339,26 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
|
||||||
* Stereo Mix
|
* Stereo Mix
|
||||||
*/
|
*/
|
||||||
/* Wave (PCM) Playback Volume (will be renamed later) */
|
/* Wave (PCM) Playback Volume (will be renamed later) */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* Synth Playback */
|
/* Synth Playback */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* Wave (PCM) Capture */
|
/* Wave (PCM) Capture */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* Synth Capture */
|
/* Synth Capture */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
|
@ -1357,23 +1366,23 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
|
||||||
* inputs
|
* inputs
|
||||||
*/
|
*/
|
||||||
#define A_ADD_VOLUME_IN(var,vol,input) \
|
#define A_ADD_VOLUME_IN(var,vol,input) \
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
|
A_OP(icode, &ptr, iMAC1, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
|
||||||
|
|
||||||
if (emu->card_capabilities->emu_model) {
|
if (emu->card_capabilities->emu_model) {
|
||||||
/* EMU1010 DSP 0 and DSP 1 Capture */
|
/* EMU1010 DSP 0 and DSP 1 Capture */
|
||||||
// The 24 MSB hold the actual value. We implicitly discard the 16 LSB.
|
// The 24 MSB hold the actual value. We implicitly discard the 16 LSB.
|
||||||
if (emu->card_capabilities->ca0108_chip) {
|
if (emu->card_capabilities->ca0108_chip) {
|
||||||
// For unclear reasons, the EMU32IN cannot be the Y operand!
|
// For unclear reasons, the EMU32IN cannot be the Y operand!
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A3_EMU32IN(0x0), A_GPR(gpr));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A3_EMU32IN(0x0), A_GPR(gpr));
|
||||||
// A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels
|
// A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels
|
||||||
// need to be delayed as well; we use an auxiliary register for that.
|
// need to be delayed as well; we use an auxiliary register for that.
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
|
||||||
A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A3_EMU32IN(0x1), A_C_00000000, A_C_00000000);
|
A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A3_EMU32IN(0x1), A_C_00000000, A_C_00000000);
|
||||||
} else {
|
} else {
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_P16VIN(0x0), A_GPR(gpr));
|
||||||
// A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels
|
// A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels
|
||||||
// need to be delayed as well; we use an auxiliary register for that.
|
// need to be delayed as well; we use an auxiliary register for that.
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_GPR(gpr+2));
|
A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
|
||||||
A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
|
A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
|
||||||
}
|
}
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
|
||||||
|
@ -1465,33 +1474,33 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stereo Mix Front Playback Volume */
|
/* Stereo Mix Front Playback Volume */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* Stereo Mix Surround Playback */
|
/* Stereo Mix Surround Playback */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
|
|
||||||
/* Stereo Mix Center Playback */
|
/* Stereo Mix Center Playback */
|
||||||
/* Center = sub = Left/2 + Right/2 */
|
/* Center = sub = Left/2 + Right/2 */
|
||||||
A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), A_C_40000000, A_GPR(stereo_mix+1));
|
A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), A_C_40000000, A_GPR(stereo_mix+1));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
|
||||||
snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
|
snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
|
||||||
gpr++;
|
gpr++;
|
||||||
|
|
||||||
/* Stereo Mix LFE Playback */
|
/* Stereo Mix LFE Playback */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
|
||||||
snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
|
snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
|
||||||
gpr++;
|
gpr++;
|
||||||
|
|
||||||
if (emu->card_capabilities->spk71) {
|
if (emu->card_capabilities->spk71) {
|
||||||
/* Stereo Mix Side Playback */
|
/* Stereo Mix Side Playback */
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
|
||||||
snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
|
snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
|
||||||
gpr += 2;
|
gpr += 2;
|
||||||
}
|
}
|
||||||
|
@ -1579,7 +1588,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
|
||||||
|
|
||||||
/* Master volume (will be renamed later) */
|
/* Master volume (will be renamed later) */
|
||||||
for (z = 0; z < 8; z++)
|
for (z = 0; z < 8; z++)
|
||||||
A_OP(icode, &ptr, iMAC0, A_GPR(playback+z), A_C_00000000, A_GPR(gpr), A_GPR(playback+z));
|
A_OP(icode, &ptr, iMAC1, A_GPR(playback+z), A_C_00000000, A_GPR(gpr), A_GPR(playback+z));
|
||||||
snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
|
snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
|
||||||
gpr++;
|
gpr++;
|
||||||
|
|
||||||
|
@ -1731,30 +1740,14 @@ __err_gpr:
|
||||||
* initial DSP configuration for Emu10k1
|
* initial DSP configuration for Emu10k1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* when volume = max, then copy only to avoid volume modification */
|
/* Volumes are in the [-2^31, 0] range, zero being mute. */
|
||||||
/* with iMAC0 (negative values) */
|
|
||||||
static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
|
static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
|
||||||
{
|
{
|
||||||
OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
|
OP(icode, ptr, iMAC1, dst, C_00000000, src, vol);
|
||||||
OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
|
|
||||||
OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
|
|
||||||
OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
|
|
||||||
}
|
}
|
||||||
static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
|
static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
|
||||||
{
|
{
|
||||||
OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
|
OP(icode, ptr, iMAC1, dst, dst, src, vol);
|
||||||
OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
|
|
||||||
OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
|
|
||||||
OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
|
|
||||||
OP(icode, ptr, iMAC0, dst, dst, src, vol);
|
|
||||||
}
|
|
||||||
static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
|
|
||||||
{
|
|
||||||
OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
|
|
||||||
OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
|
|
||||||
OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
|
|
||||||
OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
|
|
||||||
OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VOLUME(icode, ptr, dst, src, vol) \
|
#define VOLUME(icode, ptr, dst, src, vol) \
|
||||||
|
@ -1766,7 +1759,7 @@ static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst
|
||||||
#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
|
#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
|
||||||
_volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
|
_volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
|
||||||
#define VOLUME_OUT(icode, ptr, dst, src, vol) \
|
#define VOLUME_OUT(icode, ptr, dst, src, vol) \
|
||||||
_volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
|
_volume(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
|
||||||
#define _SWITCH(icode, ptr, dst, src, sw) \
|
#define _SWITCH(icode, ptr, dst, src, sw) \
|
||||||
OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
|
OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
|
||||||
#define SWITCH(icode, ptr, dst, src, sw) \
|
#define SWITCH(icode, ptr, dst, src, sw) \
|
||||||
|
|
Loading…
Add table
Reference in a new issue