- refactored

- BufferMulti numChannels is template parameter
This commit is contained in:
2025-11-09 13:20:16 +01:00
parent 01d644b76e
commit 681290c9ae
13 changed files with 318 additions and 221 deletions
+6 -31
View File
@@ -1,10 +1,7 @@
#include "delay/buffer_multi.hpp"
#include <cmath>
#ifndef MIX_HPP #ifndef MIX_HPP
#define MIX_HPP #define MIX_HPP
#include <delay/buffer.hpp> #include <cmath>
// Use like `Householder<double, 8>::inPlace(data)` - size must be ≥ 1 // Use like `Householder<double, 8>::inPlace(data)` - size must be ≥ 1
template<typename Sample, int size> template<typename Sample, int size>
@@ -69,22 +66,22 @@ class Hadamard
} }
}; };
template<typename T> template<typename T, uint numCh>
class Shuffle class Shuffle
{ {
public: public:
static inline void outOfPlace(dsp::Buffer<T> &in, dsp::Buffer<T> &out, dsp::Buffer<T> &shuffle_spec) static inline void outOfPlace(T *in, T *out, const int *shuffle_spec)
{ {
for (int c=0; c < shuffle_spec.capacity(); c++) for (int c=0; c < numCh; c++)
{ {
T sign = 1; T sign = 1;
int s = (int)shuffle_spec[c]; int s = shuffle_spec[c];
if (s < 0) if (s < 0)
{ {
sign = -1; sign = -1;
s *= -1; s *= -1;
} }
if (s >= shuffle_spec.capacity()) if (s >= numCh)
{ {
s = 0; s = 0;
} }
@@ -92,28 +89,6 @@ class Shuffle
out[s] = sign * in[c]; out[s] = sign * in[c];
} }
}; };
static inline void outOfPlace(dsp::BufferMulti<T> &in, dsp::BufferMulti<T> &out, dsp::Buffer<T> &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 #endif
-2
View File
@@ -27,12 +27,10 @@
#define DSP_BUFFER_H #define DSP_BUFFER_H
#include <vector> #include <vector>
#include <list>
#include <cstddef> #include <cstddef>
#include <math.h> #include <math.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <dsp_types.hpp>
namespace dsp { namespace dsp {
+18 -50
View File
@@ -27,23 +27,22 @@
#define DSP_BUFFER_MULTI_H #define DSP_BUFFER_MULTI_H
#include "buffer.hpp" #include "buffer.hpp"
#include <array>
namespace dsp { namespace dsp {
template <typename T> template <typename T, uint numCh>
class BufferMulti class BufferMulti
{ {
Buffer<T> *m_buffer; Buffer<T> *m_buffer;
uint m_numChannels;
size_t m_capacity; size_t m_capacity;
public: public:
BufferMulti(size_t numChannels, size_t capacity) BufferMulti(size_t capacity)
: m_buffer(new Buffer<T>[numChannels]) : m_buffer(new Buffer<T>[numCh])
, m_numChannels(numChannels)
, m_capacity(capacity) , m_capacity(capacity)
{ {
for (int c=0; c < numChannels; c++) for (int c=0; c < numCh; c++)
{ {
m_buffer[c].resize(capacity); m_buffer[c].resize(capacity);
} }
@@ -56,7 +55,7 @@ class BufferMulti
void reset() void reset()
{ {
for (int c=0; c < m_numChannels; c++) for (int c=0; c < numCh; c++)
{ {
m_buffer[c].reset(); m_buffer[c].reset();
} }
@@ -69,7 +68,7 @@ class BufferMulti
size_t numChannels() size_t numChannels()
{ {
return m_numChannels; return numCh;
} }
Buffer<T> operator[](uint channel) Buffer<T> operator[](uint channel)
@@ -84,7 +83,7 @@ class BufferMulti
BufferMulti & operator ++() BufferMulti & operator ++()
{ {
for (int c=0; c < m_numChannels; c++) for (int c=0; c < numCh; c++)
{ {
++(m_buffer[c]); ++(m_buffer[c]);
} }
@@ -93,7 +92,7 @@ class BufferMulti
BufferMulti & operator +=(int i) BufferMulti & operator +=(int i)
{ {
for (int c=0; c < m_numChannels; c++) for (int c=0; c < numCh; c++)
{ {
m_buffer[c] += i; m_buffer[c] += i;
} }
@@ -102,7 +101,7 @@ class BufferMulti
BufferMulti & operator --() BufferMulti & operator --()
{ {
for (int c=0; c < m_numChannels; c++) for (int c=0; c < numCh; c++)
{ {
--(m_buffer[c]); --(m_buffer[c]);
} }
@@ -111,7 +110,7 @@ class BufferMulti
BufferMulti & operator -=(int i) BufferMulti & operator -=(int i)
{ {
for (int c=0; c < m_numChannels; c++) for (int c=0; c < numCh; c++)
{ {
m_buffer[c] -= i; m_buffer[c] -= i;
} }
@@ -120,60 +119,29 @@ class BufferMulti
BufferMulti & operator =(const T& value) BufferMulti & operator =(const T& value)
{ {
for (uint c=0; c < m_numChannels; c++) for (uint c=0; c < numCh; c++)
{ {
m_buffer[c][0] = value; m_buffer[c][0] = value;
} }
return *this; return *this;
} }
dsp::Buffer<T> quer(int offset=0) void quer(T *out, int offset=0) const
{ {
Buffer<T> querBuffer(numChannels()); for (int c=0; c < numCh; c++)
for (int c=0; c < m_numChannels; c++)
{ {
querBuffer[c] = m_buffer[c][offset]; out[c] = m_buffer[c][offset];
} }
return querBuffer;
} }
const dsp::Buffer<T> quer(int offset=0) const void quer(T *out, const int *offsets) const
{ {
Buffer<T> querBuffer(numChannels()); for (int c=0; c < numCh; c++)
for (int c=0; c < m_numChannels; c++)
{ {
querBuffer[c] = m_buffer[c][offset]; out[c] = m_buffer[c][offsets[c]];
} }
return querBuffer;
} }
dsp::Buffer<T> quer(std::initializer_list<int> offsets)
{
Buffer<T> querBuffer(offsets.size());
uint ch = 0;
for (int offset: offsets)
{
querBuffer[ch] = m_buffer[ch][offset];
ch++;
}
return querBuffer;
}
const dsp::Buffer<T> quer(std::initializer_list<int> offsets) const
{
Buffer<T> querBuffer(offsets.size());
uint ch = 0;
for (int offset: offsets)
{
querBuffer[ch] = m_buffer[ch][offset];
ch++;
}
return querBuffer;
}
Buffer<T> at(uint channel) Buffer<T> at(uint channel)
{ {
return m_buffer[channel]; return m_buffer[channel];
-121
View File
@@ -1,121 +0,0 @@
#include "delay/buffer_multi.hpp"
#include "test_common.hpp"
#include <delay/buffer.hpp>
#include <mix.hpp>
#include <cstdio>
#include <iostream>
#include <ostream>
int test_mix_1()
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "Start test_mix_1::shuffle" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
{
dsp::Buffer<int> r_buf(5);
dsp::Buffer<int> t_buf{105, 106, 107, 108, 109};
t_buf = {105, 106, 107, 108, 109};
dsp::Buffer<int> s_spec = {1, 3, 2, 4, 0};
Shuffle<int>::outOfPlace(t_buf, r_buf, s_spec);
print(r_buf, 5, "r-buf");
}
{
dsp::BufferMulti<int> r_buf(5, 5);
dsp::BufferMulti<int> 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<int> s_spec = {-1, 0, -3, 2, -4};
Shuffle<int>::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<int> r_buf(5, 20);
for (int i=0; i < 20; i++)
{
r_buf = 100 +i ;
++r_buf;
}
r_buf.reset();
for (int c=0; c < r_buf.numChannels(); c++)
{
print(r_buf[c], 20, "r-buf");
std::cout << "----------------------------------------------" << std::endl;
}
for (int c=0; c < r_buf.numChannels(); c++)
{
dsp::Buffer<int> v(r_buf[c], c);
print(v, 20, "v-buf");
std::cout << "----------------------------------------------" << std::endl;
}
return 0;
}
int test_mix_3()
{
const int nCh = 5;
dsp::BufferMulti<double> r_buf(nCh, 10);
for (int i=0; i < r_buf.capacity(); i++)
{
r_buf = (double)i/10 ;
++r_buf;
}
// r_buf.reset();
dsp::Buffer<double> qbuf(r_buf.quer({-2, -10, -4, 3, -3}));
dsp::Buffer<double> sbuf(nCh);
dsp::Buffer<double> s_spec = {-1, 0, -3, 2, -4};
Shuffle<double>::outOfPlace(qbuf, sbuf, s_spec);
double *q = sbuf.raw();
for (int i=0; i < nCh; i++)
{
std::cout << q[i] << " ";
}
std::cout << std::endl;
Hadamard<double, nCh>::inPlace(q);
for (int i=0; i < nCh; i++)
{
std::cout << q[i] << " ";
}
std::cout << std::endl;
Householder<double, nCh>::inPlace(q);
for (int i=0; i < nCh; i++)
{
std::cout << q[i] << " ";
}
std::cout << std::endl;
return 0;
}
int test_mix()
{
test_mix_1();
test_mix_2();
test_mix_3();
return 0;
}
+106
View File
@@ -0,0 +1,106 @@
#ifndef REVERB_H
#define REVERB_H
#include <cstdlib>
#include <delay/buffer_multi.hpp>
#include <common/mix.hpp>
template<typename T, size_t numCh>
class Diffusor
{
dsp::BufferMulti<T, numCh> m_dly;
int m_delay_spec[numCh];
int m_shuffle_spec[numCh];
public:
Diffusor(uint maxDelaySize)
: m_dly(maxDelaySize)
{
float delayRagePerWindow = (float)maxDelaySize/(float)numCh;
// Delay spec
for (int i=0; i < numCh; i++)
{
float base_delay = i*delayRagePerWindow;
float z = (float)rand()/(float)RAND_MAX;
int delay = (int)(base_delay + z*delayRagePerWindow);
m_delay_spec[i] = -delay;
}
// Shuffle spec
for (int i=0; i < numCh; i++)
{
m_shuffle_spec[i] = i;
}
// Shuffle values
for (int i=0; i < 2*numCh; i++)
{
int i1 = rand() & (numCh-1);
int i2 = rand() & (numCh-1);
int temp = m_shuffle_spec[i1];
m_shuffle_spec[i1] = m_shuffle_spec[i2];
m_shuffle_spec[i2] = temp;
}
// Shuffle signs
float p = 0.3;
for (int i=0; i < numCh; i++)
{
float z = (float)rand()/(float)RAND_MAX;
if (z <= p)
{
m_shuffle_spec[i] *= (T)-1;
}
}
}
inline T process(T in)
{
m_dly = in;
T qbuf[numCh];
m_dly.quer(qbuf, m_delay_spec);
T sbuf[numCh];
Shuffle<T, numCh>::outOfPlace(qbuf, sbuf, m_shuffle_spec);
Hadamard<T, numCh>::inPlace(sbuf);
Householder<T, numCh>::inPlace(sbuf);
++m_dly;
return sbuf[0];
}
};
template<typename T, uint numCh>
class Reverb
{
std::array<Diffusor<T, numCh>, 3> m_diffusors;
public:
Reverb(uint maxDelay)
: m_diffusors({maxDelay, maxDelay, maxDelay})
{
}
void process(float *in, float *out, unsigned numPoints)
{
for (int i=0; i < numPoints; i++)
{
T temp = in[i];
for (auto diffusor: m_diffusors)
{
temp = diffusor.process(temp);
}
out[i] = temp;
}
}
};
#endif
+1 -1
View File
@@ -11,7 +11,7 @@ TARGET ?= $(NAME)
CXXFLAGS += -std=c++20 CXXFLAGS += -std=c++20
INCLUDES += -I $(realpath .) -I $(realpath ../../) INCLUDES += -I $(realpath .) -I $(realpath ../)
CXX_SRCS := test_main.cpp test_buffer.cpp test_buffer_multi.cpp test_mix.cpp CXX_SRCS := test_main.cpp test_buffer.cpp test_buffer_multi.cpp test_mix.cpp
@@ -3,7 +3,6 @@
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <vector>
int test_buffer_1() int test_buffer_1()
@@ -13,7 +13,7 @@ int test_buffer_multi_1()
std::cout << "Start test_buffer_multi_1()" << std::endl; std::cout << "Start test_buffer_multi_1()" << std::endl;
std::cout << "----------------------------------------------" << std::endl; std::cout << "----------------------------------------------" << std::endl;
dsp::BufferMulti<int>buffer(5, 10); dsp::BufferMulti<int, 5>buffer(10);
printf("Buffer capacity = %zu\n", buffer.capacity()); printf("Buffer capacity = %zu\n", buffer.capacity());
for (int i=0; i < 10; i++) for (int i=0; i < 10; i++)
@@ -49,7 +49,7 @@ int test_buffer_multi_2()
std::cout << "Start test_buffer_multi_2()" << std::endl; std::cout << "Start test_buffer_multi_2()" << std::endl;
std::cout << "----------------------------------------------" << std::endl; std::cout << "----------------------------------------------" << std::endl;
dsp::BufferMulti<int>buffer(5, 3); dsp::BufferMulti<int, 5>buffer(3);
printf("Buffer capacity = %zu\n", buffer.capacity()); printf("Buffer capacity = %zu\n", buffer.capacity());
for (int i=0; i < 10; i++) for (int i=0; i < 10; i++)
@@ -84,7 +84,7 @@ int test_buffer_multi_3()
std::cout << "Start test_buffer_multi_3()" << std::endl; std::cout << "Start test_buffer_multi_3()" << std::endl;
std::cout << "----------------------------------------------" << std::endl; std::cout << "----------------------------------------------" << std::endl;
dsp::BufferMulti<int>buffer(5, 10); dsp::BufferMulti<int, 5>buffer(10);
printf("Buffer capacity = %zu\n", buffer.capacity()); printf("Buffer capacity = %zu\n", buffer.capacity());
for (int i=0; i < 20; i++) for (int i=0; i < 20; i++)
@@ -105,7 +105,7 @@ int test_buffer_multi_4()
std::cout << "Start test_buffer_multi_4()" << std::endl; std::cout << "Start test_buffer_multi_4()" << std::endl;
std::cout << "----------------------------------------------" << std::endl; std::cout << "----------------------------------------------" << std::endl;
dsp::BufferMulti<int>buffer(5, 10); dsp::BufferMulti<int, 5>buffer(10);
printf("Buffer capacity = %zu\n", buffer.capacity()); printf("Buffer capacity = %zu\n", buffer.capacity());
dsp::Buffer<int> *mbv[6]; dsp::Buffer<int> *mbv[6];
@@ -126,7 +126,7 @@ int test_buffer_multi_4()
buffer.reset(); buffer.reset();
for (int c=0; c < 5; c++) for (int c=0; c < 5; c++)
{ {
print(*mbv[c], 10, "mbv[c]"); print(*mbv[c], 10);
} }
return 0; return 0;
} }
@@ -137,7 +137,7 @@ int test_buffer_multi_5()
std::cout << "Start test_buffer_multi_5()" << std::endl; std::cout << "Start test_buffer_multi_5()" << std::endl;
std::cout << "----------------------------------------------" << std::endl; std::cout << "----------------------------------------------" << std::endl;
dsp::BufferMulti<int>buffer(5, 10); dsp::BufferMulti<int, 5>buffer(10);
printf("Buffer capacity = %zu\n", buffer.capacity()); printf("Buffer capacity = %zu\n", buffer.capacity());
for (int i=0; i < 10; i++) for (int i=0; i < 10; i++)
@@ -149,7 +149,9 @@ int test_buffer_multi_5()
buffer.reset(); buffer.reset();
for (int i=0; i < 10; i++) for (int i=0; i < 10; i++)
{ {
print(buffer.quer(i), buffer.quer().capacity(), "Title here 5"); int qbuf[5];
buffer.quer(qbuf, i);
print(qbuf, 5);
} }
return 0; return 0;
@@ -161,7 +163,7 @@ int test_buffer_multi_6()
std::cout << "Start test_buffer_multi_6()" << std::endl; std::cout << "Start test_buffer_multi_6()" << std::endl;
std::cout << "----------------------------------------------" << std::endl; std::cout << "----------------------------------------------" << std::endl;
dsp::BufferMulti<int>buffer(5, 10); dsp::BufferMulti<int, 5>buffer(10);
printf("Buffer capacity = %zu\n", buffer.capacity()); printf("Buffer capacity = %zu\n", buffer.capacity());
for (int i=0; i < 10; i++) for (int i=0; i < 10; i++)
@@ -171,9 +173,12 @@ int test_buffer_multi_6()
} }
buffer.reset(); buffer.reset();
int qbuf[5];
int delays[] = {-2, -1, -4, -5, 0};
for (int i=0; i < 10; i++) for (int i=0; i < 10; i++)
{ {
print(buffer.quer({-2, -1, -4, -5, 0}), buffer.quer().capacity(), "Title here 6"); buffer.quer(qbuf, delays);
print(qbuf, 5);
buffer += 1; buffer += 1;
} }
@@ -10,10 +10,18 @@
#define TEST_COMMON_H #define TEST_COMMON_H
template<typename T> template<typename T>
void print(const dsp::Buffer<T> &v, size_t size, std::string name=std::string("")) void print(const dsp::Buffer<T> &v, size_t size)
{
for(int i=0; i < size; i++)
{
std::cout << v[i] << " ";
}
std::cout << std::endl;
}
template<typename T>
void print(T *v, size_t size)
{ {
std::cout << "----------------------------------------------" << std::endl;
std::cout << "- " << name << ", " << size << std::endl;
for(int i=0; i < size; i++) for(int i=0; i < size; i++)
{ {
std::cout << v[i] << " "; std::cout << v[i] << " ";
@@ -50,8 +58,10 @@ void check(const dsp::Buffer<T> &target, const dsp::Buffer<T> &actual, size_t si
if (!success) if (!success)
{ {
std::cout << "Check failed" << std::endl; std::cout << "Check failed" << std::endl;
print(target, target.capacity(), "Target"); std::cout << "Target" << std::endl;
print(actual, actual.capacity(), "Actual"); print(target, target.capacity());
std::cout << "Actual" << std::endl;
print(actual, actual.capacity());
} }
assert(success); assert(success);
} }
+157
View File
@@ -0,0 +1,157 @@
#include "delay/buffer_multi.hpp"
#include "test_common.hpp"
#include <delay/buffer.hpp>
#include <common/mix.hpp>
#include <reverb/reverb.hpp>
#include <cstdio>
#include <iostream>
#include <ostream>
int test_mix_1()
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "Start test_mix_1::shuffle" << std::endl;
std::cout << "----------------------------------------------" << std::endl;
const int numCh = 5;
{
dsp::Buffer<int> r_buf(5);
dsp::Buffer<int> t_buf{105, 106, 107, 108, 109};
t_buf = {105, 106, 107, 108, 109};
int s_spec[numCh] = {1, 3, 2, 4, 0};
int sbuf[numCh];
Shuffle<int, numCh>::outOfPlace(t_buf.raw(), sbuf, s_spec);
print(r_buf, 5);
}
{
int sbuf[numCh];
int s_spec[numCh] = {-1, 0, -3, 2, -4};
dsp::BufferMulti<int, 5> r_buf(5);
dsp::BufferMulti<int, 5> t_buf{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);
print(t_buf[1], 5);
for (int i=0; i < numCh; i++)
{
Shuffle<int, numCh>::outOfPlace(t_buf[i].raw(), sbuf, s_spec);
print(r_buf[i], 5);
}
}
return 0;
}
int test_mix_2()
{
dsp::BufferMulti<int, 5> r_buf(20);
for (int i=0; i < 20; i++)
{
r_buf = 100 +i ;
++r_buf;
}
r_buf.reset();
for (int c=0; c < r_buf.numChannels(); c++)
{
print(r_buf[c], 20);
std::cout << "----------------------------------------------" << std::endl;
}
for (int c=0; c < r_buf.numChannels(); c++)
{
dsp::Buffer<int> v(r_buf[c], c);
print(v, 20);
std::cout << "----------------------------------------------" << std::endl;
}
return 0;
}
int test_mix_3()
{
const int nCh = 5;
dsp::BufferMulti<double, nCh> r_buf(10);
for (int i=0; i < r_buf.capacity(); i++)
{
r_buf = (double)i/10 ;
++r_buf;
}
// r_buf.reset();
double sbuf[nCh];
double qbuf[nCh];
int delays[nCh] = {-2, -10, -4, 3, -3};
r_buf.quer(qbuf, delays);
int s_spec[nCh] = {-1, 0, -3, 2, -4};
Shuffle<double, nCh>::outOfPlace(qbuf, sbuf, s_spec);
for (int i=0; i < nCh; i++)
{
std::cout << sbuf[i] << " ";
}
std::cout << std::endl;
Hadamard<double, nCh>::inPlace(sbuf);
for (int i=0; i < nCh; i++)
{
std::cout << sbuf[i] << " ";
}
std::cout << std::endl;
Householder<double, nCh>::inPlace(sbuf);
for (int i=0; i < nCh; i++)
{
std::cout << sbuf[i] << " ";
}
std::cout << std::endl;
return 0;
}
void test_diffusor()
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "test_diffusor()" << std::endl;
Diffusor<double, 8> diff(5);
double data_in[10] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7,0.8, 0.9, 1.0};
double data_out[10] = {0, 0, 0, 0, 0, 0, 0,0, 0, 0};
for (int i=0; i < 10; i++)
{
data_out[i] = diff.process(data_in[i]);
}
print(data_out, 10);
}
void test_reverb()
{
std::cout << "----------------------------------------------" << std::endl;
std::cout << "test_reverb()" << std::endl;
Reverb<double, 8> rev(32);
float data_in[10] = {1, 2, 3, 4, 5, 6, 7,8, 9, 10};
float data_out[10] = {0, 0, 0, 0, 0, 0, 0,0, 0, 0};
rev.process(data_in, data_out, 10);
print(data_out, 10);
}
int test_mix()
{
test_mix_1();
test_mix_2();
test_mix_3();
test_reverb();
test_diffusor();
return 0;
}