commit 0d8fc456f716bc1f0420dcc8f27274fa87e1ccad
parent 22e363f7d27fcdbad76a7c8caab09eeb23850872
Author: [email protected] <[email protected]>
Date: Thu, 11 Aug 2016 08:50:11 +0300
Merge branch 'dev'
Diffstat:
7 files changed, 299 insertions(+), 13 deletions(-)
diff --git a/include/kfr/base/univector.hpp b/include/kfr/base/univector.hpp
@@ -109,20 +109,59 @@ struct univector_base : input_expression, output_expression
}
ringbuf_step(cursor, srcsize);
}
-
+ template <size_t N>
+ void ringbuf_write(size_t& cursor, const vec<T, N>& x)
+ {
+ ringbuf_write(cursor, x.data(), N);
+ }
void ringbuf_write(size_t& cursor, const T value)
{
T* data = get_data();
data[cursor] = value;
-
ringbuf_step(cursor, 1);
}
- void ringbuf_step(size_t& cursor, size_t step)
+ void ringbuf_step(size_t& cursor, size_t step) const
{
const size_t size = get_size();
cursor = cursor + step;
cursor = cursor >= size ? cursor - size : cursor;
}
+ void ringbuf_read(size_t& cursor, T& value)
+ {
+ T* data = get_data();
+ value = data[cursor];
+ ringbuf_step(cursor, 1);
+ }
+ template <size_t N>
+ void ringbuf_read(size_t& cursor, vec<T, N>& x)
+ {
+ ringbuf_read(cursor, x.data(), N);
+ }
+ void ringbuf_read(size_t& cursor, T* dest, size_t destsize) const
+ {
+ if (destsize == 0)
+ return;
+ // skip redundant data
+ const size_t size = get_size();
+ const T* data = get_data();
+ if (destsize > size)
+ {
+ dest = dest + destsize / size;
+ destsize = destsize % size;
+ }
+ const size_t fsize = size - cursor;
+ // one fragment
+ if (destsize <= fsize)
+ {
+ std::copy_n(data + cursor, destsize, dest);
+ }
+ else // two fragments
+ {
+ std::copy_n(data + cursor, fsize, dest);
+ std::copy_n(data, destsize - fsize, dest + fsize);
+ }
+ ringbuf_step(cursor, destsize);
+ }
protected:
template <typename Input>
diff --git a/include/kfr/dsp.hpp b/include/kfr/dsp.hpp
@@ -27,6 +27,7 @@
#include "dsp/biquad.hpp"
#include "dsp/biquad_design.hpp"
#include "dsp/dcremove.hpp"
+#include "dsp/delay.hpp"
#include "dsp/fir.hpp"
#include "dsp/fir_design.hpp"
#include "dsp/fracdelay.hpp"
diff --git a/include/kfr/dsp/delay.hpp b/include/kfr/dsp/delay.hpp
@@ -0,0 +1,98 @@
+/**
+ * Copyright (C) 2016 D Levin (http://www.kfrlib.com)
+ * This file is part of KFR
+ *
+ * KFR is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * KFR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KFR.
+ *
+ * If GPL is not suitable for your project, you must purchase a commercial license to use KFR.
+ * Buying a commercial license is mandatory as soon as you develop commercial activities without
+ * disclosing the source code of your own applications.
+ * See http://www.kfrlib.com for details.
+ */
+#pragma once
+
+#include "../base/expression.hpp"
+#include "../base/univector.hpp"
+
+namespace kfr
+{
+
+namespace internal
+{
+template <size_t delay, typename E>
+struct expression_delay : expression<E>
+{
+ using value_type = value_type_of<E>;
+ using expression<E>::expression;
+
+ template <typename T, size_t N, KFR_ENABLE_IF(N <= delay)>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ vec<T, N> out;
+ size_t c = cursor;
+ data.ringbuf_read(c, out);
+ const vec<T, N> in = this->argument_first(index, vec_t<T, N>());
+ data.ringbuf_write(cursor, in);
+ return out;
+ }
+ template <typename T>
+ vec<T, 1> operator()(cinput_t, size_t index, vec_t<T, 1>) const
+ {
+ T out;
+ size_t c = cursor;
+ data.ringbuf_read(c, out);
+ const T in = this->argument_first(index, vec_t<T, 1>())[0];
+ data.ringbuf_write(cursor, in);
+ return out;
+ }
+ template <typename T, size_t N, KFR_ENABLE_IF(N > delay)>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ vec<T, delay> out;
+ size_t c = cursor;
+ data.ringbuf_read(c, out);
+ const vec<T, N> in = this->argument_first(index, vec_t<T, N>());
+ data.ringbuf_write(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;
+};
+
+template <typename E>
+struct expression_delay<1, E> : expression<E>
+{
+ using value_type = value_type_of<E>;
+ using expression<E>::expression;
+
+ template <typename T, size_t N>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ const vec<T, N> in = this->argument_first(index, vec_t<T, N>());
+ const vec<T, N> out = insertleft(data, in);
+ data = in[N - 1];
+ return out;
+ }
+ mutable value_type data = value_type(0);
+};
+}
+
+template <size_t samples = 1, typename E1>
+CMT_INLINE internal::expression_delay<samples, E1> delay(E1&& e1, csize_t<samples> = csize<samples>)
+{
+ static_assert(samples >= 1 && samples < 1024, "");
+ return internal::expression_delay<samples, E1>(std::forward<E1>(e1));
+}
+}
diff --git a/include/kfr/dsp/fir_design.hpp b/include/kfr/dsp/fir_design.hpp
@@ -143,4 +143,29 @@ CMT_INLINE void fir_bandstop(univector<T, Tag>& taps, identity<T> frequency1, id
{
return intrinsics::fir_bandstop(taps.slice(), frequency1, frequency2, window, normalize);
}
+
+template <typename T>
+CMT_INLINE void fir_lowpass(const univector_ref<T>& taps, identity<T> cutoff,
+ const expression_pointer<T>& window, bool normalize = true)
+{
+ return intrinsics::fir_lowpass(taps, cutoff, window, normalize);
+}
+template <typename T>
+CMT_INLINE void fir_highpass(const univector_ref<T>& taps, identity<T> cutoff,
+ const expression_pointer<T>& window, bool normalize = true)
+{
+ return intrinsics::fir_highpass(taps, cutoff, window, normalize);
+}
+template <typename T>
+CMT_INLINE void fir_bandpass(const univector_ref<T>& taps, identity<T> frequency1, identity<T> frequency2,
+ const expression_pointer<T>& window, bool normalize = true)
+{
+ return intrinsics::fir_bandpass(taps, frequency1, frequency2, window, normalize);
+}
+template <typename T>
+CMT_INLINE void fir_bandstop(const univector_ref<T>& taps, identity<T> frequency1, identity<T> frequency2,
+ const expression_pointer<T>& window, bool normalize = true)
+{
+ return intrinsics::fir_bandstop(taps, frequency1, frequency2, window, normalize);
+}
}
diff --git a/include/kfr/dsp/sample_rate_conversion.hpp b/include/kfr/dsp/sample_rate_conversion.hpp
@@ -163,18 +163,14 @@ struct sample_rate_converter
{
if (srcindex >= input_position)
{
- dest[i] = dotproduct(src.slice(size_t(srcindex - input_position), size_t(depth)),
- tap_ptr /*, depth*/);
+ dest[i] =
+ dotproduct(src.slice(size_t(srcindex - input_position), size_t(depth)), tap_ptr);
}
else
{
const itype prev_count = input_position - srcindex;
- dest[i] =
- dotproduct(delay.slice(size_t(depth - prev_count)),
- tap_ptr /*, size_t(prev_count)*/) +
- dotproduct(
- src, tap_ptr.slice(size_t(prev_count),
- size_t(depth - prev_count)) /*, size_t(depth - prev_count)*/);
+ dest[i] = dotproduct(delay.slice(size_t(depth - prev_count)), tap_ptr) +
+ dotproduct(src, tap_ptr.slice(size_t(prev_count), size_t(depth - prev_count)));
}
}
}
@@ -201,9 +197,117 @@ struct sample_rate_converter
itype input_position;
itype output_position;
};
+
+template <size_t factor, typename E>
+struct expression_upsample;
+
+template <size_t factor, size_t offset, typename E>
+struct expression_downsample;
+
+template <typename E>
+struct expression_upsample<2, E> : expression<E>
+{
+ using expression<E>::expression;
+ template <typename T, size_t N>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ const vec<T, N / 2> x = this->argument_first(index / 2, vec_t<T, N / 2>());
+ return interleave(x, zerovector(x));
+ }
+ template <typename T>
+ vec<T, 1> operator()(cinput_t, size_t index, vec_t<T, 1>) const
+ {
+ if (index & 1)
+ return 0;
+ else
+ return this->argument_first(index / 2, vec_t<T, 1>());
+ }
+};
+
+template <typename E>
+struct expression_upsample<4, E> : expression<E>
+{
+ using expression<E>::expression;
+ template <typename T, size_t N>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ const vec<T, N / 4> x = this->argument_first(index / 4, vec_t<T, N / 4>());
+ const vec<T, N / 2> xx = interleave(x, zerovector(x));
+ return interleave(xx, zerovector(xx));
+ }
+ template <typename T>
+ vec<T, 2> operator()(cinput_t, size_t index, vec_t<T, 2>) const
+ {
+ switch (index & 3)
+ {
+ case 0:
+ return interleave(this->argument_first(index / 4, vec_t<T, 1>()), zerovector<T, 1>());
+ case 3:
+ return interleave(zerovector<T, 1>(), this->argument_first(index / 4, vec_t<T, 1>()));
+ default:
+ return 0;
+ }
+ }
+ template <typename T>
+ vec<T, 1> operator()(cinput_t, size_t index, vec_t<T, 1>) const
+ {
+ if (index & 3)
+ return 0;
+ else
+ return this->argument_first(index / 4, vec_t<T, 1>());
+ }
+};
+
+template <typename E, size_t offset>
+struct expression_downsample<2, offset, E> : expression<E>
+{
+ using expression<E>::expression;
+ template <typename T, size_t N>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ const vec<T, N* 2> x = this->argument_first(index * 2, vec_t<T, N * 2>());
+ return shufflevector<N, internal::shuffle_index<offset, 2>>(x);
+ }
+};
+
+template <typename E, size_t offset>
+struct expression_downsample<4, offset, E> : expression<E>
+{
+ using expression<E>::expression;
+ template <typename T, size_t N>
+ vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
+ {
+ const vec<T, N* 4> x = this->argument_first(index * 4, vec_t<T, N * 4>());
+ return shufflevector<N, internal::shuffle_index<offset, 4>>(x);
+ }
+};
+}
+
+template <typename E1, size_t offset = 0>
+CMT_INLINE internal::expression_downsample<2, offset, E1> downsample2(E1&& e1, csize_t<offset> = csize<0>)
+{
+ return internal::expression_downsample<2, offset, E1>(std::forward<E1>(e1));
+}
+
+template <typename E1, size_t offset = 0>
+CMT_INLINE internal::expression_downsample<4, offset, E1> downsample4(E1&& e1, csize_t<offset> = csize<0>)
+{
+ return internal::expression_downsample<4, offset, E1>(std::forward<E1>(e1));
+}
+
+template <typename E1>
+CMT_INLINE internal::expression_upsample<2, E1> upsample2(E1&& e1)
+{
+ return internal::expression_upsample<2, E1>(std::forward<E1>(e1));
+}
+
+template <typename E1>
+CMT_INLINE internal::expression_upsample<4, E1> upsample4(E1&& e1)
+{
+ return internal::expression_upsample<4, E1>(std::forward<E1>(e1));
}
-template <typename T, size_t quality>
+template <typename T = fbase, size_t quality>
inline internal::sample_rate_converter<T, quality> sample_rate_converter(csize_t<quality>,
size_t interpolation_factor,
size_t decimation_factor,
@@ -215,7 +319,7 @@ inline internal::sample_rate_converter<T, quality> sample_rate_converter(csize_t
}
// Deprecated in 0.9.2
-template <typename T, size_t quality>
+template <typename T = fbase, size_t quality>
inline internal::sample_rate_converter<T, quality> resampler(csize_t<quality>, size_t interpolation_factor,
size_t decimation_factor, T scale = T(1),
T cutoff = 0.49)
diff --git a/sources.cmake b/sources.cmake
@@ -66,6 +66,7 @@ set(
${PROJECT_SOURCE_DIR}/include/kfr/dsp/biquad.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/biquad_design.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/dcremove.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/dsp/delay.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fir_design.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dsp/fracdelay.hpp
diff --git a/tests/vec_test.cpp b/tests/vec_test.cpp
@@ -277,4 +277,22 @@ TEST(vec_pack_expr)
CHECK(v4[19] == f32x2{ 220, 20 });
}
+TEST(test_delay)
+{
+ const univector<float, 33> v1 = counter() + 100;
+ const univector<float, 33> v2 = delay(v1);
+ CHECK(v2[0] == 0);
+ CHECK(v2[1] == 100);
+ CHECK(v2[2] == 101);
+ CHECK(v2[19] == 118);
+
+ const univector<float, 33> v3 = delay(v1, csize<3>);
+ CHECK(v3[0] == 0);
+ CHECK(v3[1] == 0);
+ CHECK(v3[2] == 0);
+ CHECK(v3[3] == 100);
+ CHECK(v3[4] == 101);
+ CHECK(v3[19] == 116);
+}
+
int main(int argc, char** argv) { return testo::run_all("", true); }