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 c9edbe9d27d94e6def11efde4cc5c54bb7e45ff4
parent d36482b2f6389d11d5fa031d316d7b25c20e8b25
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date:   Wed, 27 Jul 2016 20:55:27 +0300

Generators: linear/exp/exp2/sin/sincos

Diffstat:
Minclude/kfr/expressions/generators.hpp | 356+++++++++++++++++++++++++++++++++++++------------------------------------------
1 file changed, 166 insertions(+), 190 deletions(-)

diff --git a/include/kfr/expressions/generators.hpp b/include/kfr/expressions/generators.hpp @@ -28,237 +28,213 @@ #include "../base/sin_cos.hpp" #include "../base/vec.hpp" -#pragma clang diagnostic push -#if CID_HAS_WARNING("-Winaccessible-base") -#pragma clang diagnostic ignored "-Winaccessible-base" -#endif - namespace kfr { namespace internal { -template <cpu_t cpu = cpu_t::native> -struct in_generators : in_log_exp<cpu>, in_select<cpu>, in_sin_cos<cpu> +template <typename T, size_t width_, typename Class> +struct generator: input_expression { -private: - using in_log_exp<cpu>::exp; - using in_log_exp<cpu>::exp2; - using in_select<cpu>::select; - using in_sin_cos<cpu>::cossin; - -public: - template <typename T, size_t width_, typename Class> - struct generator + constexpr static size_t width = width_; + using type = T; + + template <typename U, size_t N> + KFR_INLINE vec<U, N> operator()(cinput_t, size_t, vec_t<U, N> t) const { - constexpr static size_t width = width_; - using type = T; - - template <typename U, size_t N> - KFR_INLINE vec<U, N> operator()(cinput_t, size_t, vec_t<U, N> t) const - { - return cast<U>(generate(t)); - } - - void resync(T start) const { ptr_cast<Class>(this)->sync(start); } - - protected: - void call_next() const { ptr_cast<Class>(this)->next(); } - template <size_t N> - void call_shift(csize_t<N>) const - { - ptr_cast<Class>(this)->shift(csize<N>); - } - - template <size_t N> - void shift(csize_t<N>) const - { - const vec<T, width> oldvalue = value; - call_next(); - value = slice<N, width>(oldvalue, value); - } - - template <size_t N, KFR_ENABLE_IF(N == width)> - KFR_INLINE vec<T, N> generate(vec_t<T, N>) const - { - const vec<T, N> result = value; - call_next(); - return result; - } - - template <size_t N, KFR_ENABLE_IF(N < width)> - KFR_INLINE vec<T, N> generate(vec_t<T, N>) const - { - const vec<T, N> result = narrow<N>(value); - shift(csize<N>); - return result; - } - - template <size_t N, KFR_ENABLE_IF(N > width)> - KFR_INLINE vec<T, N> generate(vec_t<T, N> x) const - { - const auto lo = generate(low(x)); - const auto hi = generate(high(x)); - return concat(lo, hi); - } - - mutable vec<T, width> value; - }; - - template <typename T, size_t width = get_vector_width<T, cpu>(1, 2)> - struct generator_linear : generator<T, width, generator_linear<T, width>> + return cast<U>(generate(t)); + } + + void resync(T start) const { ptr_cast<Class>(this)->sync(start); } + +protected: + void call_next() const { ptr_cast<Class>(this)->next(); } + template <size_t N> + void call_shift(csize_t<N>) const { - constexpr generator_linear(T start, T step) noexcept : step(step), vstep(step* width) - { - this->resync(start); - } + ptr_cast<Class>(this)->shift(csize<N>); + } - KFR_INLINE void sync(T start) const noexcept { this->value = start + enumerate<T, width>() * step; } + template <size_t N> + void shift(csize_t<N>) const + { + const vec<T, width> oldvalue = value; + call_next(); + value = slice<N, width>(oldvalue, value); + } - KFR_INLINE void next() const noexcept { this->value += vstep; } + template <size_t N, KFR_ENABLE_IF(N == width)> + KFR_INLINE vec<T, N> generate(vec_t<T, N>) const + { + const vec<T, N> result = value; + call_next(); + return result; + } - protected: - T step; - T vstep; - }; + template <size_t N, KFR_ENABLE_IF(N < width)> + KFR_INLINE vec<T, N> generate(vec_t<T, N>) const + { + const vec<T, N> result = narrow<N>(value); + shift(csize<N>); + return result; + } - template <typename T, size_t width = get_vector_width<T, cpu>(1, 2)> - struct generator_exp : generator<T, width, generator_exp<T, width>> + template <size_t N, KFR_ENABLE_IF(N > width)> + KFR_INLINE vec<T, N> generate(vec_t<T, N> x) const { - generator_exp(T start, T step) noexcept : step(step), vstep(exp(make_vector(step* width))[0] - 1) - { - this->resync(start); - } + const auto lo = generate(low(x)); + const auto hi = generate(high(x)); + return concat(lo, hi); + } - KFR_INLINE void sync(T start) const noexcept - { - this->value = exp(start + enumerate<T, width>() * step); - } + mutable vec<T, width> value; +}; - KFR_INLINE void next() const noexcept { this->value += this->value * vstep; } +template <typename T, size_t width = get_vector_width<T, cpu_t::native>(1, 2)> +struct generator_linear : generator<T, width, generator_linear<T, width>> +{ + constexpr generator_linear(T start, T step) noexcept : step(step), vstep(step* width) + { + this->resync(start); + } - protected: - T step; - T vstep; - }; + KFR_INLINE void sync(T start) const noexcept { this->value = start + enumerate<T, width>() * step; } - template <typename T, size_t width = get_vector_width<T, cpu>(1, 2)> - struct generator_exp2 : generator<T, width, generator_exp2<T, width>> + KFR_INLINE void next() const noexcept { this->value += vstep; } + +protected: + T step; + T vstep; +}; + +template <typename T, size_t width = get_vector_width<T, cpu_t::native>(1, 2)> +struct generator_exp : generator<T, width, generator_exp<T, width>> +{ + generator_exp(T start, T step) noexcept : step(step), vstep(exp(make_vector(step* width))[0] - 1) { - generator_exp2(T start, T step) noexcept : step(step), vstep(exp2(make_vector(step* width))[0] - 1) - { - this->resync(start); - } + this->resync(start); + } - KFR_INLINE void sync(T start) const noexcept - { - this->value = exp2(start + enumerate<T, width>() * step); - } + KFR_INLINE void sync(T start) const noexcept { this->value = exp(start + enumerate<T, width>() * step); } - KFR_INLINE void next() const noexcept { this->value += this->value * vstep; } + KFR_INLINE void next() const noexcept { this->value += this->value * vstep; } - protected: - T step; - T vstep; - }; +protected: + T step; + T vstep; +}; - template <typename T, size_t width = get_vector_width<T, cpu>(1, 2)> - struct generator_cossin : generator<T, width, generator_cossin<T, width>> +template <typename T, size_t width = get_vector_width<T, cpu_t::native>(1, 2)> +struct generator_exp2 : generator<T, width, generator_exp2<T, width>> +{ + generator_exp2(T start, T step) noexcept : step(step), vstep(exp2(make_vector(step* width))[0] - 1) { - generator_cossin(T start, T step) - : step(step), alpha(2 * sqr(sin(width / 2 * step / 2))), beta(-sin(width / 2 * step)) - { - this->resync(start); - } - KFR_INLINE void sync(T start) const noexcept { this->value = init_cossin(step, start); } - - KFR_INLINE void next() const noexcept - { - this->value = this->value - subadd(alpha * this->value, beta * swap<2>(this->value)); - } - - protected: - T step; - T alpha; - T beta; - KFR_NOINLINE static vec<T, width> init_cossin(T w, T phase) - { - return cossin(dup(phase + enumerate<T, width / 2>() * w)); - } - }; - - template <typename T, size_t width = get_vector_width<T, cpu>(2, 4)> - struct generator_sin : generator<T, width, generator_sin<T, width>> + this->resync(start); + } + + KFR_INLINE void sync(T start) const noexcept { this->value = exp2(start + enumerate<T, width>() * step); } + + KFR_INLINE void next() const noexcept { this->value += this->value * vstep; } + +protected: + T step; + T vstep; +}; + +template <typename T, size_t width = get_vector_width<T, cpu_t::native>(1, 2)> +struct generator_cossin : generator<T, width, generator_cossin<T, width>> +{ + generator_cossin(T start, T step) + : step(step), alpha(2 * sqr(sin(width / 2 * step / 2))), beta(-sin(width / 2 * step)) + { + this->resync(start); + } + KFR_INLINE void sync(T start) const noexcept { this->value = init_cossin(step, start); } + + KFR_INLINE void next() const noexcept + { + this->value = this->value - subadd(alpha * this->value, beta * swap<2>(this->value)); + } + +protected: + T step; + T alpha; + T beta; + KFR_NOINLINE static vec<T, width> init_cossin(T w, T phase) + { + return cossin(dup(phase + enumerate<T, width / 2>() * w)); + } +}; + +template <typename T, size_t width = get_vector_width<T, cpu_t::native>(2, 4)> +struct generator_sin : generator<T, width, generator_sin<T, width>> +{ + generator_sin(T start, T step) + : step(step), alpha(2 * sqr(sin(width * step / 2))), beta(sin(width * step)) + { + this->resync(start); + } + KFR_INLINE void sync(T start) const noexcept { - generator_sin(T start, T step) - : step(step), alpha(2 * sqr(sin(width * step / 2))), beta(sin(width * step)) - { - this->resync(start); - } - KFR_INLINE void sync(T start) const noexcept - { - const vec<T, width* 2> cs = splitpairs(cossin(dup(start + enumerate<T, width>() * step))); - this->cos_value = low(cs); - this->value = high(cs); - } - - KFR_INLINE void next() const noexcept - { - const vec<T, width> c = this->cos_value; - const vec<T, width> s = this->value; - - const vec<T, width> cc = alpha * c + beta * s; - const vec<T, width> ss = alpha * s - beta * c; - - this->cos_value = c - cc; - this->value = s - ss; - } - - template <size_t N> - void shift(csize_t<N>) const noexcept - { - const vec<T, width> oldvalue = this->value; - const vec<T, width> oldcosvalue = this->cos_value; - next(); - this->value = slice<N, width>(oldvalue, this->value); - this->cos_value = slice<N, width>(oldcosvalue, this->cos_value); - } - - protected: - T step; - T alpha; - T beta; - mutable vec<T, width> cos_value; - }; + const vec<T, width* 2> cs = splitpairs(cossin(dup(start + enumerate<T, width>() * step))); + this->cos_value = low(cs); + this->value = high(cs); + } + + KFR_INLINE void next() const noexcept + { + const vec<T, width> c = this->cos_value; + const vec<T, width> s = this->value; + + const vec<T, width> cc = alpha * c + beta * s; + const vec<T, width> ss = alpha * s - beta * c; + + this->cos_value = c - cc; + this->value = s - ss; + } + + template <size_t N> + void shift(csize_t<N>) const noexcept + { + const vec<T, width> oldvalue = this->value; + const vec<T, width> oldcosvalue = this->cos_value; + next(); + this->value = slice<N, width>(oldvalue, this->value); + this->cos_value = slice<N, width>(oldcosvalue, this->cos_value); + } + +protected: + T step; + T alpha; + T beta; + mutable vec<T, width> cos_value; }; } template <typename T1, typename T2, typename TF = ftype<common_type<T1, T2>>> -KFR_SINTRIN internal::in_generators<>::generator_linear<TF> gen_linear(T1 start, T2 step) +KFR_SINTRIN internal::generator_linear<TF> gen_linear(T1 start, T2 step) { - return internal::in_generators<>::generator_linear<TF>(start, step); + return internal::generator_linear<TF>(start, step); } template <typename T1, typename T2, typename TF = ftype<common_type<T1, T2>>> -KFR_SINTRIN internal::in_generators<>::generator_exp<TF> gen_exp(T1 start, T2 step) +KFR_SINTRIN internal::generator_exp<TF> gen_exp(T1 start, T2 step) { - return internal::in_generators<>::generator_exp<TF>(start, step); + return internal::generator_exp<TF>(start, step); } template <typename T1, typename T2, typename TF = ftype<common_type<T1, T2>>> -KFR_SINTRIN internal::in_generators<>::generator_exp2<TF> gen_exp2(T1 start, T2 step) +KFR_SINTRIN internal::generator_exp2<TF> gen_exp2(T1 start, T2 step) { - return internal::in_generators<>::generator_exp2<TF>(start, step); + return internal::generator_exp2<TF>(start, step); } template <typename T1, typename T2, typename TF = ftype<common_type<T1, T2>>> -KFR_SINTRIN internal::in_generators<>::generator_sin<TF> gen_cossin(T1 start, T2 step) +KFR_SINTRIN internal::generator_cossin<TF> gen_cossin(T1 start, T2 step) { - return internal::in_generators<>::generator_cossin<TF>(start, step); + return internal::generator_cossin<TF>(start, step); } template <typename T1, typename T2, typename TF = ftype<common_type<T1, T2>>> -KFR_SINTRIN internal::in_generators<>::generator_sin<TF> gen_sin(T1 start, T2 step) +KFR_SINTRIN internal::generator_sin<TF> gen_sin(T1 start, T2 step) { - return internal::in_generators<>::generator_sin<TF>(start, step); + return internal::generator_sin<TF>(start, step); } } - -#pragma clang diagnostic pop