kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

commit 0d5f6b08a8a2655a5071337a90335f37474a649c
parent d3391550a2a5b64ef163c98fad37636030d310d9
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date:   Thu, 27 Dec 2018 01:31:01 +0000

Partial compatibility for Visual Studio 2017

Diffstat:
MCMakeLists.txt | 7+++++--
Mexamples/CMakeLists.txt | 13++++++++++---
Mexamples/fir.cpp | 4++++
Minclude/kfr/base/memory.hpp | 1+
Minclude/kfr/base/pointer.hpp | 2+-
Minclude/kfr/base/simd_clang.hpp | 4++++
Minclude/kfr/base/univector.hpp | 4++++
Minclude/kfr/base/vec.hpp | 4++--
Minclude/kfr/cometa.hpp | 22++++++++++++++++------
Minclude/kfr/cometa/array.hpp | 4++--
Minclude/kfr/data/sincos.hpp | 6+-----
Minclude/kfr/dft/impl/dft-impl.hpp | 32++++++++++++++++++--------------
Minclude/kfr/dft/impl/dft-templates.hpp | 3+++
Minclude/kfr/dft/impl/ft.hpp | 6+++---
Minclude/kfr/ext/double_double.hpp | 15+++++++++++----
Minclude/kfr/io/audiofile.hpp | 3+++
Mtests/CMakeLists.txt | 20+++++++++++++++-----
17 files changed, 103 insertions(+), 47 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -40,6 +40,7 @@ include(sources.cmake) add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE) option(ENABLE_TESTS "Enable tests and examples. This changes many compiler flags" OFF) +option(ENABLE_DFT "Enable DFT and related algorithms" ON) set(KFR_DFT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/include/kfr/dft/impl/dft-src.cpp @@ -99,8 +100,10 @@ add_library(kfr INTERFACE) target_sources(kfr INTERFACE ${KFR_SRC}) target_include_directories(kfr INTERFACE include) -add_library(kfr_dft ${KFR_DFT_SRC}) -target_link_libraries(kfr_dft kfr) +if (ENABLE_DFT) + add_library(kfr_dft ${KFR_DFT_SRC}) + target_link_libraries(kfr_dft kfr) +endif() add_library(kfr_io ${KFR_IO_SRC}) target_link_libraries(kfr_io kfr) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt @@ -28,7 +28,12 @@ add_executable(window window.cpp) target_link_libraries(window kfr) add_executable(fir fir.cpp) -target_link_libraries(fir kfr kfr_dft) + +target_link_libraries(fir kfr) +if (ENABLE_DFT) + target_link_libraries(fir kfr_dft) + target_compile_definitions(fir PRIVATE -DHAVE_DFT) +endif () add_executable(sample_rate_conversion sample_rate_conversion.cpp) target_link_libraries(sample_rate_conversion kfr kfr_io) @@ -36,5 +41,7 @@ target_link_libraries(sample_rate_conversion kfr kfr_io) add_executable(sample_rate_converter sample_rate_converter.cpp) target_link_libraries(sample_rate_converter kfr kfr_io) -add_executable(dft dft.cpp) -target_link_libraries(dft kfr kfr_dft) +if (ENABLE_DFT) + add_executable(dft dft.cpp) + target_link_libraries(dft kfr kfr_dft) +endif () diff --git a/examples/fir.cpp b/examples/fir.cpp @@ -5,7 +5,9 @@ */ #include <kfr/base.hpp> +#ifdef HAVE_DFT #include <kfr/dft.hpp> +#endif #include <kfr/dsp.hpp> #include <kfr/io.hpp> @@ -128,6 +130,7 @@ int main() plot_save("filtered_noise2", filtered_noise2, "title='Filtered noise 2', div_by_N=True"); #endif +#ifdef HAVE_DFT // -------------------------------------------------------------------------------------- // ---------------------- Convolution filter (optimized using DFT) ---------------------- // -------------------------------------------------------------------------------------- @@ -143,6 +146,7 @@ int main() // Plot results, same as filtered_noise2 plot_save("filtered_noise3", filtered_noise3, "title='Filtered noise 3', div_by_N=True"); #endif +#endif return 0; } diff --git a/include/kfr/base/memory.hpp b/include/kfr/base/memory.hpp @@ -27,6 +27,7 @@ #include "read_write.hpp" #include "types.hpp" +#include <algorithm> #include <atomic> #include <memory> diff --git a/include/kfr/base/pointer.hpp b/include/kfr/base/pointer.hpp @@ -42,7 +42,7 @@ namespace internal template <typename Expression, typename T, size_t key = 0> KFR_SINTRIN bool invoke_substitute(Expression& expr, expression_pointer<T>&& new_pointer, - csize_t<key> = csize_t<key>{}); + csize_t<key> = {}); } template <typename T, size_t N = maximum_expression_width> diff --git a/include/kfr/base/simd_clang.hpp b/include/kfr/base/simd_clang.hpp @@ -29,6 +29,8 @@ #include "platform.hpp" #include "types.hpp" +#if CMT_COMPILER_CLANG + CMT_PRAGMA_MSVC(warning(push)) CMT_PRAGMA_MSVC(warning(disable : 4324)) @@ -344,3 +346,5 @@ constexpr inline vec<T, csum<size_t, Ns...>()> concat(const vec<T, Ns>&... vs) n } // namespace kfr CMT_PRAGMA_MSVC(warning(pop)) + +#endif diff --git a/include/kfr/base/univector.hpp b/include/kfr/base/univector.hpp @@ -374,6 +374,10 @@ struct univector<T, tag_dynamic_vector> : std::vector<T, allocator<T>>, : std::vector<T, allocator<T>>(other.begin(), other.end()) { } + template <typename Allocator> + constexpr univector(const std::vector<T, Allocator>&) = delete; + template <typename Allocator> + constexpr univector(std::vector<T, Allocator>&&) = delete; constexpr static bool size_known = false; constexpr static bool is_array = false; constexpr static bool is_array_ref = false; diff --git a/include/kfr/base/vec.hpp b/include/kfr/base/vec.hpp @@ -128,14 +128,14 @@ constexpr inline size_t scale_get_index(size_t counter, size_t groupsize, size_t } template <size_t counter, size_t groupsize, size_t... indices> -constexpr inline size_t scale_get_index() +constexpr inline size_t scale_get_index(csizes_t<indices...>) { return scale_get_index(counter, groupsize, csizes_t<indices...>().get(csize_t<counter / groupsize>())); } template <size_t... indices, size_t... counter, size_t groupsize = sizeof...(counter) / sizeof...(indices)> constexpr inline auto scale_impl(csizes_t<indices...> ind, csizes_t<counter...> cnt) noexcept - -> csizes_t<scale_get_index<counter, groupsize, indices...>()...> + -> csizes_t<scale_get_index<counter, groupsize>(ind)...> { return {}; } diff --git a/include/kfr/cometa.hpp b/include/kfr/cometa.hpp @@ -253,14 +253,15 @@ namespace ops { struct empty { + constexpr empty() noexcept {} }; } // namespace ops template <typename T, T val> struct cval_t : ops::empty { - constexpr static T value = val; - constexpr cval_t() noexcept = default; + constexpr static T value = val; + constexpr cval_t() noexcept {} constexpr cval_t(const cval_t&) noexcept = default; constexpr cval_t(cval_t&&) noexcept = default; typedef T value_type; @@ -359,6 +360,9 @@ struct get_nth<0, T, first, rest...> constexpr static T value = first; }; +template <size_t index, typename T> +struct get_nth_e; + template <size_t index, typename... Types> struct get_nth_type; @@ -406,7 +410,7 @@ struct cvals_t : ops::empty return &arr[0]; } template <size_t... indices> - constexpr cvals_t<T, details::get_nth<indices, T, values...>::value...> operator[]( + constexpr cvals_t<T, details::get_nth_e<indices, type>::value...> operator[]( cvals_t<size_t, indices...>) const { return {}; @@ -427,6 +431,15 @@ struct cvals_t<T> : ops::empty constexpr static size_t size() { return 0; } }; +namespace details +{ +template <size_t index, typename T, T... vals> +struct get_nth_e<index, cvals_t<T, vals...>> +{ + constexpr static T value = get_nth<index, T, vals...>::value; +}; +} // namespace details + template <bool... values> using cbools_t = cvals_t<bool, values...>; @@ -1658,8 +1671,6 @@ constexpr bool is_sequence(csizes_t<number, numbers...>) return details::test_sequence<number, 1 + sizeof...(numbers)>(csizes_t<number, numbers...>()).value; } -#ifdef CMT_COMPILER_GNU - template <typename T, T val> constexpr cval_t<T, val> cval{}; @@ -1727,7 +1738,6 @@ template <size_t size, unsigned start = 0, ptrdiff_t step = 1> constexpr cvalseq_t<unsigned, size, start, step> cuintseq{}; template <typename... List> constexpr indicesfor_t<List...> indicesfor{}; -#endif // Workaround for GCC 4.8 template <typename T> diff --git a/include/kfr/cometa/array.hpp b/include/kfr/cometa/array.hpp @@ -51,8 +51,8 @@ public: constexpr array_ref(std::array<T, N>& arr) noexcept : m_data(arr.data()), m_size(N) { } - template <typename... Ts> - constexpr array_ref(const std::vector<T, Ts...>& vec) noexcept : m_data(vec.data()), m_size(vec.size()) + template <typename Alloc> + constexpr array_ref(const std::vector<T, Alloc>& vec) noexcept : m_data(vec.data()), m_size(vec.size()) { } diff --git a/include/kfr/data/sincos.hpp b/include/kfr/data/sincos.hpp @@ -33,11 +33,7 @@ namespace data { template <typename T> -constexpr T c_sin_table[65]; - -// data generated by mpfr -template <> -constexpr f32 c_sin_table<f32>[65] = { +constexpr T c_sin_table[65] = { /* sin(2*pi* 0/ 256) */ f32(0.0), /* sin(2*pi* 1/ 256) */ f32(0.02454122852291228803173452945928292506547), /* sin(2*pi* 2/ 256) */ f32(0.04906767432741801425495497694268265831475), diff --git a/include/kfr/dft/impl/dft-impl.hpp b/include/kfr/dft/impl/dft-impl.hpp @@ -504,22 +504,25 @@ static void dft_stage_fixed_initialize(dft_stage<T>* stage, size_t width) } } -template <typename T, size_t radix> +template <typename T, size_t fixed_radix> struct dft_stage_fixed_impl : dft_stage<T> { dft_stage_fixed_impl(size_t radix_, size_t iterations, size_t blocks) { this->name = type_name<decltype(*this)>(); - this->radix = radix; + this->radix = fixed_radix; this->blocks = blocks; this->repeats = iterations; this->recursion = false; // true; - this->data_size = - align_up((this->repeats * (radix - 1)) * sizeof(complex<T>), platform<>::native_cache_alignment); + this->data_size = align_up((this->repeats * (fixed_radix - 1)) * sizeof(complex<T>), + platform<>::native_cache_alignment); } - constexpr static size_t width = - radix >= 7 ? fft_vector_width<T> / 2 : radix >= 4 ? fft_vector_width<T> : fft_vector_width<T> * 2; + constexpr static size_t rradix = fixed_radix; + + constexpr static size_t width = fixed_radix >= 7 + ? fft_vector_width<T> / 2 + : fixed_radix >= 4 ? fft_vector_width<T> : fft_vector_width<T> * 2; virtual void do_initialize(size_t size) override final { dft_stage_fixed_initialize(this, width); } DFT_STAGE_FN @@ -529,40 +532,41 @@ struct dft_stage_fixed_impl : dft_stage<T> const size_t Nord = this->repeats; const complex<T>* twiddle = ptr_cast<complex<T>>(this->data); - const size_t N = Nord * this->radix; + const size_t N = Nord * fixed_radix; CMT_LOOP_NOUNROLL for (size_t b = 0; b < this->blocks; b++) { - butterflies(Nord, csize<width>, csize<radix>, cbool<inverse>, out, in, twiddle, Nord); + butterflies(Nord, csize<width>, csize<fixed_radix>, cbool<inverse>, out, in, twiddle, Nord); in += N; out += N; } } }; -template <typename T, size_t radix> +template <typename T, size_t fixed_radix> struct dft_stage_fixed_final_impl : dft_stage<T> { dft_stage_fixed_final_impl(size_t radix_, size_t iterations, size_t blocks) { this->name = type_name<decltype(*this)>(); - this->radix = radix; + this->radix = fixed_radix; this->blocks = blocks; this->repeats = iterations; this->recursion = false; this->can_inplace = false; } - constexpr static size_t width = - radix >= 7 ? fft_vector_width<T> / 2 : radix >= 4 ? fft_vector_width<T> : fft_vector_width<T> * 2; + constexpr static size_t width = fixed_radix >= 7 + ? fft_vector_width<T> / 2 + : fixed_radix >= 4 ? fft_vector_width<T> : fft_vector_width<T> * 2; DFT_STAGE_FN template <bool inverse> KFR_INTRIN void do_execute(complex<T>* out, const complex<T>* in, u8*) { const size_t b = this->blocks; - const size_t size = b * radix; + const size_t size = b * fixed_radix; - butterflies(b, csize<width>, csize<radix>, cbool<inverse>, out, in, b); + butterflies(b, csize<width>, csize<fixed_radix>, cbool<inverse>, out, in, b); } }; diff --git a/include/kfr/dft/impl/dft-templates.hpp b/include/kfr/dft/impl/dft-templates.hpp @@ -24,6 +24,7 @@ See https://www.kfrlib.com for details. */ +#ifdef FLOAT #include "../fft.hpp" namespace kfr @@ -42,3 +43,5 @@ template void dft_plan_real<FLOAT>::from_fmt(kfr::complex<FLOAT>* out, const kfr template void dft_plan_real<FLOAT>::to_fmt(kfr::complex<FLOAT>* out, kfr::dft_pack_format fmt) const; } // namespace kfr + +#endif diff --git a/include/kfr/dft/impl/ft.hpp b/include/kfr/dft/impl/ft.hpp @@ -1677,15 +1677,15 @@ KFR_INTRIN void spec_generic_butterfly_w(csize_t<radix>, cbool_t<inverse>, compl template <typename T, bool inverse, typename Tstride = csize_t<1>> KFR_INTRIN void generic_butterfly(size_t radix, cbool_t<inverse>, complex<T>* out, const complex<T>* in, - complex<T>* temp, const complex<T>* twiddle, Tstride ostride = Tstride{}) + complex<T>* temp, const complex<T>* twiddle, Tstride ostride = {}) { - constexpr size_t width = platform<T>::vector_width; - cswitch(csizes_t<11, 13>(), radix, [&](auto radix_) CMT_INLINE_LAMBDA { + constexpr size_t width = platform<T>::vector_width; spec_generic_butterfly_w<width>(radix_, cbool_t<inverse>(), out, in, twiddle, ostride); }, [&]() CMT_INLINE_LAMBDA { + constexpr size_t width = platform<T>::vector_width; generic_butterfly_w<width>(radix, cbool_t<inverse>(), out, in, twiddle, ostride); }); } diff --git a/include/kfr/ext/double_double.hpp b/include/kfr/ext/double_double.hpp @@ -38,10 +38,17 @@ struct double_double const double cc = ((((x.hi - u.hi) - u.lo) + x.lo) - c * y.lo) / y.hi; return { c, cc }; } - constexpr bool isinf() const noexcept { return std::isinf(hi); } - constexpr bool isnan() const noexcept { return std::isnan(hi) || std::isnan(lo); } - constexpr double ulp(float value) const noexcept +#if defined _MSC_VER && !defined __clang__ +#define DOUBLEDOUBLE_CONSTEXPR +#else +#define DOUBLEDOUBLE_CONSTEXPR constexpr +#endif + + DOUBLEDOUBLE_CONSTEXPR bool isinf() const noexcept { return std::isinf(hi); } + DOUBLEDOUBLE_CONSTEXPR bool isnan() const noexcept { return std::isnan(hi) || std::isnan(lo); } + + DOUBLEDOUBLE_CONSTEXPR double ulp(float value) const noexcept { if (std::isnan(value) && isnan()) return 0.0; @@ -51,7 +58,7 @@ struct double_double return 1.0; return (double_double(value) - *this) / double_double(std::nexttoward(value, 0.0)); } - constexpr double ulp(double value) const noexcept + DOUBLEDOUBLE_CONSTEXPR double ulp(double value) const noexcept { if (std::isnan(value) && isnan()) return 0.0; diff --git a/include/kfr/io/audiofile.hpp b/include/kfr/io/audiofile.hpp @@ -64,6 +64,9 @@ struct audio_format struct audio_format_and_length : audio_format { using audio_format::audio_format; +#ifdef CMT_COMPILER_MSVC + audio_format_and_length() noexcept {} +#endif audio_format_and_length(const audio_format& fmt) : audio_format(fmt) {} imax length = 0; // in samples diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt @@ -41,10 +41,15 @@ set(ALL_TESTS_CPP all_tests.cpp base_test.cpp complex_test.cpp - dft_test.cpp dsp_test.cpp expression_test.cpp - intrinsic_test.cpp io_test.cpp resampler_test.cpp) + intrinsic_test.cpp + io_test.cpp + resampler_test.cpp) + +if (ENABLE_DFT) + list(APPEND ALL_TESTS_CPP dft_test.cpp) +endif () if (MPFR_FOUND AND GMP_FOUND) list(APPEND ALL_TESTS_CPP transcendental_test.cpp) @@ -54,8 +59,10 @@ endif () add_executable(all_tests ${ALL_TESTS_CPP}) target_compile_definitions(all_tests PRIVATE KFR_NO_MAIN) -target_link_libraries(all_tests kfr kfr_dft) -target_link_libraries(all_tests kfr kfr_dft kfr_io) +if (ENABLE_DFT) + target_link_libraries(all_tests kfr kfr_dft) +endif () +target_link_libraries(all_tests kfr kfr_io) if (MPFR_FOUND AND GMP_FOUND) add_definitions(-DHAVE_MPFR) @@ -65,7 +72,10 @@ endif () function(add_x86_test NAME FLAGS) separate_arguments(FLAGS) - add_executable(all_tests_${NAME} ${ALL_TESTS_CPP} ${KFR_DFT_SRC} ${KFR_IO_SRC}) + add_executable(all_tests_${NAME} ${ALL_TESTS_CPP} ${KFR_IO_SRC}) + if (ENABLE_DFT) + target_sources(all_tests_${NAME} PRIVATE ${KFR_DFT_SRC}) + endif () target_compile_options(all_tests_${NAME} PRIVATE ${FLAGS}) target_compile_definitions(all_tests_${NAME} PRIVATE KFR_NO_MAIN) target_link_libraries(all_tests_${NAME} kfr)