🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
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.

295 lines
9.6 KiB

  1. #include "bsinc_tables.h"
  2. #include <algorithm>
  3. #include <array>
  4. #include <cassert>
  5. #include <cmath>
  6. #include <limits>
  7. #include <memory>
  8. #include <stdexcept>
  9. #include "alnumbers.h"
  10. #include "core/mixer/defs.h"
  11. namespace {
  12. using uint = unsigned int;
  13. /* This is the normalized cardinal sine (sinc) function.
  14. *
  15. * sinc(x) = { 1, x = 0
  16. * { sin(pi x) / (pi x), otherwise.
  17. */
  18. constexpr double Sinc(const double x)
  19. {
  20. constexpr double epsilon{std::numeric_limits<double>::epsilon()};
  21. if(!(x > epsilon || x < -epsilon))
  22. return 1.0;
  23. return std::sin(al::numbers::pi*x) / (al::numbers::pi*x);
  24. }
  25. /* The zero-order modified Bessel function of the first kind, used for the
  26. * Kaiser window.
  27. *
  28. * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
  29. * = sum_{k=0}^inf ((x / 2)^k / k!)^2
  30. */
  31. constexpr double BesselI_0(const double x) noexcept
  32. {
  33. /* Start at k=1 since k=0 is trivial. */
  34. const double x2{x / 2.0};
  35. double term{1.0};
  36. double sum{1.0};
  37. double last_sum{};
  38. int k{1};
  39. /* Let the integration converge until the term of the sum is no longer
  40. * significant.
  41. */
  42. do {
  43. const double y{x2 / k};
  44. ++k;
  45. last_sum = sum;
  46. term *= y * y;
  47. sum += term;
  48. } while(sum != last_sum);
  49. return sum;
  50. }
  51. /* Calculate a Kaiser window from the given beta value and a normalized k
  52. * [-1, 1].
  53. *
  54. * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
  55. * { 0, elsewhere.
  56. *
  57. * Where k can be calculated as:
  58. *
  59. * k = i / l, where -l <= i <= l.
  60. *
  61. * or:
  62. *
  63. * k = 2 i / M - 1, where 0 <= i <= M.
  64. */
  65. constexpr double Kaiser(const double beta, const double k, const double besseli_0_beta)
  66. {
  67. if(!(k >= -1.0 && k <= 1.0))
  68. return 0.0;
  69. return BesselI_0(beta * std::sqrt(1.0 - k*k)) / besseli_0_beta;
  70. }
  71. /* Calculates the (normalized frequency) transition width of the Kaiser window.
  72. * Rejection is in dB.
  73. */
  74. constexpr double CalcKaiserWidth(const double rejection, const uint order) noexcept
  75. {
  76. if(rejection > 21.19)
  77. return (rejection - 7.95) / (2.285 * al::numbers::pi*2.0 * order);
  78. /* This enforces a minimum rejection of just above 21.18dB */
  79. return 5.79 / (al::numbers::pi*2.0 * order);
  80. }
  81. /* Calculates the beta value of the Kaiser window. Rejection is in dB. */
  82. constexpr double CalcKaiserBeta(const double rejection)
  83. {
  84. if(rejection > 50.0)
  85. return 0.1102 * (rejection-8.7);
  86. else if(rejection >= 21.0)
  87. return (0.5842 * std::pow(rejection-21.0, 0.4)) + (0.07886 * (rejection-21.0));
  88. return 0.0;
  89. }
  90. struct BSincHeader {
  91. double width{};
  92. double beta{};
  93. double scaleBase{};
  94. double scaleRange{};
  95. double besseli_0_beta{};
  96. uint a[BSincScaleCount]{};
  97. uint total_size{};
  98. constexpr BSincHeader(uint Rejection, uint Order) noexcept
  99. {
  100. width = CalcKaiserWidth(Rejection, Order);
  101. beta = CalcKaiserBeta(Rejection);
  102. scaleBase = width / 2.0;
  103. scaleRange = 1.0 - scaleBase;
  104. besseli_0_beta = BesselI_0(beta);
  105. uint num_points{Order+1};
  106. for(uint si{0};si < BSincScaleCount;++si)
  107. {
  108. const double scale{scaleBase + (scaleRange * (si+1) / BSincScaleCount)};
  109. const uint a_{std::min(static_cast<uint>(num_points / 2.0 / scale), num_points)};
  110. const uint m{2 * a_};
  111. a[si] = a_;
  112. total_size += 4 * BSincPhaseCount * ((m+3) & ~3u);
  113. }
  114. }
  115. };
  116. /* 11th and 23rd order filters (12 and 24-point respectively) with a 60dB drop
  117. * at nyquist. Each filter will scale up the order when downsampling, to 23rd
  118. * and 47th order respectively.
  119. */
  120. constexpr BSincHeader bsinc12_hdr{60, 11};
  121. constexpr BSincHeader bsinc24_hdr{60, 23};
  122. /* NOTE: GCC 5 has an issue with BSincHeader objects being in an anonymous
  123. * namespace while also being used as non-type template parameters.
  124. */
  125. #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 6
  126. /* The number of sample points is double the a value (rounded up to a multiple
  127. * of 4), and scale index 0 includes the doubling for downsampling. bsinc24 is
  128. * currently the highest quality filter, and will use the most sample points.
  129. */
  130. constexpr uint BSincPointsMax{(bsinc24_hdr.a[0]*2 + 3) & ~3u};
  131. static_assert(BSincPointsMax <= MaxResamplerPadding, "MaxResamplerPadding is too small");
  132. template<size_t total_size>
  133. struct BSincFilterArray {
  134. alignas(16) std::array<float, total_size> mTable;
  135. const BSincHeader &hdr;
  136. BSincFilterArray(const BSincHeader &hdr_) : hdr{hdr_}
  137. {
  138. #else
  139. template<const BSincHeader &hdr>
  140. struct BSincFilterArray {
  141. alignas(16) std::array<float, hdr.total_size> mTable{};
  142. BSincFilterArray()
  143. {
  144. constexpr uint BSincPointsMax{(hdr.a[0]*2 + 3) & ~3u};
  145. static_assert(BSincPointsMax <= MaxResamplerPadding, "MaxResamplerPadding is too small");
  146. #endif
  147. using filter_type = double[BSincPhaseCount+1][BSincPointsMax];
  148. auto filter = std::make_unique<filter_type[]>(BSincScaleCount);
  149. /* Calculate the Kaiser-windowed Sinc filter coefficients for each
  150. * scale and phase index.
  151. */
  152. for(uint si{0};si < BSincScaleCount;++si)
  153. {
  154. const uint m{hdr.a[si] * 2};
  155. const size_t o{(BSincPointsMax-m) / 2};
  156. const double scale{hdr.scaleBase + (hdr.scaleRange * (si+1) / BSincScaleCount)};
  157. const double cutoff{scale - (hdr.scaleBase * std::max(1.0, scale*2.0))};
  158. const auto a = static_cast<double>(hdr.a[si]);
  159. const double l{a - 1.0/BSincPhaseCount};
  160. /* Do one extra phase index so that the phase delta has a proper
  161. * target for its last index.
  162. */
  163. for(uint pi{0};pi <= BSincPhaseCount;++pi)
  164. {
  165. const double phase{std::floor(l) + (pi/double{BSincPhaseCount})};
  166. for(uint i{0};i < m;++i)
  167. {
  168. const double x{i - phase};
  169. filter[si][pi][o+i] = Kaiser(hdr.beta, x/l, hdr.besseli_0_beta) * cutoff *
  170. Sinc(cutoff*x);
  171. }
  172. }
  173. }
  174. size_t idx{0};
  175. for(size_t si{0};si < BSincScaleCount;++si)
  176. {
  177. const size_t m{((hdr.a[si]*2) + 3) & ~3u};
  178. const size_t o{(BSincPointsMax-m) / 2};
  179. /* Write out each phase index's filter and phase delta for this
  180. * quality scale.
  181. */
  182. for(size_t pi{0};pi < BSincPhaseCount;++pi)
  183. {
  184. for(size_t i{0};i < m;++i)
  185. mTable[idx++] = static_cast<float>(filter[si][pi][o+i]);
  186. /* Linear interpolation between phases is simplified by pre-
  187. * calculating the delta (b - a) in: x = a + f (b - a)
  188. */
  189. for(size_t i{0};i < m;++i)
  190. {
  191. const double phDelta{filter[si][pi+1][o+i] - filter[si][pi][o+i]};
  192. mTable[idx++] = static_cast<float>(phDelta);
  193. }
  194. }
  195. /* Calculate and write out each phase index's filter quality scale
  196. * deltas. The last scale index doesn't have any scale or scale-
  197. * phase deltas.
  198. */
  199. if(si == BSincScaleCount-1)
  200. {
  201. for(size_t i{0};i < BSincPhaseCount*m*2;++i)
  202. mTable[idx++] = 0.0f;
  203. }
  204. else for(size_t pi{0};pi < BSincPhaseCount;++pi)
  205. {
  206. /* Linear interpolation between scales is also simplified.
  207. *
  208. * Given a difference in the number of points between scales,
  209. * the destination points will be 0, thus: x = a + f (-a)
  210. */
  211. for(size_t i{0};i < m;++i)
  212. {
  213. const double scDelta{filter[si+1][pi][o+i] - filter[si][pi][o+i]};
  214. mTable[idx++] = static_cast<float>(scDelta);
  215. }
  216. /* This last simplification is done to complete the bilinear
  217. * equation for the combination of phase and scale.
  218. */
  219. for(size_t i{0};i < m;++i)
  220. {
  221. const double spDelta{(filter[si+1][pi+1][o+i] - filter[si+1][pi][o+i]) -
  222. (filter[si][pi+1][o+i] - filter[si][pi][o+i])};
  223. mTable[idx++] = static_cast<float>(spDelta);
  224. }
  225. }
  226. }
  227. assert(idx == hdr.total_size);
  228. }
  229. constexpr const BSincHeader &getHeader() const noexcept { return hdr; }
  230. constexpr const float *getTable() const noexcept { return &mTable.front(); }
  231. };
  232. #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 6
  233. const BSincFilterArray<bsinc12_hdr.total_size> bsinc12_filter{bsinc12_hdr};
  234. const BSincFilterArray<bsinc24_hdr.total_size> bsinc24_filter{bsinc24_hdr};
  235. #else
  236. const BSincFilterArray<bsinc12_hdr> bsinc12_filter{};
  237. const BSincFilterArray<bsinc24_hdr> bsinc24_filter{};
  238. #endif
  239. template<typename T>
  240. constexpr BSincTable GenerateBSincTable(const T &filter)
  241. {
  242. BSincTable ret{};
  243. const BSincHeader &hdr = filter.getHeader();
  244. ret.scaleBase = static_cast<float>(hdr.scaleBase);
  245. ret.scaleRange = static_cast<float>(1.0 / hdr.scaleRange);
  246. for(size_t i{0};i < BSincScaleCount;++i)
  247. ret.m[i] = ((hdr.a[i]*2) + 3) & ~3u;
  248. ret.filterOffset[0] = 0;
  249. for(size_t i{1};i < BSincScaleCount;++i)
  250. ret.filterOffset[i] = ret.filterOffset[i-1] + ret.m[i-1]*4*BSincPhaseCount;
  251. ret.Tab = filter.getTable();
  252. return ret;
  253. }
  254. } // namespace
  255. const BSincTable bsinc12{GenerateBSincTable(bsinc12_filter)};
  256. const BSincTable bsinc24{GenerateBSincTable(bsinc24_filter)};