WindowedFIR.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * WindowedFIR.cpp
  3. * ---------------
  4. * Purpose: FIR resampling code
  5. * Notes : Original code from modplug-xmms
  6. * Authors: OpenMPT Devs
  7. * ModPlug-XMMS Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "WindowedFIR.h"
  12. #include "mpt/base/numbers.hpp"
  13. #include <cmath>
  14. OPENMPT_NAMESPACE_BEGIN
  15. double CWindowedFIR::coef( int _PCnr, double _POfs, double _PCut, int _PWidth, int _PType ) //float _PPos, float _PFc, int _PLen )
  16. {
  17. const double epsilon = 1e-8;
  18. const double _LWidthM1 = _PWidth - 1;
  19. const double _LWidthM1Half = 0.5 * _LWidthM1;
  20. const double _LPosU = (_PCnr - _POfs);
  21. const double _LPIdl = (2.0 * mpt::numbers::pi) / _LWidthM1;
  22. double _LPos = _LPosU - _LWidthM1Half;
  23. double _LWc, _LSi;
  24. if(std::abs(_LPos) < epsilon)
  25. {
  26. _LWc = 1.0;
  27. _LSi = _PCut;
  28. } else
  29. {
  30. switch(_PType)
  31. {
  32. case WFIR_HANN:
  33. _LWc = 0.50 - 0.50 * std::cos(_LPIdl * _LPosU);
  34. break;
  35. case WFIR_HAMMING:
  36. _LWc = 0.54 - 0.46 * std::cos(_LPIdl * _LPosU);
  37. break;
  38. case WFIR_BLACKMANEXACT:
  39. _LWc = 0.42 - 0.50 * std::cos(_LPIdl * _LPosU) + 0.08 * std::cos(2.0 * _LPIdl * _LPosU);
  40. break;
  41. case WFIR_BLACKMAN3T61:
  42. _LWc = 0.44959 - 0.49364 * std::cos(_LPIdl * _LPosU) + 0.05677 * std::cos(2.0 * _LPIdl * _LPosU);
  43. break;
  44. case WFIR_BLACKMAN3T67:
  45. _LWc = 0.42323 - 0.49755 * std::cos(_LPIdl * _LPosU) + 0.07922 * std::cos(2.0 * _LPIdl * _LPosU);
  46. break;
  47. case WFIR_BLACKMAN4T92: // blackman harris
  48. _LWc = 0.35875 - 0.48829 * std::cos(_LPIdl * _LPosU) + 0.14128 * std::cos(2.0 * _LPIdl * _LPosU) - 0.01168 * std::cos(3.0 * _LPIdl * _LPosU);
  49. break;
  50. case WFIR_BLACKMAN4T74:
  51. _LWc = 0.40217 - 0.49703 * std::cos(_LPIdl * _LPosU) + 0.09392 * std::cos(2.0 * _LPIdl * _LPosU) - 0.00183 * std::cos(3.0 * _LPIdl * _LPosU);
  52. break;
  53. case WFIR_KAISER4T: // kaiser-bessel, alpha~7.5
  54. _LWc = 0.40243 - 0.49804 * std::cos(_LPIdl * _LPosU) + 0.09831 * std::cos(2.0 * _LPIdl * _LPosU) - 0.00122 * std::cos(3.0 * _LPIdl * _LPosU);
  55. break;
  56. default:
  57. _LWc = 1.0;
  58. break;
  59. }
  60. _LPos *= mpt::numbers::pi;
  61. _LSi = std::sin(_PCut * _LPos) / _LPos;
  62. }
  63. return (_LWc * _LSi);
  64. }
  65. void CWindowedFIR::InitTable(double WFIRCutoff, uint8 WFIRType)
  66. {
  67. const double _LPcllen = (double)(1 << WFIR_FRACBITS); // number of precalculated lines for 0..1 (-1..0)
  68. const double _LNorm = 1.0 / (2.0 * _LPcllen);
  69. const double _LCut = WFIRCutoff;
  70. for(int _LPcl = 0; _LPcl < WFIR_LUTLEN; _LPcl++)
  71. {
  72. double _LGain = 0.0, _LCoefs[WFIR_WIDTH];
  73. const double _LOfs = (_LPcl - _LPcllen) * _LNorm;
  74. const int _LIdx = _LPcl << WFIR_LOG2WIDTH;
  75. for(int _LCc = 0; _LCc < WFIR_WIDTH; _LCc++)
  76. {
  77. _LGain += (_LCoefs[_LCc] = coef(_LCc, _LOfs, _LCut, WFIR_WIDTH, WFIRType));
  78. }
  79. _LGain = 1.0 / _LGain;
  80. for(int _LCc = 0; _LCc < WFIR_WIDTH; _LCc++)
  81. {
  82. #ifdef MPT_INTMIXER
  83. double _LCoef = std::floor(0.5 + WFIR_QUANTSCALE * _LCoefs[_LCc] * _LGain);
  84. lut[_LIdx + _LCc] = (signed short)((_LCoef < -WFIR_QUANTSCALE) ? -WFIR_QUANTSCALE : ((_LCoef > WFIR_QUANTSCALE) ? WFIR_QUANTSCALE : _LCoef));
  85. #else
  86. double _LCoef = _LCoefs[_LCc] * _LGain;
  87. lut[_LIdx + _LCc] = (float)_LCoef;
  88. #endif // MPT_INTMIXER
  89. }
  90. }
  91. }
  92. OPENMPT_NAMESPACE_END