diff mbox series

[5/6] ALSA: emu10k1: skip needless setting of some voice registers

Message ID 20230516093612.3536451-6-oswald.buddenhagen@gmx.de (mailing list archive)
State New, archived
Headers show
Series ALSA: emu10k1: assorted playback-related cleanups | expand

Commit Message

Oswald Buddenhagen May 16, 2023, 9:36 a.m. UTC
Many registers are meaningless for stereo slaves and the extra voices.
This patch cleans up these unnecessary register writes.

snd_emu10k1_playback_{trigger,stop}_voice() is not called for stereo
slaves any more.

snd_emu10k1_playback_prepare_voice() is renamed to
snd_emu10k1_playback_unmute_voice(), as this better reflects its
remaining function. It's not called for the extra voices any more.

Accordingly, snd_emu10k1_playback_mute_voice() is factored out from
snd_emu10k1_playback_stop_voice(), and is called selectively as well.

This doesn't add conditionals which would avoid initializing
sub-registers, as that wouldn't pull its weight.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 include/sound/emu10k1.h    |  8 ++++
 sound/pci/emu10k1/emupcm.c | 89 ++++++++++++++++++++------------------
 2 files changed, 56 insertions(+), 41 deletions(-)
diff mbox series

Patch

diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index a5e935e16651..5c1e5b123362 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -404,6 +404,14 @@  SUB_REG(HCFG, LOCKTANKCACHE,	0x00000004)	/* 1 = Cancel bustmaster accesses to ta
 //   distortion), the modulation engine sets the target registers, towards
 //   which the current registers "swerve" gradually.
 
+// For the odd channel in a stereo pair, these registers are meaningless:
+//   CPF_STEREO, CPF_CURRENTPITCH, PTRX_PITCHTARGET, CCR_CACHEINVALIDSIZE,
+//   PSST_LOOPSTARTADDR, DSL_LOOPENDADDR, CCCA_CURRADDR
+// The somewhat non-obviously still meaningful ones are:
+//   CPF_STOP, CPF_FRACADDRESS, CCR_READADDRESS (!),
+//   CCCA_INTERPROM, CCCA_8BITSELECT (!)
+// (The envelope engine is ignored here, as stereo matters only for verbatim playback.)
+
 #define CPF			0x00		/* Current pitch and fraction register			*/
 SUB_REG(CPF, CURRENTPITCH,	0xffff0000)	/* Current pitch (linear, 0x4000 == unity pitch shift) 	*/
 #define CPF_STEREO_MASK		0x00008000	/* 1 = Even channel interleave, odd channel locked	*/
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 7b0ab4e02cfd..4ade0ef2cd1b 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -301,12 +301,12 @@  static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
 			start_addr += ccis;
 			end_addr += ccis + emu->delay_pcm_irq;
 		}
-		if (stereo && !extra) {
-			snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK);
-			snd_emu10k1_ptr_write(emu, CPF, (voice + 1), CPF_STEREO_MASK);
-		} else {
-			snd_emu10k1_ptr_write(emu, CPF, voice, 0);
-		}
+	}
+	if (stereo && !extra) {
+		// Not really necessary for the slave, but it doesn't hurt
+		snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK);
+	} else {
+		snd_emu10k1_ptr_write(emu, CPF, voice, 0);
 	}
 
 	/* setup routing */
@@ -325,6 +325,7 @@  static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
 				      snd_emu10k1_compose_send_routing(send_routing));
 	/* Assumption that PT is already 0 so no harm overwriting */
 	snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
+	// Stereo slaves don't need to have the addresses set, but it doesn't hurt
 	snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
 	snd_emu10k1_ptr_write(emu, PSST, voice,
 			(start_addr + (extra ? emu->delay_pcm_irq : 0)) |
@@ -554,8 +555,6 @@  static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
 	struct snd_pcm_runtime *runtime;
 	unsigned int voice, stereo, i, ccis, cra = 64, cs, sample;
 
-	if (evoice == NULL)
-		return;
 	runtime = evoice->epcm->substream->runtime;
 	voice = evoice->number;
 	stereo = (!extra && runtime->channels == 2);
@@ -575,71 +574,79 @@  static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
 	snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra);
 	if (stereo) {
 		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0);
+		// The engine goes haywire if this one is out of sync
 		snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra);
 	}
 	/* fill cache */
 	snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
 	if (stereo) {
 		snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis);
 	}
 }
 
-static void snd_emu10k1_playback_prepare_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice,
-					       int master,
-					       struct snd_emu10k1_pcm_mixer *mix)
+static void snd_emu10k1_playback_commit_volume(struct snd_emu10k1 *emu,
+					       struct snd_emu10k1_voice *evoice,
+					       unsigned int vattn)
+{
+	snd_emu10k1_ptr_write(emu, VTFT, evoice->number, vattn | VTFT_FILTERTARGET_MASK);
+	snd_emu10k1_ptr_write(emu, CVCF, evoice->number, vattn | CVCF_CURRENTFILTER_MASK);
+}
+
+static void snd_emu10k1_playback_unmute_voice(struct snd_emu10k1 *emu,
+					      struct snd_emu10k1_voice *evoice,
+					      bool master,
+					      struct snd_emu10k1_pcm_mixer *mix)
 {
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_runtime *runtime;
 	unsigned int vattn;
-	unsigned int voice, tmp;
+	unsigned int tmp;
 
 	if (evoice == NULL)	/* skip second voice for mono */
 		return;
 	substream = evoice->epcm->substream;
 	runtime = substream->runtime;
-	voice = evoice->number;
 
 	tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0;
-	vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0;
-	snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | VTFT_FILTERTARGET_MASK);
-	snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | CVCF_CURRENTFILTER_MASK);
+	vattn = mix->attn[tmp] << 16;
+	snd_emu10k1_playback_commit_volume(emu, evoice, vattn);
 }	
 
+static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu,
+					    struct snd_emu10k1_voice *evoice)
+{
+	if (evoice == NULL)
+		return;
+	snd_emu10k1_playback_commit_volume(emu, evoice, 0);
+}
+
 static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu,
-					       struct snd_emu10k1_voice *evoice,
-					       int master)
+					       struct snd_emu10k1_voice *evoice)
 {
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_runtime *runtime;
 	unsigned int voice, pitch_target;
 
-	if (evoice == NULL)	/* skip second voice for mono */
-		return;
 	substream = evoice->epcm->substream;
 	runtime = substream->runtime;
 	voice = evoice->number;
 
 	if (emu->card_capabilities->emu_model)
 		pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
 	else 
 		pitch_target = emu10k1_calc_pitch_target(runtime->rate);
 	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
-	if (master || evoice->epcm->type == PLAYBACK_EFX)
-		snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
+	snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
 }
 
 static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu,
 					    struct snd_emu10k1_voice *evoice)
 {
 	unsigned int voice;
 
-	if (evoice == NULL)
-		return;
 	voice = evoice->number;
 	snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0);
 	snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0);
-	snd_emu10k1_ptr_write(emu, VTFT, voice, VTFT_FILTERTARGET_MASK);
-	snd_emu10k1_ptr_write(emu, CVCF, voice, CVCF_CURRENTFILTER_MASK);
 }
 
 static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu,
@@ -698,21 +705,20 @@  static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
 		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
 			snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime);
 		mix = &emu->pcm_mixer[substream->number];
-		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, mix);
-		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, mix);
-		snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, NULL);
+		snd_emu10k1_playback_unmute_voice(emu, epcm->voices[0], true, mix);
+		snd_emu10k1_playback_unmute_voice(emu, epcm->voices[1], false, mix);
 		snd_emu10k1_playback_set_running(emu, epcm);
-		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1);
-		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0);
-		snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1);
+		snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0]);
+		snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]);
-		snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]);
 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
 		snd_emu10k1_playback_set_stopped(emu, epcm);
+		snd_emu10k1_playback_mute_voice(emu, epcm->voices[0]);
+		snd_emu10k1_playback_mute_voice(emu, epcm->voices[1]);
 		break;
 	default:
 		result = -EINVAL;
@@ -844,25 +850,26 @@  static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
 		fallthrough;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_RESUME:
-		snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, NULL);
-		snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0,
-						   &emu->efx_pcm_mixer[0]);
-		for (i = 1; i < NUM_EFX_PLAYBACK; i++)
-			snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0,
-							   &emu->efx_pcm_mixer[i]);
+		for (i = 0; i < NUM_EFX_PLAYBACK; i++)
+			snd_emu10k1_playback_unmute_voice(emu, epcm->voices[i], false,
+							  &emu->efx_pcm_mixer[i]);
+
 		snd_emu10k1_playback_set_running(emu, epcm);
 		for (i = 0; i < NUM_EFX_PLAYBACK; i++)
-			snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0);
-		snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1);
+			snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i]);
+		snd_emu10k1_playback_trigger_voice(emu, epcm->extra);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		for (i = 0; i < NUM_EFX_PLAYBACK; i++) {	
 			snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]);
 		}
 		snd_emu10k1_playback_stop_voice(emu, epcm->extra);
 		snd_emu10k1_playback_set_stopped(emu, epcm);
+
+		for (i = 0; i < NUM_EFX_PLAYBACK; i++)
+			snd_emu10k1_playback_mute_voice(emu, epcm->voices[i]);
 		break;
 	default:
 		result = -EINVAL;