mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 16:14:38 +00:00
update openal-soft to 1.24.3
keeping the alt 87514151c4 (diff-73a8dc1ce58605f6c5ea53548454c3bae516ec5132a29c9d7ff7edf9730c75be)
This commit is contained in:
parent
12db0500e8
commit
ba32094b7b
276 changed files with 49304 additions and 8712 deletions
|
|
@ -1,38 +1,44 @@
|
|||
|
||||
#include "alassert.h"
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
[[noreturn]]
|
||||
void throw_error(const std::string &message)
|
||||
{
|
||||
throw std::runtime_error{message};
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
namespace al {
|
||||
|
||||
[[noreturn]]
|
||||
void do_assert(const char *message, int linenum, const char *filename, const char *funcname) noexcept
|
||||
{
|
||||
std::string errstr{filename};
|
||||
/* Throwing an exception that tries to leave a noexcept function will
|
||||
* hopefully cause the system to provide info about the caught exception in
|
||||
* an error dialog. At least on Linux, this results in the process printing
|
||||
*
|
||||
* terminate called after throwing an instance of 'std::runtime_error'
|
||||
* what(): <message here>
|
||||
*
|
||||
* before terminating from a SIGABRT. Hopefully Windows and Mac will do the
|
||||
* appropriate things with the message to alert the user about an abnormal
|
||||
* termination.
|
||||
*/
|
||||
auto errstr = std::string{filename};
|
||||
errstr += ':';
|
||||
errstr += std::to_string(linenum);
|
||||
errstr += ": ";
|
||||
errstr += funcname;
|
||||
errstr += ": ";
|
||||
errstr += message;
|
||||
/* Calling std::terminate in a catch block hopefully causes the system to
|
||||
* provide info about the caught exception in the error dialog. At least on
|
||||
* Linux, this results in the process printing
|
||||
*
|
||||
* terminate called after throwing an instance of 'std::runtime_error'
|
||||
* what(): <message here>
|
||||
*
|
||||
* before terminating from a SIGABRT. Hopefully Windows and Mac will do the
|
||||
* appropriate things with the message for an abnormal termination.
|
||||
*/
|
||||
try {
|
||||
throw std::runtime_error{errstr};
|
||||
}
|
||||
catch(...) {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
throw_error(errstr);
|
||||
}
|
||||
|
||||
} /* namespace al */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef AL_BIT_H
|
||||
#define AL_BIT_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#ifndef __GNUC__
|
||||
#include <cstdint>
|
||||
|
|
@ -25,6 +26,16 @@ To> bit_cast(const From &src) noexcept
|
|||
return *std::launder(reinterpret_cast<To*>(dst.data()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_integral_v<T>,
|
||||
T> byteswap(T value) noexcept
|
||||
{
|
||||
static_assert(std::has_unique_object_representations_v<T>);
|
||||
auto bytes = al::bit_cast<std::array<std::byte,sizeof(T)>>(value);
|
||||
std::reverse(bytes.begin(), bytes.end());
|
||||
return al::bit_cast<T>(bytes);
|
||||
}
|
||||
|
||||
#ifdef __BYTE_ORDER__
|
||||
enum class endian {
|
||||
little = __ORDER_LITTLE_ENDIAN__,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
namespace {
|
||||
|
||||
using ushort = unsigned short;
|
||||
using ushort2 = std::pair<ushort,ushort>;
|
||||
using ushort2 = std::array<ushort,2>;
|
||||
using complex_d = std::complex<double>;
|
||||
|
||||
constexpr std::size_t BitReverseCounter(std::size_t log2_size) noexcept
|
||||
|
|
@ -56,8 +56,8 @@ struct BitReverser {
|
|||
|
||||
if(idx < revidx)
|
||||
{
|
||||
mData[ret_i].first = static_cast<ushort>(idx);
|
||||
mData[ret_i].second = static_cast<ushort>(revidx);
|
||||
mData[ret_i][0] = static_cast<ushort>(idx);
|
||||
mData[ret_i][1] = static_cast<ushort>(revidx);
|
||||
++ret_i;
|
||||
}
|
||||
}
|
||||
|
|
@ -122,7 +122,7 @@ void complex_fft(const al::span<std::complex<double>> buffer, const double sign)
|
|||
if(log2_size < gBitReverses.size()) LIKELY
|
||||
{
|
||||
for(auto &rev : gBitReverses[log2_size])
|
||||
std::swap(buffer[rev.first], buffer[rev.second]);
|
||||
std::swap(buffer[rev[0]], buffer[rev[1]]);
|
||||
|
||||
/* Iterative form of Danielson-Lanczos lemma */
|
||||
for(std::size_t i{0};i < log2_size;++i)
|
||||
|
|
|
|||
|
|
@ -123,31 +123,74 @@ class out_ptr_t {
|
|||
static_assert(!std::is_same_v<PT,void*>);
|
||||
|
||||
SP &mRes;
|
||||
std::variant<PT,void*> mPtr{};
|
||||
std::variant<PT,void*> mPtr;
|
||||
|
||||
public:
|
||||
out_ptr_t(SP &res) : mRes{res} { }
|
||||
~out_ptr_t()
|
||||
{
|
||||
auto set_res = [this](auto &ptr)
|
||||
{ mRes.reset(static_cast<PT>(ptr)); };
|
||||
std::visit(set_res, mPtr);
|
||||
}
|
||||
explicit out_ptr_t(SP &res) : mRes{res} { }
|
||||
~out_ptr_t() { std::visit([this](auto &ptr) { mRes.reset(static_cast<PT>(ptr)); }, mPtr); }
|
||||
|
||||
out_ptr_t() = delete;
|
||||
out_ptr_t(const out_ptr_t&) = delete;
|
||||
out_ptr_t& operator=(const out_ptr_t&) = delete;
|
||||
|
||||
operator PT*() noexcept
|
||||
operator PT*() noexcept /* NOLINT(google-explicit-constructor) */
|
||||
{ return &std::get<PT>(mPtr); }
|
||||
|
||||
operator void**() noexcept
|
||||
operator void**() noexcept /* NOLINT(google-explicit-constructor) */
|
||||
{ return &mPtr.template emplace<void*>(); }
|
||||
};
|
||||
|
||||
template<typename T=void, typename SP, typename ...Args>
|
||||
auto out_ptr(SP &res)
|
||||
auto out_ptr(SP &res, Args&& ...args)
|
||||
{
|
||||
using ptype = typename SP::element_type*;
|
||||
return out_ptr_t<SP,ptype>{res};
|
||||
static_assert(sizeof...(args) == 0);
|
||||
if constexpr(std::is_same_v<T,void>)
|
||||
{
|
||||
using ptype = typename SP::element_type*;
|
||||
return out_ptr_t<SP,ptype,Args...>{res};
|
||||
}
|
||||
else
|
||||
return out_ptr_t<SP,T,Args...>{res};
|
||||
}
|
||||
|
||||
|
||||
template<typename SP, typename PT, typename ...Args>
|
||||
class inout_ptr_t {
|
||||
static_assert(!std::is_same_v<PT,void*>);
|
||||
|
||||
SP &mRes;
|
||||
std::variant<PT,void*> mPtr;
|
||||
|
||||
public:
|
||||
explicit inout_ptr_t(SP &res) : mRes{res}, mPtr{res.get()} { }
|
||||
~inout_ptr_t()
|
||||
{
|
||||
mRes.release();
|
||||
std::visit([this](auto &ptr) { mRes.reset(static_cast<PT>(ptr)); }, mPtr);
|
||||
}
|
||||
|
||||
inout_ptr_t() = delete;
|
||||
inout_ptr_t(const inout_ptr_t&) = delete;
|
||||
inout_ptr_t& operator=(const inout_ptr_t&) = delete;
|
||||
|
||||
operator PT*() noexcept /* NOLINT(google-explicit-constructor) */
|
||||
{ return &std::get<PT>(mPtr); }
|
||||
|
||||
operator void**() noexcept /* NOLINT(google-explicit-constructor) */
|
||||
{ return &mPtr.template emplace<void*>(mRes.get()); }
|
||||
};
|
||||
|
||||
template<typename T=void, typename SP, typename ...Args>
|
||||
auto inout_ptr(SP &res, Args&& ...args)
|
||||
{
|
||||
static_assert(sizeof...(args) == 0);
|
||||
if constexpr(std::is_same_v<T,void>)
|
||||
{
|
||||
using ptype = typename SP::element_type*;
|
||||
return inout_ptr_t<SP,ptype,Args...>{res};
|
||||
}
|
||||
else
|
||||
return inout_ptr_t<SP,T,Args...>{res};
|
||||
}
|
||||
|
||||
} // namespace al
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
#ifndef AL_NUMERIC_H
|
||||
#define AL_NUMERIC_H
|
||||
|
||||
#include "config_simd.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#ifdef HAVE_INTRIN_H
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#ifdef HAVE_SSE_INTRINSICS
|
||||
#if HAVE_SSE_INTRINSICS
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -29,19 +31,27 @@ constexpr auto operator "" _uz(unsigned long long n) noexcept { return static_ca
|
|||
constexpr auto operator "" _zu(unsigned long long n) noexcept { return static_cast<std::size_t>(n); }
|
||||
|
||||
|
||||
constexpr auto GetCounterSuffix(size_t count) noexcept -> const char*
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>,bool> = true>
|
||||
constexpr auto as_unsigned(T value) noexcept
|
||||
{
|
||||
auto &suffix = (((count%100)/10) == 1) ? "th" :
|
||||
((count%10) == 1) ? "st" :
|
||||
((count%10) == 2) ? "nd" :
|
||||
((count%10) == 3) ? "rd" : "th";
|
||||
return std::data(suffix);
|
||||
using UT = std::make_unsigned_t<T>;
|
||||
return static_cast<UT>(value);
|
||||
}
|
||||
|
||||
|
||||
constexpr inline float lerpf(float val1, float val2, float mu) noexcept
|
||||
constexpr auto GetCounterSuffix(size_t count) noexcept -> std::string_view
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
return (((count%100)/10) == 1) ? "th"sv :
|
||||
((count%10) == 1) ? "st"sv :
|
||||
((count%10) == 2) ? "nd"sv :
|
||||
((count%10) == 3) ? "rd"sv : "th"sv;
|
||||
}
|
||||
|
||||
|
||||
constexpr auto lerpf(float val1, float val2, float mu) noexcept -> float
|
||||
{ return val1 + (val2-val1)*mu; }
|
||||
constexpr inline double lerpd(double val1, double val2, double mu) noexcept
|
||||
constexpr auto lerpd(double val1, double val2, double mu) noexcept -> double
|
||||
{ return val1 + (val2-val1)*mu; }
|
||||
|
||||
|
||||
|
|
@ -84,7 +94,7 @@ constexpr T RoundUp(T value, al::type_identity_t<T> r) noexcept
|
|||
*/
|
||||
inline int fastf2i(float f) noexcept
|
||||
{
|
||||
#if defined(HAVE_SSE_INTRINSICS)
|
||||
#if HAVE_SSE_INTRINSICS
|
||||
return _mm_cvt_ss2si(_mm_set_ss(f));
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0
|
||||
|
|
@ -112,7 +122,7 @@ inline unsigned int fastf2u(float f) noexcept
|
|||
/** Converts float-to-int using standard behavior (truncation). */
|
||||
inline int float2int(float f) noexcept
|
||||
{
|
||||
#if defined(HAVE_SSE_INTRINSICS)
|
||||
#if HAVE_SSE_INTRINSICS
|
||||
return _mm_cvtt_ss2si(_mm_set_ss(f));
|
||||
|
||||
#elif (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0) \
|
||||
|
|
@ -143,7 +153,7 @@ inline unsigned int float2uint(float f) noexcept
|
|||
/** Converts double-to-int using standard behavior (truncation). */
|
||||
inline int double2int(double d) noexcept
|
||||
{
|
||||
#if defined(HAVE_SSE_INTRINSICS)
|
||||
#if HAVE_SSE_INTRINSICS
|
||||
return _mm_cvttsd_si32(_mm_set_sd(d));
|
||||
|
||||
#elif (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) \
|
||||
|
|
@ -241,7 +251,7 @@ inline float level_mb_to_gain(float x)
|
|||
// Converts gain to level (mB).
|
||||
inline float gain_to_level_mb(float x)
|
||||
{
|
||||
if (x <= 0.0f)
|
||||
if(x <= 1e-05f)
|
||||
return -10'000.0f;
|
||||
return std::max(std::log10(x) * 2'000.0f, -10'000.0f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class semaphore {
|
|||
native_type mSem{};
|
||||
|
||||
public:
|
||||
semaphore(unsigned int initial=0);
|
||||
explicit semaphore(unsigned int initial=0);
|
||||
semaphore(const semaphore&) = delete;
|
||||
~semaphore();
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,9 @@ namespace detail_ {
|
|||
|
||||
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__),bool> = true
|
||||
|
||||
/* NOLINTBEGIN(google-explicit-constructor) This largely follows std::span's
|
||||
* constructor behavior, and should be replaced once C++20 is used.
|
||||
*/
|
||||
template<typename T, std::size_t E>
|
||||
class span {
|
||||
public:
|
||||
|
|
@ -212,8 +215,10 @@ public:
|
|||
[[nodiscard]] constexpr
|
||||
auto cend() const noexcept -> const_iterator { return const_iterator{mData+E}; }
|
||||
|
||||
[[nodiscard]] constexpr auto rbegin() const noexcept -> reverse_iterator { return end(); }
|
||||
[[nodiscard]] constexpr auto rend() const noexcept -> reverse_iterator { return begin(); }
|
||||
[[nodiscard]] constexpr
|
||||
auto rbegin() const noexcept -> reverse_iterator { return reverse_iterator{end()}; }
|
||||
[[nodiscard]] constexpr
|
||||
auto rend() const noexcept -> reverse_iterator { return reverse_iterator{begin()}; }
|
||||
[[nodiscard]] constexpr
|
||||
auto crbegin() const noexcept -> const_reverse_iterator { return cend(); }
|
||||
[[nodiscard]] constexpr
|
||||
|
|
@ -336,8 +341,10 @@ public:
|
|||
[[nodiscard]] constexpr
|
||||
auto cend() const noexcept -> const_iterator { return const_iterator{mData+mDataLength}; }
|
||||
|
||||
[[nodiscard]] constexpr auto rbegin() const noexcept -> reverse_iterator { return end(); }
|
||||
[[nodiscard]] constexpr auto rend() const noexcept -> reverse_iterator { return begin(); }
|
||||
[[nodiscard]] constexpr
|
||||
auto rbegin() const noexcept -> reverse_iterator { return reverse_iterator{end()}; }
|
||||
[[nodiscard]] constexpr
|
||||
auto rend() const noexcept -> reverse_iterator { return reverse_iterator{begin()}; }
|
||||
[[nodiscard]] constexpr
|
||||
auto crbegin() const noexcept -> const_reverse_iterator { return cend(); }
|
||||
[[nodiscard]] constexpr
|
||||
|
|
@ -432,7 +439,7 @@ auto span<T,E>::subspan(std::size_t offset, std::size_t count) const noexcept
|
|||
}
|
||||
return span<element_type>{mData+offset, size()-offset};
|
||||
}
|
||||
|
||||
/* NOLINTEND(google-explicit-constructor) */
|
||||
|
||||
template<typename T, typename EndOrSize>
|
||||
span(T, EndOrSize) -> span<std::remove_reference_t<decltype(*std::declval<T&>())>>;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include <cctype>
|
||||
#include <cwctype>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace al {
|
||||
|
|
@ -52,13 +51,4 @@ int case_compare(const std::wstring_view str0, const std::wstring_view str1) noe
|
|||
return 0;
|
||||
}
|
||||
|
||||
int strcasecmp(const char *str0, const char *str1) noexcept
|
||||
{ return case_compare(str0, str1); }
|
||||
|
||||
int strncasecmp(const char *str0, const char *str1, std::size_t len) noexcept
|
||||
{
|
||||
return case_compare(std::string_view{str0, std::min(std::strlen(str0), len)},
|
||||
std::string_view{str1, std::min(std::strlen(str1), len)});
|
||||
}
|
||||
|
||||
} // namespace al
|
||||
|
|
|
|||
|
|
@ -10,11 +10,17 @@
|
|||
|
||||
namespace al {
|
||||
|
||||
template<typename T, typename Traits>
|
||||
template<typename ...Ts>
|
||||
[[nodiscard]] constexpr
|
||||
auto sizei(const std::basic_string_view<T,Traits> str) noexcept -> int
|
||||
auto sizei(const std::basic_string_view<Ts...> str) noexcept -> int
|
||||
{ return static_cast<int>(std::min<std::size_t>(str.size(), std::numeric_limits<int>::max())); }
|
||||
|
||||
template<typename ...Ts>
|
||||
[[nodiscard]] constexpr
|
||||
auto sizei(const std::basic_string<Ts...> &str) noexcept -> int
|
||||
{ return static_cast<int>(std::min<std::size_t>(str.size(), std::numeric_limits<int>::max())); }
|
||||
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool contains(const std::string_view str0, const std::string_view str1) noexcept
|
||||
{ return str0.find(str1) != std::string_view::npos; }
|
||||
|
|
@ -33,10 +39,20 @@ int case_compare(const std::string_view str0, const std::string_view str1) noexc
|
|||
[[nodiscard]]
|
||||
int case_compare(const std::wstring_view str0, const std::wstring_view str1) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
int strcasecmp(const char *str0, const char *str1) noexcept;
|
||||
[[nodiscard]]
|
||||
int strncasecmp(const char *str0, const char *str1, std::size_t len) noexcept;
|
||||
/* C++20 changes path::u8string() to return a string using a new/distinct
|
||||
* char8_t type for UTF-8 strings. However, support for this with standard
|
||||
* string functions is totally inadequate, and we already hold UTF-8 with plain
|
||||
* char strings. So this function is used to reinterpret a char8_t string as a
|
||||
* char string_view.
|
||||
*/
|
||||
#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201907L
|
||||
inline auto u8_as_char(const std::u8string_view str) -> std::string_view
|
||||
#else
|
||||
inline auto u8_as_char(const std::string_view str) -> std::string_view
|
||||
#endif
|
||||
{
|
||||
return std::string_view{reinterpret_cast<const char*>(str.data()), str.size()};
|
||||
}
|
||||
|
||||
} // namespace al
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__STDC_NO_THREADS__) || !__has_include(<threads.h>)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ public:
|
|||
[[nodiscard]]
|
||||
auto get() const noexcept -> T { return from_ptr(TlsGetValue(mTss)); }
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__STDC_NO_THREADS__) || !__has_include(<threads.h>)
|
||||
|
||||
pthread_key_t mTss{};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
#ifndef COMMON_COMPTR_H
|
||||
#define COMMON_COMPTR_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
|
@ -17,7 +15,7 @@ struct ComWrapper {
|
|||
ComWrapper(void *reserved, DWORD coinit)
|
||||
: mStatus{CoInitializeEx(reserved, coinit)}
|
||||
{ }
|
||||
ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED)
|
||||
explicit ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED)
|
||||
: mStatus{CoInitializeEx(nullptr, coinit)}
|
||||
{ }
|
||||
ComWrapper(ComWrapper&& rhs) { mStatus = std::exchange(rhs.mStatus, E_FAIL); }
|
||||
|
|
@ -46,7 +44,7 @@ struct ComWrapper {
|
|||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
template<typename T> /* NOLINTNEXTLINE(clazy-rule-of-three) False positive */
|
||||
struct ComPtr {
|
||||
using element_type = T;
|
||||
|
||||
|
|
@ -57,7 +55,7 @@ struct ComPtr {
|
|||
ComPtr(const ComPtr &rhs) noexcept(RefIsNoexcept) : mPtr{rhs.mPtr}
|
||||
{ if(mPtr) mPtr->AddRef(); }
|
||||
ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
|
||||
ComPtr(std::nullptr_t) noexcept { }
|
||||
ComPtr(std::nullptr_t) noexcept { } /* NOLINT(google-explicit-constructor) */
|
||||
explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
|
||||
~ComPtr() { if(mPtr) mPtr->Release(); }
|
||||
|
||||
|
|
@ -109,5 +107,6 @@ struct ComPtr {
|
|||
private:
|
||||
T *mPtr{nullptr};
|
||||
};
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,12 +3,16 @@
|
|||
|
||||
#if defined(_WIN32) || defined(HAVE_DLFCN_H)
|
||||
|
||||
#define HAVE_DYNLOAD
|
||||
#define HAVE_DYNLOAD 1
|
||||
|
||||
void *LoadLib(const char *name);
|
||||
void CloseLib(void *handle);
|
||||
void *GetSymbol(void *handle, const char *name);
|
||||
|
||||
#else
|
||||
|
||||
#define HAVE_DYNLOAD 0
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* AL_DYNLOAD_H */
|
||||
|
|
|
|||
61
Engine/lib/openal-soft/common/filesystem.cpp
Normal file
61
Engine/lib/openal-soft/common/filesystem.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//---------------------------------------------------------------------------------------
|
||||
//
|
||||
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
|
||||
//
|
||||
//---------------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//---------------------------------------------------------------------------------------
|
||||
// fs_std_impl.hpp - The implementation header for the header/implementation separated usage of
|
||||
// ghc::filesystem that does nothing if std::filesystem is detected.
|
||||
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
|
||||
// The cpp has to include this before including fs_std_fwd.hpp directly or via a different
|
||||
// header to work.
|
||||
//---------------------------------------------------------------------------------------
|
||||
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
|
||||
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
|
||||
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
|
||||
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
|
||||
#define GHC_USE_STD_FS
|
||||
|
||||
// Old Apple OSs don't support std::filesystem, though the header is available at compile
|
||||
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
|
||||
// and watchOS 6.0.
|
||||
#ifdef __APPLE__
|
||||
#include <Availability.h>
|
||||
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
|
||||
// released after std::filesystem, where std::filesystem is always available.
|
||||
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|
||||
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|
||||
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|
||||
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
|
||||
#undef GHC_USE_STD_FS
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GHC_USE_STD_FS
|
||||
#define GHC_FILESYSTEM_IMPLEMENTATION
|
||||
#include "ghc_filesystem.h"
|
||||
#endif
|
||||
81
Engine/lib/openal-soft/common/filesystem.h
Normal file
81
Engine/lib/openal-soft/common/filesystem.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//---------------------------------------------------------------------------------------
|
||||
//
|
||||
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
|
||||
//
|
||||
//---------------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//---------------------------------------------------------------------------------------
|
||||
// fs_std_fwd.hpp - The forwarding header for the header/implementation separated usage of
|
||||
// ghc::filesystem that uses std::filesystem if it detects it.
|
||||
// This file can be include at any place, where fs::filesystem api is needed while
|
||||
// not bleeding implementation details (e.g. system includes) into the global namespace,
|
||||
// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations.
|
||||
//---------------------------------------------------------------------------------------
|
||||
#ifndef GHC_FILESYSTEM_STD_FWD_H
|
||||
#define GHC_FILESYSTEM_STD_FWD_H
|
||||
|
||||
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
|
||||
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
|
||||
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
|
||||
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
|
||||
#define GHC_USE_STD_FS
|
||||
|
||||
// Old Apple OSs don't support std::filesystem, though the header is available at compile
|
||||
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
|
||||
// and watchOS 6.0.
|
||||
#ifdef __APPLE__
|
||||
#include <Availability.h>
|
||||
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
|
||||
// released after std::filesystem, where std::filesystem is always available.
|
||||
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|
||||
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|
||||
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|
||||
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
|
||||
#undef GHC_USE_STD_FS
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GHC_USE_STD_FS
|
||||
#include <filesystem>
|
||||
namespace fs {
|
||||
using namespace std::filesystem;
|
||||
using ifstream = std::ifstream;
|
||||
using ofstream = std::ofstream;
|
||||
using fstream = std::fstream;
|
||||
}
|
||||
#else
|
||||
#define GHC_FILESYSTEM_FWD
|
||||
#include "ghc_filesystem.h"
|
||||
|
||||
namespace fs {
|
||||
using namespace ghc::filesystem;
|
||||
using ifstream = ghc::filesystem::ifstream;
|
||||
using ofstream = ghc::filesystem::ofstream;
|
||||
using fstream = ghc::filesystem::fstream;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GHC_FILESYSTEM_STD_FWD_H
|
||||
|
|
@ -30,7 +30,7 @@ struct alignas(alignment) FlexArrayStorage : al::span<T> {
|
|||
* arrays store their payloads after the end of the object, which must be
|
||||
* the last in the whole parent chain.
|
||||
*/
|
||||
FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
|
||||
explicit FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
|
||||
: al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
|
||||
{ }
|
||||
/* NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
|
||||
|
|
@ -46,7 +46,7 @@ struct alignas(alignment) FlexArrayStorage<T,alignment,false> : al::span<T> {
|
|||
{ return sizeof(FlexArrayStorage) + sizeof(T)*count + base; }
|
||||
|
||||
/* NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
|
||||
FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
|
||||
explicit FlexArrayStorage(size_t size) noexcept(std::is_nothrow_constructible_v<T>)
|
||||
: al::span<T>{::new(static_cast<void*>(this+1)) T[size], size}
|
||||
{ }
|
||||
/* NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
|
||||
|
|
@ -88,7 +88,8 @@ struct FlexArray {
|
|||
static std::unique_ptr<FlexArray> Create(index_type count)
|
||||
{ return std::unique_ptr<FlexArray>{new(FamCount{count}) FlexArray{count}}; }
|
||||
|
||||
FlexArray(index_type size) noexcept(std::is_nothrow_constructible_v<Storage_t_,index_type>)
|
||||
explicit FlexArray(index_type size)
|
||||
noexcept(std::is_nothrow_constructible_v<Storage_t_,index_type>)
|
||||
: mStore{size}
|
||||
{ }
|
||||
~FlexArray() = default;
|
||||
|
|
|
|||
6076
Engine/lib/openal-soft/common/ghc_filesystem.h
Normal file
6076
Engine/lib/openal-soft/common/ghc_filesystem.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,9 @@ template<typename T>
|
|||
class intrusive_ref {
|
||||
std::atomic<unsigned int> mRef{1u};
|
||||
|
||||
protected:
|
||||
~intrusive_ref() = default;
|
||||
|
||||
public:
|
||||
unsigned int add_ref() noexcept { return IncrementRef(mRef); }
|
||||
unsigned int dec_ref() noexcept
|
||||
|
|
@ -48,7 +51,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
template<typename T> /* NOLINTNEXTLINE(clazy-rule-of-three) False positive */
|
||||
class intrusive_ptr {
|
||||
T *mPtr{nullptr};
|
||||
|
||||
|
|
@ -58,7 +61,7 @@ public:
|
|||
{ if(mPtr) mPtr->add_ref(); }
|
||||
intrusive_ptr(intrusive_ptr&& rhs) noexcept : mPtr{rhs.mPtr}
|
||||
{ rhs.mPtr = nullptr; }
|
||||
intrusive_ptr(std::nullptr_t) noexcept { }
|
||||
intrusive_ptr(std::nullptr_t) noexcept { } /* NOLINT(google-explicit-constructor) */
|
||||
explicit intrusive_ptr(T *ptr) noexcept : mPtr{ptr} { }
|
||||
~intrusive_ptr() { if(mPtr) mPtr->dec_ref(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,24 @@
|
|||
#define NOINLINE
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) && defined(__i386__)
|
||||
/* 32-bit MinGW targets have a bug where __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
* reports 16, despite the default operator new calling standard malloc which
|
||||
* only guarantees 8-byte alignment. As a result, structs that need and specify
|
||||
* 16-byte alignment only get 8-byte alignment. Explicitly specifying 32-byte
|
||||
* alignment forces the over-aligned operator new to be called, giving the
|
||||
* correct (if larger than necessary) alignment.
|
||||
*
|
||||
* Technically this bug affects 32-bit GCC more generally, but typically only
|
||||
* with fairly old glibc versions as newer versions do guarantee the 16-byte
|
||||
* alignment as specified. MinGW is reliant on msvcrt.dll's malloc however,
|
||||
* which can't be updated to give that guarantee.
|
||||
*/
|
||||
#define SIMDALIGN alignas(32)
|
||||
#else
|
||||
#define SIMDALIGN
|
||||
#endif
|
||||
|
||||
/* Unlike the likely attribute, ASSUME requires the condition to be true or
|
||||
* else it invokes undefined behavior. It's essentially an assert without
|
||||
* actually checking the condition at run-time, allowing for stronger
|
||||
|
|
@ -56,6 +74,12 @@
|
|||
#define UNLIKELY
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && HAS_ATTRIBUTE(gnu::visibility)
|
||||
#define DECL_HIDDEN [[gnu::visibility("hidden")]]
|
||||
#else
|
||||
#define DECL_HIDDEN
|
||||
#endif
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T>
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@
|
|||
#include "alnumbers.h"
|
||||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
|
|
@ -98,7 +100,8 @@ namespace {
|
|||
/*
|
||||
* Altivec support macros
|
||||
*/
|
||||
#if defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__) || defined(__powerpc64__)
|
||||
#if (defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__) || defined(__powerpc64__)) \
|
||||
&& (defined(__VEC__) || defined(__ALTIVEC__))
|
||||
#include <altivec.h>
|
||||
using v4sf = vector float;
|
||||
constexpr uint SimdSize{4};
|
||||
|
|
@ -127,7 +130,6 @@ force_inline void uninterleave2(v4sf in1, v4sf in2, v4sf &out1, v4sf &out2) noex
|
|||
{
|
||||
out1 = vec_perm(in1, in2, (vector unsigned char){0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27});
|
||||
out2 = vec_perm(in1, in2, (vector unsigned char){4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31});
|
||||
out1 = tmp;
|
||||
}
|
||||
|
||||
force_inline void vtranspose4(v4sf &x0, v4sf &x1, v4sf &x2, v4sf &x3) noexcept
|
||||
|
|
@ -324,7 +326,7 @@ force_inline constexpr v4sf ld_ps1(float a) noexcept { return a; }
|
|||
|
||||
#else
|
||||
|
||||
[[maybe_unused]] inline
|
||||
[[maybe_unused, nodiscard]] inline
|
||||
auto valigned(const float *ptr) noexcept -> bool
|
||||
{
|
||||
static constexpr uintptr_t alignmask{SimdSize*sizeof(float) - 1};
|
||||
|
|
@ -358,61 +360,59 @@ constexpr auto make_float_array(std::integer_sequence<T,N...>)
|
|||
{ return std::array{static_cast<float>(N)...}; }
|
||||
|
||||
/* detect bugs with the vector support macros */
|
||||
[[maybe_unused]] void validate_pffft_simd()
|
||||
[[maybe_unused]] auto validate_pffft_simd() -> bool
|
||||
{
|
||||
using float4 = std::array<float,4>;
|
||||
static constexpr auto f = make_float_array(std::make_index_sequence<16>{});
|
||||
|
||||
v4sf a0_v{vset4(f[ 0], f[ 1], f[ 2], f[ 3])};
|
||||
v4sf a1_v{vset4(f[ 4], f[ 5], f[ 6], f[ 7])};
|
||||
v4sf a2_v{vset4(f[ 8], f[ 9], f[10], f[11])};
|
||||
v4sf a3_v{vset4(f[12], f[13], f[14], f[15])};
|
||||
v4sf u_v{};
|
||||
auto a0_v = vset4(f[ 0], f[ 1], f[ 2], f[ 3]);
|
||||
auto a1_v = vset4(f[ 4], f[ 5], f[ 6], f[ 7]);
|
||||
auto a2_v = vset4(f[ 8], f[ 9], f[10], f[11]);
|
||||
auto a3_v = vset4(f[12], f[13], f[14], f[15]);
|
||||
|
||||
auto t_v = vzero();
|
||||
auto t_f = al::bit_cast<float4>(t_v);
|
||||
printf("VZERO=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]);
|
||||
fmt::println("VZERO={}", t_f);
|
||||
assertv4(t_f, 0, 0, 0, 0);
|
||||
|
||||
t_v = vadd(a1_v, a2_v);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
printf("VADD(4:7,8:11)=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]);
|
||||
fmt::println("VADD(4:7,8:11)={}", t_f);
|
||||
assertv4(t_f, 12, 14, 16, 18);
|
||||
|
||||
t_v = vmul(a1_v, a2_v);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
printf("VMUL(4:7,8:11)=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]);
|
||||
fmt::println("VMUL(4:7,8:11)={}", t_f);
|
||||
assertv4(t_f, 32, 45, 60, 77);
|
||||
|
||||
t_v = vmadd(a1_v, a2_v, a0_v);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
printf("VMADD(4:7,8:11,0:3)=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]);
|
||||
fmt::println("VMADD(4:7,8:11,0:3)={}", t_f);
|
||||
assertv4(t_f, 32, 46, 62, 80);
|
||||
|
||||
auto u_v = v4sf{};
|
||||
interleave2(a1_v, a2_v, t_v, u_v);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
auto u_f = al::bit_cast<float4>(u_v);
|
||||
printf("INTERLEAVE2(4:7,8:11)=[%2g %2g %2g %2g] [%2g %2g %2g %2g]\n",
|
||||
t_f[0], t_f[1], t_f[2], t_f[3], u_f[0], u_f[1], u_f[2], u_f[3]);
|
||||
fmt::println("INTERLEAVE2(4:7,8:11)={} {}", t_f, u_f);
|
||||
assertv4(t_f, 4, 8, 5, 9);
|
||||
assertv4(u_f, 6, 10, 7, 11);
|
||||
|
||||
uninterleave2(a1_v, a2_v, t_v, u_v);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
u_f = al::bit_cast<float4>(u_v);
|
||||
printf("UNINTERLEAVE2(4:7,8:11)=[%2g %2g %2g %2g] [%2g %2g %2g %2g]\n",
|
||||
t_f[0], t_f[1], t_f[2], t_f[3], u_f[0], u_f[1], u_f[2], u_f[3]);
|
||||
fmt::println("UNINTERLEAVE2(4:7,8:11)={} {}", t_f, u_f);
|
||||
assertv4(t_f, 4, 6, 8, 10);
|
||||
assertv4(u_f, 5, 7, 9, 11);
|
||||
|
||||
t_v = ld_ps1(f[15]);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
printf("LD_PS1(15)=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]);
|
||||
fmt::println("LD_PS1(15)={}", t_f);
|
||||
assertv4(t_f, 15, 15, 15, 15);
|
||||
|
||||
t_v = vswaphl(a1_v, a2_v);
|
||||
t_f = al::bit_cast<float4>(t_v);
|
||||
printf("VSWAPHL(4:7,8:11)=[%2g %2g %2g %2g]\n", t_f[0], t_f[1], t_f[2], t_f[3]);
|
||||
fmt::println("VSWAPHL(4:7,8:11)={}", t_f);
|
||||
assertv4(t_f, 8, 9, 6, 7);
|
||||
|
||||
vtranspose4(a0_v, a1_v, a2_v, a3_v);
|
||||
|
|
@ -420,13 +420,13 @@ constexpr auto make_float_array(std::integer_sequence<T,N...>)
|
|||
auto a1_f = al::bit_cast<float4>(a1_v);
|
||||
auto a2_f = al::bit_cast<float4>(a2_v);
|
||||
auto a3_f = al::bit_cast<float4>(a3_v);
|
||||
printf("VTRANSPOSE4(0:3,4:7,8:11,12:15)=[%2g %2g %2g %2g] [%2g %2g %2g %2g] [%2g %2g %2g %2g] [%2g %2g %2g %2g]\n",
|
||||
a0_f[0], a0_f[1], a0_f[2], a0_f[3], a1_f[0], a1_f[1], a1_f[2], a1_f[3],
|
||||
a2_f[0], a2_f[1], a2_f[2], a2_f[3], a3_f[0], a3_f[1], a3_f[2], a3_f[3]);
|
||||
fmt::println("VTRANSPOSE4(0:3,4:7,8:11,12:15)={} {} {} {}", a0_f, a1_f, a2_f, a3_f);
|
||||
assertv4(a0_f, 0, 4, 8, 12);
|
||||
assertv4(a1_f, 1, 5, 9, 13);
|
||||
assertv4(a2_f, 2, 6, 10, 14);
|
||||
assertv4(a3_f, 3, 7, 11, 15);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif //!PFFFT_SIMD_DISABLE
|
||||
|
||||
|
|
@ -1059,7 +1059,7 @@ void radf5_ps(const size_t ido, const size_t l1, const v4sf *RESTRICT cc, v4sf *
|
|||
ch_ref(1, 3, k) = vmadd(ti11, ci5, vmul(ti12, ci4));
|
||||
ch_ref(ido, 4, k) = vadd(cc_ref(1, k, 1), vmadd(tr12, cr2, vmul(tr11, cr3)));
|
||||
ch_ref(1, 5, k) = vsub(vmul(ti12, ci5), vmul(ti11, ci4));
|
||||
//printf("pffft: radf5, k=%d ch_ref=%f, ci4=%f\n", k, ch_ref(1, 5, k), ci4);
|
||||
//fmt::println("pffft: radf5, k={} ch_ref={:f}, ci4={:f}", k, ch_ref(1, 5, k), ci4);
|
||||
}
|
||||
if(ido == 1)
|
||||
return;
|
||||
|
|
@ -1534,10 +1534,10 @@ PFFFTSetupPtr pffft_new_setup(unsigned int N, pffft_transform_t transform)
|
|||
}
|
||||
|
||||
|
||||
void pffft_destroy_setup(gsl::owner<PFFFT_Setup*> s) noexcept
|
||||
void PFFFTSetupDeleter::operator()(gsl::owner<PFFFT_Setup*> setup) const noexcept
|
||||
{
|
||||
std::destroy_at(s);
|
||||
::operator delete[](gsl::owner<void*>{s}, V4sfAlignVal);
|
||||
std::destroy_at(setup);
|
||||
::operator delete[](gsl::owner<void*>{setup}, V4sfAlignVal);
|
||||
}
|
||||
|
||||
#if !defined(PFFFT_SIMD_DISABLE)
|
||||
|
|
|
|||
|
|
@ -96,9 +96,8 @@ enum pffft_direction_t { PFFFT_FORWARD, PFFFT_BACKWARD };
|
|||
/* type of transform */
|
||||
enum pffft_transform_t { PFFFT_REAL, PFFFT_COMPLEX };
|
||||
|
||||
void pffft_destroy_setup(gsl::owner<PFFFT_Setup*> setup) noexcept;
|
||||
struct PFFFTSetupDeleter {
|
||||
void operator()(gsl::owner<PFFFT_Setup*> setup) const noexcept { pffft_destroy_setup(setup); }
|
||||
void operator()(gsl::owner<PFFFT_Setup*> setup) const noexcept;
|
||||
};
|
||||
using PFFFTSetupPtr = std::unique_ptr<PFFFT_Setup,PFFFTSetupDeleter>;
|
||||
|
||||
|
|
@ -175,7 +174,7 @@ void pffft_zconvolve_accumulate(const PFFFT_Setup *setup, const float *dft_a, co
|
|||
|
||||
|
||||
struct PFFFTSetup {
|
||||
PFFFTSetupPtr mSetup{};
|
||||
PFFFTSetupPtr mSetup;
|
||||
|
||||
PFFFTSetup() = default;
|
||||
PFFFTSetup(const PFFFTSetup&) = delete;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef PHASE_SHIFTER_H
|
||||
#define PHASE_SHIFTER_H
|
||||
|
||||
#ifdef HAVE_SSE_INTRINSICS
|
||||
#include "config_simd.h"
|
||||
|
||||
#if HAVE_SSE_INTRINSICS
|
||||
#include <xmmintrin.h>
|
||||
#elif defined(HAVE_NEON)
|
||||
#elif HAVE_NEON
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -21,7 +23,7 @@
|
|||
* signal delay (FilterSize/2) to properly align.
|
||||
*/
|
||||
template<std::size_t FilterSize>
|
||||
struct PhaseShifterT {
|
||||
struct SIMDALIGN PhaseShifterT {
|
||||
static_assert(FilterSize >= 16, "FilterSize needs to be at least 16");
|
||||
static_assert((FilterSize&(FilterSize-1)) == 0, "FilterSize needs to be power-of-two");
|
||||
|
||||
|
|
@ -36,15 +38,14 @@ struct PhaseShifterT {
|
|||
*/
|
||||
for(std::size_t i{0};i < FilterSize/2;++i)
|
||||
{
|
||||
const int k{static_cast<int>(i*2 + 1) - int{FilterSize/2}};
|
||||
const auto k = static_cast<int>(i*2 + 1) - int{FilterSize/2};
|
||||
|
||||
/* Calculate the Blackman window value for this coefficient. */
|
||||
const double w{2.0*al::numbers::pi * static_cast<double>(i*2 + 1)
|
||||
/ double{FilterSize}};
|
||||
const double window{0.3635819 - 0.4891775*std::cos(w) + 0.1365995*std::cos(2.0*w)
|
||||
- 0.0106411*std::cos(3.0*w)};
|
||||
const auto w = 2.0*al::numbers::pi/double{FilterSize} * static_cast<double>(i*2 + 1);
|
||||
const auto window = 0.3635819 - 0.4891775*std::cos(w) + 0.1365995*std::cos(2.0*w)
|
||||
- 0.0106411*std::cos(3.0*w);
|
||||
|
||||
const double pk{al::numbers::pi * static_cast<double>(k)};
|
||||
const auto pk = al::numbers::pi * static_cast<double>(k);
|
||||
mCoeffs[i] = static_cast<float>(window * (1.0-std::cos(pk)) / pk);
|
||||
}
|
||||
}
|
||||
|
|
@ -52,17 +53,7 @@ struct PhaseShifterT {
|
|||
void process(const al::span<float> dst, const al::span<const float> src) const;
|
||||
|
||||
private:
|
||||
#if defined(HAVE_NEON)
|
||||
static auto unpacklo(float32x4_t a, float32x4_t b)
|
||||
{
|
||||
float32x2x2_t result{vzip_f32(vget_low_f32(a), vget_low_f32(b))};
|
||||
return vcombine_f32(result.val[0], result.val[1]);
|
||||
}
|
||||
static auto unpackhi(float32x4_t a, float32x4_t b)
|
||||
{
|
||||
float32x2x2_t result{vzip_f32(vget_high_f32(a), vget_high_f32(b))};
|
||||
return vcombine_f32(result.val[0], result.val[1]);
|
||||
}
|
||||
#if HAVE_NEON
|
||||
static auto load4(float32_t a, float32_t b, float32_t c, float32_t d)
|
||||
{
|
||||
float32x4_t ret{vmovq_n_f32(a)};
|
||||
|
|
@ -90,7 +81,7 @@ NOINLINE inline
|
|||
void PhaseShifterT<S>::process(const al::span<float> dst, const al::span<const float> src) const
|
||||
{
|
||||
auto in = src.begin();
|
||||
#ifdef HAVE_SSE_INTRINSICS
|
||||
#if HAVE_SSE_INTRINSICS
|
||||
if(const std::size_t todo{dst.size()>>2})
|
||||
{
|
||||
auto out = al::span{reinterpret_cast<__m128*>(dst.data()), todo};
|
||||
|
|
@ -146,7 +137,7 @@ void PhaseShifterT<S>::process(const al::span<float> dst, const al::span<const f
|
|||
});
|
||||
}
|
||||
|
||||
#elif defined(HAVE_NEON)
|
||||
#elif HAVE_NEON
|
||||
|
||||
if(const std::size_t todo{dst.size()>>2})
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,10 +17,6 @@ namespace {
|
|||
|
||||
constexpr double Epsilon{1e-9};
|
||||
|
||||
#if __cpp_lib_math_special_functions >= 201603L
|
||||
using std::cyl_bessel_i;
|
||||
|
||||
#else
|
||||
|
||||
/* The zero-order modified Bessel function of the first kind, used for the
|
||||
* Kaiser window.
|
||||
|
|
@ -33,7 +29,7 @@ using std::cyl_bessel_i;
|
|||
* compounding the rounding and precision error), but it's good enough.
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
U cyl_bessel_i(T nu, U x)
|
||||
constexpr auto cyl_bessel_i(T nu, U x) -> U
|
||||
{
|
||||
if(nu != T{0})
|
||||
throw std::runtime_error{"cyl_bessel_i: nu != 0"};
|
||||
|
|
@ -57,7 +53,6 @@ U cyl_bessel_i(T nu, U x)
|
|||
} while(sum != last_sum);
|
||||
return static_cast<U>(sum);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is the normalized cardinal sine (sinc) function.
|
||||
*
|
||||
|
|
@ -89,7 +84,7 @@ double Kaiser(const double beta, const double k, const double besseli_0_beta)
|
|||
{
|
||||
if(!(k >= -1.0 && k <= 1.0))
|
||||
return 0.0;
|
||||
return cyl_bessel_i(0, beta * std::sqrt(1.0 - k*k)) / besseli_0_beta;
|
||||
return ::cyl_bessel_i(0, beta * std::sqrt(1.0 - k*k)) / besseli_0_beta;
|
||||
}
|
||||
|
||||
/* Calculates the size (order) of the Kaiser window. Rejection is in dB and
|
||||
|
|
@ -130,10 +125,10 @@ constexpr double CalcKaiserBeta(const double rejection)
|
|||
* p -- gain compensation factor when sampling
|
||||
* f_t -- normalized center frequency (or cutoff; 0.5 is nyquist)
|
||||
*/
|
||||
double SincFilter(const uint l, const double beta, const double besseli_0_beta, const double gain,
|
||||
const double cutoff, const uint i)
|
||||
auto SincFilter(const uint l, const double beta, const double besseli_0_beta, const double gain,
|
||||
const double cutoff, const uint i) -> double
|
||||
{
|
||||
const double x{static_cast<double>(i) - l};
|
||||
const auto x = static_cast<double>(i) - l;
|
||||
return Kaiser(beta, x/l, besseli_0_beta) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * x);
|
||||
}
|
||||
|
||||
|
|
@ -143,77 +138,83 @@ double SincFilter(const uint l, const double beta, const double besseli_0_beta,
|
|||
// that's used to cut frequencies above the destination nyquist.
|
||||
void PPhaseResampler::init(const uint srcRate, const uint dstRate)
|
||||
{
|
||||
const uint gcd{std::gcd(srcRate, dstRate)};
|
||||
const auto gcd = std::gcd(srcRate, dstRate);
|
||||
mP = dstRate / gcd;
|
||||
mQ = srcRate / gcd;
|
||||
|
||||
/* The cutoff is adjusted by half the transition width, so the transition
|
||||
* ends before the nyquist (0.5). Both are scaled by the downsampling
|
||||
* factor.
|
||||
/* The cutoff is adjusted by the transition width, so the transition ends
|
||||
* at nyquist (0.5). Both are scaled by the downsampling factor.
|
||||
*/
|
||||
const auto [cutoff, width] = (mP > mQ) ? std::make_tuple(0.475 / mP, 0.05 / mP)
|
||||
: std::make_tuple(0.475 / mQ, 0.05 / mQ);
|
||||
const auto [cutoff, width] = (mP > mQ) ? std::make_tuple(0.47 / mP, 0.03 / mP)
|
||||
: std::make_tuple(0.47 / mQ, 0.03 / mQ);
|
||||
|
||||
// A rejection of -180 dB is used for the stop band. Round up when
|
||||
// calculating the left offset to avoid increasing the transition width.
|
||||
const uint l{(CalcKaiserOrder(180.0, width)+1) / 2};
|
||||
const double beta{CalcKaiserBeta(180.0)};
|
||||
const double besseli_0_beta{cyl_bessel_i(0, beta)};
|
||||
mM = l*2 + 1;
|
||||
static constexpr auto rejection = 180.0;
|
||||
const auto l = (CalcKaiserOrder(rejection, width)+1u) / 2u;
|
||||
const auto beta = CalcKaiserBeta(rejection);
|
||||
const auto besseli_0_beta = ::cyl_bessel_i(0, beta);
|
||||
mM = l*2u + 1u;
|
||||
mL = l;
|
||||
mF.resize(mM);
|
||||
for(uint i{0};i < mM;i++)
|
||||
mF[i] = SincFilter(l, beta, besseli_0_beta, mP, cutoff, i);
|
||||
mF[i] = SincFilter(mL, beta, besseli_0_beta, mP, cutoff, i);
|
||||
}
|
||||
|
||||
// Perform the upsample-filter-downsample resampling operation using a
|
||||
// polyphase filter implementation.
|
||||
void PPhaseResampler::process(const al::span<const double> in, const al::span<double> out)
|
||||
void PPhaseResampler::process(const al::span<const double> in, const al::span<double> out) const
|
||||
{
|
||||
if(out.empty()) UNLIKELY
|
||||
return;
|
||||
|
||||
// Handle in-place operation.
|
||||
std::vector<double> workspace;
|
||||
al::span work{out};
|
||||
auto workspace = std::vector<double>{};
|
||||
auto work = al::span{out};
|
||||
if(work.data() == in.data()) UNLIKELY
|
||||
{
|
||||
workspace.resize(out.size());
|
||||
work = workspace;
|
||||
}
|
||||
|
||||
// Resample the input.
|
||||
const uint p{mP}, q{mQ}, m{mM}, l{mL};
|
||||
const al::span<const double> f{mF};
|
||||
for(uint i{0};i < out.size();i++)
|
||||
const auto f = al::span<const double>{mF};
|
||||
const auto p = size_t{mP};
|
||||
const auto q = size_t{mQ};
|
||||
const auto m = size_t{mM};
|
||||
/* Input starts at l to compensate for the filter delay. This will drop any
|
||||
* build-up from the first half of the filter.
|
||||
*/
|
||||
auto l = size_t{mL};
|
||||
std::generate(work.begin(), work.end(), [in,f,p,q,m,&l]
|
||||
{
|
||||
// Input starts at l to compensate for the filter delay. This will
|
||||
// drop any build-up from the first half of the filter.
|
||||
std::size_t j_f{(l + q*i) % p};
|
||||
std::size_t j_s{(l + q*i) / p};
|
||||
auto j_s = l / p;
|
||||
auto j_f = l % p;
|
||||
l += q;
|
||||
|
||||
// Only take input when 0 <= j_s < in.size().
|
||||
double r{0.0};
|
||||
if(j_f < m) LIKELY
|
||||
if(j_f >= m) UNLIKELY
|
||||
return 0.0;
|
||||
|
||||
auto filt_len = (m - j_f - 1)/p + 1;
|
||||
if(j_s+1 > in.size()) LIKELY
|
||||
{
|
||||
std::size_t filt_len{(m-j_f+p-1) / p};
|
||||
if(j_s+1 > in.size()) LIKELY
|
||||
{
|
||||
std::size_t skip{std::min(j_s+1 - in.size(), filt_len)};
|
||||
j_f += p*skip;
|
||||
j_s -= skip;
|
||||
filt_len -= skip;
|
||||
}
|
||||
std::size_t todo{std::min(j_s+1, filt_len)};
|
||||
while(todo)
|
||||
{
|
||||
r += f[j_f] * in[j_s];
|
||||
j_f += p; --j_s;
|
||||
--todo;
|
||||
}
|
||||
const auto skip = std::min(j_s+1-in.size(), filt_len);
|
||||
j_f += p*skip;
|
||||
j_s -= skip;
|
||||
filt_len -= skip;
|
||||
}
|
||||
work[i] = r;
|
||||
}
|
||||
/* Get the range of input samples being used for this output sample.
|
||||
* j_s is the first sample and iterates backwards toward 0.
|
||||
*/
|
||||
const auto src = in.first(j_s+1).last(std::min(j_s+1, filt_len));
|
||||
return std::accumulate(src.rbegin(), src.rend(), 0.0, [p,f,&j_f](const double cur,
|
||||
const double smp) -> double
|
||||
{
|
||||
const auto ret = cur + f[j_f]*smp;
|
||||
j_f += p;
|
||||
return ret;
|
||||
});
|
||||
});
|
||||
// Clean up after in-place operation.
|
||||
if(work.data() != out.data())
|
||||
std::copy(work.cbegin(), work.cend(), out.begin());
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ using uint = unsigned int;
|
|||
|
||||
struct PPhaseResampler {
|
||||
void init(const uint srcRate, const uint dstRate);
|
||||
void process(const al::span<const double> in, const al::span<double> out);
|
||||
void process(const al::span<const double> in, const al::span<double> out) const;
|
||||
|
||||
explicit operator bool() const noexcept { return !mF.empty(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@
|
|||
#include "ringbuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
|
||||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
|
||||
|
||||
auto RingBuffer::Create(std::size_t sz, std::size_t elem_sz, bool limit_writes) -> RingBufferPtr
|
||||
|
|
@ -76,8 +77,8 @@ auto RingBuffer::read(void *dest, std::size_t count) noexcept -> std::size_t
|
|||
const std::size_t read_idx{r & mSizeMask};
|
||||
|
||||
const std::size_t rdend{read_idx + to_read};
|
||||
const auto [n1, n2] = (rdend <= mSizeMask+1) ? std::make_tuple(to_read, 0_uz)
|
||||
: std::make_tuple(mSizeMask+1 - read_idx, rdend&mSizeMask);
|
||||
const auto [n1, n2] = (rdend <= mSizeMask+1) ? std::array{to_read, 0_uz}
|
||||
: std::array{mSizeMask+1 - read_idx, rdend&mSizeMask};
|
||||
|
||||
auto dstbytes = al::span{static_cast<std::byte*>(dest), count*mElemSize};
|
||||
auto outiter = std::copy_n(mBuffer.begin() + ptrdiff_t(read_idx*mElemSize), n1*mElemSize,
|
||||
|
|
@ -99,8 +100,8 @@ auto RingBuffer::peek(void *dest, std::size_t count) const noexcept -> std::size
|
|||
const std::size_t read_idx{r & mSizeMask};
|
||||
|
||||
const std::size_t rdend{read_idx + to_read};
|
||||
const auto [n1, n2] = (rdend <= mSizeMask+1) ? std::make_tuple(to_read, 0_uz)
|
||||
: std::make_tuple(mSizeMask+1 - read_idx, rdend&mSizeMask);
|
||||
const auto [n1, n2] = (rdend <= mSizeMask+1) ? std::array{to_read, 0_uz}
|
||||
: std::array{mSizeMask+1 - read_idx, rdend&mSizeMask};
|
||||
|
||||
auto dstbytes = al::span{static_cast<std::byte*>(dest), count*mElemSize};
|
||||
auto outiter = std::copy_n(mBuffer.begin() + ptrdiff_t(read_idx*mElemSize), n1*mElemSize,
|
||||
|
|
@ -121,8 +122,8 @@ auto RingBuffer::write(const void *src, std::size_t count) noexcept -> std::size
|
|||
const std::size_t write_idx{w & mSizeMask};
|
||||
|
||||
const std::size_t wrend{write_idx + to_write};
|
||||
const auto [n1, n2] = (wrend <= mSizeMask+1) ? std::make_tuple(to_write, 0_uz)
|
||||
: std::make_tuple(mSizeMask+1 - write_idx, wrend&mSizeMask);
|
||||
const auto [n1, n2] = (wrend <= mSizeMask+1) ? std::array{to_write, 0_uz}
|
||||
: std::array{mSizeMask+1 - write_idx, wrend&mSizeMask};
|
||||
|
||||
auto srcbytes = al::span{static_cast<const std::byte*>(src), count*mElemSize};
|
||||
std::copy_n(srcbytes.cbegin(), n1*mElemSize, mBuffer.begin() + ptrdiff_t(write_idx*mElemSize));
|
||||
|
|
@ -146,10 +147,10 @@ auto RingBuffer::getReadVector() noexcept -> DataPair
|
|||
/* Two part vector: the rest of the buffer after the current read ptr,
|
||||
* plus some from the start of the buffer.
|
||||
*/
|
||||
return DataPair{{mBuffer.data() + read_idx*mElemSize, mSizeMask+1 - read_idx},
|
||||
{mBuffer.data(), rdend&mSizeMask}};
|
||||
return DataPair{{{mBuffer.data() + read_idx*mElemSize, mSizeMask+1 - read_idx},
|
||||
{mBuffer.data(), rdend&mSizeMask}}};
|
||||
}
|
||||
return DataPair{{mBuffer.data() + read_idx*mElemSize, readable}, {}};
|
||||
return DataPair{{{mBuffer.data() + read_idx*mElemSize, readable}, {}}};
|
||||
}
|
||||
|
||||
auto RingBuffer::getWriteVector() noexcept -> DataPair
|
||||
|
|
@ -165,8 +166,8 @@ auto RingBuffer::getWriteVector() noexcept -> DataPair
|
|||
/* Two part vector: the rest of the buffer after the current write ptr,
|
||||
* plus some from the start of the buffer.
|
||||
*/
|
||||
return DataPair{{mBuffer.data() + write_idx*mElemSize, mSizeMask+1 - write_idx},
|
||||
{mBuffer.data(), wrend&mSizeMask}};
|
||||
return DataPair{{{mBuffer.data() + write_idx*mElemSize, mSizeMask+1 - write_idx},
|
||||
{mBuffer.data(), wrend&mSizeMask}}};
|
||||
}
|
||||
return DataPair{{mBuffer.data() + write_idx*mElemSize, writable}, {}};
|
||||
return DataPair{{{mBuffer.data() + write_idx*mElemSize, writable}, {}}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
|
@ -40,7 +39,7 @@ public:
|
|||
std::byte *buf;
|
||||
std::size_t len;
|
||||
};
|
||||
using DataPair = std::pair<Data,Data>;
|
||||
using DataPair = std::array<Data,2>;
|
||||
|
||||
RingBuffer(const std::size_t writesize, const std::size_t mask, const std::size_t elemsize,
|
||||
const std::size_t numbytes)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "alstring.h"
|
||||
|
||||
/* NOLINTBEGIN(bugprone-suspicious-stringview-data-usage) */
|
||||
std::string wstr_to_utf8(std::wstring_view wstr)
|
||||
{
|
||||
std::string ret;
|
||||
|
|
@ -40,6 +41,7 @@ std::wstring utf8_to_wstr(std::string_view str)
|
|||
|
||||
return ret;
|
||||
}
|
||||
/* NOLINTEND(bugprone-suspicious-stringview-data-usage) */
|
||||
#endif
|
||||
|
||||
namespace al {
|
||||
|
|
|
|||
|
|
@ -45,13 +45,12 @@ public:
|
|||
mVals[2] - rhs.mVals[2], mVals[3] - rhs.mVals[3]};
|
||||
}
|
||||
|
||||
constexpr auto normalize(float limit = std::numeric_limits<float>::epsilon()) -> float
|
||||
constexpr auto normalize() -> float
|
||||
{
|
||||
limit = std::max(limit, std::numeric_limits<float>::epsilon());
|
||||
const auto length_sqr = float{mVals[0]*mVals[0] + mVals[1]*mVals[1] + mVals[2]*mVals[2]};
|
||||
if(length_sqr > limit*limit)
|
||||
if(length_sqr > std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
const auto length = float{std::sqrt(length_sqr)};
|
||||
const auto length = std::sqrt(length_sqr);
|
||||
auto inv_length = float{1.0f / length};
|
||||
mVals[0] *= inv_length;
|
||||
mVals[1] *= inv_length;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue