diff options
author | Jesse Talavera <jesse@jesse.tg> | 2023-12-05 06:41:28 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-05 12:41:28 +0100 |
commit | ae91d89f7c18f6b4153deeef7e3ebe14a1d849fe (patch) | |
tree | 5fb6734c3edc9b3bae4b41c1bfc02d32da4b0a06 | |
parent | 2e8cca9ca18a7d4375bc1ae4be6dfedbba6c6d79 (diff) |
Use a `constexpr`-friendly cosine implementation (#1903)
-rw-r--r-- | src/SPU.cpp | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/src/SPU.cpp b/src/SPU.cpp index cff38d3..1ec3c90 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -65,16 +65,56 @@ const s16 SPUChannel::PSGTable[8][8] = {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF} }; +template <typename T> +constexpr T ipow(T num, unsigned int pow) +{ + T product = 1; + for (int i = 0; i < pow; ++i) + { + product *= num; + } + + return product; +} + +template <typename T> +constexpr T factorial(T num) +{ + T product = 1; + for (T i = 1; i <= num; ++i) + { + product *= i; + } + + return product; +} + +// We can't use std::cos in constexpr functions until C++26, +// so we need to compute the cosine ourselves with the Taylor series. +// Code adapted from https://prosepoetrycode.potterpcs.net/2015/07/a-simple-constexpr-power-function-c/ +template <int Iterations = 10> +constexpr double cosine (double theta) +{ + return (ipow(-1, Iterations) * ipow(theta, 2 * Iterations)) / + static_cast<double>(factorial(2ull * Iterations)) + + cosine<Iterations-1>(theta); +} + +template <> +constexpr double cosine<0> (double theta) +{ + return 1.0; +} + // generate interpolation tables // values are 1:1:14 fixed-point constexpr std::array<s16, 0x100> InterpCos = []() constexpr { std::array<s16, 0x100> interp {}; - float m_pi = std::acos(-1.0f); for (int i = 0; i < 0x100; i++) { - float ratio = (i * m_pi) / 255.0f; - ratio = 1.0f - std::cos(ratio); + float ratio = (i * M_PI) / 255.0f; + ratio = 1.0f - cosine(ratio); interp[i] = (s16)(ratio * 0x2000); } |