All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
To: alsa-devel@alsa-project.org
Cc: Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>
Subject: [PATCH v2 4/8] ALSA: emu10k1: make playback in E-MU D.A.S. mode 32-bit
Date: Fri, 30 Jun 2023 16:45:38 +0200	[thread overview]
Message-ID: <20230630144542.664190-5-oswald.buddenhagen@gmx.de> (raw)
In-Reply-To: <20230630144542.664190-1-oswald.buddenhagen@gmx.de>

Each channel now uses a stereo voice pair. But the FX send amounts and
attenuation are per voice, so we have to use fixed values tuned to the
DSP code to avoid messing up the split samples.

As "regular" mode allows manipulating the amounts and att'n via mixer
controls, we can either:
- "Fake" them with DSP code, which doesn't seem worth the bother
- Ignore them, which doesn't seem very nice

So 32-bit playback simply remains unavailable in non-D.A.S. mode.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emufx.c  | 18 ++++++++++-----
 sound/pci/emu10k1/emupcm.c | 46 +++++++++++++++++++++++++-------------
 2 files changed, 43 insertions(+), 21 deletions(-)

diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 428ae365eb99..103cb35b39e0 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1290,7 +1290,8 @@ static int _snd_emu10k1_das_init_efx(struct snd_emu10k1 *emu)
 {
 	enum {
 		ENUM_GPR(bit_shifter16, 1),
-		ENUM_GPR(tmp, 1),
+		ENUM_GPR(lowword_mask, 1),
+		ENUM_GPR(tmp, 2),
 		num_static_gprs
 	};
 	int gpr = num_static_gprs;
@@ -1321,10 +1322,14 @@ static int _snd_emu10k1_das_init_efx(struct snd_emu10k1 *emu)
 
 	gpr_map = icode->gpr_map;
 	gpr_map[bit_shifter16] = 0x00008000;
+	gpr_map[lowword_mask] = 0x0000ffff;
 
 	if (emu->card_capabilities->ca0108_chip) {
-		for (int z = 0; z < 16; z++)
-			A_OP(icode, &ptr, iMACINT0, A3_EMU32OUT(z), A_C_00000000, A_FXBUS(z), A_C_00000002);
+		for (int z = 0; z < 16; z++) {
+			A_OP(icode, &ptr, iMAC0, A_GPR(tmp), A_C_00000000, A_FXBUS(z * 2), A_C_00010000); // >> 15
+			A_OP(icode, &ptr, iMACINT0, A_GPR(tmp + 1), A_C_00000000, A_FXBUS(z * 2 + 1), A_C_00000002); // << 1
+			A_OP(icode, &ptr, iANDXOR, A3_EMU32OUT(z), A_GPR(tmp), A_GPR(lowword_mask), A_GPR(tmp + 1));
+		}
 
 		snd_emu10k1_audigy_dsp_convert_32_to_2x16(
 			icode, &ptr, tmp, bit_shifter16, A3_EMU32IN(0), A_EXTOUT(0));
@@ -1337,8 +1342,11 @@ static int _snd_emu10k1_das_init_efx(struct snd_emu10k1 *emu)
 			gpr_map[gpr++] = 0x00000000;
 		}
 	} else {
-		for (int z = 0; z < 16; z++)
-			A_OP(icode, &ptr, iMACINT0, A_EMU32OUTL(z), A_C_00000000, A_FXBUS(z), A_C_00000002);
+		for (int z = 0; z < 16; z++) {
+			A_OP(icode, &ptr, iMAC0, A_GPR(tmp), A_C_00000000, A_FXBUS(z * 2), A_C_00010000); // >> 15
+			A_OP(icode, &ptr, iMACINT0, A_GPR(tmp + 1), A_C_00000000, A_FXBUS(z * 2 + 1), A_C_00000002); // << 1
+			A_OP(icode, &ptr, iANDXOR, A_EMU32OUTL(z), A_GPR(tmp), A_GPR(lowword_mask), A_GPR(tmp + 1));
+		}
 
 		/* Note that the Alice2 DSPs have 6 I2S inputs which we don't use. */
 		snd_emu10k1_audigy_dsp_convert_32_to_2x16(
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index bd222de7ea9f..7aed356637ab 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -366,13 +366,16 @@ static void snd_emu10k1_pcm_init_das_voices(struct snd_emu10k1 *emu,
 					    unsigned char channel)
 {
 	static const unsigned char send_amount[8] = { 255, 0, 0, 0, 0, 0, 0, 0 };
-	unsigned char send_routing[8];
+	unsigned char send_routing[9];
 
 	for (int i = 0; i < ARRAY_SIZE(send_routing); i++)
 		send_routing[i] = (channel + i) % NUM_G;
-	snd_emu10k1_pcm_init_voice(emu, evoice, true, false,
+	snd_emu10k1_pcm_init_voice(emu, evoice, true, true,
 				   start_addr, end_addr,
 				   send_routing, send_amount);
+	snd_emu10k1_pcm_init_voice(emu, evoice + 1, true, true,
+				   start_addr, end_addr,
+				   send_routing + 1, send_amount);
 }
 
 static void snd_emu10k1_pcm_init_extra_voice(struct snd_emu10k1 *emu,
@@ -406,7 +409,7 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream,
 	} else {
 		type = EMU10K1_EFX;
 		channels = params_channels(hw_params);
-		count = 1;
+		count = 1 + emu->das_mode;
 	}
 	err = snd_emu10k1_pcm_channel_alloc(epcm, type, count, channels);
 	if (err < 0)
@@ -509,15 +512,17 @@ static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream)
 	snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, true,
 					 start_addr, start_addr + extra_size);
 
-	epcm->ccca_start_addr = start_addr;
 	if (das_mode) {
+		start_addr >>= 1;
+		epcm->ccca_start_addr = start_addr;
 		for (i = 0; i < runtime->channels; i++) {
 			snd_emu10k1_pcm_init_das_voices(emu, epcm->voices[i],
 							start_addr, start_addr + channel_size,
-							i);
+							i * 2);
 			start_addr += channel_size;
 		}
 	} else {
+		epcm->ccca_start_addr = start_addr;
 		for (i = 0; i < runtime->channels; i++) {
 			snd_emu10k1_pcm_init_voices(emu, epcm->voices[i], true, false,
 						    start_addr, start_addr + channel_size,
@@ -722,6 +727,7 @@ static void snd_emu10k1_playback_unmute_das_voices(struct snd_emu10k1 *emu,
 						   struct snd_emu10k1_voice *evoice)
 {
 	snd_emu10k1_playback_commit_volume(emu, evoice, 0x8000 << 16);
+	snd_emu10k1_playback_commit_volume(emu, evoice + 1, 0x8000 << 16);
 }
 
 static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu,
@@ -936,24 +942,29 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
 }
 
 static u64 snd_emu10k1_efx_playback_voice_mask(struct snd_emu10k1_pcm *epcm,
-					       int channels)
+					       bool stereo, int channels)
 {
 	u64 mask = 0;
+	u64 mask0 = (1 << (1 << stereo)) - 1;
 
 	for (int i = 0; i < channels; i++) {
 		int voice = epcm->voices[i]->number;
-		mask |= 1ULL << voice;
+		mask |= mask0 << voice;
 	}
 	return mask;
 }
 
 static void snd_emu10k1_efx_playback_freeze_voices(struct snd_emu10k1 *emu,
 						   struct snd_emu10k1_pcm *epcm,
-						   int channels)
+						   bool stereo, int channels)
 {
 	for (int i = 0; i < channels; i++) {
 		int voice = epcm->voices[i]->number;
 		snd_emu10k1_ptr_write(emu, CPF_STOP, voice, 1);
+		if (stereo) {
+			// Weirdly enough, the stereo slave needs to be stopped separately
+			snd_emu10k1_ptr_write(emu, CPF_STOP, voice + 1, 1);
+		}
 		snd_emu10k1_playback_commit_pitch(emu, voice, PITCH_48000 << 16);
 	}
 }
@@ -977,14 +988,14 @@ static void snd_emu10k1_efx_playback_unmute_das_voices(struct snd_emu10k1 *emu,
 
 static void snd_emu10k1_efx_playback_stop_voices(struct snd_emu10k1 *emu,
 						 struct snd_emu10k1_pcm *epcm,
-						 int channels)
+						 bool stereo, int channels)
 {
 	for (int i = 0; i < channels; i++)
 		snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
 	snd_emu10k1_playback_set_stopped(emu, epcm);
 
 	for (int i = 0; i < channels; i++)
-		snd_emu10k1_playback_mute_voice(emu, epcm->voices[i]);
+		snd_emu10k1_playback_mute_voices(emu, epcm->voices[i], stereo);
 }
 
 static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
@@ -1003,15 +1014,15 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
 		mask = snd_emu10k1_efx_playback_voice_mask(
-				epcm, runtime->channels);
+				epcm, das_mode, runtime->channels);
 		for (int i = 0; i < 10; i++) {
 			// Note that the freeze is not interruptible, so we make no
 			// effort to reset the bits outside the error handling here.
 			snd_emu10k1_voice_set_loop_stop_multiple(emu, mask);
 			snd_emu10k1_efx_playback_freeze_voices(
-					emu, epcm, runtime->channels);
+					emu, epcm, das_mode, runtime->channels);
 			snd_emu10k1_playback_prepare_voices(
-					emu, epcm, true, false, runtime->channels);
+					emu, epcm, true, das_mode, runtime->channels);
 
 			// It might seem to make more sense to unmute the voices only after
 			// they have been started, to potentially avoid torturing the speakers
@@ -1033,7 +1044,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
 			}
 
 			snd_emu10k1_efx_playback_stop_voices(
-					emu, epcm, runtime->channels);
+					emu, epcm, das_mode, runtime->channels);
 
 			if (result != -EAGAIN)
 				break;
@@ -1046,7 +1057,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
 		snd_emu10k1_efx_playback_stop_voices(
-				emu, epcm, runtime->channels);
+				emu, epcm, das_mode, runtime->channels);
 
 		epcm->resume_pos = snd_emu10k1_playback_pointer(substream);
 		break;
@@ -1232,8 +1243,11 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream)
 	runtime->private_data = epcm;
 	runtime->private_free = snd_emu10k1_pcm_free_substream;
 	runtime->hw = snd_emu10k1_efx_playback;
-	if (emu->card_capabilities->emu_model)
+	if (emu->card_capabilities->emu_model) {
 		snd_emu1010_constrain_efx_rate(emu, runtime);
+		if (emu->das_mode)
+			runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+	}
 	err = snd_emu10k1_playback_set_constraints(runtime);
 	if (err < 0) {
 		kfree(epcm);
-- 
2.40.0.152.g15d061e6df


  parent reply	other threads:[~2023-06-30 14:48 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-30 14:45 [PATCH v2 0/8] ALSA: emu10k1: add support for high-bitrate modes of E-MU cards Oswald Buddenhagen
2023-06-30 14:45 ` [PATCH v2 1/8] ALSA: emu10k1: introduce alternative E-MU D.A.S. mode Oswald Buddenhagen
2023-06-30 14:45 ` [PATCH v2 2/8] ALSA: emu10k1: improve mixer control naming in " Oswald Buddenhagen
2023-06-30 14:45 ` [PATCH v2 3/8] ALSA: emu10k1: set the "no filtering" bits on PCM voices Oswald Buddenhagen
2023-06-30 14:45 ` Oswald Buddenhagen [this message]
2023-06-30 14:45 ` [PATCH v2 5/8] ALSA: add snd_ctl_add_locked() Oswald Buddenhagen
2023-06-30 14:45 ` [PATCH v2 6/8] ALSA: emu10k1: add support for 2x/4x word clocks in E-MU D.A.S. mode Oswald Buddenhagen
2023-06-30 14:45 ` [PATCH v2 7/8] ALSA: emu10k1: add high-rate capture " Oswald Buddenhagen
2023-06-30 14:45 ` [PATCH v2 8/8] ALSA: emu10k1: add high-rate playback " Oswald Buddenhagen
2023-07-10 15:06 ` [PATCH v2 0/8] ALSA: emu10k1: add support for high-bitrate modes of E-MU cards Takashi Iwai
2023-07-11 10:15   ` Oswald Buddenhagen
2023-07-11 11:08     ` Takashi Iwai
2023-07-17 10:19       ` Oswald Buddenhagen
2023-07-17 12:53         ` Takashi Iwai
2023-07-17 15:32           ` Oswald Buddenhagen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230630144542.664190-5-oswald.buddenhagen@gmx.de \
    --to=oswald.buddenhagen@gmx.de \
    --cc=alsa-devel@alsa-project.org \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.