summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorAhmad Fatoum <ahmad@a3f.at>2021-01-31 21:18:42 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2021-02-08 10:57:05 +0100
commit01a55d345dbb8d861cda0d430d42c3bbbaff718a (patch)
treee22881f24ddb8ae83eb7211137ccb92ff331be44 /include
parent78dd61b47e5d93240b3d112c51fa3b1896c4f6e6 (diff)
downloadbarebox-01a55d345dbb8d861cda0d430d42c3bbbaff718a.tar.gz
barebox-01a55d345dbb8d861cda0d430d42c3bbbaff718a.tar.xz
sound: add basic synthesizers for PCM beeper use
For beeping on PCM sound cards, barebox will need to synthesize samples. Add basic sine and square wave synthesizers to achieve this. Client code can either call __synth_F to explicitly select synth F or synth_F, which depending on CONFIG_SYNTH_SQUARES may expand to either __synth_F or a gain-adjusted __synth_generate_square. The latter is mainly useful for slow systems that can't synthesize enough sine samples in a poller without impacting boot performance. Signed-off-by: Ahmad Fatoum <ahmad@a3f.at> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'include')
-rw-r--r--include/linux/fixp-arith.h144
-rw-r--r--include/sound.h32
2 files changed, 176 insertions, 0 deletions
diff --git a/include/linux/fixp-arith.h b/include/linux/fixp-arith.h
new file mode 100644
index 0000000000..8396013785
--- /dev/null
+++ b/include/linux/fixp-arith.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _FIXP_ARITH_H
+#define _FIXP_ARITH_H
+
+#include <linux/math64.h>
+
+/*
+ * Simplistic fixed-point arithmetics.
+ * Hmm, I'm probably duplicating some code :(
+ *
+ * Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <johann.deneux@gmail.com>
+ */
+
+#include <linux/types.h>
+
+static const s32 sin_table[] = {
+ 0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c,
+ 0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd,
+ 0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e,
+ 0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44,
+ 0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb,
+ 0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1,
+ 0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04,
+ 0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82,
+ 0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039,
+ 0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879,
+ 0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf,
+ 0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af,
+ 0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884,
+ 0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095,
+ 0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e,
+ 0x7fffffff
+};
+
+/**
+ * __fixp_sin32() returns the sin of an angle in degrees
+ *
+ * @degrees: angle, in degrees, from 0 to 360.
+ *
+ * The returned value ranges from -0x7fffffff to +0x7fffffff.
+ */
+static inline s32 __fixp_sin32(int degrees)
+{
+ s32 ret;
+ bool negative = false;
+
+ if (degrees > 180) {
+ negative = true;
+ degrees -= 180;
+ }
+ if (degrees > 90)
+ degrees = 180 - degrees;
+
+ ret = sin_table[degrees];
+
+ return negative ? -ret : ret;
+}
+
+/**
+ * fixp_sin32() returns the sin of an angle in degrees
+ *
+ * @degrees: angle, in degrees. The angle can be positive or negative
+ *
+ * The returned value ranges from -0x7fffffff to +0x7fffffff.
+ */
+static inline s32 fixp_sin32(int degrees)
+{
+ degrees = (degrees % 360 + 360) % 360;
+
+ return __fixp_sin32(degrees);
+}
+
+/* cos(x) = sin(x + 90 degrees) */
+#define fixp_cos32(v) fixp_sin32((v) + 90)
+
+/*
+ * 16 bits variants
+ *
+ * The returned value ranges from -0x7fff to 0x7fff
+ */
+
+#define fixp_sin16(v) (fixp_sin32(v) >> 16)
+#define fixp_cos16(v) (fixp_cos32(v) >> 16)
+
+/**
+ * fixp_sin32_rad() - calculates the sin of an angle in radians
+ *
+ * @radians: angle, in radians
+ * @twopi: value to be used for 2*pi
+ *
+ * Provides a variant for the cases where just 360
+ * values is not enough. This function uses linear
+ * interpolation to a wider range of values given by
+ * twopi var.
+ *
+ * Experimental tests gave a maximum difference of
+ * 0.000038 between the value calculated by sin() and
+ * the one produced by this function, when twopi is
+ * equal to 360000. That seems to be enough precision
+ * for practical purposes.
+ *
+ * Please notice that two high numbers for twopi could cause
+ * overflows, so the routine will not allow values of twopi
+ * bigger than 1^18.
+ */
+static inline s32 fixp_sin32_rad(u32 radians, u32 twopi)
+{
+ int degrees;
+ s32 v1, v2, dx, dy;
+ s64 tmp;
+
+ /*
+ * Avoid too large values for twopi, as we don't want overflows.
+ */
+ BUG_ON(twopi > 1 << 18);
+
+ degrees = (radians * 360) / twopi;
+ tmp = radians - (degrees * twopi) / 360;
+
+ degrees = (degrees % 360 + 360) % 360;
+ v1 = __fixp_sin32(degrees);
+
+ v2 = fixp_sin32(degrees + 1);
+
+ dx = twopi / 360;
+ dy = v2 - v1;
+
+ tmp *= dy;
+
+ return v1 + div_s64(tmp, dx);
+}
+
+/* cos(x) = sin(x + pi/2 radians) */
+
+#define fixp_cos32_rad(rad, twopi) \
+ fixp_sin32_rad(rad + twopi / 4, twopi)
+
+#endif
diff --git a/include/sound.h b/include/sound.h
index f5124aebbd..62fef106ee 100644
--- a/include/sound.h
+++ b/include/sound.h
@@ -42,4 +42,36 @@ static inline int beep_cancel(void)
return sound_card_beep_cancel(sound_card_get_default());
}
+
+/*
+ * Synthesizers all have the same prototype, but their implementation
+ * is replaced with a gain-adjusted square wave if CONFIG_SYNTH_SQUARES=y.
+ * This is to support PCM beeping on systems, where sine generation may
+ * spend to much time in the poller.
+ */
+typedef void synth_t(unsigned freq, s16 amplitude, s16 *stream,
+ unsigned sample_rate, unsigned nsamples);
+
+#ifdef CONFIG_SYNTH_SQUARES
+#define SYNTH(fn, volume_percent) \
+ static inline void fn(unsigned f, s16 amplitude, s16 *s, \
+ unsigned r, unsigned n) { \
+ synth_t __synth_square; \
+ amplitude = amplitude * volume_percent / 100; \
+ __synth_square(f, amplitude, s, r, n); \
+ } \
+ synth_t __##fn
+#else
+#define SYNTH(fn, volume_percent) \
+ static inline void fn(unsigned f, s16 a, s16 *s, \
+ unsigned r, unsigned n) { \
+ synth_t __##fn; \
+ __##fn(f, a, s, r, n); \
+ } \
+ synth_t __##fn
+#endif
+
+SYNTH(synth_square, 100); /* square wave always has full amplitude */
+SYNTH(synth_sin, 64); /* ∫₀¹ sin(πx) dx ≈ 64% */
+
#endif