You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CDSPSincFilterGen.h 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. //$ nobt
  2. //$ nocpp
  3. /**
  4. * @file CDSPSincFilterGen.h
  5. *
  6. * @brief Sinc function-based FIR filter generator class.
  7. *
  8. * This file includes the CDSPSincFilterGen class implementation that
  9. * generates FIR filters.
  10. *
  11. * r8brain-free-src Copyright (c) 2013-2014 Aleksey Vaneev
  12. * See the "License.txt" file for license.
  13. */
  14. #ifndef R8B_CDSPSINCFILTERGEN_INCLUDED
  15. #define R8B_CDSPSINCFILTERGEN_INCLUDED
  16. #include "r8bbase.h"
  17. namespace r8b
  18. {
  19. /**
  20. * @brief Sinc function-based FIR filter generator class.
  21. *
  22. * Structure that holds state used to perform generation of sinc functions of
  23. * various types, windowed by the Blackman window by default (but the window
  24. * function can be changed if necessary).
  25. */
  26. class CDSPSincFilterGen
  27. {
  28. public:
  29. double Len2 = 0; ///< Required half filter kernel's length in samples (can be
  30. ///< a fractional value). Final physical kernel length will be
  31. ///< provided in the KernelLen variable. Len2 should be >= 2.
  32. ///<
  33. int KernelLen = 0; ///< Resulting length of the filter kernel, this variable
  34. ///< is set after the call to one of the "init" functions.
  35. ///<
  36. int fl2 = 0; ///< Internal "half kernel length" value. This value can be used
  37. ///< as filter's latency in samples (taps), this variable is set after
  38. ///< the call to one of the "init" functions.
  39. ///<
  40. union
  41. {
  42. struct
  43. {
  44. double Freq1; ///< Required corner circular frequency 1 [0; pi].
  45. ///< Used only in the generateBand() function.
  46. ///<
  47. double Freq2; ///< Required corner circular frequency 2 [0; pi].
  48. ///< Used only in the generateBand() function. The range
  49. ///< [Freq1; Freq2] defines a pass band for the generateBand()
  50. ///< function.
  51. ///<
  52. };
  53. struct
  54. {
  55. double FracDelay; ///< Fractional delay in the range [0; 1], used
  56. ///< only in the generateFrac() function. Note that the
  57. ///< FracDelay parameter is actually inversed. At 0.0 value it
  58. ///< produces 1 sample delay (with the latency equal to fl2),
  59. ///< at 1.0 value it produces 0 sample delay (with the latency
  60. ///< equal to fl2 - 1).
  61. ///<
  62. };
  63. };
  64. /**
  65. * Window function type.
  66. */
  67. enum EWindowFunctionType
  68. {
  69. wftCosine, ///< Generalized cosine window function. No parameters
  70. ///< required. The "Power" parameter is optional.
  71. ///<
  72. wftKaiser, ///< Kaiser window function. Requires the "Beta" parameter.
  73. ///< The "Power" parameter is optional.
  74. ///<
  75. wftGaussian, ///< Gaussian window function. Requires the "Sigma"
  76. ///< parameter. The "Power" parameter is optional.
  77. ///<
  78. wftVaneev ///< Vaneev window function, mainly used for short
  79. ///< fractional delay filters, requires 4 cosine width parameters,
  80. ///< plus the "Power" parameter which is mandatory.
  81. ///<
  82. };
  83. typedef double ( CDSPSincFilterGen::*CWindowFunc )(); ///< Window
  84. ///< calculation function pointer type.
  85. ///<
  86. /**
  87. * Function initializes *this structure for generation of a window
  88. * function, odd-sized.
  89. *
  90. * @param WinType Window function type.
  91. * @param Params Window function's parameters. If NULL, the table values
  92. * may be used.
  93. * @param UsePower "True" if the power factor should be used to raise the
  94. * window function. If "true", the power factor should be specified as the
  95. * last value in the Params array. If Params is NULL, the table or default
  96. * value of -1.0 (off) will be used.
  97. */
  98. void initWindow(const EWindowFunctionType WinType = wftCosine,
  99. const double* const Params = nullptr, const bool UsePower = false)
  100. {
  101. R8BASSERT(Len2 >= 2.0);
  102. fl2 = (int)floor(Len2);
  103. KernelLen = fl2 + fl2 + 1;
  104. setWindow(WinType, Params, UsePower, true);
  105. }
  106. /**
  107. * Function initializes *this structure for generation of band-limited
  108. * sinc filter kernel. The generateBand() or generateBandPow() functions
  109. * should be used to calculate the filter.
  110. *
  111. * @param WinType Window function type.
  112. * @param Params Window function's parameters. If NULL, the table values
  113. * may be used.
  114. * @param UsePower "True" if the power factor should be used to raise the
  115. * window function. If "true", the power factor should be specified as the
  116. * last value in the Params array. If Params is NULL, the table or default
  117. * value of -1.0 (off) will be used.
  118. */
  119. void initBand(const EWindowFunctionType WinType = wftCosine,
  120. const double* const Params = nullptr, const bool UsePower = false)
  121. {
  122. R8BASSERT(Len2 >= 2.0);
  123. fl2 = (int)floor(Len2);
  124. KernelLen = fl2 + fl2 + 1;
  125. f1.init(Freq1, 0.0);
  126. f2.init(Freq2, 0.0);
  127. setWindow(WinType, Params, UsePower, true);
  128. }
  129. /**
  130. * Function initializes *this structure for Hilbert transformation filter
  131. * calculation. Freq1 and Freq2 variables are not used.
  132. * The generateHilbert() function should be used to calculate the filter.
  133. *
  134. * @param WinType Window function type.
  135. * @param Params Window function's parameters. If NULL, the table values
  136. * may be used.
  137. * @param UsePower "True" if the power factor should be used to raise the
  138. * window function. If "true", the power factor should be specified as the
  139. * last value in the Params array. If Params is NULL, the table or default
  140. * value of -1.0 (off) will be used.
  141. */
  142. void initHilbert(const EWindowFunctionType WinType = wftCosine,
  143. const double* const Params = nullptr, const bool UsePower = false)
  144. {
  145. R8BASSERT(Len2 >= 2.0);
  146. fl2 = (int)floor(Len2);
  147. KernelLen = fl2 + fl2 + 1;
  148. setWindow(WinType, Params, UsePower, true);
  149. }
  150. /**
  151. * Function initializes *this structure for generation of full-bandwidth
  152. * fractional delay sinc filter kernel. Freq1 and Freq2 variables are not
  153. * used. The generateFrac() function should be used to calculate the
  154. * filter.
  155. *
  156. * @param WinType Window function type.
  157. * @param Params Window function's parameters. If NULL, the table values
  158. * may be used.
  159. * @param UsePower "True" if the power factor should be used to raise the
  160. * window function. If "true", the power factor should be specified as the
  161. * last value in the Params array. If Params is NULL, the table or default
  162. * value of -1.0 (off) will be used.
  163. */
  164. void initFrac(const EWindowFunctionType WinType = wftCosine,
  165. const double* const Params = nullptr, const bool UsePower = false)
  166. {
  167. R8BASSERT(Len2 >= 2.0);
  168. fl2 = (int)ceil(Len2);
  169. KernelLen = fl2 + fl2;
  170. setWindow(WinType, Params, UsePower, false, FracDelay);
  171. }
  172. /**
  173. * @return The next "Hann" window function coefficient.
  174. */
  175. double calcWindowHann() { return (0.5 + 0.5 * w1.generate()); }
  176. /**
  177. * @return The next "Hamming" window function coefficient.
  178. */
  179. double calcWindowHamming() { return (0.54 + 0.46 * w1.generate()); }
  180. /**
  181. * @return The next "Blackman" window function coefficient.
  182. */
  183. double calcWindowBlackman() { return (0.42 + 0.5 * w1.generate() + 0.08 * w2.generate()); }
  184. /**
  185. * @return The next "Nuttall" window function coefficient.
  186. */
  187. double calcWindowNuttall()
  188. {
  189. return (0.355768 + 0.487396 * w1.generate() +
  190. 0.144232 * w2.generate() + 0.012604 * w3.generate());
  191. }
  192. /**
  193. * @return The next "Blackman-Nuttall" window function coefficient.
  194. */
  195. double calcWindowBlackmanNuttall()
  196. {
  197. return (0.3635819 + 0.4891775 * w1.generate() +
  198. 0.1365995 * w2.generate() + 0.0106411 * w3.generate());
  199. }
  200. /**
  201. * @return The next "Kaiser" window function coefficient.
  202. */
  203. double calcWindowKaiser()
  204. {
  205. const double n = 1.0 - sqr(wn / Len2 + KaiserLen2Frac);
  206. wn++;
  207. if (n < 0.0) { return (0.0); }
  208. return (besselI0(KaiserBeta * sqrt(n)) / KaiserDiv);
  209. }
  210. /**
  211. * @return The next "Gaussian" window function coefficient.
  212. */
  213. double calcWindowGaussian()
  214. {
  215. const double f = exp(-0.5 * sqr(wn / GaussianSigma +
  216. GaussianSigmaFrac));
  217. wn++;
  218. return (f);
  219. }
  220. /**
  221. * @return The next "Vaneev" windowing function coefficient, for use with
  222. * the fractional delay filters.
  223. */
  224. double calcWindowVaneev()
  225. {
  226. const double v1 = 0.5 + 0.5 * w1.generate();
  227. const double v2 = 0.5 + 0.5 * w2.generate();
  228. const double v3 = 0.5 + 0.5 * w3.generate();
  229. const double v4 = 0.5 + 0.5 * w4.generate();
  230. return (v1 * sqr(v2) * sqr(sqr(v3)) * sqr(sqr(sqr(v4))));
  231. }
  232. /**
  233. * Function calculates window function only.
  234. *
  235. * @param[out] op Output buffer, length = KernelLen.
  236. * @param wfunc Window calculation function to use.
  237. */
  238. template <class T>
  239. void generateWindow(T* op,
  240. CWindowFunc wfunc = &CDSPSincFilterGen::calcWindowBlackman)
  241. {
  242. op += fl2;
  243. T* op2 = op;
  244. int l = fl2;
  245. if (Power < 0.0)
  246. {
  247. *op = (*this.*wfunc)();
  248. while (l > 0)
  249. {
  250. const double v = (*this.*wfunc)();
  251. ++op;
  252. --op2;
  253. *op = v;
  254. *op2 = v;
  255. l--;
  256. }
  257. }
  258. else
  259. {
  260. *op = pows((*this.*wfunc)(), Power);
  261. while (l > 0)
  262. {
  263. const double v = pows((*this.*wfunc)(), Power);
  264. ++op;
  265. --op2;
  266. *op = v;
  267. *op2 = v;
  268. l--;
  269. }
  270. }
  271. }
  272. /**
  273. * Function calculates band-limited windowed sinc function-based filter
  274. * kernel.
  275. *
  276. * @param[out] op Output buffer, length = KernelLen.
  277. * @param wfunc Window calculation function to use.
  278. */
  279. template <class T>
  280. void generateBand(T* op,
  281. CWindowFunc wfunc = &CDSPSincFilterGen::calcWindowBlackman)
  282. {
  283. op += fl2;
  284. T* op2 = op;
  285. f1.generate();
  286. f2.generate();
  287. int t = 1;
  288. if (Power < 0.0)
  289. {
  290. *op = (Freq2 - Freq1) * (*this.*wfunc)() / M_PI;
  291. while (t <= fl2)
  292. {
  293. const double v = (f2.generate() - f1.generate()) *
  294. (*this.*wfunc)() / t / M_PI;
  295. ++op;
  296. --op2;
  297. *op = v;
  298. *op2 = v;
  299. t++;
  300. }
  301. }
  302. else
  303. {
  304. *op = (Freq2 - Freq1) * pows((*this.*wfunc)(), Power) / M_PI;
  305. while (t <= fl2)
  306. {
  307. const double v = (f2.generate() - f1.generate()) *
  308. pows((*this.*wfunc)(), Power) / t / M_PI;
  309. ++op;
  310. --op2;
  311. *op = v;
  312. *op2 = v;
  313. t++;
  314. }
  315. }
  316. }
  317. /**
  318. * Function calculates windowed Hilbert transformer filter kernel.
  319. *
  320. * @param[out] op Output buffer, length = KernelLen.
  321. * @param wfunc Window calculation function to use.
  322. */
  323. template <class T>
  324. void generateHilbert(T* op,
  325. CWindowFunc wfunc = &CDSPSincFilterGen::calcWindowBlackman)
  326. {
  327. static const double fvalues[ 2 ] = { 0.0, 2.0 };
  328. op += fl2;
  329. T* op2 = op;
  330. (*this.*wfunc)();
  331. *op = 0.0;
  332. int t = 1;
  333. if (Power < 0.0)
  334. {
  335. while (t <= fl2)
  336. {
  337. const double v = fvalues[t & 1] *
  338. (*this.*wfunc)() / t / M_PI;
  339. ++op;
  340. --op2;
  341. *op = v;
  342. *op2 = -v;
  343. t++;
  344. }
  345. }
  346. else
  347. {
  348. while (t <= fl2)
  349. {
  350. const double v = fvalues[t & 1] *
  351. pows((*this.*wfunc)(), Power) / t / M_PI;
  352. ++op;
  353. --op2;
  354. *op = v;
  355. *op2 = -v;
  356. t++;
  357. }
  358. }
  359. }
  360. /**
  361. * Function calculates windowed fractional delay filter kernel.
  362. *
  363. * @param[out] op Output buffer, length = KernelLen.
  364. * @param wfunc Window calculation function to use.
  365. * @param opinc Output buffer increment, in "op" elements.
  366. */
  367. template <class T>
  368. void generateFrac(T* op,
  369. CWindowFunc wfunc = &CDSPSincFilterGen::calcWindowBlackman,
  370. const int opinc = 1)
  371. {
  372. R8BASSERT(opinc != 0);
  373. double f[ 2 ];
  374. f[0] = sin(FracDelay * M_PI);
  375. f[1] = -f[0];
  376. int t = -fl2;
  377. if (t + FracDelay < -Len2)
  378. {
  379. (*this.*wfunc)();
  380. *op = 0.0;
  381. op += opinc;
  382. t++;
  383. }
  384. int mt = (FracDelay >= 1.0 - 1e-13 && FracDelay <= 1.0 + 1e-13 ? -1 : 0);
  385. if (Power < 0.0)
  386. {
  387. while (t < mt)
  388. {
  389. *op = f[t & 1] * (*this.*wfunc)() / (t + FracDelay) /
  390. M_PI;
  391. op += opinc;
  392. t++;
  393. }
  394. double ut = t + FracDelay;
  395. *op = (fabs(ut) <= 1e-13 ? (*this.*wfunc)() : f[t & 1] * (*this.*wfunc)() / ut / M_PI);
  396. mt = fl2 - 2;
  397. while (t < mt)
  398. {
  399. op += opinc;
  400. t++;
  401. *op = f[t & 1] * (*this.*wfunc)() / (t + FracDelay) /
  402. M_PI;
  403. }
  404. op += opinc;
  405. t++;
  406. ut = t + FracDelay;
  407. *op = (ut > Len2 ? 0.0 : f[t & 1] * (*this.*wfunc)() / ut / M_PI);
  408. }
  409. else
  410. {
  411. while (t < mt)
  412. {
  413. *op = f[t & 1] * pows((*this.*wfunc)(), Power) /
  414. (t + FracDelay) / M_PI;
  415. op += opinc;
  416. t++;
  417. }
  418. double ut = t + FracDelay;
  419. *op = (fabs(ut) <= 1e-13 ? pows((*this.*wfunc)(), Power) : f[t & 1] * pows((*this.*wfunc)(), Power) / ut / M_PI);
  420. mt = fl2 - 2;
  421. while (t < mt)
  422. {
  423. op += opinc;
  424. t++;
  425. *op = f[t & 1] * pows((*this.*wfunc)(), Power) /
  426. (t + FracDelay) / M_PI;
  427. }
  428. op += opinc;
  429. t++;
  430. ut = t + FracDelay;
  431. *op = (ut > Len2 ? 0.0 : f[t & 1] * pows((*this.*wfunc)(), Power) / ut / M_PI);
  432. }
  433. }
  434. private:
  435. double Power = 0; ///< The power factor used to raise the window function.
  436. ///< Equals a negative value if the power factor should not be used.
  437. ///<
  438. CSineGen f1; ///< Sine function 1. Used in the generateBand() function.
  439. ///<
  440. CSineGen f2; ///< Sine function 2. Used in the generateBand() function.
  441. ///<
  442. int wn = 0; ///< Window function integer position. 0 - center of the window
  443. ///< function. This variable may not be used by some window functions.
  444. ///<
  445. CSineGen w1; ///< Cosine wave 1 for window function.
  446. ///<
  447. CSineGen w2; ///< Cosine wave 2 for window function.
  448. ///<
  449. CSineGen w3; ///< Cosine wave 3 for window function.
  450. ///<
  451. CSineGen w4; ///< Cosine wave 4 for window function.
  452. ///<
  453. union
  454. {
  455. struct
  456. {
  457. double KaiserBeta; // Kaiser window function's "Beta" coefficient.
  458. double KaiserDiv; // Kaiser window function's divisor.
  459. double KaiserLen2Frac; // Equals FracDelay / Len2.
  460. };
  461. struct
  462. {
  463. double GaussianSigma; // Gaussian window function's "Sigma" coefficient.
  464. double GaussianSigmaFrac; // Equals FracDelay / GaussianSigma.
  465. };
  466. };
  467. /**
  468. * @param FilterLen2 Half filter length in samples (taps).
  469. * @return The Kaiser power-raised window function parameters for the
  470. * specified filter length.
  471. */
  472. static const double* getKaiserParams(const int FilterLen2)
  473. {
  474. R8BASSERT(FilterLen2 >= 3 && FilterLen2 <= 15);
  475. static const double Coeffs[][ 2 ] = {
  476. { 3.41547411, 1.41275111 }, // 6 @ 51.38
  477. { 3.72300147, 1.75212634 }, // 8 @ 67.60
  478. { 4.34839223, 1.85801372 }, // 10 @ 79.86
  479. { 4.90860405, 1.97194591 }, // 12 @ 93.29
  480. { 5.17430411, 2.20609617 }, // 14 @ 106.74
  481. { 21.08445389, 0.59684098 }, // 16 @ 119.71
  482. { 9.14552738, 1.57619894 }, // 18 @ 134.53
  483. { 22.02344341, 0.71669064 }, // 20 @ 148.44
  484. { 16.41763757, 1.05884118 }, // 22 @ 164.61
  485. { 12.55262798, 1.51553897 }, // 24 @ 180.15
  486. { 9.84861210, 2.09912671 }, // 26 @ 194.15
  487. { 9.73150659, 2.29079494 }, // 28 @ 206.91
  488. { 10.42657217, 2.29183875 }, // 30 @ 218.20
  489. };
  490. return (Coeffs[FilterLen2 - 3]);
  491. }
  492. /**
  493. * Function initializes Kaiser window function calculation. The FracDelay
  494. * variable should be initialized when using this window function.
  495. *
  496. * @param Params Function parameters. If NULL, the table values will be
  497. * used. If not NULL, the first parameter should specify the "Beta" value.
  498. * @param UsePower "True" if the power factor should be used to raise the
  499. * window function.
  500. * @param IsCentered "True" if centered window should be used. This
  501. * parameter usually equals to "false" for fractional delay filters only.
  502. */
  503. void setWindowKaiser(const double* Params, const bool UsePower,
  504. const bool IsCentered)
  505. {
  506. wn = (IsCentered ? 0 : -fl2);
  507. if (Params == nullptr)
  508. {
  509. Params = getKaiserParams(fl2);
  510. KaiserBeta = Params[0];
  511. Power = (UsePower ? Params[1] : -1.0);
  512. }
  513. else
  514. {
  515. KaiserBeta = clampr(Params[0], 1.0, 350.0);
  516. Power = (UsePower ? fabs(Params[1]) : -1.0);
  517. }
  518. KaiserDiv = besselI0(KaiserBeta);
  519. KaiserLen2Frac = FracDelay / Len2;
  520. }
  521. /**
  522. * Function initializes Gaussian window function calculation. The FracDelay
  523. * variable should be initialized when using this window function.
  524. *
  525. * @param Params Function parameters. If NULL, the table values will be
  526. * used. If not NULL, the first parameter should specify the "Sigma"
  527. * value.
  528. * @param UsePower "True" if the power factor should be used to raise the
  529. * window function.
  530. * @param IsCentered "True" if centered window should be used. This
  531. * parameter usually equals to "false" for fractional delay filters only.
  532. */
  533. void setWindowGaussian(const double* Params, const bool UsePower,
  534. const bool IsCentered)
  535. {
  536. wn = (IsCentered ? 0 : -fl2);
  537. if (Params == nullptr)
  538. {
  539. GaussianSigma = 1.0;
  540. Power = -1.0;
  541. }
  542. else
  543. {
  544. GaussianSigma = clampr(fabs(Params[0]), 1e-1, 100.0);
  545. Power = (UsePower ? fabs(Params[1]) : -1.0);
  546. }
  547. GaussianSigma *= Len2;
  548. GaussianSigmaFrac = FracDelay / GaussianSigma;
  549. }
  550. /**
  551. * Function initializes "Vaneev" window function calculation.
  552. *
  553. * @param Params Function parameters. If NULL, the table values will be
  554. * used. If not NULL, the first 4 parameters should specify the cosine
  555. * multipliers while the fifth parameter should specify the "Power" value.
  556. * @param IsCentered "True" if centered window should be used. This
  557. * parameter usually equals to "false" for fractional delay filters only.
  558. */
  559. void setWindowVaneev(const double* Params, const bool IsCentered)
  560. {
  561. R8BASSERT(fl2 >= 3 && fl2 <= 15);
  562. // This set of parameters was obtained via probabilistic optimization.
  563. // The number after @ shows the approximate (+/- 1 dB) signal-to-noise
  564. // ratio for the given filter. SNR can be also decreased by using a
  565. // filter bank with suboptimal number of sampled fractional delay
  566. // filters: thus the FilterFracs should be selected with care.
  567. static const double Coeffs[][ 5 ] = {
  568. { 0.35926104, 0.66154037, 0.79264845, 0.31897879, 0.18844972 }, // 6 @ 51.91
  569. { 0.81690764, 0.39409966, 0.01546567, 0.02067949, 1.15143000 }, // 8 @ 67.87
  570. { 0.26545140, 0.84346586, 0.12114879, 0.23640230, 0.72659219 }, // 10 @ 81.82
  571. { 0.56254211, 0.32615646, 0.88375690, 0.46944169, 0.32862728 }, // 12 @ 95.36
  572. { 0.51926261, 0.41265523, 0.89552919, 0.47699008, 0.37308306 }, // 14 @ 109.60
  573. { 0.55650321, 0.92583533, 0.58934379, 0.16399064, 0.67129777 }, // 16 @ 122.89
  574. { 0.27930548, 0.94898807, 0.70335882, 0.32080180, 0.59102482 }, // 18 @ 136.45
  575. { 0.12620836, 0.94993219, 0.70209891, 0.34747431, 0.64429174 }, // 20 @ 150.52
  576. { 0.83595860, 0.95040751, 0.64127591, 0.30856013, 0.69692727 }, // 22 @ 163.41
  577. { 0.41252871, 0.96236749, 0.74895429, 0.41669175, 0.65996102 }, // 24 @ 174.32
  578. { 0.98567539, 0.88907131, 0.65652775, 0.34585902, 0.77265757 }, // 26 @ 191.26
  579. { 0.64526843, 0.67729329, 0.91813705, 0.43972488, 0.68332682 }, // 28 @ 195.77
  580. { 0.65310281, 0.66723395, 0.91751074, 0.43956737, 0.73651421 }, // 30 @ 207.04
  581. };
  582. double p[ 4 ];
  583. if (Params == nullptr)
  584. {
  585. Params = Coeffs[fl2 - 3];
  586. Power = Params[4];
  587. }
  588. else
  589. {
  590. p[0] = clampr(Params[0], -4.0, 4.0);
  591. p[1] = clampr(Params[1], -4.0, 4.0);
  592. p[2] = clampr(Params[2], -4.0, 4.0);
  593. p[3] = clampr(Params[3], -4.0, 4.0);
  594. Power = fabs(Params[4]);
  595. Params = p;
  596. }
  597. if (IsCentered)
  598. {
  599. w1.init(Params[0] * M_PI / Len2, M_PI * 0.5);
  600. w2.init(Params[1] * M_PI / Len2, M_PI * 0.5);
  601. w3.init(Params[2] * M_PI / Len2, M_PI * 0.5);
  602. w4.init(Params[3] * M_PI / Len2, M_PI * 0.5);
  603. }
  604. else
  605. {
  606. const double step1 = Params[0] * M_PI / Len2;
  607. w1.init(step1, M_PI * 0.5 - step1 * fl2 + step1 * FracDelay);
  608. const double step2 = Params[1] * M_PI / Len2;
  609. w2.init(step2, M_PI * 0.5 - step2 * fl2 + step2 * FracDelay);
  610. const double step3 = Params[2] * M_PI / Len2;
  611. w3.init(step3, M_PI * 0.5 - step3 * fl2 + step3 * FracDelay);
  612. const double step4 = Params[3] * M_PI / Len2;
  613. w4.init(step4, M_PI * 0.5 - step4 * fl2 + step4 * FracDelay);
  614. }
  615. }
  616. /**
  617. * Function initializes calculation of window function of the specified
  618. * type.
  619. *
  620. * @param WinType Window function type.
  621. * @param Params Window function's parameters. If NULL, the table values
  622. * may be used.
  623. * @param UsePower "True" if the power factor should be used to raise the
  624. * window function. If "true", the power factor should be specified as the
  625. * last value in the Params array. If Params is NULL, the table or default
  626. * value of -1.0 (off) will be used.
  627. * @param IsCentered "True" if centered window should be used. This
  628. * parameter usually equals to "false" for fractional delay filters only.
  629. * @param UseFracDelay Fractional delay to use.
  630. */
  631. void setWindow(const EWindowFunctionType WinType,
  632. const double* const Params, const bool UsePower,
  633. const bool IsCentered, const double UseFracDelay = 0.0)
  634. {
  635. FracDelay = UseFracDelay;
  636. if (WinType == wftCosine)
  637. {
  638. if (IsCentered)
  639. {
  640. w1.init(M_PI / Len2, M_PI * 0.5);
  641. w2.init(M_2PI / Len2, M_PI * 0.5);
  642. w3.init(M_3PI / Len2, M_PI * 0.5);
  643. }
  644. else
  645. {
  646. const double step1 = M_PI / Len2;
  647. w1.init(step1, M_PI * 0.5 - step1 * fl2 +
  648. step1 * FracDelay);
  649. const double step2 = M_2PI / Len2;
  650. w2.init(step2, M_PI * 0.5 - step2 * fl2 +
  651. step2 * FracDelay);
  652. const double step3 = M_3PI / Len2;
  653. w3.init(step3, M_PI * 0.5 - step3 * fl2 +
  654. step3 * FracDelay);
  655. }
  656. Power = (UsePower && Params != nullptr ? Params[0] : -1.0);
  657. }
  658. else if (WinType == wftKaiser) { setWindowKaiser(Params, UsePower, IsCentered); }
  659. else if (WinType == wftGaussian) { setWindowGaussian(Params, UsePower, IsCentered); }
  660. else { setWindowVaneev(Params, IsCentered); }
  661. }
  662. };
  663. } // namespace r8b
  664. #endif // R8B_CDSPSINCFILTERGEN_INCLUDED