refactor, higher-order LPF

This commit is contained in:
Sébastien Bourdeauducq 2024-12-30 23:45:14 +08:00 committed by sb
parent b7973f13db
commit cc49d54585
2 changed files with 46 additions and 12 deletions

36
dsp_lib.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
class DDS {
private:
uint32_t phase = 0;
public:
uint32_t ftw = 0;
void set_frequency(double f) {
ftw = f*(double)UINT32_MAX;
}
double get() {
phase += ftw; // wraps on overflow
return sin(phase*2.0*M_PI/(double)UINT32_MAX);
}
};
template<typename T, unsigned int N>
class Lowpass {
private:
double k = 0.0;
T s[N] = {};
public:
void set_bandwidth(double f) {
k = 2.0*M_PI*f;
}
T update(T x) {
T a = x;
for(int i=0;i<N;i++) {
s[i] += (a - s[i])*k;
a = s[i];
}
return a;
}
};

View File

@ -12,6 +12,8 @@
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include "dsp_lib.h"
#define SND_BITS 24 #define SND_BITS 24
#define SND_PCHAN 2 #define SND_PCHAN 2
#define SND_RCHAN 2 #define SND_RCHAN 2
@ -60,12 +62,12 @@ static void dsp_thread()
return; return;
} }
uint32_t phase_out[SND_PCHAN] = { 0 }; DDS dds[SND_PCHAN];
int32_t buf_out[SND_BUFLEN*SND_PCHAN]; int32_t buf_out[SND_BUFLEN*SND_PCHAN];
size_t buf_out_offset = sizeof(buf_out); size_t buf_out_offset = sizeof(buf_out);
uint32_t phase_in[SND_PCHAN] = { 0 }; uint32_t phase_in[SND_PCHAN] = { 0 };
std::complex<double> lpf_y[SND_PCHAN]; Lowpass<std::complex<double>, 4> lpf[SND_PCHAN];
int lpf_count[SND_PCHAN] = { 0 }; int lpf_count[SND_PCHAN] = { 0 };
nfds_t nfds = sio_nfds(hdl); nfds_t nfds = sio_nfds(hdl);
@ -75,21 +77,18 @@ static void dsp_thread()
poll(pfd, nfds, INFTIM); poll(pfd, nfds, INFTIM);
int revents = sio_revents(hdl, pfd); int revents = sio_revents(hdl, pfd);
uint32_t ftw[SND_PCHAN];
double lpf_k[SND_PCHAN]; double lpf_k[SND_PCHAN];
for(int i=0;i<SND_PCHAN;i++) { for(int i=0;i<SND_PCHAN;i++) {
ftw[i] = frequency[i]*(double)UINT32_MAX/SND_RATE; dds[i].set_frequency(frequency[i]/SND_RATE);
lpf_k[i] = 2.0*M_PI*lpf_bandwidth[i]/SND_RATE; lpf[i].set_bandwidth(lpf_bandwidth[i]/SND_RATE);
} }
if(revents & POLLOUT) { if(revents & POLLOUT) {
double scale = pow(2.0, SND_BITS-1) - 1.0; double scale = pow(2.0, SND_BITS-1) - 1.0;
if(buf_out_offset == sizeof(buf_out)) { if(buf_out_offset == sizeof(buf_out)) {
for(int i=0;i<SND_PCHAN;i++) for(int i=0;i<SND_PCHAN;i++)
for(int j=0;j<SND_BUFLEN;j++) { for(int j=0;j<SND_BUFLEN;j++)
buf_out[SND_PCHAN*j+i] = scale*sin(phase_out[i]*2.0*M_PI/(double)UINT32_MAX); buf_out[SND_PCHAN*j+i] = scale*dds[i].get();
phase_out[i] += ftw[i]; // wraps on overflow
}
buf_out_offset = 0; buf_out_offset = 0;
} }
size_t written = sio_write(hdl, (const char *)buf_out + buf_out_offset, sizeof(buf_out) - buf_out_offset); size_t written = sio_write(hdl, (const char *)buf_out + buf_out_offset, sizeof(buf_out) - buf_out_offset);
@ -108,10 +107,9 @@ static void dsp_thread()
sample += (double)buf_in[SND_RCHAN*j+k]; sample += (double)buf_in[SND_RCHAN*j+k];
std::complex<double> rotated; std::complex<double> rotated;
rotated = sample*std::polar(scale, phase_in[i]*2.0*M_PI/(double)UINT32_MAX); rotated = sample*std::polar(scale, phase_in[i]*2.0*M_PI/(double)UINT32_MAX);
phase_in[i] -= ftw[i]; // wraps on underflow phase_in[i] -= dds[i].ftw; // wraps on underflow
lpf_y[i] += (rotated - lpf_y[i])*lpf_k[i]; double mag = std::abs(lpf[i].update(rotated));
double mag = std::abs(lpf_y[i]);
lpf_count[i]++; lpf_count[i]++;
if(lpf_count[i] == 200) { if(lpf_count[i] == 200) {