From 8310d4617638105ecad912d1fc8e240fb442b640 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Thu, 6 Nov 2025 22:16:59 +0100 Subject: [PATCH] - added mix - redesigned multi buffer --- delay/buffer.hpp | 39 ++++++++++-- delay/buffer_multi.hpp | 60 +++++++++++++----- delay/tests/Makefile | 2 +- delay/tests/test_common.hpp | 6 +- delay/tests/test_main.cpp | 5 +- delay/tests/test_mix.cpp | 79 ++++++++++++++++++++++++ mix.hpp | 119 ++++++++++++++++++++++++++++++++++++ 7 files changed, 285 insertions(+), 25 deletions(-) create mode 100644 delay/tests/test_mix.cpp create mode 100644 mix.hpp diff --git a/delay/buffer.hpp b/delay/buffer.hpp index dafcb42..c5c9e1c 100644 --- a/delay/buffer.hpp +++ b/delay/buffer.hpp @@ -49,7 +49,7 @@ class Buffer std::vector &m_buffer; public: - Buffer(size_t capacity) + Buffer(size_t capacity=1) : m_index(0) , m_mask(0) , m_offset(0) @@ -59,7 +59,6 @@ class Buffer , m_allocated_capacity(1) { resize(capacity); - m_buffer.assign(m_allocated_capacity, T()); } Buffer(const Buffer &buffer, int offset=0, uint increment=1) @@ -82,7 +81,7 @@ class Buffer , m_buffer(*new std::vector(v)) , m_allocated_capacity(1) { - resize(v.size()); + resize(v.size(), false); } size_t capacity() const @@ -95,13 +94,18 @@ class Buffer m_index = 0; } - void resize(uint capacity) + void resize(uint capacity, bool doAssign=true) { m_allocated_capacity = 1; while (m_allocated_capacity < capacity) { m_allocated_capacity *= 2; } + + if (doAssign) + { + m_buffer.assign(m_allocated_capacity, T()); + } m_capacity = capacity; m_mask = unsigned(m_allocated_capacity - 1); @@ -163,6 +167,33 @@ class Buffer return true; } + Buffer& operator = (const std::initializer_list &v) + { + if (v.size() > m_allocated_capacity) + { + resize(v.size()); + } + + int i=0; + for (auto v_: v) + { + (*this)[i++] = v_; + } + return *this; + } + + Buffer& operator = (const Buffer &other) + { + m_buffer = other.m_buffer; + m_index = other.m_index; + m_mask = other.m_mask; + m_offset = other.m_offset; + m_increment = other.m_increment; + m_capacity = other.m_capacity; + m_allocated_capacity = other.m_allocated_capacity; + return *this; + } + protected: diff --git a/delay/buffer_multi.hpp b/delay/buffer_multi.hpp index 8e1275d..06845c9 100644 --- a/delay/buffer_multi.hpp +++ b/delay/buffer_multi.hpp @@ -33,16 +33,20 @@ namespace dsp { template class BufferMulti { - Buffer m_buffer; - size_t m_numChannels; + Buffer *m_buffer; + uint m_numChannels; size_t m_capacity; public: BufferMulti(size_t numChannels, size_t capacity) - : m_buffer(capacity*numChannels) + : m_buffer(new Buffer[numChannels]) , m_numChannels(numChannels) , m_capacity(capacity) { + for (int c=0; c < numChannels; c++) + { + m_buffer[c].resize(capacity); + } } Buffer & buffer() @@ -52,7 +56,10 @@ class BufferMulti void reset() { - m_buffer.reset(); + for (int c=0; c < m_numChannels; c++) + { + m_buffer[c].reset(); + } } size_t capacity() @@ -77,58 +84,81 @@ class BufferMulti BufferMulti & operator ++() { - ++m_buffer; + for (int c=0; c < m_numChannels; c++) + { + ++(m_buffer[c]); + } return *this; } BufferMulti & operator +=(int i) { - m_buffer += i; + for (int c=0; c < m_numChannels; c++) + { + m_buffer[c] += i; + } return *this; } BufferMulti & operator --() { - --m_buffer; + for (int c=0; c < m_numChannels; c++) + { + --(m_buffer[c]); + } return *this; } BufferMulti & operator -=(int i) { - m_buffer -= i; + for (int c=0; c < m_numChannels; c++) + { + m_buffer[c] -= i; + } return *this; } - BufferMulti & operator =(T value) + BufferMulti & operator = (const T& value) { for (uint c=0; c < m_numChannels; c++) { - this->at(c)[0] = value; + m_buffer[c][0] = value; } return *this; } dsp::Buffer quer(int offset=0) { - return Buffer(m_buffer, offset, m_capacity); + Buffer querBuffer(numChannels()); + for (int c=0; c < m_numChannels; c++) + { + querBuffer[c] = m_buffer[c][offset]; + } + return querBuffer; } const dsp::Buffer quer(int offset=0) const { - return Buffer(m_buffer, offset, m_capacity); + Buffer querBuffer(numChannels()); + for (int c=0; c < m_numChannels; c++) + { + querBuffer[c] = m_buffer[c][offset]; + } + return querBuffer; } -protected: Buffer at(uint channel) { - return Buffer(m_buffer, channel*m_capacity); + return m_buffer[channel]; } const Buffer at(uint channel) const { - return Buffer(m_buffer, channel*m_capacity); + return m_buffer[channel]; } +protected: + }; } diff --git a/delay/tests/Makefile b/delay/tests/Makefile index a63d90d..9cb5ad8 100644 --- a/delay/tests/Makefile +++ b/delay/tests/Makefile @@ -13,7 +13,7 @@ CXXFLAGS += -std=c++20 INCLUDES += -I $(realpath .) -I $(realpath ../../) -CXX_SRCS := test_main.cpp test_buffer.cpp test_buffer_multi.cpp +CXX_SRCS := test_main.cpp test_buffer.cpp test_buffer_multi.cpp test_mix.cpp LIBS := -lstdc++ diff --git a/delay/tests/test_common.hpp b/delay/tests/test_common.hpp index 131e230..66735b8 100644 --- a/delay/tests/test_common.hpp +++ b/delay/tests/test_common.hpp @@ -13,12 +13,12 @@ template void print(const dsp::Buffer &v, size_t size, std::string name=std::string("")) { std::cout << "----------------------------------------------" << std::endl; - std::cout << "- " << name << std::endl; - std::cout << "----------------------------------------------" << std::endl; + std::cout << "- " << name << ", " << size << std::endl; for(int i=0; i < size; i++) { - std::cout << v[i] << std::endl; + std::cout << v[i] << " "; } + std::cout << std::endl; } template diff --git a/delay/tests/test_main.cpp b/delay/tests/test_main.cpp index f39f7f8..4045405 100644 --- a/delay/tests/test_main.cpp +++ b/delay/tests/test_main.cpp @@ -1,10 +1,11 @@ extern void test_buffer(); extern void test_buffer_multi(); +extern void test_mix(); int main() { test_buffer(); -// test_buffer_multi(); - + test_buffer_multi(); + test_mix(); return 0; } \ No newline at end of file diff --git a/delay/tests/test_mix.cpp b/delay/tests/test_mix.cpp new file mode 100644 index 0000000..d802d92 --- /dev/null +++ b/delay/tests/test_mix.cpp @@ -0,0 +1,79 @@ +#include "delay/buffer_multi.hpp" +#include "test_common.hpp" +#include +#include + +#include +#include + + +int test_mix_1() +{ + std::cout << "----------------------------------------------" << std::endl; + std::cout << "Start test_mix_1::shuffle" << std::endl; + std::cout << "----------------------------------------------" << std::endl; + + { + dsp::Buffer r_buf(5); + dsp::Buffer t_buf{105, 106, 107, 108, 109}; + t_buf = {105, 106, 107, 108, 109}; + + dsp::Buffer s_spec = {1, 3, 2, 4, 0}; + Shuffle::outOfPlace(t_buf, r_buf, s_spec); + print(r_buf, 5, "r-buf"); + } + { + dsp::BufferMulti r_buf(5, 5); + dsp::BufferMulti t_buf{5, 5}; + t_buf[0] = {105, 106, 107, 108, 109}; + t_buf[1] = {205, 206, 207, 208, 209}; + t_buf[2] = {305, 306, 307, 308, 309}; + t_buf[3] = {405, 406, 407, 408, 409}; + t_buf[4] = {505, 506, 507, 508, 509}; + print(t_buf[0], 5, "t-buf 0"); + print(t_buf[1], 5, "t-buf 1"); + + dsp::Buffer s_spec = {-1, 0, -3, 2, -4}; + Shuffle::outOfPlace(t_buf, r_buf, s_spec); + print(r_buf[0], 5, "r-buf 0"); + print(r_buf[1], 5, "r-buf 1"); + print(r_buf[2], 5, "r-buf 2"); + print(r_buf[3], 5, "r-buf 3"); + print(r_buf[4], 5, "r-buf 4"); + } + return 0; +} + +int test_mix_2() +{ + dsp::BufferMulti r_buf(5, 20); + + for (int i=0; i < r_buf.capacity(); i++) + { + r_buf = 100 +i ; + ++r_buf; + } + + r_buf.reset(); + for (int c=0; c < r_buf.numChannels(); c++) + { + print(r_buf[c], r_buf.capacity(), "r-buf"); + std::cout << "----------------------------------------------" << std::endl; + } + + for (int c=0; c < r_buf.numChannels(); c++) + { + dsp::Buffer v(r_buf[c], c); + print(v, r_buf.capacity(), "v-buf"); + std::cout << "----------------------------------------------" << std::endl; + } + + return 0; +} + +int test_mix() +{ + test_mix_1(); + test_mix_2(); + return 0; +} \ No newline at end of file diff --git a/mix.hpp b/mix.hpp new file mode 100644 index 0000000..8007d6a --- /dev/null +++ b/mix.hpp @@ -0,0 +1,119 @@ +#include "delay/buffer_multi.hpp" +#include + +#ifndef MIX_HPP +#define MIX_HPP + +#include + +// Use like `Householder::inPlace(data)` - size must be ≥ 1 +template +class Householder +{ + static constexpr Sample multiplier{-2.0/size}; + + public: + static void inPlace(Sample *arr) + { + double sum = 0; + for (int i = 0; i < size; ++i) + { + sum += arr[i]; + } + + sum *= multiplier; + + for (int i = 0; i < size; ++i) + { + arr[i] += sum; + } + }; +}; + +// Use like `Hadamard::inPlace(data)` - size must be a power of 2 +template +class Hadamard +{ + public: + static inline void recursiveUnscaled(Sample * data) + { + if (size <= 1) + { + return; + } + constexpr int hSize = size/2; + + // Two (unscaled) Hadamards of half the size + Hadamard::recursiveUnscaled(data); + Hadamard::recursiveUnscaled(data + hSize); + + // Combine the two halves using sum/difference + for (int i = 0; i < hSize; ++i) + { + double a = data[i]; + double b = data[i + hSize]; + data[i] = (a + b); + data[i + hSize] = (a - b); + } + } + + static inline void inPlace(Sample * data) + { + recursiveUnscaled(data); + + Sample scalingFactor = std::sqrt(1.0/size); + for (int c = 0; c < size; ++c) + { + data[c] *= scalingFactor; + } + } +}; + +template +class Shuffle +{ + public: + static inline void outOfPlace(dsp::Buffer &in, dsp::Buffer &out, dsp::Buffer &shuffle_spec) + { + for (int c=0; c < shuffle_spec.capacity(); c++) + { + T sign = 1; + int s = (int)shuffle_spec[c]; + if (s < 0) + { + sign = -1; + s *= -1; + } + if (s >= shuffle_spec.capacity()) + { + s = 0; + } + + out[s] = sign * in[c]; + } + }; + static inline void outOfPlace(dsp::BufferMulti &in, dsp::BufferMulti &out, dsp::Buffer &shuffle_spec) + { + for (int c=0; c < shuffle_spec.capacity(); c++) + { + T sign = 1; + int s = (int)shuffle_spec[c]; + if (s < 0) + { + sign = -1; + s *= -1; + } + if (s >= shuffle_spec.capacity()) + { + s = 0; + } + + for (int n=0; n < in.capacity(); n++) + { + out[c][n] = sign * in[s][n]; + } + } + }; +}; + +#endif