From 9c0501bb90e0ff0c82083c669a3dccdf961cf9d2 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 19 Feb 2024 23:53:52 +0100 Subject: [PATCH] audio: simplify sample conversion code --- include/lol/private/audio/stream.h | 36 ++++++++++++------------------ 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/include/lol/private/audio/stream.h b/include/lol/private/audio/stream.h index bfe79f25..2b754944 100644 --- a/include/lol/private/audio/stream.h +++ b/include/lol/private/audio/stream.h @@ -50,7 +50,7 @@ public: // - add min, round down, and clamp to min…max FROM constexpr min(std::numeric_limits::min()); FROM constexpr max(std::numeric_limits::max()); - x = (x + 1) * ((max - min + 1) / 2); + x = (max - min + 1) / 2 * (x + 1); return TO(std::max(min, std::min(max, std::floor(x + min)))); } else if constexpr (to_fp) @@ -60,33 +60,25 @@ public: // - change range from 0…1 to -1…1 TO constexpr min(std::numeric_limits::min()); TO constexpr max(std::numeric_limits::max()); - return (TO(x) - min) * 2 / (max - min) - 1; + return 2 / (max - min) * (TO(x) - min) - 1; } else { + // Conversion between integer types: + // - convert to unsigned + // - shift right or multiply by a magic constant such as 0x0101 to propagate bytes + // - convert back to signed if necessary + // Most operations are done using the UBIG type, which is an unsigned integer type + // at least as large as FROM and TO. using UFROM = std::make_unsigned_t; using UTO = std::make_unsigned_t; + using UBIG = std::conditional_t<(sizeof(FROM) > sizeof(TO)), UFROM, UTO>; - if constexpr (sizeof(FROM) > sizeof(TO)) - { - // From a larger integer type to a smaller integer type: - // - convert to unsigned - // - shift right - // - convert back to signed if necessary - UFROM constexpr m = UFROM(1) << (8 * (sizeof(FROM) - sizeof(TO))); - UFROM tmp = UFROM(UFROM(x) - UFROM(std::numeric_limits::min())) / m; - return TO(UTO(tmp) + UTO(std::numeric_limits::min())); - } - else - { - // From a smaller integer type to a larger integer type: - // - convert to unsigned - // - multiply by a magic constant such as 0x01010101 to propagate bytes - // - convert back to signed if necessary - UTO constexpr m = std::numeric_limits::max() / std::numeric_limits::max(); - UTO tmp = UFROM(UFROM(x) - UFROM(std::numeric_limits::min())) * m; - return TO(UTO(tmp) + UTO(std::numeric_limits::min())); - } + UBIG constexpr div = UBIG(1) << 8 * (sizeof(UBIG) - sizeof(UTO)); + UBIG constexpr mul = std::numeric_limits::max() / std::numeric_limits::max(); + auto tmp = UFROM(UFROM(x) - UFROM(std::numeric_limits::min())) * mul / div; + + return TO(UTO(tmp) + UTO(std::numeric_limits::min())); } } };