/* SPDX-License-Identifier: BSD-3-Clause */ /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */ #pragma once #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/arithmetic_shift.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/math.hpp" #include "mpt/base/saturate_cast.hpp" #include "openmpt/base/Int24.hpp" #include "openmpt/base/Types.hpp" #include "openmpt/soundbase/SampleConvert.hpp" #include #include #include #include OPENMPT_NAMESPACE_BEGIN namespace SC { // SC = _S_ample_C_onversion #if MPT_COMPILER_MSVC template MPT_FORCEINLINE Tfloat fastround(Tfloat x) { static_assert(std::is_floating_point::value); return std::floor(x + static_cast(0.5)); } #else template MPT_FORCEINLINE Tfloat fastround(Tfloat x) { static_assert(std::is_floating_point::value); return mpt::round(x); } #endif // Shift input_t down by shift and saturate to output_t. template struct ConvertShift { using input_t = Tsrc; using output_t = Tdst; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::saturate_cast(mpt::rshift_signed(val, shift)); } }; // Shift input_t up by shift and saturate to output_t. template struct ConvertShiftUp { using input_t = Tsrc; using output_t = Tdst; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::saturate_cast(mpt::lshift_signed(val, shift)); } }; // Every sample conversion functor has to typedef its input_t and output_t. // The input_t argument is taken by value because we only deal with per-single-sample conversions here. // straight forward type conversions, clamping when converting from floating point. template struct Convert; template struct Convert { using input_t = Tid; using output_t = Tid; MPT_FORCEINLINE output_t operator()(input_t val) { return val; } }; template <> struct Convert { using input_t = int8; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val + 0x80); } }; template <> struct Convert { using input_t = int16; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(val, 8)) + 0x80); } }; template <> struct Convert { using input_t = int24; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(static_cast(val), 16)) + 0x80); } }; template <> struct Convert { using input_t = int32; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(val, 24)) + 0x80); } }; template <> struct Convert { using input_t = int64; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(mpt::rshift_signed(val, 56)) + 0x80); } }; template <> struct Convert { using input_t = float32; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 128.0f; return static_cast(mpt::saturate_cast(static_cast(SC::fastround(val))) + 0x80); } }; template <> struct Convert { using input_t = double; using output_t = uint8; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 128.0; return static_cast(mpt::saturate_cast(static_cast(SC::fastround(val))) + 0x80); } }; template <> struct Convert { using input_t = uint8; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(static_cast(val) - 0x80); } }; template <> struct Convert { using input_t = int16; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int24; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(static_cast(val), 16)); } }; template <> struct Convert { using input_t = int32; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 24)); } }; template <> struct Convert { using input_t = int64; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 56)); } }; template <> struct Convert { using input_t = float32; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 128.0f; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = double; using output_t = int8; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 128.0; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = uint8; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val) - 0x80, 8)); } }; template <> struct Convert { using input_t = int8; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int24; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(static_cast(val), 8)); } }; template <> struct Convert { using input_t = int32; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 16)); } }; template <> struct Convert { using input_t = int64; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 48)); } }; template <> struct Convert { using input_t = float32; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 32768.0f; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = double; using output_t = int16; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 32768.0; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = uint8; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val) - 0x80, 16)); } }; template <> struct Convert { using input_t = int8; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 16)); } }; template <> struct Convert { using input_t = int16; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int32; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 8)); } }; template <> struct Convert { using input_t = int64; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 40)); } }; template <> struct Convert { using input_t = float32; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 2147483648.0f; return static_cast(mpt::rshift_signed(mpt::saturate_cast(static_cast(SC::fastround(val))), 8)); } }; template <> struct Convert { using input_t = double; using output_t = int24; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 2147483648.0; return static_cast(mpt::rshift_signed(mpt::saturate_cast(static_cast(SC::fastround(val))), 8)); } }; template <> struct Convert { using input_t = uint8; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val) - 0x80, 24)); } }; template <> struct Convert { using input_t = int8; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 24)); } }; template <> struct Convert { using input_t = int16; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(val, 16)); } }; template <> struct Convert { using input_t = int24; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::lshift_signed(static_cast(val), 8)); } }; template <> struct Convert { using input_t = int64; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(mpt::rshift_signed(val, 32)); } }; template <> struct Convert { using input_t = float32; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= 2147483648.0f; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = double; using output_t = int32; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= 2147483648.0; return mpt::saturate_cast(static_cast(SC::fastround(val))); } }; template <> struct Convert { using input_t = uint8; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val) - 0x80, 56); } }; template <> struct Convert { using input_t = int8; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 56); } }; template <> struct Convert { using input_t = int16; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 48); } }; template <> struct Convert { using input_t = int24; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 40); } }; template <> struct Convert { using input_t = int32; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { return mpt::lshift_signed(static_cast(val), 32); } }; template <> struct Convert { using input_t = float32; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { val = mpt::safe_clamp(val, -1.0f, 1.0f); val *= static_cast(uint64(1) << 63); return mpt::saturate_cast(SC::fastround(val)); } }; template <> struct Convert { using input_t = double; using output_t = int64; MPT_FORCEINLINE output_t operator()(input_t val) { val = std::clamp(val, -1.0, 1.0); val *= static_cast(uint64(1) << 63); return mpt::saturate_cast(SC::fastround(val)); } }; template <> struct Convert { using input_t = uint8; using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { return (static_cast(val) - 0x80) * (1.0f / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int8; using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0f / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int16; using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0f / static_cast(static_cast(1) << 15)); } }; template <> struct Convert { using input_t = int24; using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0f / static_cast(static_cast(1) << 23)); } }; template <> struct Convert { using input_t = int32; using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0f / static_cast(static_cast(1) << 31)); } }; template <> struct Convert { using input_t = int64; using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0f / static_cast(static_cast(1) << 63)); } }; template <> struct Convert { using input_t = uint8; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return (static_cast(val) - 0x80) * (1.0 / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int8; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0 / static_cast(static_cast(1) << 7)); } }; template <> struct Convert { using input_t = int16; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0 / static_cast(static_cast(1) << 15)); } }; template <> struct Convert { using input_t = int24; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0 / static_cast(static_cast(1) << 23)); } }; template <> struct Convert { using input_t = int32; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0 / static_cast(static_cast(1) << 31)); } }; template <> struct Convert { using input_t = int64; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return val * (1.0 / static_cast(static_cast(1) << 63)); } }; template <> struct Convert { using input_t = float; using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val); } }; template <> struct Convert { using input_t = double; using output_t = float; MPT_FORCEINLINE output_t operator()(input_t val) { return static_cast(val); } }; template MPT_FORCEINLINE Tdst sample_cast(Tsrc src) { return SC::Convert{}(src); } } // namespace SC OPENMPT_NAMESPACE_END