+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
+
+#define FILTER(name, type) \
+static int filter_channels_## name(AVFilterContext *ctx, void *arg, \
+ int jobnr, int nb_jobs) \
+{ \
+ ASuperCutContext *s = ctx->priv; \
+ ThreadData *td = arg; \
+ AVFrame *out = td->out; \
+ AVFrame *in = td->in; \
+ const int start = (in->channels * jobnr) / nb_jobs; \
+ const int end = (in->channels * (jobnr+1)) / nb_jobs; \
+ \
+ for (int ch = start; ch < end; ch++) { \
+ const type *src = (const type *)in->extended_data[ch]; \
+ type *dst = (type *)out->extended_data[ch]; \
+ \
+ for (int b = 0; b < s->filter_count; b++) { \
+ BiquadCoeffs *coeffs = &s->coeffs[b]; \
+ const type a1 = coeffs->a1; \
+ const type a2 = coeffs->a2; \
+ const type b0 = coeffs->b0; \
+ const type b1 = coeffs->b1; \
+ const type b2 = coeffs->b2; \
+ type *w = ((type *)s->w->extended_data[ch]) + b * 2; \
+ \
+ for (int n = 0; n < in->nb_samples; n++) { \
+ type sin = b ? dst[n] : src[n]; \
+ type sout = sin * b0 + w[0]; \
+ \
+ w[0] = b1 * sin + w[1] + a1 * sout; \
+ w[1] = b2 * sin + a2 * sout; \
+ \
+ dst[n] = sout; \
+ } \
+ } \
+ } \
+ \
+ return 0; \
+}
+
+FILTER(fltp, float)
+FILTER(dblp, double)
+