diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2005-08-10 04:21:43 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-08-30 02:44:46 -0400 |
commit | 9bcf655109ae06a8e652671a0de6fe2da5c213c2 (patch) | |
tree | 13c6001737bf5f0ae3e32b188259bff64c8d4e01 /sound | |
parent | a55bfdc5821df787068da15a6864f2c669d7d22c (diff) |
[ALSA] ymfpci: add per-voice volume controls
YMFPCI driver
Implements mixer controls for the volume of each playback substream of
the main PCM device.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/ymfpci/ymfpci_main.c | 232 |
1 files changed, 160 insertions, 72 deletions
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index d54f88a1b525..054836412dc4 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -321,6 +321,26 @@ static void snd_ymfpci_pcm_interrupt(ymfpci_t *chip, ymfpci_voice_t *voice) | |||
321 | snd_pcm_period_elapsed(ypcm->substream); | 321 | snd_pcm_period_elapsed(ypcm->substream); |
322 | spin_lock(&chip->reg_lock); | 322 | spin_lock(&chip->reg_lock); |
323 | } | 323 | } |
324 | |||
325 | if (unlikely(ypcm->update_pcm_vol)) { | ||
326 | unsigned int subs = ypcm->substream->number; | ||
327 | unsigned int next_bank = 1 - chip->active_bank; | ||
328 | snd_ymfpci_playback_bank_t *bank; | ||
329 | u32 volume; | ||
330 | |||
331 | bank = &voice->bank[next_bank]; | ||
332 | volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15); | ||
333 | bank->left_gain_end = volume; | ||
334 | if (ypcm->output_rear) | ||
335 | bank->eff2_gain_end = volume; | ||
336 | if (ypcm->voices[1]) | ||
337 | bank = &ypcm->voices[1]->bank[next_bank]; | ||
338 | volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15); | ||
339 | bank->right_gain_end = volume; | ||
340 | if (ypcm->output_rear) | ||
341 | bank->eff3_gain_end = volume; | ||
342 | ypcm->update_pcm_vol--; | ||
343 | } | ||
324 | } | 344 | } |
325 | spin_unlock(&chip->reg_lock); | 345 | spin_unlock(&chip->reg_lock); |
326 | } | 346 | } |
@@ -451,87 +471,74 @@ static int snd_ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices) | |||
451 | return 0; | 471 | return 0; |
452 | } | 472 | } |
453 | 473 | ||
454 | static void snd_ymfpci_pcm_init_voice(ymfpci_voice_t *voice, int stereo, | 474 | static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx, |
455 | int rate, int w_16, unsigned long addr, | 475 | snd_pcm_runtime_t *runtime, |
456 | unsigned int end, | 476 | int has_pcm_volume) |
457 | int output_front, int output_rear) | ||
458 | { | 477 | { |
478 | ymfpci_voice_t *voice = ypcm->voices[voiceidx]; | ||
459 | u32 format; | 479 | u32 format; |
460 | u32 delta = snd_ymfpci_calc_delta(rate); | 480 | u32 delta = snd_ymfpci_calc_delta(runtime->rate); |
461 | u32 lpfQ = snd_ymfpci_calc_lpfQ(rate); | 481 | u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate); |
462 | u32 lpfK = snd_ymfpci_calc_lpfK(rate); | 482 | u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate); |
463 | snd_ymfpci_playback_bank_t *bank; | 483 | snd_ymfpci_playback_bank_t *bank; |
464 | unsigned int nbank; | 484 | unsigned int nbank; |
485 | u32 vol_left, vol_right; | ||
486 | u8 use_left, use_right; | ||
465 | 487 | ||
466 | snd_assert(voice != NULL, return); | 488 | snd_assert(voice != NULL, return); |
467 | format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000); | 489 | if (runtime->channels == 1) { |
490 | use_left = 1; | ||
491 | use_right = 1; | ||
492 | } else { | ||
493 | use_left = (voiceidx & 1) == 0; | ||
494 | use_right = !use_left; | ||
495 | } | ||
496 | if (has_pcm_volume) { | ||
497 | vol_left = cpu_to_le32(ypcm->chip->pcm_mixer | ||
498 | [ypcm->substream->number].left << 15); | ||
499 | vol_right = cpu_to_le32(ypcm->chip->pcm_mixer | ||
500 | [ypcm->substream->number].right << 15); | ||
501 | } else { | ||
502 | vol_left = cpu_to_le32(0x40000000); | ||
503 | vol_right = cpu_to_le32(0x40000000); | ||
504 | } | ||
505 | format = runtime->channels == 2 ? 0x00010000 : 0; | ||
506 | if (snd_pcm_format_width(runtime->format) == 8) | ||
507 | format |= 0x80000000; | ||
508 | if (runtime->channels == 2 && (voiceidx & 1) != 0) | ||
509 | format |= 1; | ||
468 | for (nbank = 0; nbank < 2; nbank++) { | 510 | for (nbank = 0; nbank < 2; nbank++) { |
469 | bank = &voice->bank[nbank]; | 511 | bank = &voice->bank[nbank]; |
512 | memset(bank, 0, sizeof(*bank)); | ||
470 | bank->format = cpu_to_le32(format); | 513 | bank->format = cpu_to_le32(format); |
471 | bank->loop_default = 0; | 514 | bank->base = cpu_to_le32(runtime->dma_addr); |
472 | bank->base = cpu_to_le32(addr); | 515 | bank->loop_end = cpu_to_le32(ypcm->buffer_size); |
473 | bank->loop_start = 0; | ||
474 | bank->loop_end = cpu_to_le32(end); | ||
475 | bank->loop_frac = 0; | ||
476 | bank->eg_gain_end = cpu_to_le32(0x40000000); | ||
477 | bank->lpfQ = cpu_to_le32(lpfQ); | 516 | bank->lpfQ = cpu_to_le32(lpfQ); |
478 | bank->status = 0; | ||
479 | bank->num_of_frames = 0; | ||
480 | bank->loop_count = 0; | ||
481 | bank->start = 0; | ||
482 | bank->start_frac = 0; | ||
483 | bank->delta = | 517 | bank->delta = |
484 | bank->delta_end = cpu_to_le32(delta); | 518 | bank->delta_end = cpu_to_le32(delta); |
485 | bank->lpfK = | 519 | bank->lpfK = |
486 | bank->lpfK_end = cpu_to_le32(lpfK); | 520 | bank->lpfK_end = cpu_to_le32(lpfK); |
487 | bank->eg_gain = cpu_to_le32(0x40000000); | 521 | bank->eg_gain = |
488 | bank->lpfD1 = | 522 | bank->eg_gain_end = cpu_to_le32(0x40000000); |
489 | bank->lpfD2 = 0; | 523 | |
490 | 524 | if (ypcm->output_front) { | |
491 | bank->left_gain = | 525 | if (use_left) { |
492 | bank->right_gain = | 526 | bank->left_gain = |
493 | bank->left_gain_end = | 527 | bank->left_gain_end = vol_left; |
494 | bank->right_gain_end = | 528 | } |
495 | bank->eff1_gain = | 529 | if (use_right) { |
496 | bank->eff2_gain = | ||
497 | bank->eff3_gain = | ||
498 | bank->eff1_gain_end = | ||
499 | bank->eff2_gain_end = | ||
500 | bank->eff3_gain_end = 0; | ||
501 | |||
502 | if (!stereo) { | ||
503 | if (output_front) { | ||
504 | bank->left_gain = | ||
505 | bank->right_gain = | 530 | bank->right_gain = |
506 | bank->left_gain_end = | 531 | bank->right_gain_end = vol_right; |
507 | bank->right_gain_end = cpu_to_le32(0x40000000); | ||
508 | } | 532 | } |
509 | if (output_rear) { | 533 | } |
534 | if (ypcm->output_rear) { | ||
535 | if (use_left) { | ||
510 | bank->eff2_gain = | 536 | bank->eff2_gain = |
511 | bank->eff2_gain_end = | 537 | bank->eff2_gain_end = vol_left; |
512 | bank->eff3_gain = | ||
513 | bank->eff3_gain_end = cpu_to_le32(0x40000000); | ||
514 | } | ||
515 | } else { | ||
516 | if (output_front) { | ||
517 | if ((voice->number & 1) == 0) { | ||
518 | bank->left_gain = | ||
519 | bank->left_gain_end = cpu_to_le32(0x40000000); | ||
520 | } else { | ||
521 | bank->format |= cpu_to_le32(1); | ||
522 | bank->right_gain = | ||
523 | bank->right_gain_end = cpu_to_le32(0x40000000); | ||
524 | } | ||
525 | } | 538 | } |
526 | if (output_rear) { | 539 | if (use_right) { |
527 | if ((voice->number & 1) == 0) { | 540 | bank->eff3_gain = |
528 | bank->eff3_gain = | 541 | bank->eff3_gain_end = vol_right; |
529 | bank->eff3_gain_end = cpu_to_le32(0x40000000); | ||
530 | } else { | ||
531 | bank->format |= cpu_to_le32(1); | ||
532 | bank->eff2_gain = | ||
533 | bank->eff2_gain_end = cpu_to_le32(0x40000000); | ||
534 | } | ||
535 | } | 542 | } |
536 | } | 543 | } |
537 | } | 544 | } |
@@ -613,7 +620,7 @@ static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream) | |||
613 | 620 | ||
614 | static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream) | 621 | static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream) |
615 | { | 622 | { |
616 | // ymfpci_t *chip = snd_pcm_substream_chip(substream); | 623 | ymfpci_t *chip = snd_pcm_substream_chip(substream); |
617 | snd_pcm_runtime_t *runtime = substream->runtime; | 624 | snd_pcm_runtime_t *runtime = substream->runtime; |
618 | ymfpci_pcm_t *ypcm = runtime->private_data; | 625 | ymfpci_pcm_t *ypcm = runtime->private_data; |
619 | unsigned int nvoice; | 626 | unsigned int nvoice; |
@@ -623,14 +630,8 @@ static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream) | |||
623 | ypcm->period_pos = 0; | 630 | ypcm->period_pos = 0; |
624 | ypcm->last_pos = 0; | 631 | ypcm->last_pos = 0; |
625 | for (nvoice = 0; nvoice < runtime->channels; nvoice++) | 632 | for (nvoice = 0; nvoice < runtime->channels; nvoice++) |
626 | snd_ymfpci_pcm_init_voice(ypcm->voices[nvoice], | 633 | snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime, |
627 | runtime->channels == 2, | 634 | substream->pcm == chip->pcm); |
628 | runtime->rate, | ||
629 | snd_pcm_format_width(runtime->format) == 16, | ||
630 | runtime->dma_addr, | ||
631 | ypcm->buffer_size, | ||
632 | ypcm->output_front, | ||
633 | ypcm->output_rear); | ||
634 | return 0; | 635 | return 0; |
635 | } | 636 | } |
636 | 637 | ||
@@ -882,6 +883,7 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream) | |||
882 | ymfpci_t *chip = snd_pcm_substream_chip(substream); | 883 | ymfpci_t *chip = snd_pcm_substream_chip(substream); |
883 | snd_pcm_runtime_t *runtime = substream->runtime; | 884 | snd_pcm_runtime_t *runtime = substream->runtime; |
884 | ymfpci_pcm_t *ypcm; | 885 | ymfpci_pcm_t *ypcm; |
886 | snd_kcontrol_t *kctl; | ||
885 | int err; | 887 | int err; |
886 | 888 | ||
887 | if ((err = snd_ymfpci_playback_open_1(substream)) < 0) | 889 | if ((err = snd_ymfpci_playback_open_1(substream)) < 0) |
@@ -895,6 +897,10 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream) | |||
895 | chip->rear_opened++; | 897 | chip->rear_opened++; |
896 | } | 898 | } |
897 | spin_unlock_irq(&chip->reg_lock); | 899 | spin_unlock_irq(&chip->reg_lock); |
900 | |||
901 | kctl = chip->pcm_mixer[substream->number].ctl; | ||
902 | kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
903 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); | ||
898 | return 0; | 904 | return 0; |
899 | } | 905 | } |
900 | 906 | ||
@@ -987,6 +993,7 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream) | |||
987 | { | 993 | { |
988 | ymfpci_t *chip = snd_pcm_substream_chip(substream); | 994 | ymfpci_t *chip = snd_pcm_substream_chip(substream); |
989 | ymfpci_pcm_t *ypcm = substream->runtime->private_data; | 995 | ymfpci_pcm_t *ypcm = substream->runtime->private_data; |
996 | snd_kcontrol_t *kctl; | ||
990 | 997 | ||
991 | spin_lock_irq(&chip->reg_lock); | 998 | spin_lock_irq(&chip->reg_lock); |
992 | if (ypcm->output_rear && chip->rear_opened > 0) { | 999 | if (ypcm->output_rear && chip->rear_opened > 0) { |
@@ -994,6 +1001,9 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream) | |||
994 | ymfpci_close_extension(chip); | 1001 | ymfpci_close_extension(chip); |
995 | } | 1002 | } |
996 | spin_unlock_irq(&chip->reg_lock); | 1003 | spin_unlock_irq(&chip->reg_lock); |
1004 | kctl = chip->pcm_mixer[substream->number].ctl; | ||
1005 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
1006 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); | ||
997 | return snd_ymfpci_playback_close_1(substream); | 1007 | return snd_ymfpci_playback_close_1(substream); |
998 | } | 1008 | } |
999 | 1009 | ||
@@ -1665,6 +1675,66 @@ static snd_kcontrol_new_t snd_ymfpci_rear_shared __devinitdata = { | |||
1665 | .private_value = 2, | 1675 | .private_value = 2, |
1666 | }; | 1676 | }; |
1667 | 1677 | ||
1678 | /* | ||
1679 | * PCM voice volume | ||
1680 | */ | ||
1681 | |||
1682 | static int snd_ymfpci_pcm_vol_info(snd_kcontrol_t *kcontrol, | ||
1683 | snd_ctl_elem_info_t *uinfo) | ||
1684 | { | ||
1685 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1686 | uinfo->count = 2; | ||
1687 | uinfo->value.integer.min = 0; | ||
1688 | uinfo->value.integer.max = 0x8000; | ||
1689 | return 0; | ||
1690 | } | ||
1691 | |||
1692 | static int snd_ymfpci_pcm_vol_get(snd_kcontrol_t *kcontrol, | ||
1693 | snd_ctl_elem_value_t *ucontrol) | ||
1694 | { | ||
1695 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); | ||
1696 | unsigned int subs = kcontrol->id.subdevice; | ||
1697 | |||
1698 | ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left; | ||
1699 | ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right; | ||
1700 | return 0; | ||
1701 | } | ||
1702 | |||
1703 | static int snd_ymfpci_pcm_vol_put(snd_kcontrol_t *kcontrol, | ||
1704 | snd_ctl_elem_value_t *ucontrol) | ||
1705 | { | ||
1706 | ymfpci_t *chip = snd_kcontrol_chip(kcontrol); | ||
1707 | unsigned int subs = kcontrol->id.subdevice; | ||
1708 | snd_pcm_substream_t *substream; | ||
1709 | unsigned long flags; | ||
1710 | |||
1711 | if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left || | ||
1712 | ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { | ||
1713 | chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; | ||
1714 | chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; | ||
1715 | |||
1716 | substream = (snd_pcm_substream_t *)kcontrol->private_value; | ||
1717 | spin_lock_irqsave(&chip->voice_lock, flags); | ||
1718 | if (substream->runtime && substream->runtime->private_data) { | ||
1719 | ymfpci_pcm_t *ypcm = substream->runtime->private_data; | ||
1720 | ypcm->update_pcm_vol = 2; | ||
1721 | } | ||
1722 | spin_unlock_irqrestore(&chip->voice_lock, flags); | ||
1723 | return 1; | ||
1724 | } | ||
1725 | return 0; | ||
1726 | } | ||
1727 | |||
1728 | static snd_kcontrol_new_t snd_ymfpci_pcm_volume __devinitdata = { | ||
1729 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
1730 | .name = "PCM Playback Volume", | ||
1731 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1732 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
1733 | .info = snd_ymfpci_pcm_vol_info, | ||
1734 | .get = snd_ymfpci_pcm_vol_get, | ||
1735 | .put = snd_ymfpci_pcm_vol_put, | ||
1736 | }; | ||
1737 | |||
1668 | 1738 | ||
1669 | /* | 1739 | /* |
1670 | * Mixer routines | 1740 | * Mixer routines |
@@ -1686,6 +1756,7 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch) | |||
1686 | { | 1756 | { |
1687 | ac97_template_t ac97; | 1757 | ac97_template_t ac97; |
1688 | snd_kcontrol_t *kctl; | 1758 | snd_kcontrol_t *kctl; |
1759 | snd_pcm_substream_t *substream; | ||
1689 | unsigned int idx; | 1760 | unsigned int idx; |
1690 | int err; | 1761 | int err; |
1691 | static ac97_bus_ops_t ops = { | 1762 | static ac97_bus_ops_t ops = { |
@@ -1739,6 +1810,23 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch) | |||
1739 | return err; | 1810 | return err; |
1740 | } | 1811 | } |
1741 | 1812 | ||
1813 | /* per-voice volume */ | ||
1814 | substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | ||
1815 | for (idx = 0; idx < 32; ++idx) { | ||
1816 | kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip); | ||
1817 | if (!kctl) | ||
1818 | return -ENOMEM; | ||
1819 | kctl->id.device = chip->pcm->device; | ||
1820 | kctl->id.subdevice = idx; | ||
1821 | kctl->private_value = (unsigned long)substream; | ||
1822 | if ((err = snd_ctl_add(chip->card, kctl)) < 0) | ||
1823 | return err; | ||
1824 | chip->pcm_mixer[idx].left = 0x8000; | ||
1825 | chip->pcm_mixer[idx].right = 0x8000; | ||
1826 | chip->pcm_mixer[idx].ctl = kctl; | ||
1827 | substream = substream->next; | ||
1828 | } | ||
1829 | |||
1742 | return 0; | 1830 | return 0; |
1743 | } | 1831 | } |
1744 | 1832 | ||