From ae91d89f7c18f6b4153deeef7e3ebe14a1d849fe Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Tue, 5 Dec 2023 06:41:28 -0500 Subject: [PATCH] Use a `constexpr`-friendly cosine implementation (#1903) --- src/SPU.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/SPU.cpp b/src/SPU.cpp index cff38d3ab1..1ec3c90f89 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 +constexpr T ipow(T num, unsigned int pow) +{ + T product = 1; + for (int i = 0; i < pow; ++i) + { + product *= num; + } + + return product; +} + +template +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 +constexpr double cosine (double theta) +{ + return (ipow(-1, Iterations) * ipow(theta, 2 * Iterations)) / + static_cast(factorial(2ull * Iterations)) + + cosine(theta); +} + +template <> +constexpr double cosine<0> (double theta) +{ + return 1.0; +} + // generate interpolation tables // values are 1:1:14 fixed-point constexpr std::array InterpCos = []() constexpr { std::array 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); }