From 02a964d4536c5214ea866b035b786d7603f77ee7 Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Tue, 14 Mar 2023 15:50:00 +0100 Subject: [PATCH] tentative bw_src_int, cosmetic change to bw_svf --- TODO | 1 + include/bw_src_int.h | 197 +++++++++++++++++++++++++++++++++++++++++++ include/bw_svf.h | 2 +- 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 include/bw_src_int.h diff --git a/TODO b/TODO index be7454b..f1cd935 100644 --- a/TODO +++ b/TODO @@ -31,6 +31,7 @@ code: * MEM_REQ_ROUGH() macro? * use BW_SIZE_T, check constant types * web examples: need to export memset? +* cite papers, thank authors build system: * make makefiles handle paths with spaces etc diff --git a/include/bw_src_int.h b/include/bw_src_int.h new file mode 100644 index 0000000..816a75d --- /dev/null +++ b/include/bw_src_int.h @@ -0,0 +1,197 @@ +/* + * Brickworks + * + * Copyright (C) 2023 Orastron Srl unipersonale + * + * Brickworks is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * Brickworks is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Brickworks. If not, see . + * + * File author: Stefano D'Angelo + */ + +/*! + * module_type {{{ dsp }}} + * version {{{ 0.4.0 }}} + * requires {{{ bw_config bw_common bw_math }}} + * description {{{ + * Integer-ratio IIR sample rate converter. + * + * Multi-rate filtering inspired by + * + * M. Holters and J.Parker, "A Combined Model for a Bucket Brigade Device and + * its Input and Output Filters", 21st Intl. Conf. Digital Audio Effects + * (DAFx-18), Aveiro, Portugal, September 2018. + * }}} + * changelog {{{ + * + * }}} + */ + +#ifndef _BW_SRC_INT_H +#define _BW_SRC_INT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*! api {{{ + * #### bw_src_int_coeffs + * ```>>> */ +typedef struct _bw_src_int_coeffs bw_src_int_coeffs; +/*! <<<``` + * Coefficients and related. + * + * ### bw_src_int_state + * ```>>> */ +typedef struct _bw_src_int_state bw_src_int_state; +/*! <<<``` + * Internal state and related. + * + * #### bw_src_int_init() + * ```>>> */ +static inline void bw_src_int_init(bw_src_int_coeffs *BW_RESTRICT coeffs, int ratio); +/*! <<<``` + * Initializes input parameter values in `coeffs`. + * XXX + * + * #### bw_src_int_reset_state() + * ```>>> */ +static inline void bw_src_int_reset_state(const bw_src_int_coeffs *BW_RESTRICT coeffs, bw_src_int_state *BW_RESTRICT state, float x0); +/*! <<<``` + * XXX + * + * #### bw_src_int_process() + * ```>>> */ +static inline int bw_src_int_process(const bw_src_int_coeffs *BW_RESTRICT coeffs, bw_src_int_state *BW_RESTRICT state, const float *x, float *y, int n_in_samples); +/*! <<<``` + * XXX + * }}} */ + +/*** Implementation ***/ + +/* WARNING: This part of the file is not part of the public API. Its content may + * change at any time in future versions. Please, do not use it directly. */ + +#include + +struct _bw_src_int_coeffs { + int ratio; + float a1; + float a2; + float a3; + float a4; + float b0; + float b1; + float b2; + float b3; + float b4; +}; + +struct _bw_src_int_state { + int i; + float z1; + float z2; + float z3; + float z4; + float xz1; + float xz2; + float xz3; + float xz4; +}; + +static inline void bw_src_int_init(bw_src_int_coeffs *BW_RESTRICT coeffs, int ratio) { + coeffs->ratio = ratio; + // TODO: better filter, perhaps optimzied coefficients + ratio = ratio >= 0 ? ratio : -ratio; + coeffs->a1 = (12.56637061435917f - 8.f * ratio) / (2.f * ratio + 3.141592653589793f); + coeffs->a2 = (ratio * (24.f * ratio - 75.39822368615503f) + 59.21762640653615f) / (ratio * (4.f * ratio + 12.56637061435917f) + 9.869604401089358f); + coeffs->a3 = (ratio * ((150.7964473723101f - 32.f * ratio) * ratio - 236.8705056261446f) + 124.0251067211993f) / (ratio * (ratio * (8.f * ratio + 37.69911184307752f) + 59.21762640653615f) + 31.00627668029982f); + coeffs->a4 = (ratio * (ratio * (ratio * (16.f * ratio - 100.5309649148734f) + 236.8705056261446f) - 248.0502134423985f) + 97.40909103400242f) / (ratio * (ratio * (ratio * (16.f * ratio + 100.5309649148734f) + 236.8705056261446f) + 248.0502134423985f) + 97.40909103400242f); + coeffs->b0 = 97.40909103400242f / (ratio * (ratio * (ratio * (16.f * ratio + 100.5309649148734f) + 236.8705056261446f) + 248.0502134423985f) + 97.40909103400242f); + coeffs->b1 = 4.f * coeffs->b0; + coeffs->b2 = 6.f * coeffs->b0; + coeffs->b3 = coeffs->b1; + coeffs->b4 = coeffs->b0; +} + +static inline void bw_src_int_reset_state(const bw_src_int_coeffs *BW_RESTRICT coeffs, bw_src_int_state *BW_RESTRICT state, float x0) { + if (coeffs->ratio < 0) { + // DF-II + state->z1 = x0 / (1.f + coeffs->a1 + coeffs->a2 + coeffs->a3 + coeffs->a4); + state->z2 = state->z1; + state->z3 = state->z2; + state->z4 = state->z3; + state->i = -coeffs->ratio; + } else { + // DF-I + state->z1 = x0; + state->z2 = x0; + state->z3 = x0; + state->z4 = x0; + state->xz1 = x0; + state->xz2 = x0; + state->xz3 = x0; + state->xz4 = x0; + } +} + +static inline int bw_src_int_process(const bw_src_int_coeffs *BW_RESTRICT coeffs, bw_src_int_state *BW_RESTRICT state, const float *x, float *y, int n_in_samples) { + n = 0; + if (coeffs->ratio < 0) { + for (int i = 0; i < n_in_samples; i++) { + // DF-II + const float z0 = x[i] - coeffs->a1 * state->z1 - coeffs->a2 * state->z2 - coeffs->a3 * state->z3 - coeffs->a4 * state->z4; + state->i--; + if (!state->i) { + state->i = -coeffs->ratio; + y[n] = coeffs->b0 * z0 + coeffs->b1 * state->z1 + coeffs->b2 * state->z2 + coeffs->b3 * state->z3 + coeffs->b4 * state->z4; + n++; + } + state->z4 = state->z3; + state->z3 = state->z2; + state->z2 = state->z1; + state->z1 = z0; + } + } else { + for (int i = 0; i < n_in_samples; i++) { + // DF-I + const float v = coeffs->b0 * x[i] + coeffs->b1 * state->xz1 + coeffs->b2 * state->xz2 + coeffs->b3 * state->xz3 + coeffs->b4 * state->xz4; + state->xz4 = state->xz3; + state->xz3 = state->xz2; + state->xz2 = state->xz1; + state->xz1 = x[i]; + for (int j = 0; j < coeffs->ratio; j++) { + y[n] = v - coeffs->a1 * state->z1 - coeffs->a2 * state->z2 - coeffs->a3 * state->z3 - coeffs->a4 * state->z4; + state->z4 = state->z3; + state->z3 = state->z2; + state->z2 = state->z1; + state->z1 = y[n]; + n++; + } + } + } + return n; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/bw_svf.h b/include/bw_svf.h index 7544e37..0141af5 100644 --- a/include/bw_svf.h +++ b/include/bw_svf.h @@ -21,7 +21,7 @@ /*! * module_type {{{ dsp }}} * version {{{ 0.3.0 }}} - * requires {{{ bw_config bw_common bw_one_pole bw_math }}} + * requires {{{ bw_config bw_common bw_math bw_one_pole }}} * description {{{ * State variable filter (2nd order, 12 dB/oct) model with separated lowpass, * bandpass, and highpass outputs.