update openal-soft to 1.24.3

keeping the alt 87514151c4 (diff-73a8dc1ce58605f6c5ea53548454c3bae516ec5132a29c9d7ff7edf9730c75be)
This commit is contained in:
AzaezelX 2025-09-03 11:09:27 -05:00
parent 12db0500e8
commit ba32094b7b
276 changed files with 49304 additions and 8712 deletions

View file

@ -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 */

View file

@ -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__,

View file

@ -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)

View file

@ -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

View file

@ -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);
}

View file

@ -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();

View file

@ -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&>())>>;

View file

@ -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

View file

@ -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

View file

@ -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{};

View file

@ -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

View file

@ -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 */

View 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

View 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

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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(); }

View file

@ -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>

View file

@ -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)

View file

@ -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;

View file

@ -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})
{

View file

@ -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());

View file

@ -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(); }

View file

@ -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}, {}}};
}

View file

@ -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)

View file

@ -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 {

View file

@ -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;