Commit 3bac07c8 authored by Jaroslav Kysela's avatar Jaroslav Kysela

[ALSA] split snd_emu10k1_trigger_voice into trigger and prepare functions

EMU10K1/EMU10K2 driver
This patch provides better sync between multiple voices by separating
the trigger_voice function into prepare_voice which sets up the volume
and filter parameters and trigger_voice which sets pitch target, current
and initial pitch and enables the voice interrupt.  For standard PCM
this should not make much of a difference but will be important for
minimizing phase error between voices for multichannel PCM.

This behavior was derived from the opensource.creative.com driver.
Signed-off-by: default avatarLee Revell <rlrevell@joe-job.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent cb72b251
...@@ -510,35 +510,50 @@ static void snd_emu10k1_playback_invalidate_cache(emu10k1_t *emu, emu10k1_voice_ ...@@ -510,35 +510,50 @@ static void snd_emu10k1_playback_invalidate_cache(emu10k1_t *emu, emu10k1_voice_
snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis);
} }
static void snd_emu10k1_playback_trigger_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra) static void snd_emu10k1_playback_prepare_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra)
{ {
snd_pcm_substream_t *substream; snd_pcm_substream_t *substream;
snd_pcm_runtime_t *runtime; snd_pcm_runtime_t *runtime;
emu10k1_pcm_mixer_t *mix; emu10k1_pcm_mixer_t *mix;
unsigned int voice, pitch, pitch_target, tmp;
unsigned int attn; unsigned int attn;
unsigned int voice, tmp;
if (evoice == NULL) /* skip second voice for mono */ if (evoice == NULL) /* skip second voice for mono */
return; return;
substream = evoice->epcm->substream; substream = evoice->epcm->substream;
runtime = substream->runtime; runtime = substream->runtime;
mix = &emu->pcm_mixer[substream->number];
voice = evoice->number; voice = evoice->number;
pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; mix = &emu->pcm_mixer[substream->number];
pitch_target = emu10k1_calc_pitch_target(runtime->rate);
attn = extra ? 0 : 0x00ff; attn = extra ? 0 : 0x00ff;
tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0; tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0;
snd_emu10k1_ptr_write(emu, IFATN, voice, attn); snd_emu10k1_ptr_write(emu, IFATN, voice, attn);
snd_emu10k1_ptr_write(emu, VTFT, voice, (mix->attn[tmp] << 16) | 0xffff); snd_emu10k1_ptr_write(emu, VTFT, voice, (mix->attn[tmp] << 16) | 0xffff);
snd_emu10k1_ptr_write(emu, CVCF, voice, (mix->attn[tmp] << 16) | 0xffff); snd_emu10k1_ptr_write(emu, CVCF, voice, (mix->attn[tmp] << 16) | 0xffff);
snd_emu10k1_voice_clear_loop_stop(emu, voice);
if (extra)
snd_emu10k1_voice_intr_enable(emu, voice);
snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f); snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f);
snd_emu10k1_voice_clear_loop_stop(emu, voice);
}
static void snd_emu10k1_playback_trigger_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra)
{
snd_pcm_substream_t *substream;
snd_pcm_runtime_t *runtime;
unsigned int voice, pitch, pitch_target;
if (evoice == NULL) /* skip second voice for mono */
return;
substream = evoice->epcm->substream;
runtime = substream->runtime;
voice = evoice->number;
pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
pitch_target = emu10k1_calc_pitch_target(runtime->rate);
snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target);
if (master) if (master)
snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target);
snd_emu10k1_ptr_write(emu, IP, voice, pitch); snd_emu10k1_ptr_write(emu, IP, voice, pitch);
if (extra)
snd_emu10k1_voice_intr_enable(emu, voice);
} }
static void snd_emu10k1_playback_stop_voice(emu10k1_t *emu, emu10k1_voice_t *evoice) static void snd_emu10k1_playback_stop_voice(emu10k1_t *emu, emu10k1_voice_t *evoice)
...@@ -573,6 +588,9 @@ static int snd_emu10k1_playback_trigger(snd_pcm_substream_t * substream, ...@@ -573,6 +588,9 @@ static int snd_emu10k1_playback_trigger(snd_pcm_substream_t * substream,
snd_emu10k1_playback_invalidate_cache(emu, epcm->voices[0]); snd_emu10k1_playback_invalidate_cache(emu, epcm->voices[0]);
/* follow thru */ /* follow thru */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0);
snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0);
snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1);
snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0); snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0);
snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0); snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0);
snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment