Interpolate mic response at an arbitrary frequency (Hz). Uses log-frequency linear interpolation with binary search. Clamps to endpoint values outside the data range.
| 227 | /// Uses log-frequency linear interpolation with binary search. |
| 228 | /// Clamps to endpoint values outside the data range. |
| 229 | inline float interpolateMicResponse(const MicResponseCurve& curve, float freq_hz) { |
| 230 | if (curve.count <= 0 || !curve.freqs || !curve.gains) return 1.0f; |
| 231 | |
| 232 | float f0 = fl_progmem_read_float(&curve.freqs[0]); |
| 233 | float fN = fl_progmem_read_float(&curve.freqs[curve.count - 1]); |
| 234 | |
| 235 | // Clamp to endpoints |
| 236 | if (freq_hz <= f0) return fl_progmem_read_float(&curve.gains[0]); |
| 237 | if (freq_hz >= fN) return fl_progmem_read_float(&curve.gains[curve.count - 1]); |
| 238 | |
| 239 | // Binary search for bracketing interval |
| 240 | int lo = 0, hi = curve.count - 1; |
| 241 | while (hi - lo > 1) { |
| 242 | int mid = (lo + hi) / 2; |
| 243 | float fMid = fl_progmem_read_float(&curve.freqs[mid]); |
| 244 | if (freq_hz < fMid) { |
| 245 | hi = mid; |
| 246 | } else { |
| 247 | lo = mid; |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | float fLo = fl_progmem_read_float(&curve.freqs[lo]); |
| 252 | float fHi = fl_progmem_read_float(&curve.freqs[hi]); |
| 253 | float gLo = fl_progmem_read_float(&curve.gains[lo]); |
| 254 | float gHi = fl_progmem_read_float(&curve.gains[hi]); |
| 255 | |
| 256 | // Log-frequency linear interpolation |
| 257 | float logFrac = fl::logf(freq_hz / fLo) / fl::logf(fHi / fLo); |
| 258 | return gLo + (gHi - gLo) * logFrac; |
| 259 | } |
| 260 | |
| 261 | /// Downsample a high-resolution mic response curve to N output bins. |
| 262 | /// @param curve The source mic response curve |
no test coverage detected