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