From 7e5a01f9592be7bfe21b0cb8e534f4c983914ae6 Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Sun, 12 Jan 2025 05:08:18 +0100 Subject: [PATCH] wip noise gate --- gate.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ gate.h | 29 ++++++++++++++++++ guitfx.c | 32 +++++++++++++++++--- meson.build | 1 + 4 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 gate.c create mode 100644 gate.h diff --git a/gate.c b/gate.c new file mode 100644 index 0000000..9eb0949 --- /dev/null +++ b/gate.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include "gate.h" +#include + +void gate_init( + struct gate * gate +) { + + gate->threshold = 0.0; + gate->enable_calibration = false; + + gate->block_size = 1024; + gate->hist_size = 256; + gate->hist_idx = 0; + gate->hist = malloc( sizeof(float) * gate->hist_size ); + gate->cur_block_count = 0; + gate->cur_block_sum = 0.0; +} + +void gate_process( + struct gate * gate, + size_t frame_size, + float const * in, + float * out +) { + float sum = 0.0; + + + int last_frame = 0; + + for( size_t i = 0; i < frame_size; ++i ) { + gate->cur_block_sum += fabs( in[i] ); + gate->cur_block_count += 1; + + if( gate->cur_block_count >= gate->block_size ) { + printf("new block sum [%lu] (frame %lu) : %f\n", gate->hist_idx, i, gate->cur_block_sum); + + if( gate->cur_block_sum > 20.0 ) { + gate->is_active = true; + } else { + gate->is_active = false; + } + + gate->hist[ gate->hist_idx ] = gate->cur_block_sum; + gate->hist_idx = (gate->hist_idx + 1) % gate->hist_size; + gate->cur_block_sum = 0.0; + gate->cur_block_count = 0; + + + last_frame = i; + } + } + + unsigned enable_pos = gate->is_active ? 0 : frame_size; + unsigned disable_pos = gate->is_active ? frame_size : 0; + + unsigned blocks_per_buffer = frame_size / gate->block_size; + + /* start from last block sum and iterate backwards to find + * the timepoint where a block sum crosses the threshold + */ + /* + unsigned i = gate->hist_idx; + while( last_frame > 0 ) { + if( gate->hist[ i ] < gate->threshold ) { + disable_pos = last_frame; + } + + last_frame -= gate->block_size; + i -= 1; + } + */ + + + for( size_t i = 0; i < frame_size; ++i ) { + // if( i >= enable_pos && i < disable_pos ) + if( gate->is_active ) + out[i] = in[i]; + else + out[i] = 0.0; + } +} diff --git a/gate.h b/gate.h new file mode 100644 index 0000000..9456ccd --- /dev/null +++ b/gate.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +struct gate { + float threshold; + bool enable_calibration; + + unsigned block_size; + + unsigned hist_idx; + unsigned hist_size; + float * hist; + + unsigned cur_block_count; + float cur_block_sum; + + bool is_active; +}; + +void gate_init(); +void gate_process( + struct gate * gate, + size_t frame_size, + float const * in, + float * out +); diff --git a/guitfx.c b/guitfx.c index a512079..824310a 100644 --- a/guitfx.c +++ b/guitfx.c @@ -15,8 +15,10 @@ #include "delay.h" #include "sust.h" +#include "gate.h" float envelope( float x ); + struct data; struct port { @@ -34,6 +36,7 @@ struct data { uint64_t last_tap; struct delay delay; struct sust sust; + struct gate gate; unsigned prog; @@ -100,7 +103,16 @@ static void on_process(void *userdata, struct spa_io_position *position) break; case 0x42: - // sust pedal + + // noise gate calibration + if( data->prog == 2 ) { + if( midi_data[2] >= 64) { + data->gate.threshold = 0.0;//data->gate.cur_avg; + printf("calibrate noise gate: threshold = %f\n", data->gate.threshold); + } + } + + // sust pedal if( data->prog == 1 ) { if( midi_data[2] >= 64) { sust_swap( &data->sust ); @@ -133,6 +145,15 @@ static void on_process(void *userdata, struct spa_io_position *position) case 0xc0: // program change + if( midi_data[2] >= 64) { + sust_swap( &data->sust ); + data->sust.playing = true; + + data->sust.start_idx = data->sust.idx; + data->sust.idx = 0; + } else { + data->sust.playing = false; + } printf("program change: %u\n", midi_data[1]); data->prog = midi_data[1]; break; @@ -155,11 +176,13 @@ static void on_process(void *userdata, struct spa_io_position *position) float * const in = pw_filter_get_dsp_buffer(data->guit_in_port, n_samples); - float tmp[n_samples]; + float tmp1[n_samples]; + float tmp2[n_samples]; float * out = pw_filter_get_dsp_buffer(data->out_port, n_samples); if( in && out ) { - sust_process( &data->sust, n_samples, in, tmp ); - delay_process( &data->delay, n_samples, tmp, out ); + gate_process( &data->gate, n_samples, in, tmp1 ); + sust_process( &data->sust, n_samples, tmp1, tmp2 ); + delay_process( &data->delay, n_samples, tmp2, out ); } } @@ -178,6 +201,7 @@ int main(int argc, char *argv[]) { struct data data = { 0, }; + gate_init( &data.gate ); delay_init( &data.delay ); sust_init( &data.sust ); data.prog = 0; diff --git a/meson.build b/meson.build index 9fc0dd8..d59ef2b 100644 --- a/meson.build +++ b/meson.build @@ -9,5 +9,6 @@ executable( 'guitfx.c', 'delay.c', 'sust.c', + 'gate.c', dependencies : [pipewire_dep, m_dep], )