mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-05-12 20:40:23 -05:00
263 lines
7.9 KiB
C++
263 lines
7.9 KiB
C++
/* 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 <algorithm>
|
|
#include <limits>
|
|
|
|
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
|
|
namespace SC
|
|
{ // SC = _S_ample_C_onversion
|
|
|
|
|
|
template <typename Tdst, typename Tsrc, int fractionalBits>
|
|
struct ConvertFixedPoint;
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<uint8, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = uint8;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round
|
|
if(val < std::numeric_limits<int8>::min()) val = std::numeric_limits<int8>::min();
|
|
if(val > std::numeric_limits<int8>::max()) val = std::numeric_limits<int8>::max();
|
|
return static_cast<uint8>(val + 0x80); // unsigned
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<int8, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = int8;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round
|
|
if(val < std::numeric_limits<int8>::min()) val = std::numeric_limits<int8>::min();
|
|
if(val > std::numeric_limits<int8>::max()) val = std::numeric_limits<int8>::max();
|
|
return static_cast<int8>(val);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<int16, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = int16;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round
|
|
if(val < std::numeric_limits<int16>::min()) val = std::numeric_limits<int16>::min();
|
|
if(val > std::numeric_limits<int16>::max()) val = std::numeric_limits<int16>::max();
|
|
return static_cast<int16>(val);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<int24, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = int24;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
val = mpt::rshift_signed((val + (1 << (shiftBits - 1))), shiftBits); // round
|
|
if(val < std::numeric_limits<int24>::min()) val = std::numeric_limits<int24>::min();
|
|
if(val > std::numeric_limits<int24>::max()) val = std::numeric_limits<int24>::max();
|
|
return static_cast<int24>(val);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<int32, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = int32;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
return static_cast<int32>(std::clamp(val, static_cast<int32>(-((1 << fractionalBits) - 1)), static_cast<int32>(1 << fractionalBits) - 1)) << (sizeof(input_t) * 8 - 1 - fractionalBits);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<float32, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = float32;
|
|
const float factor;
|
|
MPT_FORCEINLINE ConvertFixedPoint()
|
|
: factor(1.0f / static_cast<float>(1 << fractionalBits))
|
|
{
|
|
return;
|
|
}
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
return val * factor;
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertFixedPoint<float64, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = float64;
|
|
const double factor;
|
|
MPT_FORCEINLINE ConvertFixedPoint()
|
|
: factor(1.0 / static_cast<double>(1 << fractionalBits))
|
|
{
|
|
return;
|
|
}
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
return val * factor;
|
|
}
|
|
};
|
|
|
|
|
|
template <typename Tdst, typename Tsrc, int fractionalBits>
|
|
struct ConvertToFixedPoint;
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, uint8, fractionalBits>
|
|
{
|
|
using input_t = uint8;
|
|
using output_t = int32;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
return mpt::lshift_signed(static_cast<output_t>(static_cast<int>(val) - 0x80), shiftBits);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, int8, fractionalBits>
|
|
{
|
|
using input_t = int8;
|
|
using output_t = int32;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
return mpt::lshift_signed(static_cast<output_t>(val), shiftBits);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, int16, fractionalBits>
|
|
{
|
|
using input_t = int16;
|
|
using output_t = int32;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
return mpt::lshift_signed(static_cast<output_t>(val), shiftBits);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, int24, fractionalBits>
|
|
{
|
|
using input_t = int24;
|
|
using output_t = int32;
|
|
static constexpr int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1);
|
|
static_assert(shiftBits >= 1);
|
|
return mpt::lshift_signed(static_cast<output_t>(val), shiftBits);
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, int32, fractionalBits>
|
|
{
|
|
using input_t = int32;
|
|
using output_t = int32;
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(output_t) * 8 - 1);
|
|
return mpt::rshift_signed(static_cast<output_t>(val), (sizeof(input_t) * 8 - 1 - fractionalBits));
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, float32, fractionalBits>
|
|
{
|
|
using input_t = float32;
|
|
using output_t = int32;
|
|
const float factor;
|
|
MPT_FORCEINLINE ConvertToFixedPoint()
|
|
: factor(static_cast<float>(1 << fractionalBits))
|
|
{
|
|
return;
|
|
}
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
val = mpt::sanitize_nan(val);
|
|
return mpt::saturate_cast<output_t>(SC::fastround(val * factor));
|
|
}
|
|
};
|
|
|
|
template <int fractionalBits>
|
|
struct ConvertToFixedPoint<int32, float64, fractionalBits>
|
|
{
|
|
using input_t = float64;
|
|
using output_t = int32;
|
|
const double factor;
|
|
MPT_FORCEINLINE ConvertToFixedPoint()
|
|
: factor(static_cast<double>(1 << fractionalBits))
|
|
{
|
|
return;
|
|
}
|
|
MPT_FORCEINLINE output_t operator()(input_t val)
|
|
{
|
|
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
|
|
val = mpt::sanitize_nan(val);
|
|
return mpt::saturate_cast<output_t>(SC::fastround(val * factor));
|
|
}
|
|
};
|
|
|
|
|
|
} // namespace SC
|
|
|
|
|
|
OPENMPT_NAMESPACE_END
|