--- /dev/null
+/*
+ * Kaiser Window digital filter
+ *
+ * Copyright © 2001, Keith Packard
+ * All Rights Reserved. See the file COPYING in this directory
+ * for licensing information.
+ */
+
+real i0(real x)
+{
+ real ds, d, s;
+
+ ds = 1;
+ d = 0;
+ s = 0;
+ do
+ {
+ d = d + 2;
+ ds = ds * x**2 / d**2;
+ s = s + ds;
+# printf ("ds %g s %g dist %g\n", ds, s,
+# ds - 0.2e-8 * s);
+ }
+ while (ds - 0.2e-8 * s > 0);
+ return s;
+}
+
+real highpass (real n, real m, real wc)
+{
+ real alpha = m/2;
+ real dist;
+
+ dist = n - alpha;
+ if (dist == 0)
+ return (pi/2 - wc) / pi;
+ return -sin(dist * (pi/2-wc)) / (pi * dist);
+}
+
+real lowpass (real n, real m, real wc)
+{
+ real alpha = m/2;
+ real dist;
+ dist = n - alpha;
+ if (dist == 0)
+ return wc / pi;
+ return sin (wc * dist) / (pi * dist);
+}
+
+real kaiser (real n, real m, real beta)
+{
+ real alpha = m / 2;
+ return i0 (beta * sqrt (1 - ((n - alpha) / alpha)**2)) / i0(beta);
+}
+
+void write_high (string filename,
+ real m,
+ real wc,
+ real beta,
+ real step)
+{
+ real n;
+ file f;
+
+ f = File::open (filename, "w");
+ for (n = 0; n <= m; n += step)
+ File::fprintf (f, "%g,\n", highpass (n, m, wc) * kaiser (n, m, beta));
+ File::close (f);
+}
+
+void write_low (string filename,
+ real m,
+ real wc,
+ real beta,
+ real step)
+{
+ real n;
+ file f;
+
+ f = File::open (filename, "w");
+ for (n = 0; n <= m; n += step)
+ File::fprintf (f, "%g,\n", lowpass (n, m, wc) * kaiser (n, m, beta));
+ File::close (f);
+}
+
+real β (real A)
+{
+ if (A > 50)
+ return 0.1102 * (A - 8.7);
+ else if (A >= 21)
+ return 0.5842 * (A - 21) ** 0.4 + 0.07886 * (A - 21);
+ else
+ return 0.0;
+}
+
+int M (real A, real Δω)
+{
+ if (A > 21)
+ return ceil ((A - 7.95) / (2.285 * Δω));
+ else
+ return ceil(5.79 / Δω);
+}
+
+typedef struct {
+ real ωpass;
+ real Δω;
+ real A;
+ real β;
+ int M;
+} filter_param_t;
+
+filter_param_t filter (real ωpass, real ωstop, real error)
+{
+ filter_param_t p;
+ p.ωpass = ωpass;
+ p.Δω = ωstop - ωpass;
+ p.A = -20 * log10 (error);
+ p.β = β (p.A);
+ p.M = M (p.A, p.Δω);
+ if ((p.M & 1) == 1)
+ p.M++;
+ return p;
+}
+
+real[] low_pass_filter(real ωpass, real ωstop, real error)
+{
+ filter_param_t p = filter(ωpass, ωstop, error);
+
+ return (real[p.M + 1]) {
+ [n] = lowpass(n, p.M, ωpass) * kaiser(n, p.M, p.β)
+ };
+}
+
+