39#ifdef HAVE_KERNEL_OPTION_HEADERS
47#include "snd_fxdiv_gen.h"
52#include "feeder_eq_gen.h"
54#define FEEDEQ_LEVELS \
55 (((FEEDEQ_GAIN_MAX - FEEDEQ_GAIN_MIN) * \
56 (FEEDEQ_GAIN_DIV / FEEDEQ_GAIN_STEP)) + 1)
58#define FEEDEQ_L2GAIN(v) \
59 ((int)min(((v) * FEEDEQ_LEVELS) / 100, FEEDEQ_LEVELS - 1))
61#define FEEDEQ_PREAMP_IPART(x) (abs(x) >> FEEDEQ_GAIN_SHIFT)
62#define FEEDEQ_PREAMP_FPART(x) (abs(x) & FEEDEQ_GAIN_FMASK)
63#define FEEDEQ_PREAMP_SIGNVAL(x) ((x) < 0 ? -1 : 1)
64#define FEEDEQ_PREAMP_SIGNMARK(x) (((x) < 0) ? '-' : '+')
66#define FEEDEQ_PREAMP_IMIN -192
67#define FEEDEQ_PREAMP_IMAX 192
68#define FEEDEQ_PREAMP_FMIN 0
69#define FEEDEQ_PREAMP_FMAX 9
71#define FEEDEQ_PREAMP_INVALID INT_MAX
73#define FEEDEQ_IF2PREAMP(i, f) \
74 ((abs(i) << FEEDEQ_GAIN_SHIFT) | \
75 (((abs(f) / FEEDEQ_GAIN_STEP) * FEEDEQ_GAIN_STEP) & \
78#define FEEDEQ_PREAMP_MIN \
79 (FEEDEQ_PREAMP_SIGNVAL(FEEDEQ_GAIN_MIN) * \
80 FEEDEQ_IF2PREAMP(FEEDEQ_GAIN_MIN, 0))
82#define FEEDEQ_PREAMP_MAX \
83 (FEEDEQ_PREAMP_SIGNVAL(FEEDEQ_GAIN_MAX) * \
84 FEEDEQ_IF2PREAMP(FEEDEQ_GAIN_MAX, 0))
86#define FEEDEQ_PREAMP_DEFAULT FEEDEQ_IF2PREAMP(0, 0)
88#define FEEDEQ_PREAMP2IDX(v) \
89 ((int32_t)((FEEDEQ_GAIN_MAX * (FEEDEQ_GAIN_DIV / \
90 FEEDEQ_GAIN_STEP)) + (FEEDEQ_PREAMP_SIGNVAL(v) * \
91 FEEDEQ_PREAMP_IPART(v) * (FEEDEQ_GAIN_DIV / \
92 FEEDEQ_GAIN_STEP)) + (FEEDEQ_PREAMP_SIGNVAL(v) * \
93 (FEEDEQ_PREAMP_FPART(v) / FEEDEQ_GAIN_STEP))))
130#if !defined(_KERNEL) && defined(FEEDEQ_ERR_CLIP)
131#define FEEDEQ_ERR_CLIP_CHECK(t, v) do { \
132 if ((v) < PCM_S32_MIN || (v) > PCM_S32_MAX) \
133 errx(1, "\n\n%s(): ["#t"] Sample clipping: %jd\n", \
134 __func__, (intmax_t)(v)); \
137#define FEEDEQ_ERR_CLIP_CHECK(...)
140#define FEEDEQ_CLAMP(v) (((v) > PCM_S32_MAX) ? PCM_S32_MAX : \
141 (((v) < PCM_S32_MIN) ? PCM_S32_MIN : \
144#define FEEDEQ_DECLARE(SIGN, BIT, ENDIAN) \
146feed_eq_biquad_##SIGN##BIT##ENDIAN(struct feed_eq_info *info, \
147 uint8_t *dst, uint32_t count) \
149 struct feed_eq_coeff_tone *treble, *bass; \
153 int32_t pmul, pshift; \
155 pmul = feed_eq_preamp[info->preamp].mul; \
156 pshift = feed_eq_preamp[info->preamp].shift; \
158 if (info->state == FEEDEQ_DISABLE) { \
159 j = count * info->channels; \
160 dst += j * PCM_##BIT##_BPS; \
162 dst -= PCM_##BIT##_BPS; \
163 v = _PCM_READ_##SIGN##BIT##_##ENDIAN(dst); \
164 v = ((intpcm64_t)pmul * v) >> pshift; \
165 _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, v); \
166 } while (--j != 0); \
171 treble = &(info->coeff[info->treble.gain].treble); \
172 bass = &(info->coeff[info->bass.gain].bass); \
176 j = info->channels; \
178 v = _PCM_READ_##SIGN##BIT##_##ENDIAN(dst); \
180 v = ((intpcm64_t)pmul * v) >> pshift; \
182 w = (intpcm64_t)v * treble->b0; \
183 w += (intpcm64_t)info->treble.i1[i] * treble->b1; \
184 w += (intpcm64_t)info->treble.i2[i] * treble->b2; \
185 w -= (intpcm64_t)info->treble.o1[i] * treble->a1; \
186 w -= (intpcm64_t)info->treble.o2[i] * treble->a2; \
187 info->treble.i2[i] = info->treble.i1[i]; \
188 info->treble.i1[i] = v; \
189 info->treble.o2[i] = info->treble.o1[i]; \
190 w >>= FEEDEQ_COEFF_SHIFT; \
191 FEEDEQ_ERR_CLIP_CHECK(treble, w); \
192 v = FEEDEQ_CLAMP(w); \
193 info->treble.o1[i] = v; \
195 w = (intpcm64_t)v * bass->b0; \
196 w += (intpcm64_t)info->bass.i1[i] * bass->b1; \
197 w += (intpcm64_t)info->bass.i2[i] * bass->b2; \
198 w -= (intpcm64_t)info->bass.o1[i] * bass->a1; \
199 w -= (intpcm64_t)info->bass.o2[i] * bass->a2; \
200 info->bass.i2[i] = info->bass.i1[i]; \
201 info->bass.i1[i] = v; \
202 info->bass.o2[i] = info->bass.o1[i]; \
203 w >>= FEEDEQ_COEFF_SHIFT; \
204 FEEDEQ_ERR_CLIP_CHECK(bass, w); \
205 v = FEEDEQ_CLAMP(w); \
206 info->bass.o1[i] = v; \
209 _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, v); \
210 dst += PCM_##BIT##_BPS; \
212 } while (--j != 0); \
213 } while (--count != 0); \
216#if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
220#if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
224#ifdef SND_FEEDER_MULTIFORMAT
237#define FEEDEQ_ENTRY(SIGN, BIT, ENDIAN) \
239 AFMT_##SIGN##BIT##_##ENDIAN, \
240 feed_eq_biquad_##SIGN##BIT##ENDIAN \
247#if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
251#if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
255#ifdef SND_FEEDER_MULTIFORMAT
269#define FEEDEQ_BIQUAD_TAB_SIZE \
270 ((int32_t)(sizeof(feed_eq_biquad_tab) / sizeof(feed_eq_biquad_tab[0])))
272static struct feed_eq_coeff *
275 uint32_t
spd, threshold;
278 if (rate < FEEDEQ_RATE_MIN || rate > FEEDEQ_RATE_MAX)
285 for (i = 0; i < FEEDEQ_TAB_SIZE; i++) {
286 spd = feed_eq_tab[i].rate;
287 threshold =
spd + ((i < (FEEDEQ_TAB_SIZE - 1) &&
288 feed_eq_tab[i + 1].
rate >
spd) ?
289 ((feed_eq_tab[i + 1].rate -
spd) >> 1) : 0);
292 return (feed_eq_tab[i].coeff);
313 for (i = 0; i < info->
channels; i++) {
330 if (info->
coeff == NULL)
355 if (biquad_op == NULL)
358 info = malloc(
sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO);
365 info->
rate = FEEDEQ_RATE_MIN;
403 if (value < 0 || value > 100)
437 free(info, M_DEVBUF);
467 if (count < info->
align)
475 info->
biquad(info, dst, j);
481 }
while (
count != 0);
512 r = sscanf(s,
"%d.%d", &i, &f);
515 snprintf(
buf,
sizeof(
buf),
"%c%d",
521 snprintf(
buf,
sizeof(
buf),
"%c%d.%d",
527 if (
len > 2 && strcasecmp(s +
len - 2,
"dB") == 0)
528 strlcat(
buf,
"dB",
sizeof(
buf));
530 if (i == 0 && *s ==
'-')
533 if (strcasecmp(
buf + ((*s >=
'0' && *s <=
'9') ? 1 : 0), s) != 0)
536 while ((f / FEEDEQ_GAIN_DIV) > 0)
537 f /= FEEDEQ_GAIN_DIV;
567 err = sysctl_handle_int(oidp, &
val, 0,
req);
569 if (err == 0 &&
req->newptr != NULL &&
val != oval) {
570 if (!(
val == 0 ||
val == 1 ||
val == 2)) {
581 }
else if (
val == 1) {
620 (void)snprintf(
buf,
sizeof(
buf),
"%c%d.%ddB",
627 err = sysctl_handle_string(oidp,
buf,
sizeof(
buf),
req);
629 if (err == 0 &&
req->newptr != NULL) {
670 d = device_get_softc(
dev);
672 if (!(resource_string_value(device_get_name(
dev), device_get_unit(
dev),
673 "eq_preamp", &preamp) == 0 &&
683 SYSCTL_ADD_PROC(device_get_sysctl_ctx(
dev),
684 SYSCTL_CHILDREN(device_get_sysctl_tree(
dev)), OID_AUTO,
685 "eq", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d,
687 "Bass/Treble Equalizer (0=disable, 1=enable, 2=bypass)");
689 (void)snprintf(
buf,
sizeof(
buf),
"Bass/Treble Equalizer Preamp "
690 "(-/+ %d.0dB , %d.%ddB step)",
691 FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_STEP / FEEDEQ_GAIN_DIV,
692 FEEDEQ_GAIN_STEP - ((FEEDEQ_GAIN_STEP / FEEDEQ_GAIN_DIV) *
695 SYSCTL_ADD_PROC(device_get_sysctl_ctx(
dev),
696 SYSCTL_CHILDREN(device_get_sysctl_tree(
dev)), OID_AUTO,
697 "eq_preamp", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
#define CHN_FOREACH(x, y, z)
struct pcm_feeder * chn_findfeeder(struct pcm_channel *c, u_int32_t type)
#define FEEDEQ_PREAMP_IMAX
#define FEEDEQ_ENTRY(SIGN, BIT, ENDIAN)
static int sysctl_dev_pcm_eq_preamp(SYSCTL_HANDLER_ARGS)
static struct feed_eq_coeff * feed_eq_coeff_rate(uint32_t rate)
FEEDER_DECLARE(feeder_eq, NULL)
#define FEEDEQ_IF2PREAMP(i, f)
static int feeder_eq_exact_rate
static struct pcm_feederdesc feeder_eq_desc[]
static char feeder_eq_presets[]
void feeder_eq_initsys(device_t dev)
#define FEEDEQ_PREAMP_INVALID
#define FEEDEQ_PREAMP_FPART(x)
int feeder_eq_validrate(uint32_t rate)
static int32_t feed_eq_scan_preamp_arg(const char *s)
static const struct @42 feed_eq_biquad_tab[]
static int feed_eq_set(struct pcm_feeder *f, int what, int value)
#define FEEDEQ_PREAMP_FMAX
SND_DECLARE_FILE("$FreeBSD$")
#define FEEDEQ_PREAMP2IDX(v)
#define FEEDEQ_PREAMP_MIN
static int feed_eq_init(struct pcm_feeder *f)
static int feed_eq_setup(struct feed_eq_info *info)
SYSCTL_STRING(_hw_snd, OID_AUTO, feeder_eq_presets, CTLFLAG_RD, &feeder_eq_presets, 0, "compile-time eq presets")
void(* feed_eq_t)(struct feed_eq_info *, uint8_t *, uint32_t)
SYSCTL_INT(_hw_snd, OID_AUTO, feeder_eq_exact_rate, CTLFLAG_RWTUN, &feeder_eq_exact_rate, 0, "force exact rate validation")
static int feed_eq_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source)
static void feed_eq_reset(struct feed_eq_info *info)
#define FEEDEQ_BIQUAD_TAB_SIZE
static kobj_method_t feeder_eq_methods[]
#define FEEDEQ_PREAMP_DEFAULT
#define FEEDEQ_PREAMP_MAX
static int feed_eq_free(struct pcm_feeder *f)
#define FEEDEQ_DECLARE(SIGN, BIT, ENDIAN)
#define FEEDEQ_PREAMP_IPART(x)
static int sysctl_dev_pcm_eq(SYSCTL_HANDLER_ARGS)
#define FEEDEQ_PREAMP_SIGNMARK(x)
#define PCM_RELEASE_QUICK(x)
#define PCM_REGISTERED(x)
struct feed_eq_tone treble
struct feed_eq_coeff * coeff
struct pcm_feeder * source
struct pcm_feederdesc * desc
struct snddev_info::@49::@50::@51 busy
struct snddev_info::@49::@50 pcm