git: b2adb71308af - stable/14 - sound: Remove macro magic from pcm/feeder_eq.c

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

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

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

    sound: Remove macro magic from pcm/feeder_eq.c
    
    Turn the FEEDEQ_DECLARE macro into a single inline function
    (feed_eq_biquad()). There is no reason to have this as a macro, and it
    only complicates the code. An advantage of this patch is that, because
    we no longer call the functions created by the macro through function
    pointers (biquad_op), we can call feed_eq_biquad() directly in
    feed_eq_feed().
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D48032
    
    (cherry picked from commit e18d66d9c515abc729f5c4740b9b999d28abc333)
---
 sys/dev/sound/pcm/feeder_eq.c | 226 +++++++++++++++---------------------------
 1 file changed, 82 insertions(+), 144 deletions(-)

diff --git a/sys/dev/sound/pcm/feeder_eq.c b/sys/dev/sound/pcm/feeder_eq.c
index c5f82a2f18fc..4ed5fa57a485 100644
--- a/sys/dev/sound/pcm/feeder_eq.c
+++ b/sys/dev/sound/pcm/feeder_eq.c
@@ -101,10 +101,6 @@ SYSCTL_INT(_hw_snd, OID_AUTO, feeder_eq_exact_rate, CTLFLAG_RWTUN,
     &feeder_eq_exact_rate, 0, "force exact rate validation");
 #endif
 
-struct feed_eq_info;
-
-typedef void (*feed_eq_t)(struct feed_eq_info *, uint8_t *, uint32_t);
-
 struct feed_eq_tone {
 	intpcm_t o1[SND_CHN_MAX];
 	intpcm_t o2[SND_CHN_MAX];
@@ -117,7 +113,7 @@ struct feed_eq_info {
 	struct feed_eq_tone treble;
 	struct feed_eq_tone bass;
 	struct feed_eq_coeff *coeff;
-	feed_eq_t biquad;
+	uint32_t fmt;
 	uint32_t channels;
 	uint32_t rate;
 	uint32_t align;
@@ -135,133 +131,74 @@ struct feed_eq_info {
 #define FEEDEQ_ERR_CLIP_CHECK(...)
 #endif
 
-#define FEEDEQ_DECLARE(SIGN, BIT, ENDIAN)					\
-static void									\
-feed_eq_biquad_##SIGN##BIT##ENDIAN(struct feed_eq_info *info,			\
-    uint8_t *dst, uint32_t count)						\
-{										\
-	struct feed_eq_coeff_tone *treble, *bass;				\
-	intpcm64_t w;								\
-	intpcm_t v;								\
-	uint32_t i, j;								\
-	int32_t pmul, pshift;							\
-										\
-	pmul = feed_eq_preamp[info->preamp].mul;				\
-	pshift = feed_eq_preamp[info->preamp].shift;				\
-										\
-	if (info->state == FEEDEQ_DISABLE) {					\
-		j = count * info->channels;					\
-		dst += j * PCM_##BIT##_BPS;					\
-		do {								\
-			dst -= PCM_##BIT##_BPS;					\
-			v = pcm_sample_read(dst, AFMT_##SIGN##BIT##_##ENDIAN);	\
-			v = ((intpcm64_t)pmul * v) >> pshift;			\
-			pcm_sample_write(dst, v, AFMT_##SIGN##BIT##_##ENDIAN);	\
-		} while (--j != 0);						\
-										\
-		return;								\
-	}									\
-										\
-	treble = &(info->coeff[info->treble.gain].treble);			\
-	bass   = &(info->coeff[info->bass.gain].bass);				\
-										\
-	do {									\
-		i = 0;								\
-		j = info->channels;						\
-		do {								\
-			v = pcm_sample_read_norm(dst,				\
-			    AFMT_##SIGN##BIT##_##ENDIAN);			\
-			v = ((intpcm64_t)pmul * v) >> pshift;			\
-										\
-			w  = (intpcm64_t)v * treble->b0;			\
-			w += (intpcm64_t)info->treble.i1[i] * treble->b1;	\
-			w += (intpcm64_t)info->treble.i2[i] * treble->b2;	\
-			w -= (intpcm64_t)info->treble.o1[i] * treble->a1;	\
-			w -= (intpcm64_t)info->treble.o2[i] * treble->a2;	\
-			info->treble.i2[i] = info->treble.i1[i];		\
-			info->treble.i1[i] = v;					\
-			info->treble.o2[i] = info->treble.o1[i];		\
-			w >>= FEEDEQ_COEFF_SHIFT;				\
-			FEEDEQ_ERR_CLIP_CHECK(treble, w);			\
-			v = pcm_clamp(w, AFMT_S32_NE);				\
-			info->treble.o1[i] = v;					\
-										\
-			w  = (intpcm64_t)v * bass->b0;				\
-			w += (intpcm64_t)info->bass.i1[i] * bass->b1;		\
-			w += (intpcm64_t)info->bass.i2[i] * bass->b2;		\
-			w -= (intpcm64_t)info->bass.o1[i] * bass->a1;		\
-			w -= (intpcm64_t)info->bass.o2[i] * bass->a2;		\
-			info->bass.i2[i] = info->bass.i1[i];			\
-			info->bass.i1[i] = v;					\
-			info->bass.o2[i] = info->bass.o1[i];			\
-			w >>= FEEDEQ_COEFF_SHIFT;				\
-			FEEDEQ_ERR_CLIP_CHECK(bass, w);				\
-			v = pcm_clamp(w, AFMT_S32_NE);				\
-			info->bass.o1[i] = v;					\
-										\
-			pcm_sample_write_norm(dst, v,				\
-			    AFMT_##SIGN##BIT##_##ENDIAN);			\
-			dst += PCM_##BIT##_BPS;					\
-			i++;							\
-		} while (--j != 0);						\
-	} while (--count != 0);							\
-}
-
-#if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-FEEDEQ_DECLARE(S, 16, LE)
-FEEDEQ_DECLARE(S, 32, LE)
-#endif
-#if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-FEEDEQ_DECLARE(S, 16, BE)
-FEEDEQ_DECLARE(S, 32, BE)
-#endif
-#ifdef SND_FEEDER_MULTIFORMAT
-FEEDEQ_DECLARE(S,  8, NE)
-FEEDEQ_DECLARE(S, 24, LE)
-FEEDEQ_DECLARE(S, 24, BE)
-FEEDEQ_DECLARE(U,  8, NE)
-FEEDEQ_DECLARE(U, 16, LE)
-FEEDEQ_DECLARE(U, 24, LE)
-FEEDEQ_DECLARE(U, 32, LE)
-FEEDEQ_DECLARE(U, 16, BE)
-FEEDEQ_DECLARE(U, 24, BE)
-FEEDEQ_DECLARE(U, 32, BE)
-#endif
-
-#define FEEDEQ_ENTRY(SIGN, BIT, ENDIAN)					\
-	{								\
-		AFMT_##SIGN##BIT##_##ENDIAN,				\
-		feed_eq_biquad_##SIGN##BIT##ENDIAN			\
+__always_inline static void
+feed_eq_biquad(struct feed_eq_info *info, uint8_t *dst, uint32_t count,
+    const uint32_t fmt)
+{
+	struct feed_eq_coeff_tone *treble, *bass;
+	intpcm64_t w;
+	intpcm_t v;
+	uint32_t i, j;
+	int32_t pmul, pshift;
+
+	pmul = feed_eq_preamp[info->preamp].mul;
+	pshift = feed_eq_preamp[info->preamp].shift;
+
+	if (info->state == FEEDEQ_DISABLE) {
+		j = count * info->channels;
+		dst += j * AFMT_BPS(fmt);
+		do {
+			dst -= AFMT_BPS(fmt);
+			v = pcm_sample_read(dst, fmt);
+			v = ((intpcm64_t)pmul * v) >> pshift;
+			pcm_sample_write(dst, v, fmt);
+		} while (--j != 0);
+
+		return;
 	}
 
-static const struct {
-	uint32_t format;
-	feed_eq_t biquad;
-} feed_eq_biquad_tab[] = {
-#if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-	FEEDEQ_ENTRY(S, 16, LE),
-	FEEDEQ_ENTRY(S, 32, LE),
-#endif
-#if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
-	FEEDEQ_ENTRY(S, 16, BE),
-	FEEDEQ_ENTRY(S, 32, BE),
-#endif
-#ifdef SND_FEEDER_MULTIFORMAT
-	FEEDEQ_ENTRY(S,  8, NE),
-	FEEDEQ_ENTRY(S, 24, LE),
-	FEEDEQ_ENTRY(S, 24, BE),
-	FEEDEQ_ENTRY(U,  8, NE),
-	FEEDEQ_ENTRY(U, 16, LE),
-	FEEDEQ_ENTRY(U, 24, LE),
-	FEEDEQ_ENTRY(U, 32, LE),
-	FEEDEQ_ENTRY(U, 16, BE),
-	FEEDEQ_ENTRY(U, 24, BE),
-	FEEDEQ_ENTRY(U, 32, BE)
-#endif
-};
+	treble = &(info->coeff[info->treble.gain].treble);
+	bass   = &(info->coeff[info->bass.gain].bass);
 
-#define FEEDEQ_BIQUAD_TAB_SIZE						\
-	((int32_t)(sizeof(feed_eq_biquad_tab) / sizeof(feed_eq_biquad_tab[0])))
+	do {
+		i = 0;
+		j = info->channels;
+		do {
+			v = pcm_sample_read_norm(dst, fmt);
+			v = ((intpcm64_t)pmul * v) >> pshift;
+
+			w  = (intpcm64_t)v * treble->b0;
+			w += (intpcm64_t)info->treble.i1[i] * treble->b1;
+			w += (intpcm64_t)info->treble.i2[i] * treble->b2;
+			w -= (intpcm64_t)info->treble.o1[i] * treble->a1;
+			w -= (intpcm64_t)info->treble.o2[i] * treble->a2;
+			info->treble.i2[i] = info->treble.i1[i];
+			info->treble.i1[i] = v;
+			info->treble.o2[i] = info->treble.o1[i];
+			w >>= FEEDEQ_COEFF_SHIFT;
+			FEEDEQ_ERR_CLIP_CHECK(treble, w);
+			v = pcm_clamp(w, AFMT_S32_NE);
+			info->treble.o1[i] = v;
+
+			w  = (intpcm64_t)v * bass->b0;
+			w += (intpcm64_t)info->bass.i1[i] * bass->b1;
+			w += (intpcm64_t)info->bass.i2[i] * bass->b2;
+			w -= (intpcm64_t)info->bass.o1[i] * bass->a1;
+			w -= (intpcm64_t)info->bass.o2[i] * bass->a2;
+			info->bass.i2[i] = info->bass.i1[i];
+			info->bass.i1[i] = v;
+			info->bass.o2[i] = info->bass.o1[i];
+			w >>= FEEDEQ_COEFF_SHIFT;
+			FEEDEQ_ERR_CLIP_CHECK(bass, w);
+			v = pcm_clamp(w, AFMT_S32_NE);
+			info->bass.o1[i] = v;
+
+			pcm_sample_write_norm(dst, v, fmt);
+			dst += AFMT_BPS(fmt);
+			i++;
+		} while (--j != 0);
+	} while (--count != 0);
+}
 
 static struct feed_eq_coeff *
 feed_eq_coeff_rate(uint32_t rate)
@@ -333,26 +270,15 @@ static int
 feed_eq_init(struct pcm_feeder *f)
 {
 	struct feed_eq_info *info;
-	feed_eq_t biquad_op;
-	int i;
 
 	if (f->desc->in != f->desc->out)
 		return (EINVAL);
 
-	biquad_op = NULL;
-
-	for (i = 0; i < FEEDEQ_BIQUAD_TAB_SIZE && biquad_op == NULL; i++) {
-		if (AFMT_ENCODING(f->desc->in) == feed_eq_biquad_tab[i].format)
-			biquad_op = feed_eq_biquad_tab[i].biquad;
-	}
-
-	if (biquad_op == NULL)
-		return (EINVAL);
-
 	info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (info == NULL)
 		return (ENOMEM);
 
+	info->fmt = AFMT_ENCODING(f->desc->in);
 	info->channels = AFMT_CHANNEL(f->desc->in);
 	info->align = info->channels * AFMT_BPS(f->desc->in);
 
@@ -362,8 +288,6 @@ feed_eq_init(struct pcm_feeder *f)
 	info->preamp = FEEDEQ_PREAMP2IDX(FEEDEQ_PREAMP_DEFAULT);
 	info->state = FEEDEQ_UNKNOWN;
 
-	info->biquad = biquad_op;
-
 	f->data = info;
 
 	return (feed_eq_setup(info));
@@ -466,7 +390,21 @@ feed_eq_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
 		if (j == 0)
 			break;
 
-		info->biquad(info, dst, j);
+		/* Optimize some common formats. */
+		switch (info->fmt) {
+		case AFMT_S16_NE:
+			feed_eq_biquad(info, dst, j, AFMT_S16_NE);
+			break;
+		case AFMT_S24_NE:
+			feed_eq_biquad(info, dst, j, AFMT_S24_NE);
+			break;
+		case AFMT_S32_NE:
+			feed_eq_biquad(info, dst, j, AFMT_S32_NE);
+			break;
+		default:
+			feed_eq_biquad(info, dst, j, info->fmt);
+			break;
+		}
 
 		j *= info->align;
 		dst += j;