From 7e5a01f9592be7bfe21b0cb8e534f4c983914ae6 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
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 <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "gate.h"
+#include <math.h>
+
+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 <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+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],
 )