Commit c36fd8c3cd682fa9bbe5b2cb4b99e16625a37c94
Committed by
Jaroslav Kysela
1 parent
ebe9e289d8
Exists in
master
and in
7 other branches
[ALSA] cmipci: fix distortion on rear channels
When playing multichannel data, the rear channels can get distorted if the last sample of the last played stereo stream was not zero. To avoid this, add a hack to play a few silence samples after the stream is stopped. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Showing 1 changed file with 67 additions and 1 deletions Side-by-side Diff
sound/pci/cmipci.c
... | ... | @@ -434,6 +434,7 @@ |
434 | 434 | u8 running; /* dac/adc running? */ |
435 | 435 | u8 fmt; /* format bits */ |
436 | 436 | u8 is_dac; |
437 | + u8 needs_silencing; | |
437 | 438 | unsigned int dma_size; /* in frames */ |
438 | 439 | unsigned int shift; |
439 | 440 | unsigned int ch; /* channel (0/1) */ |
... | ... | @@ -903,6 +904,7 @@ |
903 | 904 | cm->ctrl &= ~chen; |
904 | 905 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset); |
905 | 906 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); |
907 | + rec->needs_silencing = rec->is_dac; | |
906 | 908 | break; |
907 | 909 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
908 | 910 | case SNDRV_PCM_TRIGGER_SUSPEND: |
909 | 911 | |
910 | 912 | |
... | ... | @@ -1304,14 +1306,78 @@ |
1304 | 1306 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); |
1305 | 1307 | } |
1306 | 1308 | |
1309 | +/* | |
1310 | + * Apparently, the samples last played on channel A stay in some buffer, even | |
1311 | + * after the channel is reset, and get added to the data for the rear DACs when | |
1312 | + * playing a multichannel stream on channel B. This is likely to generate | |
1313 | + * wraparounds and thus distortions. | |
1314 | + * To avoid this, we play at least one zero sample after the actual stream has | |
1315 | + * stopped. | |
1316 | + */ | |
1317 | +static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) | |
1318 | +{ | |
1319 | + struct snd_pcm_runtime *runtime = rec->substream->runtime; | |
1320 | + unsigned int reg, val; | |
1321 | + | |
1322 | + if (rec->needs_silencing && runtime && runtime->dma_area) { | |
1323 | + /* set up a small silence buffer */ | |
1324 | + memset(runtime->dma_area, 0, PAGE_SIZE); | |
1325 | + reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; | |
1326 | + val = ((PAGE_SIZE / 4) - 1) | (((PAGE_SIZE / 4) / 2 - 1) << 16); | |
1327 | + snd_cmipci_write(cm, reg, val); | |
1328 | + | |
1329 | + /* configure for 16 bits, 2 channels, 8 kHz */ | |
1330 | + if (runtime->channels > 2) | |
1331 | + set_dac_channels(cm, rec, 2); | |
1332 | + spin_lock_irq(&cm->reg_lock); | |
1333 | + val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); | |
1334 | + val &= ~(CM_ASFC_MASK << (rec->ch * 3)); | |
1335 | + val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3); | |
1336 | + snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); | |
1337 | + val = snd_cmipci_read(cm, CM_REG_CHFORMAT); | |
1338 | + val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); | |
1339 | + val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); | |
1340 | + if (cm->chip_version == 68) { | |
1341 | + val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); | |
1342 | + val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); | |
1343 | + } | |
1344 | + snd_cmipci_write(cm, CM_REG_CHFORMAT, val); | |
1345 | + | |
1346 | + /* start stream (we don't need interrupts) */ | |
1347 | + cm->ctrl |= CM_CHEN0 << rec->ch; | |
1348 | + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); | |
1349 | + spin_unlock_irq(&cm->reg_lock); | |
1350 | + | |
1351 | + msleep(1); | |
1352 | + | |
1353 | + /* stop and reset stream */ | |
1354 | + spin_lock_irq(&cm->reg_lock); | |
1355 | + cm->ctrl &= ~(CM_CHEN0 << rec->ch); | |
1356 | + val = CM_RST_CH0 << rec->ch; | |
1357 | + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val); | |
1358 | + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val); | |
1359 | + spin_unlock_irq(&cm->reg_lock); | |
1360 | + | |
1361 | + rec->needs_silencing = 0; | |
1362 | + } | |
1363 | +} | |
1364 | + | |
1307 | 1365 | static int snd_cmipci_playback_hw_free(struct snd_pcm_substream *substream) |
1308 | 1366 | { |
1309 | 1367 | struct cmipci *cm = snd_pcm_substream_chip(substream); |
1310 | 1368 | setup_spdif_playback(cm, substream, 0, 0); |
1311 | 1369 | restore_mixer_state(cm); |
1370 | + snd_cmipci_silence_hack(cm, &cm->channel[0]); | |
1312 | 1371 | return snd_cmipci_hw_free(substream); |
1313 | 1372 | } |
1314 | 1373 | |
1374 | +static int snd_cmipci_playback2_hw_free(struct snd_pcm_substream *substream) | |
1375 | +{ | |
1376 | + struct cmipci *cm = snd_pcm_substream_chip(substream); | |
1377 | + snd_cmipci_silence_hack(cm, &cm->channel[1]); | |
1378 | + return snd_cmipci_hw_free(substream); | |
1379 | +} | |
1380 | + | |
1315 | 1381 | /* capture */ |
1316 | 1382 | static int snd_cmipci_capture_prepare(struct snd_pcm_substream *substream) |
1317 | 1383 | { |
... | ... | @@ -1736,7 +1802,7 @@ |
1736 | 1802 | .close = snd_cmipci_playback2_close, |
1737 | 1803 | .ioctl = snd_pcm_lib_ioctl, |
1738 | 1804 | .hw_params = snd_cmipci_playback2_hw_params, |
1739 | - .hw_free = snd_cmipci_hw_free, | |
1805 | + .hw_free = snd_cmipci_playback2_hw_free, | |
1740 | 1806 | .prepare = snd_cmipci_capture_prepare, /* channel B */ |
1741 | 1807 | .trigger = snd_cmipci_capture_trigger, /* channel B */ |
1742 | 1808 | .pointer = snd_cmipci_capture_pointer, /* channel B */ |