ALSA: emu10k1: skip needless setting of some voice registers
authorOswald Buddenhagen <oswald.buddenhagen@gmx.de>
Tue, 16 May 2023 09:36:11 +0000 (11:36 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 17 May 2023 15:04:35 +0000 (17:04 +0200)
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>
Link: https://lore.kernel.org/r/20230516093612.3536451-6-oswald.buddenhagen@gmx.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/sound/emu10k1.h
sound/pci/emu10k1/emupcm.c

index a5e935e..5c1e5b1 100644 (file)
@@ -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      */
index 7b0ab4e..4ade0ef 100644 (file)
@@ -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,6 +574,7 @@ 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 */
@@ -584,37 +584,49 @@ static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int e
        }
 }
 
-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;
@@ -624,8 +636,7 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu,
        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,
@@ -633,13 +644,9 @@ static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu,
 {
        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,16 +850,14 @@ 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:
@@ -863,6 +867,9 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
                }
                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;