Skip to content

Commit

Permalink
release and testing
Browse files Browse the repository at this point in the history
  • Loading branch information
FriedDede committed Jul 11, 2022
1 parent e0e84c0 commit 24aed96
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 91 deletions.
14 changes: 8 additions & 6 deletions Jack_AntiLarsen/include/Analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class Analyzer {
public:
explicit Analyzer(const bool *settings);
void run(const float *jackBuffer);
void analyzeBuffer(const float *jackBuffer);
void setInputBuffer(const float *jackBuffer);
void setEnableAlgo(const bool *);
float getPhprThreshold() const;
Expand All @@ -23,27 +23,29 @@ class Analyzer {
int found_howls[N_PEAKS];
virtual ~Analyzer();

std::complex<float> *getFtOut() const;
float *getOutBuffer() const;

private:
bool phpr(const float *);
bool pnpr(const float *);
bool imsd(const float *);
void fftWrapper(const float *);
void updateBuffer(const float *);
static void inline minHead(const float*, int *);
void blackman_win(int);

fftwf_plan ft_plan;
std::complex<float> *ft_in;
float *ft_in;
std::complex<float> *ft_out;
const float *jack_buffer;
float *buffers[3];
float blackman[BUF_LENGTH];
/*
* Thresholds for howling frequencies detection (in dB)
*/
float phpr_threshold = 10.0f;
float pnpr_threshold = 30.0f;
float imsd_threshold = 1.0f;
static constexpr float phpr_threshold = 10.0f;
static constexpr float pnpr_threshold = 25.5f;
static constexpr float imsd_threshold = 1.0f;

bool run_phpr = true;
bool run_pnpr = true;
Expand Down
2 changes: 1 addition & 1 deletion Jack_AntiLarsen/include/DSP.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ class DSP{
bool applyFilters();
void reset_bank();
void add_filter_to_bank(int index,t_filter*);
t_bank bank;
void setInOutBuffers(float *in, float* out, int nframes);
float *getBufOut() const;
private:
float *buf_in;
float *buf_out;
int nframes = 0;
t_bank bank;
};

#endif
10 changes: 8 additions & 2 deletions Jack_AntiLarsen/include/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
#define JACK_ANTILARSEN_CONST_H

#define BUF_LENGTH 1024
#define N_PRE_FILTERS 1024
#define N_PRE_FILTERS 512
#define MAX_ACTIVE_FILTERS 10
#define PI 3.1415926
#define N_PEAKS 10

#define FSTEP 46.875 //Hz
#define INT_TIME 21.333 //ms
/*
* r2c fftw output format:
* https://www.fftw.org/fftw3_doc/The-1d-Real_002ddata-DFT.html
*/
#define FFTOUT_BUF_LENGTH BUF_LENGTH/2+1
#endif
2 changes: 1 addition & 1 deletion Jack_AntiLarsen/include/iir.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class preFiltersBank{
void setQFactor(float new_q_factor);
private:
// Default values
float f_sampling = 44100;
float f_sampling = 48000;
float gb = -10;
float q_factor = 30;
float f_step;
Expand Down
15 changes: 8 additions & 7 deletions Jack_AntiLarsen/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "include/DSP.h"
#include <cstdlib>
#include <cstring>
#include <unistd.h>

jack_port_t *input_port;
jack_port_t *output_port;
Expand All @@ -21,15 +22,15 @@ int process (jack_nframes_t nframes, void *arg){
bool larsen = false;
in = (float *)jack_port_get_buffer (input_port, nframes);
out = (float *)jack_port_get_buffer (output_port, nframes);
analyzer->run(in);
analyzer->analyzeBuffer(in);

dsp->setInOutBuffers(in,out, (int) nframes);
for (auto f_idx: analyzer->found_howls) {
if (f_idx != 0){
dsp->add_filter_to_bank(f_idx, filters->filters);
larsen = true;
// debug only
std::cout << f_idx << std::endl;
std::cout << f_idx*FSTEP << std::endl;
}
}
if (larsen) dsp->applyFilters();
Expand Down Expand Up @@ -60,13 +61,13 @@ int main (int argc, char *argv[])
bool analyzer_settings[3];

/* Default settings */
analyzer_settings[0]= true; // enable pnpr
analyzer_settings[1]= true; // enable phpr
analyzer_settings[0]= true; // enable phpr
analyzer_settings[1]= true; // enable pnpr
analyzer_settings[2]= false; // enable imsd
float f_sampling = 44100;

float gb = -10;
float q_factor = 30;
float f_min = 20;
float f_min = 0;

/* open a client connection to the JACK server */
client = jack_client_open (client_name, options, &status, server_name);
Expand Down Expand Up @@ -186,7 +187,7 @@ int main (int argc, char *argv[])
free (ports);

/* keep running until stopped by the user */
while(true);
sleep(-1);
/* this is never reached but if the program
* had some other way to exit besides being killed,
* they would be important to call.
Expand Down
101 changes: 45 additions & 56 deletions Jack_AntiLarsen/src/Analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,47 @@
Analyzer::Analyzer(const bool settings[3]) {
// locate jack audio buffer
this->jack_buffer = nullptr;
/*
* todo: test fftw_complex *fftw_malloc() for SSE/AVX speedup
*/
this->ft_in = (std::complex<float> *) calloc(BUF_LENGTH, sizeof(std::complex<float>));
this->ft_out = (std::complex<float> *) calloc(BUF_LENGTH, sizeof(std::complex<float>));

for (auto &buf: this->buffers) buf = (float *) calloc(BUF_LENGTH, sizeof(float));
this->ft_in = (float *) calloc(BUF_LENGTH,sizeof(float));
this->ft_out = (std::complex<float> *) fftwf_alloc_complex(FFTOUT_BUF_LENGTH);

for (auto &buf: this->buffers)
buf = (float *) calloc(FFTOUT_BUF_LENGTH, sizeof(float));

for (auto &i: this->found_howls) i = 0;

// select which algorithm will be run
setEnableAlgo(settings);
blackman_win(BUF_LENGTH);
// fftw3 plan creation
this->ft_plan = fftwf_plan_dft_1d(BUF_LENGTH, reinterpret_cast<fftwf_complex *>(ft_in),\
reinterpret_cast<fftwf_complex *>(ft_out), FFTW_FORWARD, FFTW_MEASURE);
this->ft_plan = fftwf_plan_dft_r2c_1d(BUF_LENGTH, ft_in,\
reinterpret_cast<fftwf_complex *>(ft_out), FFTW_MEASURE);

}

void Analyzer::blackman_win(int nsamples) {
int nsamples_periodic = nsamples++;
for (int i = 0; i < (nsamples_periodic+1)/2; ++i) {
int nsamples_periodic = nsamples + 1;
this->blackman[0]=0.0f;
for (int i = 1; i < (nsamples_periodic+1)/2; ++i) {
this->blackman[i]=0.42f -
0.5f*cosf(2.0f*PI*(float)i/(nsamples_periodic-1)) +
0.08f*cosf(4.0f*PI*(float)i/(nsamples_periodic-1));
if (i + (nsamples_periodic+1)/2 < nsamples){
this->blackman[i+(nsamples_periodic+1/2)]= this->blackman[i];
}
this->blackman[nsamples_periodic-i-1]= this->blackman[i];
}
}
/*
* buf_out = abs(fft(buf_in))
* buf_out = abs(fft(jack_buf))
*/
void Analyzer::fftWrapper(const float *buf_in) {
void Analyzer::fftWrapper(const float *jack_buf) {
for (int i = 0; i < BUF_LENGTH; ++i) {
this->ft_in[i] = buf_in[i]*this->blackman[i];
this->ft_in[i] = jack_buf[i]* this->blackman[i];
}
fftwf_execute(this->ft_plan);
for (int i = 0; i < BUF_LENGTH; ++i) {
this->buffers[0][i] = std::abs(this->ft_out[i]);
for (int i = 0; i < (BUF_LENGTH/2)+1; ++i) {
this->buffers[0][i] = std::abs(this->ft_out[i])/213.0f;
}
}

void Analyzer::updateBuffer(const float *jack_buffer_update) {
this->jack_buffer = jack_buffer_update;
}
/*
* Peak to Harmonics Power Ratio:
* Test if the frequency peaks at index[i] has significant harmonics.
Expand All @@ -68,14 +65,14 @@ bool Analyzer::phpr(const float *buf_in) {
for (int i = 0; i < N_PEAKS; ++i) {
if (this->found_howls[i] != 0){
ret = true;
if (i*2 < BUF_LENGTH) {
if (2 * log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] * 2])\
if (i*2 < FFTOUT_BUF_LENGTH) {
if (20 * log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] * 2])\
< phpr_threshold) {
this->found_howls[i] = 0;
}
}
if (i*3 < BUF_LENGTH){
if (2 * log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] * 3])\
if (i*3 < FFTOUT_BUF_LENGTH){
if (20 * log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] * 3])\
< phpr_threshold) {
this->found_howls[i] = 0;
}
Expand All @@ -96,26 +93,14 @@ bool Analyzer::pnpr(const float *buf_in) {
for (int i = 0; i < N_PEAKS; ++i) {
if(this->found_howls[i] != 0){
ret = true;
if (i+1 < BUF_LENGTH){
if (2*log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i]+1])\
< pnpr_threshold) {
this->found_howls[i] = 0;
}
}
if (i+2 < BUF_LENGTH) {
if (2*log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] + 2])\
if (i+1 < FFTOUT_BUF_LENGTH){
if (20 *log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i]+1])\
< pnpr_threshold) {
this->found_howls[i] = 0;
}
}
if (i-1 > 0){
if (2*log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] - 1])\
< pnpr_threshold) {
this->found_howls[i] = 0;
}
}
if (i-2 > 0) {
if (2*log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] - 2])\
if (20 *log10f_fast(buf_in[this->found_howls[i]] / buf_in[this->found_howls[i] - 1])\
< pnpr_threshold) {
this->found_howls[i] = 0;
}
Expand All @@ -138,28 +123,29 @@ bool Analyzer::imsd(const float *buf_in) {
* find 10 highest peaks, run phpr, pnpr, imsd if enabled.
* write howling frequencies indexes in found_howls, if detected.
*/
void Analyzer::run(const float *jackBuffer) {
updateBuffer(jackBuffer);
void Analyzer::analyzeBuffer(const float *jackBuffer) {
// swap buffers order
float *t = this->buffers[2];
this->buffers[2]= this->buffers[1];
this->buffers[1]= this->buffers[0];
this->buffers[0]=t;

setInputBuffer(jackBuffer);
fftWrapper(this->jack_buffer);
float *buf_in = this->buffers[0];
for (int & found_howl : this->found_howls) {
found_howl = 0;
}
for (int i = 0; i < BUF_LENGTH; ++i) {
for (int i = 0; i < FFTOUT_BUF_LENGTH; ++i) {
if (buf_in[i] > buf_in[this->found_howls[0]]){
this->found_howls[0] = i;
minHead(buf_in,this->found_howls);
}
}
// recognize larsen effetcs
if(this->run_pnpr) { if (!pnpr(buf_in)) return; }
if(this->run_phpr) { if (!phpr(buf_in)) return; }
if(this->run_pnpr) { if (!pnpr(buf_in)) return; }
if(this->run_imsd) imsd(buf_in);
// swap buffers order
float *t = this->buffers[2];
this->buffers[2]= this->buffers[1];
this->buffers[1]= this->buffers[0];
this->buffers[0]=t;
}

void inline Analyzer::minHead(const float *buf_in, int *peaks) {
Expand All @@ -183,23 +169,21 @@ Analyzer::~Analyzer() {
fftwf_destroy_plan(this->ft_plan);
free(ft_in);
free(ft_out);
free(found_howls);
for (auto &buf: this->buffers) {
free(buf);
}
free(buffers);
}

float Analyzer::getPhprThreshold() const {
return phpr_threshold;
return this->phpr_threshold;
}

float Analyzer::getPnprThreshold() const {
return pnpr_threshold;
return this->pnpr_threshold;
}

float Analyzer::getImsdThreshold() const {
return imsd_threshold;
return this->imsd_threshold;
}

bool Analyzer::isRunPhpr() const {
Expand All @@ -215,8 +199,13 @@ bool Analyzer::isRunImsd() const {
}

void Analyzer::setInputBuffer(const float *jackBuffer) {
jack_buffer = jackBuffer;
this->jack_buffer = jackBuffer;
}

std::complex<float> *Analyzer::getFtOut() const {
return ft_out;
}


float *Analyzer::getOutBuffer() const {
return buffers[0];
}
28 changes: 15 additions & 13 deletions Jack_AntiLarsen/src/DSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ DSP::DSP() {
}

void DSP::add_filter_to_bank(int index, t_filter filters[]) {
if (this->bank.active_filters < MAX_ACTIVE_FILTERS){
this->bank.p_filter[this->bank.active_filters] = &filters[index];
this->bank.active_filters++;
}
if (this->bank.active_filters == MAX_ACTIVE_FILTERS){
this->bank.p_filter[this->bank.next_insert] = &filters[index];
this->bank.next_insert++;
if (this->bank.next_insert == 9){
this->bank.next_insert = 0;
if (index < N_PRE_FILTERS){
if (this->bank.active_filters < MAX_ACTIVE_FILTERS){
this->bank.p_filter[this->bank.active_filters] = &filters[index];
this->bank.active_filters++;
}
if (this->bank.active_filters == MAX_ACTIVE_FILTERS){
this->bank.p_filter[this->bank.next_insert] = &filters[index];
this->bank.next_insert++;
if (this->bank.next_insert == 9){
this->bank.next_insert = 0;
}
}
}
}
Expand All @@ -41,11 +43,11 @@ bool DSP::applyFilters() {
if (this->bank.p_filter[i] != nullptr){
for (int j = 0; j < BUF_LENGTH; ++j) {
// IIR Filters Equation
buf_out[j] = this->bank.p_filter[i]->e * buf_in[j] +
buf_out[j] = 0.5f*(this->bank.p_filter[i]->e * buf_in[j] +
this->bank.p_filter[i]->p * x_1 +
this->bank.p_filter[i]->d[0] * x_2 +
this->bank.p_filter[i]->d[1] * y_1 +
this->bank.p_filter[i]->d[2] * y_2;
this->bank.p_filter[i]->d[0] * x_2 -
this->bank.p_filter[i]->d[1] * y_1 -
this->bank.p_filter[i]->d[2] * y_2);
// shift delayed x, y samples
x_2 = x_1;
x_1 = buf_in[j];
Expand Down
Loading

0 comments on commit 24aed96

Please sign in to comment.