git: a33356100b85 - stable/14 - sound: Simplify pcm/feeder_mixer.c

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Mon, 17 Mar 2025 18:36:51 UTC
The branch stable/14 has been updated by christos:

URL: https://cgit.FreeBSD.org/src/commit/?id=a33356100b850d79d11b3630fda2b421f1ccba8d

commit a33356100b850d79d11b3630fda2b421f1ccba8d
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2025-03-10 20:38:23 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2025-03-17 18:28:54 +0000

    sound: Simplify pcm/feeder_mixer.c
    
    - Get rid of macro magic.
    - Make feed_mixer_info handling similar to most feeders.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D48394
    
    (cherry picked from commit 4021fa32d92d656d3d43186cc231695c7ad53d33)
---
 sys/dev/sound/pcm/feeder_mixer.c | 173 +++++++++++++++------------------------
 1 file changed, 68 insertions(+), 105 deletions(-)

diff --git a/sys/dev/sound/pcm/feeder_mixer.c b/sys/dev/sound/pcm/feeder_mixer.c
index 9a7d75198692..f5f2b9bc9c36 100644
--- a/sys/dev/sound/pcm/feeder_mixer.c
+++ b/sys/dev/sound/pcm/feeder_mixer.c
@@ -42,136 +42,83 @@
 #undef SND_FEEDER_MULTIFORMAT
 #define SND_FEEDER_MULTIFORMAT	1
 
-typedef void (*feed_mixer_t)(uint8_t *, uint8_t *, uint32_t);
-
-#define FEEDMIXER_DECLARE(SIGN, BIT, ENDIAN)				\
-static void								\
-feed_mixer_##SIGN##BIT##ENDIAN(uint8_t *src, uint8_t *dst,		\
-    uint32_t count)							\
-{									\
-	intpcm##BIT##_t z;						\
-	intpcm_t x, y;							\
-									\
-	src += count;							\
-	dst += count;							\
-									\
-	do {								\
-		src -= PCM_##BIT##_BPS;					\
-		dst -= PCM_##BIT##_BPS;					\
-		count -= PCM_##BIT##_BPS;				\
-		x = pcm_sample_read_calc(src,				\
-		    AFMT_##SIGN##BIT##_##ENDIAN);			\
-		y = pcm_sample_read_calc(dst,				\
-		    AFMT_##SIGN##BIT##_##ENDIAN);			\
-		z = INTPCM##BIT##_T(x) + y;				\
-		x = pcm_clamp_calc(z, AFMT_##SIGN##BIT##_##ENDIAN);	\
-		pcm_sample_write(dst, x,				\
-		    AFMT_##SIGN##BIT##_##ENDIAN);			\
-	} while (count != 0);						\
-}
-
-#if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-FEEDMIXER_DECLARE(S, 16, LE)
-FEEDMIXER_DECLARE(S, 32, LE)
-#endif
-#if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-FEEDMIXER_DECLARE(S, 16, BE)
-FEEDMIXER_DECLARE(S, 32, BE)
-#endif
-#ifdef SND_FEEDER_MULTIFORMAT
-FEEDMIXER_DECLARE(S,  8, NE)
-FEEDMIXER_DECLARE(S, 24, LE)
-FEEDMIXER_DECLARE(S, 24, BE)
-FEEDMIXER_DECLARE(U,  8, NE)
-FEEDMIXER_DECLARE(U, 16, LE)
-FEEDMIXER_DECLARE(U, 24, LE)
-FEEDMIXER_DECLARE(U, 32, LE)
-FEEDMIXER_DECLARE(U, 16, BE)
-FEEDMIXER_DECLARE(U, 24, BE)
-FEEDMIXER_DECLARE(U, 32, BE)
-#endif
-
 struct feed_mixer_info {
 	uint32_t format;
+	uint32_t channels;
 	int bps;
-	feed_mixer_t mix;
 };
 
-#define FEEDMIXER_ENTRY(SIGN, BIT, ENDIAN)				\
-	{								\
-		AFMT_##SIGN##BIT##_##ENDIAN, PCM_##BIT##_BPS,		\
-		feed_mixer_##SIGN##BIT##ENDIAN				\
-	}
-
-static struct feed_mixer_info feed_mixer_info_tab[] = {
-	FEEDMIXER_ENTRY(S,  8, NE),
-#if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-	FEEDMIXER_ENTRY(S, 16, LE),
-	FEEDMIXER_ENTRY(S, 32, LE),
-#endif
-#if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-	FEEDMIXER_ENTRY(S, 16, BE),
-	FEEDMIXER_ENTRY(S, 32, BE),
-#endif
-#ifdef SND_FEEDER_MULTIFORMAT
-	FEEDMIXER_ENTRY(S, 24, LE),
-	FEEDMIXER_ENTRY(S, 24, BE),
-	FEEDMIXER_ENTRY(U,  8, NE),
-	FEEDMIXER_ENTRY(U, 16, LE),
-	FEEDMIXER_ENTRY(U, 24, LE),
-	FEEDMIXER_ENTRY(U, 32, LE),
-	FEEDMIXER_ENTRY(U, 16, BE),
-	FEEDMIXER_ENTRY(U, 24, BE),
-	FEEDMIXER_ENTRY(U, 32, BE),
-#endif
-	{    AFMT_AC3, PCM_16_BPS, NULL },
-	{ AFMT_MU_LAW,  PCM_8_BPS, feed_mixer_U8NE },	/* dummy */
-	{  AFMT_A_LAW,  PCM_8_BPS, feed_mixer_U8NE }	/* dummy */
-};
+static void
+feed_mixer_apply(uint8_t *src, uint8_t *dst, uint32_t count, const uint32_t fmt)
+{
+	intpcm32_t z;
+	intpcm_t x, y;
 
-#define FEEDMIXER_TAB_SIZE	((int32_t)				\
-				 (sizeof(feed_mixer_info_tab) /		\
-				  sizeof(feed_mixer_info_tab[0])))
+	src += count;
+	dst += count;
 
-#define FEEDMIXER_DATA(i, c)	((void *)				\
-				 ((uintptr_t)((((i) & 0x1f) << 7) |	\
-				 ((c) & 0x7f))))
-#define FEEDMIXER_INFOIDX(d)	((uint32_t)((uintptr_t)(d) >> 7) & 0x1f)
-#define FEEDMIXER_CHANNELS(d)	((uint32_t)((uintptr_t)(d)) & 0x7f)
+	do {
+		src -= AFMT_BPS(fmt);
+		dst -= AFMT_BPS(fmt);
+		count -= AFMT_BPS(fmt);
+		x = pcm_sample_read_calc(src, fmt);
+		y = pcm_sample_read_calc(dst, fmt);
+		z = INTPCM_T(x) + y;
+		x = pcm_clamp_calc(z, fmt);
+		pcm_sample_write(dst, x, fmt);
+	} while (count != 0);
+}
 
 static int
 feed_mixer_init(struct pcm_feeder *f)
 {
-	int i;
+	struct feed_mixer_info *info;
 
 	if (f->desc->in != f->desc->out)
 		return (EINVAL);
 
-	for (i = 0; i < FEEDMIXER_TAB_SIZE; i++) {
-		if (AFMT_ENCODING(f->desc->in) ==
-		    feed_mixer_info_tab[i].format) {
-		    	f->data =
-			    FEEDMIXER_DATA(i, AFMT_CHANNEL(f->desc->in));
-			return (0);
-		}
-	}
+	info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (info == NULL)
+		return (ENOMEM);
+
+	info->format = AFMT_ENCODING(f->desc->in);
+	info->channels = AFMT_CHANNEL(f->desc->in);
+	info->bps = AFMT_BPS(f->desc->in);
+
+	f->data = info;
 
-	return (EINVAL);
+	return (0);
+}
+
+static int
+feed_mixer_free(struct pcm_feeder *f)
+{
+	struct feed_mixer_info *info;
+
+	info = f->data;
+	if (info != NULL)
+		free(info, M_DEVBUF);
+
+	f->data = NULL;
+
+	return (0);
 }
 
 static int
 feed_mixer_set(struct pcm_feeder *f, int what, int value)
 {
+	struct feed_mixer_info *info;
+
+	info = f->data;
 
 	switch (what) {
 	case FEEDMIXER_CHANNELS:
 		if (value < SND_CHN_MIN || value > SND_CHN_MAX)
 			return (EINVAL);
-		f->data = FEEDMIXER_DATA(FEEDMIXER_INFOIDX(f->data), value);
+		info->channels = (uint32_t)value;
 		break;
 	default:
 		return (EINVAL);
-		break;
 	}
 
 	return (0);
@@ -297,8 +244,8 @@ feed_mixer_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
 	if (sz < count)
 		count = sz;
 
-	info = &feed_mixer_info_tab[FEEDMIXER_INFOIDX(f->data)];
-	sz = info->bps * FEEDMIXER_CHANNELS(f->data);
+	info = f->data;
+	sz = info->bps * info->channels;
 	count = SND_FXROUND(count, sz);
 	if (count < sz)
 		return (0);
@@ -331,7 +278,7 @@ feed_mixer_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
 		if ((ch->flags & CHN_F_MMAP) && !(ch->flags & CHN_F_CLOSING))
 			sndbuf_acquire(ch->bufsoft, NULL,
 			    sndbuf_getfree(ch->bufsoft));
-		if (info->mix == NULL) {
+		if (c->flags & CHN_F_PASSTHROUGH) {
 			/*
 			 * Passthrough. Dump the first digital/passthrough
 			 * channel into destination buffer, and the rest into
@@ -373,7 +320,22 @@ feed_mixer_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
 						    f->desc->out), mcnt);
 						mcnt = 0;
 					}
-					info->mix(tmp, b, cnt);
+					switch (info->format) {
+					case AFMT_S16_NE:
+						feed_mixer_apply(tmp, b, cnt,
+						    AFMT_S16_NE);
+						break;
+					case AFMT_S24_NE:
+						feed_mixer_apply(tmp, b, cnt,
+						    AFMT_S24_NE);
+						break;
+					case AFMT_S32_NE:
+						feed_mixer_apply(tmp, b, cnt,
+						    AFMT_S32_NE);
+						break;
+					}
+					feed_mixer_apply(tmp, b, cnt,
+					    info->format);
 					if (cnt > rcnt)
 						rcnt = cnt;
 				}
@@ -397,6 +359,7 @@ static struct pcm_feederdesc feeder_mixer_desc[] = {
 
 static kobj_method_t feeder_mixer_methods[] = {
 	KOBJMETHOD(feeder_init,		feed_mixer_init),
+	KOBJMETHOD(feeder_free,		feed_mixer_free),
 	KOBJMETHOD(feeder_set,		feed_mixer_set),
 	KOBJMETHOD(feeder_feed,		feed_mixer_feed),
 	KOBJMETHOD_END