commit 0902232812a92dcdcf78d2bbb05f9187cdde6270
parent dfb5ea94d8c96e4d3384a1c7dc9fac109881a4a6
Author: Stephen Larew <stephen@slarew.net>
Date: Thu, 20 Feb 2020 12:30:28 -0800
factor out delay_state from delay expression
Diffstat:
4 files changed, 131 insertions(+), 40 deletions(-)
diff --git a/include/kfr/dsp/delay.hpp b/include/kfr/dsp/delay.hpp
@@ -25,42 +25,73 @@
*/
#pragma once
+#include "../base/basic_expressions.hpp"
#include "../base/expression.hpp"
#include "../base/univector.hpp"
+#include "state_holder.hpp"
namespace kfr
{
inline namespace CMT_ARCH_NAME
{
+template <typename T, size_t samples, univector_tag Tag = samples>
+struct delay_state
+{
+ template <size_t S2 = samples, KFR_ENABLE_IF(S2 == Tag)>
+ delay_state() : data({ 0 }), cursor(0)
+ {
+ }
+
+ template <size_t S2 = samples, KFR_ENABLE_IF(S2 != Tag)>
+ delay_state() : data(samples), cursor(0)
+ {
+ }
+
+ mutable univector<T, Tag> data;
+ mutable size_t cursor;
+};
+
+template <typename T>
+struct delay_state<T, 1, 1>
+{
+ mutable T data = T(0);
+};
+
namespace internal
{
-template <size_t delay, typename E>
+
+template <size_t delay, typename E, bool stateless, univector_tag STag>
struct expression_delay : expression_with_arguments<E>
{
using value_type = value_type_of<E>;
using T = value_type;
using expression_with_arguments<E>::expression_with_arguments;
+ expression_delay(E&& e, const delay_state<T, delay, STag>& state)
+ : expression_with_arguments<E>(std::forward<E>(e)), state(state)
+ {
+ }
+
template <size_t N, KFR_ENABLE_IF(N <= delay)>
friend KFR_INTRINSIC vec<T, N> get_elements(const expression_delay& self, cinput_t cinput, size_t index,
vec_shape<T, N>)
{
vec<T, N> out;
- size_t c = self.cursor;
- self.data.ringbuf_read(c, out);
+ size_t c = self.state.s.cursor;
+ self.state.s.data.ringbuf_read(c, out);
const vec<T, N> in = self.argument_first(cinput, index, vec_shape<T, N>());
- self.data.ringbuf_write(self.cursor, in);
+ self.state.s.data.ringbuf_write(self.state.s.cursor, in);
return out;
}
friend vec<T, 1> get_elements(const expression_delay& self, cinput_t cinput, size_t index,
vec_shape<T, 1>)
{
T out;
- size_t c = self.cursor;
- self.data.ringbuf_read(c, out);
+ size_t c = self.state.s.cursor;
+ self.state.s.data.ringbuf_read(c, out);
const T in = self.argument_first(cinput, index, vec_shape<T, 1>())[0];
- self.data.ringbuf_write(self.cursor, in);
+ self.state.s.data.ringbuf_write(self.state.s.cursor, in);
return out;
}
template <size_t N, KFR_ENABLE_IF(N > delay)>
@@ -68,34 +99,38 @@ struct expression_delay : expression_with_arguments<E>
vec_shape<T, N>)
{
vec<T, delay> out;
- size_t c = self.cursor;
- self.data.ringbuf_read(c, out);
+ size_t c = self.state.s.cursor;
+ self.state.s.data.ringbuf_read(c, out);
const vec<T, N> in = self.argument_first(cinput, index, vec_shape<T, N>());
- self.data.ringbuf_write(self.cursor, slice<N - delay, delay>(in));
+ self.state.s.data.ringbuf_write(self.state.s.cursor, slice<N - delay, delay>(in));
return concat_and_slice<0, N>(out, in);
}
- mutable univector<value_type, delay> data = scalar(value_type(0));
- mutable size_t cursor = 0;
+ state_holder<delay_state<T, delay, STag>, stateless> state;
};
-template <typename E>
-struct expression_delay<1, E> : expression_with_arguments<E>
+template <typename E, bool stateless, univector_tag STag>
+struct expression_delay<1, E, stateless, STag> : expression_with_arguments<E>
{
using value_type = value_type_of<E>;
using T = value_type;
using expression_with_arguments<E>::expression_with_arguments;
+ expression_delay(E&& e, const delay_state<T, 1, STag>& state)
+ : expression_with_arguments<E>(std::forward<E>(e)), state(state)
+ {
+ }
+
template <size_t N>
friend KFR_INTRINSIC vec<T, N> get_elements(const expression_delay& self, cinput_t cinput, size_t index,
vec_shape<T, N>)
{
const vec<T, N> in = self.argument_first(cinput, index, vec_shape<T, N>());
- const vec<T, N> out = insertleft(self.data, in);
- self.data = in[N - 1];
+ const vec<T, N> out = insertleft(self.state.s.data, in);
+ self.state.s.data = in[N - 1];
return out;
}
- mutable value_type data = value_type(0);
+ state_holder<delay_state<T, 1, STag>, stateless> state;
};
} // namespace internal
@@ -108,11 +143,30 @@ struct expression_delay<1, E> : expression_with_arguments<E>
* auto d = delay(v, csize<4>);
* @endcode
*/
-template <size_t samples = 1, typename E1>
-KFR_INTRINSIC internal::expression_delay<samples, E1> delay(E1&& e1, csize_t<samples> = csize_t<samples>())
+template <size_t samples = 1, typename E1, typename T = value_type_of<E1>>
+KFR_INTRINSIC internal::expression_delay<samples, E1, false, samples> delay(E1&& e1)
{
static_assert(samples >= 1 && samples < 1024, "");
- return internal::expression_delay<samples, E1>(std::forward<E1>(e1));
+ return internal::expression_delay<samples, E1, false, samples>(std::forward<E1>(e1),
+ delay_state<T, samples>());
+}
+
+/**
+ * @brief Returns template expression that applies delay to the input (uses ring buffer in state)
+ * @param state delay filter state
+ * @param e1 an input expression
+ * @code
+ * univector<double, 10> v = counter();
+ * delay_state<double, 4> state;
+ * auto d = delay(state, v);
+ * @endcode
+ */
+template <size_t samples, typename T, typename E1, univector_tag STag>
+KFR_INTRINSIC internal::expression_delay<samples, E1, true, STag> delay(delay_state<T, samples, STag>& state,
+ E1&& e1)
+{
+ static_assert(STag == tag_dynamic_vector || (samples >= 1 && samples < 1024), "");
+ return internal::expression_delay<samples, E1, true, STag>(std::forward<E1>(e1), state);
}
} // namespace CMT_ARCH_NAME
} // namespace kfr
diff --git a/include/kfr/dsp/fir.hpp b/include/kfr/dsp/fir.hpp
@@ -31,6 +31,7 @@
#include "../base/reduce.hpp"
#include "../base/univector.hpp"
#include "../simd/vec.hpp"
+#include "state_holder.hpp"
namespace kfr
{
@@ -73,26 +74,6 @@ struct fir_state
namespace internal
{
-template <typename T, bool stateless>
-struct state_holder
-{
- state_holder() = delete;
- state_holder(const state_holder&) = default;
- state_holder(state_holder&&) = default;
- constexpr state_holder(const T& state) CMT_NOEXCEPT : s(state) {}
- T s;
-};
-
-template <typename T>
-struct state_holder<T, true>
-{
- state_holder() = delete;
- state_holder(const state_holder&) = default;
- state_holder(state_holder&&) = default;
- constexpr state_holder(const T& state) CMT_NOEXCEPT : s(state) {}
- const T& s;
-};
-
template <size_t tapcount, typename T, typename U, typename E1, bool stateless = false>
struct expression_short_fir : expression_with_arguments<E1>
{
diff --git a/include/kfr/dsp/state_holder.hpp b/include/kfr/dsp/state_holder.hpp
@@ -0,0 +1,41 @@
+/** @addtogroup fir
+ * @{
+ */
+/**
+ * KFR (http://kfrlib.com)
+ * Copyright (C) 2016 D Levin
+ * See LICENSE.txt for details
+ */
+#pragma once
+
+#include "../cident.h"
+
+namespace kfr
+{
+inline namespace CMT_ARCH_NAME
+{
+namespace internal
+{
+
+template <typename T, bool stateless>
+struct state_holder
+{
+ state_holder() = delete;
+ state_holder(const state_holder&) = default;
+ state_holder(state_holder&&) = default;
+ constexpr state_holder(const T& state) CMT_NOEXCEPT : s(state) {}
+ T s;
+};
+
+template <typename T>
+struct state_holder<T, true>
+{
+ state_holder() = delete;
+ state_holder(const state_holder&) = default;
+ state_holder(state_holder&&) = default;
+ constexpr state_holder(const T& state) CMT_NOEXCEPT : s(state) {}
+ const T& s;
+};
+} // namespace internal
+} // namespace CMT_ARCH_NAME
+} // namespace kfr
diff --git a/tests/dsp_test.cpp b/tests/dsp_test.cpp
@@ -287,6 +287,12 @@ TEST(delay)
CHECK_EXPRESSION(delay(v1), 33, [](size_t i) { return i < 1 ? 0.f : (i - 1) + 100.f; });
CHECK_EXPRESSION(delay<3>(v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
+
+ delay_state<float, 3> state1;
+ CHECK_EXPRESSION(delay(state1, v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
+
+ delay_state<float, 3, tag_dynamic_vector> state2;
+ CHECK_EXPRESSION(delay(state2, v1), 33, [](size_t i) { return i < 3 ? 0.f : (i - 3) + 100.f; });
}
TEST(fracdelay)
@@ -396,6 +402,15 @@ TEST(fir)
return result;
});
+ fir_state state(taps.ref());
+
+ CHECK_EXPRESSION(fir(state, data), 100, [&](size_t index) -> T {
+ T result = 0;
+ for (size_t i = 0; i < taps.size(); i++)
+ result += data.get(index - i, 0) * taps[i];
+ return result;
+ });
+
CHECK_EXPRESSION(short_fir(data, taps), 100, [&](size_t index) -> T {
T result = 0;
for (size_t i = 0; i < taps.size(); i++)