snd_pcm seperate vchan pcm volume mixing
Simon 'corecode' Schubert
corecode at fs.ei.tum.de
Thu Jan 19 08:45:57 PST 2006
joerg at xxxxxxxxxxxxxxxxx wrote:
On Thu, Jan 19, 2006 at 02:56:20PM +0100, Simon 'corecode' Schubert wrote:
opinions?
Don't use a percentage, but e.g. 256 level, replacing the division by a
normal shift. Please also conditionalize that part of the code to be
only used for non-maximum (max == default?) loudness, so it doesn't add
a penalty when not in use.
how about this
--
Serve - BSD +++ RENT this banner advert +++ ASCII Ribbon /"\
Work - Mac +++ space for low â¬â¬â¬ NOW!1 +++ Campaign \ /
Party Enjoy Relax | http://dragonflybsd.org Against HTML \
Dude 2c 2 the max ! http://golden-apple.biz Mail + News / \
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/channel.c
--- a/sys/dev/sound/pcm/channel.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/channel.c Thu Jan 19 17:30:11 2006 +0100
@@ -724,6 +724,9 @@
if (ret)
goto out;
+ ret = chn_setvolume(c, 100, 100);
+ if (ret)
+ goto out;
out:
if (ret) {
@@ -783,7 +786,7 @@
{
CHN_LOCKASSERT(c);
/* could add a feeder for volume changing if channel returns -1 */
- c->volume = (left << 8) | right;
+ c->volume = (right << 8) | left;
return 0;
}
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/dsp.c
--- a/sys/dev/sound/pcm/dsp.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/dsp.c Thu Jan 19 17:30:11 2006 +0100
@@ -432,6 +432,46 @@
return ret;
}
+int
+dsp_vchanvolume(dev_t i_dev, int write, int *volume, int *ret,
+ struct thread *td)
+{
+ struct snddev_info *d;
+ void *cookie;
+ struct pcm_channel *ch;
+ int vol_left, vol_right;
+
+ crit_enter();
+ d = dsp_get_info(i_dev);
+ if (d == NULL) {
+ crit_exit();
+ return 0;
+ }
+ /*
+ * We search for a vchan which is owned by the current process.
+ */
+ for (cookie = NULL; (ch = pcm_chn_iterate(d, &cookie)) != NULL;)
+ if (ch->flags & CHN_F_VIRTUAL &&
+ ch->pid == td->td_proc->p_pid)
+ break;
+
+ if (ch == NULL) {
+ crit_exit();
+ return 0;
+ }
+
+ if (write) {
+ vol_left = min(*volume & 0x00ff, 100);
+ vol_right = min((*volume & 0xff00) >> 8, 100);
+ *ret = chn_setvolume(ch, vol_left, vol_right);
+ } else {
+ *volume = ch->volume;
+ *ret = 0;
+ }
+ crit_exit();
+ return 1;
+}
+
static int
dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
{
@@ -439,19 +479,6 @@
struct snddev_info *d;
int kill;
int ret = 0, *arg_i = (int *)arg, tmp;
-
- /*
- * this is an evil hack to allow broken apps to perform mixer ioctls
- * on dsp devices.
- */
-
- if (IOCGROUP(cmd) == 'M') {
- dev_t pdev;
-
- pdev = make_adhoc_dev(&dsp_cdevsw,
- PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0));
- return mixer_ioctl(pdev, cmd, arg, mode, td);
- }
crit_enter();
d = dsp_get_info(i_dev);
@@ -471,6 +498,40 @@
wrch = NULL;
if (kill & 2)
rdch = NULL;
+
+ /*
+ * 4Front OSS specifies that dsp devices allow mixer controls to
+ * control PCM == their volume.
+ */
+ if (IOCGROUP(cmd) == 'M') {
+ dev_t pdev;
+
+ /*
+ * For now only set the channel volume for vchans, pass
+ * all others to the mixer.
+ */
+ if (wrch != NULL && wrch->flags & CHN_F_VIRTUAL &&
+ (cmd & 0xff) == SOUND_MIXER_PCM) {
+ if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
+ int vol_raw = *(int *)arg;
+ int vol_left, vol_right;
+
+ vol_left = min(vol_raw & 0x00ff, 100);
+ vol_right = min((vol_raw & 0xff00) >> 8, 100);
+ ret = chn_setvolume(wrch, vol_left, vol_right);
+ } else {
+ *(int *)arg = wrch->volume;
+ }
+ } else {
+ pdev = make_adhoc_dev(&dsp_cdevsw,
+ PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0));
+ ret = mixer_ioctl(pdev, cmd, arg, mode, td);
+ }
+
+ relchns(i_dev, rdch, wrch, 0);
+ crit_exit();
+ return ret;
+ }
switch(cmd) {
#ifdef OLDPCM_IOCTL
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/dsp.h
--- a/sys/dev/sound/pcm/dsp.h Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/dsp.h Thu Jan 19 17:30:11 2006 +0100
@@ -31,3 +31,5 @@
int dsp_registerrec(int unit, int channel);
int dsp_unregister(int unit, int channel);
int dsp_unregisterrec(int unit, int channel);
+int dsp_vchanvolume(dev_t i_dev, int write, int *volume, int *ret,
+ struct thread *td);
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/mixer.c
--- a/sys/dev/sound/pcm/mixer.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/mixer.c Thu Jan 19 17:30:11 2006 +0100
@@ -451,6 +451,23 @@
if (!m->busy)
return EBADF;
+ /*
+ * If we are handling PCM, maybe the app really wants to
+ * set its vchan, and fails to use the correct fd.
+ */
+ if (j == SOUND_MIXER_PCM) {
+ dev_t pdev;
+
+ pdev = make_adhoc_dev(&mixer_cdevsw,
+ PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_DSP, 0));
+
+ if (dsp_vchanvolume(pdev,
+ (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0),
+ arg_i, &ret, td))
+ return ret;
+ /* else proceed as usual */
+ }
+
crit_enter();
snd_mtxlock(m->lock);
if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/sound.c
--- a/sys/dev/sound/pcm/sound.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/sound.c Thu Jan 19 17:30:11 2006 +0100
@@ -402,6 +402,22 @@
}
return ch;
+}
+
+struct pcm_channel *
+pcm_chn_iterate(struct snddev_info *d, void **cookie)
+{
+ struct snddev_channel **last = (struct snddev_channel **)cookie;
+
+ if (*last == NULL)
+ *last = SLIST_FIRST(&d->channels);
+ else
+ *last = SLIST_NEXT(*last, link);
+
+ if (*last == NULL)
+ return NULL;
+ else
+ return (*last)->channel;
}
int
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/sound.h
--- a/sys/dev/sound/pcm/sound.h Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/sound.h Thu Jan 19 17:30:11 2006 +0100
@@ -222,6 +222,7 @@
int pcm_inprog(struct snddev_info *d, int delta);
struct pcm_channel *pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo);
+struct pcm_channel *pcm_chn_iterate(struct snddev_info *d, void **cookie);
int pcm_chn_destroy(struct pcm_channel *ch);
int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev);
int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev);
diff -r 04ea340a2ccb -r a27ad04bd731 sys/dev/sound/pcm/vchan.c
--- a/sys/dev/sound/pcm/vchan.c Wed Jan 18 09:59:34 2006 +0000
+++ b/sys/dev/sound/pcm/vchan.c Thu Jan 19 17:30:11 2006 +0100
@@ -45,18 +45,27 @@
};
static int
-vchan_mix_s16(int16_t *to, int16_t *tmp, unsigned int count)
+vchan_mix_s16(int16_t *to, int16_t *tmp, unsigned int count, int volume)
{
/*
* to is the output buffer, tmp is the input buffer
* count is the number of 16bit samples to mix
+ * volume is in range 0-100
*/
int i;
int x;
+ int scale;
+ int doscale;
+
+ scale = (volume << 16) / 100;
+ doscale = volume != 100;
for(i = 0; i < count; i++) {
x = to[i];
- x += tmp[i];
+ if (doscale)
+ x += ((int)tmp[i] * scale) >> 16;
+ else
+ x += tmp[i];
if (x < -32768) {
/* printf("%d + %d = %d (u)\n", to[i], tmp[i], x); */
x = -32768;
@@ -79,6 +88,7 @@
struct pcm_channel *ch;
int16_t *tmp, *dst;
unsigned int cnt;
+ int volume;
KASSERT(sndbuf_getsize(src) >= count, ("bad bufsize"));
count &= ~1;
@@ -99,7 +109,10 @@
if (ch->flags & CHN_F_MAPPED)
sndbuf_acquire(ch->bufsoft, NULL, sndbuf_getfree(ch->bufsoft));
cnt = FEEDER_FEED(ch->feeder, ch, (u_int8_t *)tmp, count, ch->bufsoft);
- vchan_mix_s16(dst, tmp, cnt / 2);
+ volume = ch->volume & 0xff; /* XXX do special stereo processing? */
+ volume += (ch->volume >> 8) & 0xff;
+ volume /= 2;
+ vchan_mix_s16(dst, tmp, cnt / 2, volume);
}
}
More information about the Kernel
mailing list