From 937284a78ad6effbfd17a200fd1fb43d9bc78f62 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 19 Feb 2024 11:06:00 +0100 Subject: [PATCH] audio: implement a more generic format conversion function --- include/lol/private/audio/stream.h | 45 +++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/include/lol/private/audio/stream.h b/include/lol/private/audio/stream.h index 7d933617..26e7b050 100644 --- a/include/lol/private/audio/stream.h +++ b/include/lol/private/audio/stream.h @@ -19,6 +19,7 @@ // #include // std::function +#include // std::numeric_limits #include // std::shared_ptr #include // std::is_same_v #include // std::unordered_set @@ -123,17 +124,41 @@ protected: std::unordered_set>> m_streams; }; +// Convert samples from and to different types (float, int16_t, uint8_t, …) template -static inline T convert_sample(T0); - -template<> -inline float convert_sample(float x) { return x; } - -template<> -inline float convert_sample(int16_t x) { return x / 32768.0f; } +static inline T convert_sample(T0 x) +{ + constexpr auto from_fp = std::is_floating_point_v; + constexpr auto from_signed = !from_fp && std::is_signed_v; + constexpr auto to_fp = std::is_floating_point_v; + constexpr auto to_signed = !to_fp && std::is_signed_v; -template<> -inline float convert_sample(uint16_t x) { return x / 32767.0f - 1.0f; } + if constexpr (std::is_same_v || (from_fp && to_fp)) + { + // If types are the same, or both floating-point, no conversion is needed + return T(x); + } + else if constexpr (from_fp) + { + // From floating point to integer + if constexpr (to_signed) + x = (x + T0(1.0)) * T0(0.5); + return T(x * std::numeric_limits::max()); + } + else if constexpr (to_fp) + { + // From integer to floating point + if constexpr (from_signed) + return x / -T(std::numeric_limits::min()); + else + return x / (T(std::numeric_limits::max()) * T(0.5)) - T(1.0); + } + else + { + // FIXME: this is better than nothing but we need a better implementation + return convert_sample(convert_sample(x)); + } +} template class converter : public stream @@ -146,7 +171,7 @@ public: virtual size_t get(T *buf, size_t frames) override { - if constexpr(std::is_same_v) + if constexpr (std::is_same_v) return m_in->get(buf, frames); size_t samples = frames * this->channels();