Skip to content

Commit 23035e2

Browse files
committed
Linear interpolation (fine tuning) of sin cos coefficients
1 parent 53ef2d5 commit 23035e2

File tree

1 file changed

+56
-9
lines changed

1 file changed

+56
-9
lines changed

src/rvoice/fluid_iir_filter.cpp

+56-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323

2424
#include <algorithm>
2525
#include <cmath>
26-
26+
#include <iostream>
27+
#include <iomanip>
2728

2829
// Calculate the filter coefficients with single precision
2930
typedef float IIR_COEFF_T;
@@ -56,6 +57,30 @@ extern "C" void fluid_iir_filter_init_table(fluid_real_t sample_rate)
5657
}
5758
}
5859

60+
template<typename R>
61+
static R interp_lin(R y0, R y1, R x0, R x1, R x)
62+
{
63+
return (y0 * (x1 - x) + y1 * (x - x0)) / (x1 - x0);
64+
}
65+
66+
template<typename R>
67+
static void interp_sin_cos(R fres, sincos_t *coeff)
68+
{
69+
R diff = (fres - 1500.0f) / CENTS_STEP;
70+
71+
unsigned idx_prev = std::max(std::min(static_cast<int>(std::floor(diff)), SINCOS_TAB_SIZE - 1), 0);
72+
unsigned idx_next = std::max(std::min(static_cast<int>(std::ceil(diff)), SINCOS_TAB_SIZE - 1), 0);
73+
74+
sincos_t prev = sincos_table[idx_prev];
75+
sincos_t next = sincos_table[idx_next];
76+
77+
R x0 = idx_prev * CENTS_STEP + 1500;
78+
R x1 = idx_next * CENTS_STEP + 1500;
79+
80+
coeff->sin = interp_lin<R>(prev.sin, next.sin, x0, x1, fres);
81+
coeff->cos = interp_lin<R>(prev.cos, next.cos, x0, x1, fres);
82+
}
83+
5984

6085
template<typename R, bool GAIN_NORM, enum fluid_iir_filter_type TYPE>
6186
static inline void fluid_iir_filter_calculate_coefficients(R fres,
@@ -77,10 +102,32 @@ static inline void fluid_iir_filter_calculate_coefficients(R fres,
77102
* into account for both significant frequency relocation and for
78103
* bandwidth readjustment'. */
79104

80-
unsigned tab_idx = (fres - 1500) / CENTS_STEP;
81-
R sin_coeff = sincos_table[tab_idx].sin;
82-
R cos_coeff = sincos_table[tab_idx].cos;
83-
R alpha_coeff = sin_coeff / (2.0f * q);
105+
sincos_t coeff;
106+
interp_sin_cos<R>(fres, &coeff);
107+
108+
#ifdef DBG_FILTER
109+
{
110+
sincos_t coeff_accurate;
111+
fluid_real_t fres_hz = fluid_ct2hz(fres);
112+
R omega = (R)(2.0 * M_PI) * (fres_hz / output_rate);
113+
coeff_accurate.sin = std::sin(omega);
114+
coeff_accurate.cos = std::cos(omega);
115+
116+
std::cerr << "fres: " << std::fixed << std::setprecision(2) << fres_hz << " Hz | "
117+
<< "fres: " << std::fixed << std::setprecision(2) << fres << " Cents | "
118+
<< "sin: " << std::fixed << std::setprecision(6) << coeff.sin << " | "
119+
<< "sin_accurate: " << std::fixed << std::setprecision(6) << coeff_accurate.sin << " | "
120+
<< "abs(sin_diff): " << std::fixed << std::setprecision(6)
121+
<< std::fabs(coeff.sin - coeff_accurate.sin) << " | "
122+
<< "cos: " << std::fixed << std::setprecision(6) << coeff.cos << " | "
123+
<< "cos_accurate: " << std::fixed << std::setprecision(6) << coeff_accurate.cos << " | "
124+
<< "abs(cos_diff): " << std::fixed << std::setprecision(6)
125+
<< std::fabs(coeff.cos - coeff_accurate.cos) << std::endl;
126+
}
127+
#endif
128+
129+
130+
R alpha_coeff = coeff.sin / (2.0f * q);
84131
R a0_inv = 1.0f / (1.0f + alpha_coeff);
85132

86133
/* Calculate the filter coefficients. All coefficients are
@@ -93,7 +140,7 @@ static inline void fluid_iir_filter_calculate_coefficients(R fres,
93140
* iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*filter_gain; */
94141

95142
/* "a" coeffs are same for all 3 available filter types */
96-
R a1_temp = -2.0f * cos_coeff * a0_inv;
143+
R a1_temp = -2.0f * coeff.cos * a0_inv;
97144
R a2_temp = (1.0f - alpha_coeff) * a0_inv;
98145
R b02_temp, b1_temp;
99146

@@ -116,7 +163,7 @@ static inline void fluid_iir_filter_calculate_coefficients(R fres,
116163
switch (TYPE)
117164
{
118165
case FLUID_IIR_HIGHPASS:
119-
b1_temp = (1.0f + cos_coeff) * a0_inv * filter_gain;
166+
b1_temp = (1.0f + coeff.cos) * a0_inv * filter_gain;
120167

121168
/* both b0 -and- b2 */
122169
b02_temp = b1_temp * 0.5f;
@@ -125,7 +172,7 @@ static inline void fluid_iir_filter_calculate_coefficients(R fres,
125172
break;
126173

127174
case FLUID_IIR_LOWPASS:
128-
b1_temp = (1.0f - cos_coeff) * a0_inv * filter_gain;
175+
b1_temp = (1.0f - coeff.cos) * a0_inv * filter_gain;
129176

130177
/* both b0 -and- b2 */
131178
b02_temp = b1_temp * 0.5f;
@@ -259,7 +306,7 @@ fluid_iir_filter_apply_local(fluid_iir_filter_t *iir_filter, fluid_real_t *dsp_b
259306
q += q_incr;
260307
}
261308

262-
LOG_FILTER("last_fres: %.2f Hz | target_fres: %.2f Hz |---| last_q: %.4f | target_q: %.4f", iir_filter->last_fres, iir_filter->target_fres, iir_filter->last_q, iir_filter->target_q);
309+
LOG_FILTER("last_fres: %.2f Cents | target_fres: %.2f Cents |---| last_q: %.4f | target_q: %.4f", iir_filter->last_fres, iir_filter->target_fres, iir_filter->last_q, iir_filter->target_q);
263310

264311
fluid_iir_filter_calculate_coefficients<IIR_COEFF_T, GAIN_NORM, TYPE>(fres, q, output_rate, &dsp_a1, &dsp_a2, &dsp_b02, &dsp_b1);
265312
}

0 commit comments

Comments
 (0)