bw_delay optimized coefficient computation + fixed doc

This commit is contained in:
Stefano D'Angelo 2023-04-04 10:40:35 +02:00
parent 8fe8a6f995
commit 389c6266b5
2 changed files with 49 additions and 17 deletions

1
TODO
View File

@ -35,6 +35,7 @@ code:
* process1 and multi-channel
* add initial state (x0) to reset state of lp1, ap1, mm1, hs1, ls1, others? all?
* multichannel process (multiple buffers, non interleaved)
* check unused param warning visual studio
build system:
* make makefiles handle paths with spaces etc

View File

@ -24,6 +24,10 @@
* requires {{{ bw_buf bw_config bw_common bw_math }}}
* description {{{
* Interpolated delay line.
*
* You can either use the usual API for updating coefficients and processing
* signals or you can directly write and read from the delay line which,
* for example, allows you to implement smoothing and multi-tap output.
* }}}
* changelog {{{
* <ul>
@ -62,8 +66,8 @@ typedef struct _bw_delay_state bw_delay_state;
* ```>>> */
static inline void bw_delay_init(bw_delay_coeffs *BW_RESTRICT coeffs, float max_delay);
/*! <<<```
* Initializes input parameter values in `coeffs`.
* XXX
* Initializes input parameter values in `coeffs` using `max_delay` (s) as
* the maximum delay time.
*
* #### bw_delay_set_sample_rate()
* ```>>> */
@ -75,13 +79,14 @@ static inline void bw_delay_set_sample_rate(bw_delay_coeffs *BW_RESTRICT coeffs,
* ```>>> */
static inline BW_SIZE_T bw_delay_mem_req(bw_delay_coeffs *BW_RESTRICT coeffs);
/*! <<<```
* XXX
* Returns the size, in bytes, of contiguous memory to be supplied to
* `bw_delay_mem_set()` using `coeffs`.
*
* ### bw_delay_mem_set()
* ```>>> */
static inline void bw_delay_mem_set(bw_delay_state *BW_RESTRICT state, void *mem);
/*! <<<```
* XXX
* Associates the contiguous memory block `mem` to the given `state`.
*
* #### bw_delay_reset_coeffs()
* ```>>> */
@ -95,6 +100,22 @@ static inline void bw_delay_reset_state(const bw_delay_coeffs *BW_RESTRICT coeff
/*! <<<```
* Resets the given `state` to its initial values using the given `coeffs`.
*
* #### bw_delay_read()
* ```>>> */
static float bw_delay_read(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, BW_SIZE_T di, float df);
/*! <<<```
* Returns the interpolated value read from the delay line identified by
* `coeffs` and `state` by applying a delay of `di` + `df` samples.
*
* `df` must be in [`0.f`, `1.f`) and `di` + `df` must not exceed the delay line
* length (maximum delay times the sample rate).
*
* #### bw_delay_write()
* ```>>> */
static void bw_delay_write(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, float x);
/*! <<<```
* Pushes the new sample `x` on the delay line identified by `coeffs` and `state.
*
* #### bw_delay_update_coeffs_ctrl()
* ```>>> */
static inline void bw_delay_update_coeffs_ctrl(bw_delay_coeffs *BW_RESTRICT coeffs);
@ -126,7 +147,7 @@ static inline void bw_delay_process(bw_delay_coeffs *BW_RESTRICT coeffs, bw_dela
* ```>>> */
static inline void bw_delay_set_delay(bw_delay_coeffs *BW_RESTRICT coeffs, float value);
/*! <<<```
* XXX
* Sets the delay time `value` (s) in `coeffs`.
*
* Default value: `0.f`.
* }}} */
@ -144,9 +165,13 @@ struct _bw_delay_coeffs {
float fs;
BW_SIZE_T len;
BW_SIZE_T di;
float df;
// Parameters
float max_delay;
float delay;
char delay_changed;
};
struct _bw_delay_state {
@ -173,7 +198,8 @@ static inline void bw_delay_mem_set(bw_delay_state *BW_RESTRICT state, void *mem
}
static inline void bw_delay_reset_coeffs(bw_delay_coeffs *BW_RESTRICT coeffs) {
(void)coeffs;
coeffs->delay_changed = 1;
bw_delay_update_coeffs_ctrl(coeffs);
}
static inline void bw_delay_reset_state(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state) {
@ -181,10 +207,10 @@ static inline void bw_delay_reset_state(const bw_delay_coeffs *BW_RESTRICT coeff
state->idx = 0;
}
static float bw_delay_read(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, BW_SIZE_T d_int, float d_frac) {
const BW_SIZE_T n = (state->idx + (state->idx >= d_int ? 0 : coeffs->len)) - d_int;
static float bw_delay_read(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, BW_SIZE_T di, float df) {
const BW_SIZE_T n = (state->idx + (state->idx >= di ? 0 : coeffs->len)) - di;
const BW_SIZE_T p = (n ? n : coeffs->len) - 1;
return state->buf[n] + d_frac * (state->buf[p] - state->buf[n]);
return state->buf[n] + df * (state->buf[p] - state->buf[n]);
}
static void bw_delay_write(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, float x) {
@ -194,7 +220,13 @@ static void bw_delay_write(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_s
}
static inline void bw_delay_update_coeffs_ctrl(bw_delay_coeffs *BW_RESTRICT coeffs) {
(void)coeffs;
if (coeffs->delay_changed) {
const float s = coeffs->delay * coeffs->fs;
const float f = bw_floorf(s);
coeffs->di = (BW_SIZE_T)f;
coeffs->df = s - f;
coeffs->delay_changed = 0;
}
}
static inline void bw_delay_update_coeffs_audio(bw_delay_coeffs *BW_RESTRICT coeffs) {
@ -202,22 +234,21 @@ static inline void bw_delay_update_coeffs_audio(bw_delay_coeffs *BW_RESTRICT coe
}
static inline float bw_delay_process1(const bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, float x) {
// XXX optim, coeffs
const float s = coeffs->delay * coeffs->fs;
const float f = bw_floorf(s);
const float d = s - f;
const BW_SIZE_T j = (BW_SIZE_T)f;
bw_delay_write(coeffs, state, x);
return bw_delay_read(coeffs, state, j, d);
return bw_delay_read(coeffs, state, coeffs->di, coeffs->df);
}
static inline void bw_delay_process(bw_delay_coeffs *BW_RESTRICT coeffs, bw_delay_state *BW_RESTRICT state, const float *x, float *y, int n_samples) {
bw_delay_update_coeffs_ctrl(coeffs);
for (int i = 0; i < n_samples; i++)
y[i] = bw_delay_process1(coeffs, state, x[i]);
}
static inline void bw_delay_set_delay(bw_delay_coeffs *BW_RESTRICT coeffs, float value) {
coeffs->delay = value;
if (value != coeffs->delay) {
coeffs->delay = value;
coeffs->delay_changed = 1;
}
}
#ifdef __cplusplus