patch for 24-bit soft volume and uaudio's tiny fix

Kazuhito HONDA kazuhito at ph.noda.tus.ac.jp
Fri Dec 16 10:37:18 PST 2005


Hello,

We have already had a soft volume, feeder_volume_s16().
But it is of 16 bit.  So 24-bit sound streams are
always downgraded to 16-bit before soft volume 
even though a sound device has a 24-bit port.  
Thus 24-bit soft volume is necessary.

This mail has a patch for 24-bit soft volume.
I tried to use it with `SB Live! 24-bit external'
and it worked.

And the patch includes a fix of tiny mistakes in uaudio.c, too.

Sincerely yours,
Kazuhito HONDA
-------------- next part --------------
--- sys/dev/sound/pcm/feeder_volume.c.old	Tue Nov 22 10:13:37 2005
+++ sys/dev/sound/pcm/feeder_volume.c	Sat Dec 17 02:41:08 2005
@@ -67,6 +67,49 @@ feed_volume_s16(struct pcm_feeder *f, st
 	return k;
 }
 
+static int
+feed_volume_s24(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
+		uint32_t count, void *source)
+{
+	int i, k, vol[2];
+	int32_t buf, j;
+	uint8_t *buf8;
+
+	k = FEEDER_FEED(f->source, c, b, (count / 3) * 3, source);
+	if (k < 3) {
+#if 0
+		device_printf(c->dev, "%s: Not enough data (Got: %d bytes)\n",
+				__func__, k);
+#endif
+		return 0;
+	}
+#if 0
+	if (k % 3)
+		device_printf(c->dev, "%s: Bytes not 24bit aligned.\n", __func__);
+#endif
+	k -= k % 3;
+	i = k;
+	vol[0] = c->volume & 0x7f;
+	vol[1] = (c->volume >> 8) & 0x7f;
+	while (i > 2) {
+		buf = 0;
+		buf8 = (int8_t *) (&buf);
+		buf8[0] = b[--i];
+		buf8[1] = b[--i];
+		buf8[2] = b[--i];
+		j = (vol[i & 1] * buf) / 100;
+		if (j > 8388607)
+			j = 8388607;
+		if (j < -8388608)
+			j = -8388608;
+		buf8 = (int8_t *) (&j);
+		b[i + 2] = buf8[0];
+		b[i + 1] = buf8[1];
+		b[i] = buf8[2];
+	}
+	return k;
+}
+
 static struct pcm_feederdesc feeder_volume_s16_desc[] = {
 	{FEEDER_VOLUME, AFMT_S16_LE|AFMT_STEREO, AFMT_S16_LE|AFMT_STEREO, 0},
 	{0, 0, 0, 0},
@@ -76,3 +119,13 @@ static kobj_method_t feeder_volume_s16_m
 	{0, 0}
 };
 FEEDER_DECLARE(feeder_volume_s16, 2, NULL);
+
+static struct pcm_feederdesc feeder_volume_s24_desc[] = {
+	{FEEDER_VOLUME, AFMT_S24_LE|AFMT_STEREO, AFMT_S24_LE|AFMT_STEREO, 0},
+	{0, 0, 0, 0},
+};
+static kobj_method_t feeder_volume_s24_methods[] = {
+    	KOBJMETHOD(feeder_feed, feed_volume_s24),
+	{0, 0}
+};
+FEEDER_DECLARE(feeder_volume_s24, 2, NULL);
--- sys/dev/sound/pcm/channel.c.old	Fri Dec 16 23:44:24 2005
+++ sys/dev/sound/pcm/channel.c	Fri Dec 16 23:57:30 2005
@@ -1372,9 +1372,19 @@ chn_buildfeeder(struct pcm_channel *c)
 	for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) {
 		if (flags & (1 << type)) {
 			desc.type = type;
-			desc.in = 0;
 			desc.out = 0;
 			desc.flags = 0;
+			if (type == FEEDER_VOLUME) {
+				if (c->feeder->desc->out & (AFMT_S24_LE | AFMT_S24_BE | AFMT_U24_LE | AFMT_U24_BE)) {
+					desc.in = AFMT_S24_LE | AFMT_STEREO;
+				} else if (c->feeder->desc->out & (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)) {
+					desc.in = AFMT_S16_LE | AFMT_STEREO;
+				} else {
+					desc.in = 0;
+				}
+			} else {
+				desc.in = 0;
+			}
 			DEB(printf("find feeder type %d, ", type));
 			fc = feeder_getclass(&desc);
 			DEB(printf("got %p\n", fc));
--- sys/dev/sound/usb/uaudio.c.old	Sun Nov 13 23:20:26 2005
+++ sys/dev/sound/usb/uaudio.c	Sat Dec 17 00:00:11 2005
@@ -3909,10 +3909,10 @@ const struct uaudio_conversion const acc
 	{AUDIO_ENCODING_SLINEAR_LE, 8, AFMT_S8},
 	{AUDIO_ENCODING_SLINEAR_LE, 16, AFMT_S16_LE},
 	{AUDIO_ENCODING_SLINEAR_LE, 24, AFMT_S24_LE},
-	{AUDIO_ENCODING_SLINEAR_LE, 24, AFMT_S32_LE},
+	{AUDIO_ENCODING_SLINEAR_LE, 32, AFMT_S32_LE},
 	{AUDIO_ENCODING_SLINEAR_BE, 16, AFMT_S16_BE},
 	{AUDIO_ENCODING_SLINEAR_BE, 24, AFMT_S24_BE},
-	{AUDIO_ENCODING_SLINEAR_BE, 24, AFMT_S32_BE},
+	{AUDIO_ENCODING_SLINEAR_BE, 32, AFMT_S32_BE},
 	{AUDIO_ENCODING_ALAW, 8, AFMT_A_LAW},
 	{AUDIO_ENCODING_ULAW, 8, AFMT_MU_LAW},
 	{0,0,0}


More information about the freebsd-multimedia mailing list