2 #include "cubic_tables.h"
9 #include "cubic_defs.h"
11 /* These filter tables are inspired by the gaussian-like filter found in the
12 * SNES. This is based on the public domain code developed by Near, with the
13 * help of Ryphecha and nocash, from the nesdev.org forums.
15 * <https://forums.nesdev.org/viewtopic.php?p=251534#p251534>
17 * Additional changes were made here, the most obvious being that is has full
18 * floating-point precision instead of 11-bit fixed-point, but also an offset
19 * adjustment for the phase coefficients to more cleanly transition from the
20 * end of one sample set to the start of the next.
25 auto GetCoeff(double idx
) noexcept
-> double
27 const double k
{0.5 + idx
};
28 if(k
> 512.0) return 0.0;
29 const double s
{ std::sin(al::numbers::pi
*1.280/1024 * k
)};
30 const double t
{(std::cos(al::numbers::pi
*2.000/1023 * k
) - 1.0) * 0.50};
31 const double u
{(std::cos(al::numbers::pi
*4.000/1023 * k
) - 1.0) * 0.08};
32 return s
* (t
+ u
+ 1.0) / k
;
35 struct GaussFilterArray
{
36 alignas(16) std::array
<CubicCoefficients
,CubicPhaseCount
> mTable
{};
40 static constexpr double IndexScale
{512.0 / double{CubicPhaseCount
*2}};
41 /* Fill in the main coefficients. */
42 for(std::size_t pi
{0};pi
< CubicPhaseCount
;++pi
)
44 const double coeff0
{GetCoeff(static_cast<double>(CubicPhaseCount
+ pi
)*IndexScale
)};
45 const double coeff1
{GetCoeff(static_cast<double>(pi
)*IndexScale
)};
46 const double coeff2
{GetCoeff(static_cast<double>(CubicPhaseCount
- pi
)*IndexScale
)};
47 const double coeff3
{GetCoeff(static_cast<double>(CubicPhaseCount
*2 - pi
)*IndexScale
)};
49 const double scale
{1.0 / (coeff0
+ coeff1
+ coeff2
+ coeff3
)};
50 mTable
[pi
].mCoeffs
[0] = static_cast<float>(coeff0
* scale
);
51 mTable
[pi
].mCoeffs
[1] = static_cast<float>(coeff1
* scale
);
52 mTable
[pi
].mCoeffs
[2] = static_cast<float>(coeff2
* scale
);
53 mTable
[pi
].mCoeffs
[3] = static_cast<float>(coeff3
* scale
);
56 /* Fill in the coefficient deltas. */
57 for(std::size_t pi
{0};pi
< CubicPhaseCount
-1;++pi
)
59 mTable
[pi
].mDeltas
[0] = mTable
[pi
+1].mCoeffs
[0] - mTable
[pi
].mCoeffs
[0];
60 mTable
[pi
].mDeltas
[1] = mTable
[pi
+1].mCoeffs
[1] - mTable
[pi
].mCoeffs
[1];
61 mTable
[pi
].mDeltas
[2] = mTable
[pi
+1].mCoeffs
[2] - mTable
[pi
].mCoeffs
[2];
62 mTable
[pi
].mDeltas
[3] = mTable
[pi
+1].mCoeffs
[3] - mTable
[pi
].mCoeffs
[3];
65 const std::size_t pi
{CubicPhaseCount
- 1};
66 mTable
[pi
].mDeltas
[0] = 0.0f
- mTable
[pi
].mCoeffs
[0];
67 mTable
[pi
].mDeltas
[1] = mTable
[0].mCoeffs
[0] - mTable
[pi
].mCoeffs
[1];
68 mTable
[pi
].mDeltas
[2] = mTable
[0].mCoeffs
[1] - mTable
[pi
].mCoeffs
[2];
69 mTable
[pi
].mDeltas
[3] = mTable
[0].mCoeffs
[2] - mTable
[pi
].mCoeffs
[3];
73 const GaussFilterArray GaussFilter
{};
77 const CubicTable gGaussianFilter
{GaussFilter
.mTable
};
79 CubicFilter::CubicFilter()
81 static constexpr double IndexScale
{512.0 / double{sTableSteps
*2}};
82 /* Only half the coefficients need to be iterated here, since Coeff2 and
83 * Coeff3 are just Coeff1 and Coeff0 in reverse respectively.
85 for(size_t i
{0};i
< sTableSteps
/2;++i
)
87 const double coeff0
{GetCoeff(static_cast<double>(sTableSteps
+ i
)*IndexScale
)};
88 const double coeff1
{GetCoeff(static_cast<double>(i
)*IndexScale
)};
89 const double coeff2
{GetCoeff(static_cast<double>(sTableSteps
- i
)*IndexScale
)};
90 const double coeff3
{GetCoeff(static_cast<double>(sTableSteps
*2 - i
)*IndexScale
)};
92 const double scale
{1.0 / (coeff0
+ coeff1
+ coeff2
+ coeff3
)};
93 mFilter
[sTableSteps
+ i
] = static_cast<float>(coeff0
* scale
);
94 mFilter
[i
] = static_cast<float>(coeff1
* scale
);
95 mFilter
[sTableSteps
- i
] = static_cast<float>(coeff2
* scale
);
96 mFilter
[sTableSteps
*2 - i
] = static_cast<float>(coeff3
* scale
);