diff --git a/TODO b/TODO index 092ccb9..5556e6e 100644 --- a/TODO +++ b/TODO @@ -75,6 +75,7 @@ code: * reset_state_multi allow NULL input? * process allow NULL output? * #if __cplusplus >= 201103L ? - see https://stackoverflow.com/questions/5047971/how-do-i-check-for-c11-support +* get current compression level, knee build system: * make makefiles handle paths with spaces etc diff --git a/examples/fx_comp/src/bw_example_fx_comp.c b/examples/fx_comp/src/bw_example_fx_comp.c index 964c220..98c32d1 100644 --- a/examples/fx_comp/src/bw_example_fx_comp.c +++ b/examples/fx_comp/src/bw_example_fx_comp.c @@ -30,7 +30,7 @@ void bw_example_fx_comp_set_sample_rate(bw_example_fx_comp *instance, float samp void bw_example_fx_comp_reset(bw_example_fx_comp *instance) { bw_comp_reset_coeffs(&instance->comp_coeffs); - bw_comp_reset_state(&instance->comp_coeffs, &instance->comp_state); + bw_comp_reset_state(&instance->comp_coeffs, &instance->comp_state, 0.f, 0.f); } void bw_example_fx_comp_process(bw_example_fx_comp *instance, const float** x, float** y, int n_samples) { diff --git a/examples/fx_comp/vst3/Makefile b/examples/fx_comp/vst3/Makefile index c182254..2201ec4 100644 --- a/examples/fx_comp/vst3/Makefile +++ b/examples/fx_comp/vst3/Makefile @@ -4,3 +4,6 @@ NAME := bw_example_fx_comp SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fx_comp.c include ${ROOT_DIR}/../../common/vst3/vst3.mk + +CXXFLAGS += -DRELEASE=1 -DNDEBUG -DBW_NO_DEBUG +#CXXFLAGS += -DDEVELOPMENT=1 -DBW_DEBUG_DEEP diff --git a/examples/fxpp_comp/vst3/Makefile b/examples/fxpp_comp/vst3/Makefile index b5e9cc7..7320974 100644 --- a/examples/fxpp_comp/vst3/Makefile +++ b/examples/fxpp_comp/vst3/Makefile @@ -4,3 +4,6 @@ NAME := bw_example_fxpp_comp SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_fxpp_comp.cpp include ${ROOT_DIR}/../../common/vst3/vst3.mk + +CXXFLAGS += -DRELEASE=1 -DNDEBUG -DBW_NO_DEBUG +#CXXFLAGS += -DDEVELOPMENT=1 -DBW_DEBUG_DEEP diff --git a/include/bw_comp.h b/include/bw_comp.h index 84c17d1..44799c7 100644 --- a/include/bw_comp.h +++ b/include/bw_comp.h @@ -45,6 +45,7 @@ *
  • Moved C++ code to C header.
  • *
  • Added overloaded C++ process() function taking * C-style arrays as arguments.
  • + *
  • Fixed missing smoothing filter initialization.
  • *
  • Removed usage of reserved identifiers.
  • *
  • Clearly specified parameter validity ranges.
  • *
  • Added debugging code.
  • @@ -290,6 +291,34 @@ static inline void bw_comp_set_gain_dB( * `value` must be less than or equal to `770.630f`. * * Default value: `0.f`. + * + * #### bw_comp_coeffs_is_valid() + * ```>>> */ +static inline char bw_comp_coeffs_is_valid( + const bw_comp_coeffs * BW_RESTRICT coeffs); +/*! <<<``` + * Tries to determine whether `coeffs` is valid and returns non-`0` if it + * seems to be the case and `0` if it is certainly not. False positives are + * possible, false negatives are not. + * + * `coeffs` must at least point to a readable memory block of size greater + * than or equal to that of `bw_comp_coeffs`. + * + * #### bw_comp_state_is_valid() + * ```>>> */ +static inline char bw_comp_state_is_valid( + const bw_comp_coeffs * BW_RESTRICT coeffs, + const bw_comp_state * BW_RESTRICT state); +/*! <<<``` + * Tries to determine whether `state` is valid and returns non-`0` if it + * seems to be the case and `0` if it is certainly not. False positives are + * possible, false negatives are not. + * + * If `coeffs` is not `NULL` extra cross-checks might be performed (`state` + * is supposed to be associated to `coeffs`). + * + * `state` must at least point to a readable memory block of size greater + * than or equal to that of `bw_comp_state`. * }}} */ #ifdef __cplusplus @@ -357,6 +386,7 @@ static inline void bw_comp_init( bw_env_follow_init(&coeffs->env_follow_coeffs); bw_gain_init(&coeffs->gain_coeffs); + bw_one_pole_init(&coeffs->smooth_coeffs); bw_one_pole_set_tau(&coeffs->smooth_coeffs, 0.05f); coeffs->thresh = 1.f; coeffs->ratio = 1.f; @@ -411,26 +441,109 @@ static inline void bw_comp_reset_coeffs( static inline float bw_comp_reset_state( const bw_comp_coeffs * BW_RESTRICT coeffs, - bw_comp_state * BW_RESTRICT state, - float x_0, - float x_sc_0) { - (void)x_0; - bw_env_follow_reset_state(&coeffs->env_follow_coeffs, &state->env_follow_state, x_sc_0); + bw_comp_state * BW_RESTRICT state, + float x_0, + float x_sc_0) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT(state != NULL); + BW_ASSERT(bw_is_finite(x_0)); + + const float env = bw_env_follow_reset_state(&coeffs->env_follow_coeffs, &state->env_follow_state, x_sc_0); + const float thresh = bw_one_pole_get_y_z1(&coeffs->smooth_thresh_state); + float y; + if (env > thresh) { + float v = thresh * bw_rcpf(env); + if (v >= 1.175494350822287e-38f) { + v = coeffs->kc * bw_log2f(v); + y = v > -126.f ? bw_pow2f(v) * x_0 : thresh; + } else + y = thresh; + } else + y = x_0; + y = bw_gain_get_gain_cur(&coeffs->gain_coeffs) * y; + +#ifdef BW_DEBUG_DEEP + state->hash = bw_hash_sdbm("bw_comp_state"); + state->coeffs_reset_id = coeffs->reset_id; +#endif + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT_DEEP(bw_comp_state_is_valid(coeffs, state)); + BW_ASSERT(bw_is_finite(y)); + + return y; } -static inline void bw_comp_update_coeffs_ctrl(bw_comp_coeffs *BW_RESTRICT coeffs) { +static inline void bw_comp_reset_state_multi( + const bw_comp_coeffs * BW_RESTRICT coeffs, + bw_comp_state * BW_RESTRICT const * BW_RESTRICT state, + const float * x_0, + const float * x_sc_0, + float * y_0, + size_t n_channels) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT(state != NULL); + BW_ASSERT(x_0 != NULL); + BW_ASSERT(x_sc_0 != NULL); + + if (y_0 != NULL) + for (size_t i = 0; i < n_channels; i++) + y_0[i] = bw_comp_reset_state(coeffs, state[i], x_0[i], x_sc_0[i]); + else + for (size_t i = 0; i < n_channels; i++) + bw_comp_reset_state(coeffs, state[i], x_0[i], x_sc_0[i]); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT_DEEP(bw_has_only_finite(y_0, n_channels)); + BW_ASSERT_DEEP(y_0 != NULL ? bw_has_only_finite(y_0, n_channels) : 1); +} + +static inline void bw_comp_update_coeffs_ctrl( + bw_comp_coeffs * BW_RESTRICT coeffs) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + bw_env_follow_update_coeffs_ctrl(&coeffs->env_follow_coeffs); bw_gain_update_coeffs_ctrl(&coeffs->gain_coeffs); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); } -static inline void bw_comp_update_coeffs_audio(bw_comp_coeffs *BW_RESTRICT coeffs) { +static inline void bw_comp_update_coeffs_audio( + bw_comp_coeffs * BW_RESTRICT coeffs) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + bw_env_follow_update_coeffs_audio(&coeffs->env_follow_coeffs); bw_gain_update_coeffs_audio(&coeffs->gain_coeffs); bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_thresh_state, coeffs->thresh); coeffs->kc = 1.f - bw_one_pole_process1(&coeffs->smooth_coeffs, &coeffs->smooth_ratio_state, coeffs->ratio); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); } -static inline float bw_comp_process1(const bw_comp_coeffs *BW_RESTRICT coeffs, bw_comp_state *BW_RESTRICT state, float x, float x_sc) { +static inline float bw_comp_process1( + const bw_comp_coeffs * BW_RESTRICT coeffs, + bw_comp_state * BW_RESTRICT state, + float x, + float x_sc) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT(state != NULL); + BW_ASSERT_DEEP(bw_comp_state_is_valid(coeffs, state)); + BW_ASSERT(bw_is_finite(x)); + BW_ASSERT(bw_is_finite(x_sc)); + const float env = bw_env_follow_process1(&coeffs->env_follow_coeffs, &state->env_follow_state, x_sc); const float thresh = bw_one_pole_get_y_z1(&coeffs->smooth_thresh_state); float y; @@ -438,58 +551,231 @@ static inline float bw_comp_process1(const bw_comp_coeffs *BW_RESTRICT coeffs, b float v = thresh * bw_rcpf(env); if (v >= 1.175494350822287e-38f) { v = coeffs->kc * bw_log2f(v); - y = v > -126.f ? bw_pow2f(v) * x: thresh; + y = v > -126.f ? bw_pow2f(v) * x : thresh; } else y = thresh; } else y = x; y = bw_gain_process1(&coeffs->gain_coeffs, y); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT_DEEP(bw_comp_state_is_valid(coeffs, state)); + BW_ASSERT(bw_is_finite(y)); + return y; } -static inline void bw_comp_process(bw_comp_coeffs *BW_RESTRICT coeffs, bw_comp_state *BW_RESTRICT state, const float *x, const float *x_sc, float *y, size_t n_samples) { +static inline void bw_comp_process( + bw_comp_coeffs * BW_RESTRICT coeffs, + bw_comp_state * BW_RESTRICT state, + const float * x, + const float * x_sc, + float * y, + size_t n_samples) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT(state != NULL); + BW_ASSERT_DEEP(bw_comp_state_is_valid(coeffs, state)); + BW_ASSERT(x != NULL); + BW_ASSERT_DEEP(bw_has_only_finite(x, n_samples)); + BW_ASSERT(y != NULL); + bw_comp_update_coeffs_ctrl(coeffs); for (size_t i = 0; i < n_samples; i++) { bw_comp_update_coeffs_audio(coeffs); y[i] = bw_comp_process1(coeffs, state, x[i], x_sc[i]); } + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT_DEEP(bw_comp_state_is_valid(coeffs, state)); + BW_ASSERT_DEEP(bw_has_only_finite(y, n_samples)); } -static inline void bw_comp_process_multi(bw_comp_coeffs *BW_RESTRICT coeffs, bw_comp_state *BW_RESTRICT const *BW_RESTRICT state, const float * const *x, const float * const *x_sc, float * const *y, size_t n_channels, size_t n_samples) { +static inline void bw_comp_process_multi( + bw_comp_coeffs * BW_RESTRICT coeffs, + bw_comp_state * BW_RESTRICT const * BW_RESTRICT state, + const float * const * x, + const float * const * x_sc, + float * const * y, + size_t n_channels, + size_t n_samples) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); + BW_ASSERT(state != NULL); + BW_ASSERT(x != NULL); + BW_ASSERT(x_sc != NULL); + BW_ASSERT(y != NULL); + bw_comp_update_coeffs_ctrl(coeffs); for (size_t i = 0; i < n_samples; i++) { bw_comp_update_coeffs_audio(coeffs); for (size_t j = 0; j < n_channels; j++) y[j][i] = bw_comp_process1(coeffs, state[j], x[j][i], x_sc[j][i]); } + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_reset_coeffs); } -static inline void bw_comp_set_thresh_lin(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_thresh_lin( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(bw_is_finite(value)); + BW_ASSERT(value >= 1e-20f && value <= 1e20f); + coeffs->thresh = value; + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); } -static inline void bw_comp_set_thresh_dBFS(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_thresh_dBFS( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(bw_is_finite(value)); + BW_ASSERT(value >= -400.f && value <= 400.f); + coeffs->thresh = bw_dB2linf(value); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); } -static inline void bw_comp_set_ratio(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_ratio( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(bw_is_finite(value)); + BW_ASSERT(value >= 0.f && value <= 1.f); + coeffs->ratio = value; + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); } -static inline void bw_comp_set_attack_tau(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_attack_tau( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(bw_is_finite(value)); + BW_ASSERT(value >= 0.f); + bw_env_follow_set_attack_tau(&coeffs->env_follow_coeffs, value); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); } -static inline void bw_comp_set_release_tau(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_release_tau( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(bw_is_finite(value)); + BW_ASSERT(value >= 0.f); + bw_env_follow_set_release_tau(&coeffs->env_follow_coeffs, value); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); } -static inline void bw_comp_set_gain_lin(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_gain_lin( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(bw_is_finite(value)); + bw_gain_set_gain_lin(&coeffs->gain_coeffs, value); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); } -static inline void bw_comp_set_gain_dB(bw_comp_coeffs *BW_RESTRICT coeffs, float value) { +static inline void bw_comp_set_gain_dB( + bw_comp_coeffs * BW_RESTRICT coeffs, + float value) { + BW_ASSERT(coeffs != NULL); + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); + BW_ASSERT(!bw_is_nan(value)); + BW_ASSERT(value <= 770.630f); + bw_gain_set_gain_dB(&coeffs->gain_coeffs, value); + + BW_ASSERT_DEEP(bw_comp_coeffs_is_valid(coeffs)); + BW_ASSERT_DEEP(coeffs->state >= bw_comp_coeffs_state_init); +} + +static inline char bw_comp_coeffs_is_valid( + const bw_comp_coeffs * BW_RESTRICT coeffs) { + BW_ASSERT(coeffs != NULL); + +#ifdef BW_DEBUG_DEEP + if (coeffs->hash != bw_hash_sdbm("bw_comp_coeffs")) + return 0; + if (coeffs->state < bw_comp_coeffs_state_init || coeffs->state > bw_comp_coeffs_state_reset_coeffs) + return 0; +#endif + + if (!bw_is_finite(coeffs->thresh) || coeffs->thresh < 1e-20f || coeffs->thresh > 1e20f) + return 0; + if (!bw_is_finite(coeffs->ratio) || coeffs->ratio < 0.f || coeffs->ratio > 1.f) + return 0; + + if (!bw_one_pole_coeffs_is_valid(&coeffs->smooth_coeffs)) + return 0; + +#ifdef BW_DEBUG_DEEP + if (coeffs->state >= bw_comp_coeffs_state_reset_coeffs) { + if (!bw_is_finite(coeffs->kc) || coeffs->kc < 0.f || coeffs->kc > 1.f) + return 0; + + if (!bw_one_pole_state_is_valid(&coeffs->smooth_coeffs, &coeffs->smooth_thresh_state)) + return 0; + if (!bw_one_pole_state_is_valid(&coeffs->smooth_coeffs, &coeffs->smooth_ratio_state)) + return 0; + } +#endif + + return bw_env_follow_coeffs_is_valid(&coeffs->env_follow_coeffs) + && bw_gain_coeffs_is_valid(&coeffs->gain_coeffs); +} + +static inline char bw_comp_state_is_valid( + const bw_comp_coeffs * BW_RESTRICT coeffs, + const bw_comp_state * BW_RESTRICT state) { + BW_ASSERT(state != NULL); + +#ifdef BW_DEBUG_DEEP + if (state->hash != bw_hash_sdbm("bw_comp_state")) + return 0; + + if (coeffs != NULL && coeffs->reset_id != state->coeffs_reset_id) + return 0; +#endif + + (void)coeffs; + + return bw_env_follow_state_is_valid(&coeffs->env_follow_coeffs, &state->env_follow_state); } #ifdef __cplusplus @@ -509,34 +795,61 @@ class Comp { public: Comp(); - void setSampleRate(float sampleRate); - void reset( - float x_0 = 0.f, - float x_sc_0 = 0.f); - void reset( - const float *x_0, - const float *x_sc_0); - void reset( - const std::array x_0, - const std::array x_sc_0); - void process( - const float * const *x, - const float * const *x_sc, - float * const *y, - size_t nSamples); - void process( - const std::array x, - const std::array x_sc, - const std::array y, - size_t nSamples); + void setSampleRate( + float sampleRate); - void setTreshLin(float value); - void setTreshDBFS(float value); - void setRatio(float value); - void setAttackTau(float value); - void setReleaseTau(float value); - void setGainLin(float value); - void setGainDB(float value); + void reset( + float x0 = 0.f, + float xSc0 = 0.f, + float * BW_RESTRICT y0 = nullptr); + + void reset( + float x0, + float xSc0, + std::array * BW_RESTRICT y0); + + void reset( + const float * x0, + const float * xSc0, + float * y0 = nullptr); + + void reset( + std::array x0, + std::array xSc0, + std::array * BW_RESTRICT y0 = nullptr); + + void process( + const float * const * x, + const float * const * xSc, + float * const * y, + size_t nSamples); + + void process( + std::array x, + std::array xSc, + std::array y, + size_t nSamples); + + void setTreshLin( + float value); + + void setTreshDBFS( + float value); + + void setRatio( + float value); + + void setAttackTau( + float value); + + void setReleaseTau( + float value); + + void setGainLin( + float value); + + void setGainDB( + float value); /*! <<<... * } * ``` @@ -548,9 +861,9 @@ public: * change at any time in future versions. Please, do not use it directly. */ private: - bw_comp_coeffs coeffs; - bw_comp_state states[N_CHANNELS]; - bw_comp_state *BW_RESTRICT statesP[N_CHANNELS]; + bw_comp_coeffs coeffs; + bw_comp_state states[N_CHANNELS]; + bw_comp_state * BW_RESTRICT statesP[N_CHANNELS]; }; template @@ -561,85 +874,107 @@ inline Comp::Comp() { } template -inline void Comp::setSampleRate(float sampleRate) { +inline void Comp::setSampleRate( + float sampleRate) { bw_comp_set_sample_rate(&coeffs, sampleRate); } template inline void Comp::reset( - float x_0, - float x_sc_0) { + float x0, + float xSc0, + float * BW_RESTRICT y0) { bw_comp_reset_coeffs(&coeffs); - for (size_t i = 0; i < N_CHANNELS; i++) - bw_comp_reset_state(&coeffs, states + i, x_0, x_sc_0); + if (y0 != nullptr) + for (size_t i = 0; i < N_CHANNELS; i++) + y0[i] = bw_comp_reset_state(&coeffs, states + i, x0, xSc0); + else + for (size_t i = 0; i < N_CHANNELS; i++) + bw_comp_reset_state(&coeffs, states + i, x0, xSc0); } template inline void Comp::reset( - const float *x_0, - const float *x_sc_0) { - bw_comp_reset_coeffs(&coeffs); - for (size_t i = 0; i < N_CHANNELS; i++) - bw_comp_reset_state(&coeffs, states + i, x_0[i], x_sc_0[i]); + float x0, + float xSc0, + std::array * BW_RESTRICT y0) { + reset(x0, xSc0, y0 != nullptr ? y0->data() : nullptr); } template inline void Comp::reset( - const std::array x_0, - const std::array x_sc_0) { - reset(x_0.data(), x_sc_0.data()); + const float * x0, + const float * xSc0, + float * y0) { + bw_comp_reset_coeffs(&coeffs); + bw_comp_reset_state_multi(&coeffs, statesP, x0, xSc0, y0, N_CHANNELS); +} + +template +inline void Comp::reset( + std::array x0, + std::array xSc0, + std::array * BW_RESTRICT y0) { + reset(x0.data(), xSc0.data(), y0 != nullptr ? y0->data() : nullptr); } template inline void Comp::process( - const float * const *x, - const float * const *x_sc, - float * const *y, - size_t nSamples) { - bw_comp_process_multi(&coeffs, statesP, x, x_sc, y, N_CHANNELS, nSamples); + const float * const * x, + const float * const * xSc, + float * const * y, + size_t nSamples) { + bw_comp_process_multi(&coeffs, statesP, x, xSc, y, N_CHANNELS, nSamples); } template inline void Comp::process( - const std::array x, - const std::array x_sc, - const std::array y, - size_t nSamples) { - process(x.data(), x_sc.data(), y.data(), nSamples); + std::array x, + std::array xSc, + std::array y, + size_t nSamples) { + process(x.data(), xSc.data(), y.data(), nSamples); } template -inline void Comp::setTreshLin(float value) { +inline void Comp::setTreshLin( + float value) { bw_comp_set_thresh_lin(&coeffs, value); } template -inline void Comp::setTreshDBFS(float value) { +inline void Comp::setTreshDBFS( + float value) { bw_comp_set_thresh_dBFS(&coeffs, value); } template -inline void Comp::setRatio(float value) { +inline void Comp::setRatio( + float value) { bw_comp_set_ratio(&coeffs, value); } template -inline void Comp::setAttackTau(float value) { +inline void Comp::setAttackTau( + float value) { bw_comp_set_attack_tau(&coeffs, value); } template -inline void Comp::setReleaseTau(float value) { +inline void Comp::setReleaseTau( + float value) { bw_comp_set_release_tau(&coeffs, value); } template -inline void Comp::setGainLin(float value) { +inline void Comp::setGainLin( + float value) { bw_comp_set_gain_lin(&coeffs, value); } template -inline void Comp::setGainDB(float value) { +inline void Comp::setGainDB( + float value) { bw_comp_set_gain_dB(&coeffs, value); }