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 
11 
12 #include "stdafx.h"
13 #include "WindowedFIR.h"
14 #include "mpt/base/numbers.hpp"
15 #include <cmath>
16 
17 OPENMPT_NAMESPACE_BEGIN
18 
coef(int _PCnr,double _POfs,double _PCut,int _PWidth,int _PType)19 double CWindowedFIR::coef( int _PCnr, double _POfs, double _PCut, int _PWidth, int _PType ) //float _PPos, float _PFc, int _PLen )
20 {
21 	const double epsilon = 1e-8;
22 	const double _LWidthM1 = _PWidth - 1;
23 	const double _LWidthM1Half = 0.5 * _LWidthM1;
24 	const double _LPosU = (_PCnr - _POfs);
25 	const double _LPIdl = (2.0 * mpt::numbers::pi) / _LWidthM1;
26 	double _LPos = _LPosU - _LWidthM1Half;
27 	double _LWc, _LSi;
28 	if(std::abs(_LPos) < epsilon)
29 	{
30 		_LWc = 1.0;
31 		_LSi = _PCut;
32 	} else
33 	{
34 		switch(_PType)
35 		{
36 		case WFIR_HANN:
37 			_LWc = 0.50 - 0.50 * std::cos(_LPIdl * _LPosU);
38 			break;
39 		case WFIR_HAMMING:
40 			_LWc = 0.54 - 0.46 * std::cos(_LPIdl * _LPosU);
41 			break;
42 		case WFIR_BLACKMANEXACT:
43 			_LWc = 0.42 - 0.50 * std::cos(_LPIdl * _LPosU) + 0.08 * std::cos(2.0 * _LPIdl * _LPosU);
44 			break;
45 		case WFIR_BLACKMAN3T61:
46 			_LWc = 0.44959 - 0.49364 * std::cos(_LPIdl * _LPosU) + 0.05677 * std::cos(2.0 * _LPIdl * _LPosU);
47 			break;
48 		case WFIR_BLACKMAN3T67:
49 			_LWc = 0.42323 - 0.49755 * std::cos(_LPIdl * _LPosU) + 0.07922 * std::cos(2.0 * _LPIdl * _LPosU);
50 			break;
51 		case WFIR_BLACKMAN4T92: // blackman harris
52 			_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);
53 			break;
54 		case WFIR_BLACKMAN4T74:
55 			_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);
56 			break;
57 		case WFIR_KAISER4T: // kaiser-bessel, alpha~7.5
58 			_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);
59 			break;
60 		default:
61 			_LWc = 1.0;
62 			break;
63 		}
64 		_LPos *= mpt::numbers::pi;
65 		_LSi = std::sin(_PCut * _LPos) / _LPos;
66 	}
67 	return (_LWc * _LSi);
68 }
69 
InitTable(double WFIRCutoff,uint8 WFIRType)70 void CWindowedFIR::InitTable(double WFIRCutoff, uint8 WFIRType)
71 {
72 	const double _LPcllen = (double)(1 << WFIR_FRACBITS);  // number of precalculated lines for 0..1 (-1..0)
73 	const double _LNorm = 1.0 / (2.0 * _LPcllen);
74 	const double _LCut = WFIRCutoff;
75 	for(int _LPcl = 0; _LPcl < WFIR_LUTLEN; _LPcl++)
76 	{
77 		double _LGain = 0.0, _LCoefs[WFIR_WIDTH];
78 		const double _LOfs = (_LPcl - _LPcllen) * _LNorm;
79 		const int _LIdx = _LPcl << WFIR_LOG2WIDTH;
80 		for(int _LCc = 0; _LCc < WFIR_WIDTH; _LCc++)
81 		{
82 			_LGain += (_LCoefs[_LCc] = coef(_LCc, _LOfs, _LCut, WFIR_WIDTH, WFIRType));
83 		}
84 		_LGain = 1.0 / _LGain;
85 		for(int _LCc = 0; _LCc < WFIR_WIDTH; _LCc++)
86 		{
87 #ifdef MPT_INTMIXER
88 			double _LCoef = std::floor(0.5 + WFIR_QUANTSCALE * _LCoefs[_LCc] * _LGain);
89 			lut[_LIdx + _LCc] = (signed short)((_LCoef < -WFIR_QUANTSCALE) ? -WFIR_QUANTSCALE : ((_LCoef > WFIR_QUANTSCALE) ? WFIR_QUANTSCALE : _LCoef));
90 #else
91 			double _LCoef = _LCoefs[_LCc] * _LGain;
92 			lut[_LIdx + _LCc] = (float)_LCoef;
93 #endif // MPT_INTMIXER
94 		}
95 	}
96 }
97 
98 
99 OPENMPT_NAMESPACE_END
100