[PATCH 0/4] ALSA: emu10k1: capture-related improvements
Oswald Buddenhagen (4): ALSA: emu10k1: fix capture buffer size confusion ALSA: emu10k1: fix support for 24 kHz capture ALSA: emu10k1: don't restrict capture channel count to powers of two ALSA: emu10k1: fix multi-channel capture config for E-MU cards
sound/pci/emu10k1/emupcm.c | 122 +++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 60 deletions(-)
The buffer size register sets the size of the whole buffer, not just one period. We actually handled it like that, except that the constraint was set on the wrong parameter. The period size is implicitly constrained by the buffer size and the fixed period count of 2.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emupcm.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 0572dfb80943..6a24e3e80aea 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -122,20 +122,20 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm *epcm, return 0; }
-static const unsigned int capture_period_sizes[31] = { +static const unsigned int capture_buffer_sizes[31] = { 384, 448, 512, 640, 384*2, 448*2, 512*2, 640*2, 384*4, 448*4, 512*4, 640*4, 384*8, 448*8, 512*8, 640*8, 384*16, 448*16, 512*16, 640*16, 384*32, 448*32, 512*32, 640*32, 384*64, 448*64, 512*64, 640*64, 384*128,448*128,512*128 };
-static const struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_capture_buffer_sizes = { .count = 31, - .list = capture_period_sizes, + .list = capture_buffer_sizes, .mask = 0 };
@@ -498,7 +498,7 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream); epcm->capture_bs_val = 0; for (idx = 0; idx < 31; idx++) { - if (capture_period_sizes[idx] == epcm->capture_bufsize) { + if (capture_buffer_sizes[idx] == epcm->capture_bufsize) { epcm->capture_bs_val = idx + 1; break; } @@ -1154,9 +1154,10 @@ static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_capture; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + &hw_constraints_capture_buffer_sizes); emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt; emu->pcm_capture_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates); return 0; } @@ -1193,9 +1194,10 @@ static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream) runtime->hw.rates = SNDRV_PCM_RATE_8000; runtime->hw.rate_min = runtime->hw.rate_max = 8000; runtime->hw.channels_min = 1; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + &hw_constraints_capture_buffer_sizes); emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt; emu->pcm_capture_mic_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); return 0; }
@@ -1300,9 +1302,10 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) epcm->capture_cr_val = emu->efx_voices_mask[0]; epcm->capture_cr_val2 = emu->efx_voices_mask[1]; spin_unlock_irq(&emu->reg_lock); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + &hw_constraints_capture_buffer_sizes); emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt; emu->pcm_capture_efx_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); return 0; }
We need to specify that the hardware supports non-standard rates, as otherwise the sound core creates a constraint which limits the rate to the specified standard rates. That also made the rate constraint we were already adding meaningless.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emupcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 6a24e3e80aea..fd3fc96c08e9 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -941,7 +941,7 @@ static const struct snd_pcm_hardware snd_emu10k1_capture = SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, .rate_max = 48000, .channels_min = 1,
The hardware can deal with primes up to 7 and power-of-two multiples thereof; the limitation is reflected by the possible buffer sizes.
Note that setting the voice mask will not allow more than 16 channels even on Sound Blaster Audigy anymore, as 32 seems a bit excessive (the code overall appears to think so, just not in this case).
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emupcm.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index fd3fc96c08e9..ac10b53525fd 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -122,6 +122,17 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm *epcm, return 0; }
+// Primes 2-7 and 2^n multiples thereof, up to 16. +static const unsigned int efx_capture_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16 +}; + +static const struct snd_pcm_hw_constraint_list hw_constraints_efx_capture_channels = { + .count = ARRAY_SIZE(efx_capture_channels), + .list = efx_capture_channels, + .mask = 0 +}; + static const unsigned int capture_buffer_sizes[31] = { 384, 448, 512, 640, 384*2, 448*2, 512*2, 640*2, @@ -1216,7 +1227,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) struct snd_emu10k1_pcm *epcm; struct snd_pcm_runtime *runtime = substream->runtime; int nefx = emu->audigy ? 64 : 32; - int idx; + int idx, err;
epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) @@ -1302,6 +1313,12 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) epcm->capture_cr_val = emu->efx_voices_mask[0]; epcm->capture_cr_val2 = emu->efx_voices_mask[1]; spin_unlock_irq(&emu->reg_lock); + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &hw_constraints_efx_capture_channels); + if (err < 0) { + kfree(epcm); + return err; + } snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, &hw_constraints_capture_buffer_sizes); emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt; @@ -1466,22 +1483,16 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int nval[2], bits; int nefx = emu->audigy ? 64 : 32; - int nefxb = emu->audigy ? 7 : 6; int change, idx; nval[0] = nval[1] = 0; for (idx = 0, bits = 0; idx < nefx; idx++) if (ucontrol->value.integer.value[idx]) { nval[idx / 32] |= 1 << (idx % 32); bits++; }
- // Check that the number of requested channels is a power of two - // not bigger than the number of available channels. - for (idx = 0; idx < nefxb; idx++) - if (1 << idx == bits) - break; - if (idx >= nefxb) + if (bits == 9 || bits == 11 || bits == 13 || bits == 15 || bits > 16) return -EINVAL;
spin_lock_irq(&emu->reg_lock);
On SB cards the number of captured channels is derived from the voice mask mixer control. But for E-MU cards this wasn't actually "wired up", so changing the mask would simply mess up the recording.
We could fix that, but the channel routing through the FPGA makes the masking redundant. So instead we hide the control, and let the user specify the PCM channel count the traditional way.
Signed-off-by: Oswald Buddenhagen oswald.buddenhagen@gmx.de --- sound/pci/emu10k1/emupcm.c | 76 ++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 44 deletions(-)
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index ac10b53525fd..c7f17b6e7469 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -494,6 +494,12 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); break; case CAPTURE_EFX: + if (emu->card_capabilities->emu_model) { + // The upper 32 16-bit capture voices, two for each of the 16 32-bit channels. + // The lower voices are occupied by A_EXTOUT_*_CAP*. + epcm->capture_cr_val = 0; + epcm->capture_cr_val2 = 0xffffffff >> (32 - runtime->channels * 2); + } if (emu->audigy) { snd_emu10k1_ptr_write_multiple(emu, 0, A_FXWC1, 0, @@ -977,8 +983,8 @@ static const struct snd_pcm_hardware snd_emu10k1_capture_efx = SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, .rate_min = 44100, .rate_max = 192000, - .channels_min = 8, - .channels_max = 8, + .channels_min = 1, + .channels_max = 16, .buffer_bytes_max = (64*1024), .period_bytes_min = 384, .period_bytes_max = (64*1024), @@ -1204,7 +1210,6 @@ static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream) runtime->hw = snd_emu10k1_capture; runtime->hw.rates = SNDRV_PCM_RATE_8000; runtime->hw.rate_min = runtime->hw.rate_max = 8000; - runtime->hw.channels_min = 1; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, &hw_constraints_capture_buffer_sizes); emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt; @@ -1245,16 +1250,13 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) runtime->hw = snd_emu10k1_capture_efx; runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; - spin_lock_irq(&emu->reg_lock); if (emu->card_capabilities->emu_model) { /* TODO * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 * rate_min = 44100, * rate_max = 192000, - * channels_min = 16, - * channels_max = 16, * Need to add mixer control to fix sample rate * * There are 32 mono channels of 16bits each. @@ -1273,15 +1275,11 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) /* For 44.1kHz */ runtime->hw.rates = SNDRV_PCM_RATE_44100; runtime->hw.rate_min = runtime->hw.rate_max = 44100; - runtime->hw.channels_min = - runtime->hw.channels_max = 16; break; case 1: /* For 48kHz */ runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; - runtime->hw.channels_min = - runtime->hw.channels_max = 16; break; } #endif @@ -1298,21 +1296,19 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) runtime->hw.channels_min = runtime->hw.channels_max = 2; #endif runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; - /* efx_voices_mask[0] is expected to be zero - * efx_voices_mask[1] is expected to have 32bits set - */ } else { + spin_lock_irq(&emu->reg_lock); runtime->hw.channels_min = runtime->hw.channels_max = 0; for (idx = 0; idx < nefx; idx++) { if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { runtime->hw.channels_min++; runtime->hw.channels_max++; } } + epcm->capture_cr_val = emu->efx_voices_mask[0]; + epcm->capture_cr_val2 = emu->efx_voices_mask[1]; + spin_unlock_irq(&emu->reg_lock); } - epcm->capture_cr_val = emu->efx_voices_mask[0]; - epcm->capture_cr_val2 = emu->efx_voices_mask[1]; - spin_unlock_irq(&emu->reg_lock); err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_efx_capture_channels); if (err < 0) { @@ -1779,37 +1775,29 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) strcpy(pcm->name, "Multichannel Capture/PT Playback"); emu->pcm_efx = pcm;
- /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs - * to these - */ - - if (emu->audigy) { - emu->efx_voices_mask[0] = 0; - if (emu->card_capabilities->emu_model) - /* Pavel Hofman - 32 voices will be used for - * capture (write mode) - - * each bit = corresponding voice - */ - emu->efx_voices_mask[1] = 0xffffffff; - else + if (!emu->card_capabilities->emu_model) { + // On Sound Blasters, the DSP code copies the EXTINs to FXBUS2. + // The mask determines which of these and the EXTOUTs the multi- + // channel capture actually records (the channel order is fixed). + if (emu->audigy) { + emu->efx_voices_mask[0] = 0; emu->efx_voices_mask[1] = 0xffff; + } else { + emu->efx_voices_mask[0] = 0xffff0000; + emu->efx_voices_mask[1] = 0; + } + kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu); + if (!kctl) + return -ENOMEM; + kctl->id.device = device; + err = snd_ctl_add(emu->card, kctl); + if (err < 0) + return err; } else { - emu->efx_voices_mask[0] = 0xffff0000; - emu->efx_voices_mask[1] = 0; + // On E-MU cards, the DSP code copies the P16VINs/EMU32INs to + // FXBUS2. These are already selected & routed by the FPGA, + // so there is no need to apply additional masking. } - /* For emu1010, the control has to set 32 upper bits (voices) - * out of the 64 bits (voices) to true for the 16-channels capture - * to work correctly. Correct A_FXWC2 initial value (0xffffffff) - * is already defined but the snd_emu10k1_pcm_efx_voices_mask - * control can override this register's value. - */ - kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu); - if (!kctl) - return -ENOMEM; - kctl->id.device = device; - err = snd_ctl_add(emu->card, kctl); - if (err < 0) - return err;
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev, 64*1024, 64*1024);
On Tue, 23 May 2023 22:07:05 +0200, Oswald Buddenhagen wrote:
Oswald Buddenhagen (4): ALSA: emu10k1: fix capture buffer size confusion ALSA: emu10k1: fix support for 24 kHz capture ALSA: emu10k1: don't restrict capture channel count to powers of two ALSA: emu10k1: fix multi-channel capture config for E-MU cards
Applied all patches now. Thanks.
Takashi
participants (2)
-
Oswald Buddenhagen
-
Takashi Iwai