diff mbox series

[05/14] ALSA: emu10k1: apply channel delay hack to all E-MU cards

Message ID 20230510173917.3073107-6-oswald.buddenhagen@gmx.de
State Accepted
Commit f549466b8b8519260e49460543dff9b37f280cc9
Headers show
Series ALSA: emu10k1: various improvements to the DSP-based mixer code | expand

Commit Message

Oswald Buddenhagen May 10, 2023, 5:39 p.m. UTC
Evidently, the channel delay bug exists in all E-MU cards; it's in the
Hana FPGA program, and was never fixed.

Note that the implementation is somewhat lazy - to localize the code
paths, we actually waste a GPR and a DSP instruction by keeping two
delay registers for the same physical source.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 include/sound/emu10k1.h   |  1 +
 sound/pci/emu10k1/emufx.c | 23 ++++++++++++++++++-----
 2 files changed, 19 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 8fe80dcee71b..7129b9249eb3 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1192,6 +1192,7 @@ 
  * emumixer.c - snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
  */
 #define EMU_DST_ALICE2_EMU32_0	0x000f	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+					/* This channel is delayed by one sample. */
 #define EMU_DST_ALICE2_EMU32_1	0x0000	/* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_2	0x0001	/* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_3	0x0002	/* 16 EMU32 channels to Alice2 +0 to +0xf */
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 8ba294138dfe..2e139ae8b41b 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1326,13 +1326,20 @@  A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 		if (emu->card_capabilities->ca0108_chip) {
 			// 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, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A3_EMU32IN(0x1), A_GPR(gpr+1));
+			// 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.
+			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, iACC3, A_GPR(gpr+2), A3_EMU32IN(0x1), A_C_00000000, A_C_00000000);
 		} else {
 			A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
-			A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
+			// 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.
+			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, 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);
-		gpr += 2;
+		gpr_map[gpr + 2] = 0x00000000;
+		gpr += 3;
 	}
 	/* AC'97 Playback Volume - used only for mic (renamed later) */
 	A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
@@ -1624,11 +1631,17 @@  A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 			dev_info(emu->card->dev, "EMU2 inputs on\n");
 			/* Note that the Tina[2] DSPs have 16 more EMU32 inputs which we don't use. */
 
-			for (z = 0; z < 0x10; z++) {
+			snd_emu10k1_audigy_dsp_convert_32_to_2x16(
+				icode, &ptr, tmp, bit_shifter16, A3_EMU32IN(0), A_FXBUS2(0));
+			// 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.
+			for (z = 1; z < 0x10; z++) {
 				snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, 
 									bit_shifter16,
-									A3_EMU32IN(z),
+									A_GPR(gpr),
 									A_FXBUS2(z*2) );
+				A_OP(icode, &ptr, iACC3, A_GPR(gpr), A3_EMU32IN(z), A_C_00000000, A_C_00000000);
+				gpr_map[gpr++] = 0x00000000;
 			}
 		} else {
 			dev_info(emu->card->dev, "EMU inputs on\n");