From bcead0e0b5034de1d78f9cfa79505815385a473b Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Sun, 12 Jan 2025 05:07:05 +0100 Subject: [PATCH 01/10] expr pedal threshold --- guitfx.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/guitfx.c b/guitfx.c index 052e37a..a512079 100644 --- a/guitfx.c +++ b/guitfx.c @@ -87,13 +87,16 @@ static void on_process(void *userdata, struct spa_io_position *position) switch( midi_data[1] ) { case 0x0b: // expr pedal - float val_f = ((float)midi_data[2]) / 128.0; - printf("Expr Pedal %f\n", val_f); - if ( val_f > 0.1 ) { - data->delay.mix = val_f; - } else { - data->delay.mix = 0.0; - } + float val_f = ((float)midi_data[2]) / 128.0; + + float thres = 0.4; + + if ( val_f > thres ) { + printf("Expr Pedal %f\n", val_f); + data->delay.mix = (val_f - thres) / (1.0-thres); + } else { + data->delay.mix = 0.0; + } break; case 0x42: 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 02/10] 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], ) From f4bbf94e30fb54e16bfd9fc2cb54284cd885e73b Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Mon, 27 Jan 2025 21:27:49 +0100 Subject: [PATCH 03/10] noise gate: simple attack&release envelope --- gate.c | 37 ++++++++++++++++++++++++------------- gate.h | 4 ++++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/gate.c b/gate.c index 9eb0949..a25a39c 100644 --- a/gate.c +++ b/gate.c @@ -8,7 +8,6 @@ void gate_init( struct gate * gate ) { - gate->threshold = 0.0; gate->enable_calibration = false; @@ -17,7 +16,12 @@ void gate_init( gate->hist_idx = 0; gate->hist = malloc( sizeof(float) * gate->hist_size ); gate->cur_block_count = 0; - gate->cur_block_sum = 0.0; + gate->cur_block_sum = 0.0; + + gate->is_active = false; + gate->cur_gain = 1.0; + gate->attack = 1.0 / 4096.0; + gate->release = 1.0 / 4096.0; } void gate_process( @@ -53,7 +57,7 @@ void gate_process( last_frame = i; } } - + /* unsigned enable_pos = gate->is_active ? 0 : frame_size; unsigned disable_pos = gate->is_active ? frame_size : 0; @@ -61,8 +65,8 @@ void gate_process( /* 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 ) { @@ -70,16 +74,23 @@ void gate_process( } last_frame -= gate->block_size; - i -= 1; + i = (i - 1) % gate->hist_size; } - */ - +*/ 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; + if( gate->is_active ) { + gate->cur_gain += gate->attack; + if( gate->cur_gain > 1.0 ) { + gate->cur_gain = 1.0; + } + } else { + gate->cur_gain -= gate->attack; + if( gate->cur_gain < 0.0 ) { + gate->cur_gain = 0.0; + } + } + + out[i] = in[i] * gate->cur_gain; } } diff --git a/gate.h b/gate.h index 9456ccd..c921d1b 100644 --- a/gate.h +++ b/gate.h @@ -18,6 +18,10 @@ struct gate { float cur_block_sum; bool is_active; + float cur_gain; + + float attack; + float release; }; void gate_init(); From e36a4635e8632b12819eac3d1f417c722c00c237 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Mon, 27 Jan 2025 23:16:59 +0100 Subject: [PATCH 04/10] simplify noise gate --- gate.c | 70 +++++++++++++++----------------------------------------- gate.h | 6 +---- guitfx.c | 2 +- 3 files changed, 21 insertions(+), 57 deletions(-) diff --git a/gate.c b/gate.c index a25a39c..bb11f25 100644 --- a/gate.c +++ b/gate.c @@ -12,15 +12,12 @@ void gate_init( 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; gate->is_active = false; gate->cur_gain = 1.0; - gate->attack = 1.0 / 4096.0; + gate->attack = 1.0 / 512.0; gate->release = 1.0 / 4096.0; } @@ -30,67 +27,38 @@ void gate_process( float const * in, float * out ) { - float sum = 0.0; - - int last_frame = 0; + bool act = false; for( size_t i = 0; i < frame_size; ++i ) { gate->cur_block_sum += fabs( in[i] ); - gate->cur_block_count += 1; + 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); + //printf("new block sum %f, gain = %f\n", gate->cur_block_sum, gate->cur_gain); - if( gate->cur_block_sum > 20.0 ) { - gate->is_active = true; + gate->last_block_sum = gate->cur_block_sum; + gate->cur_block_sum = 0.0; + + if( gate->last_block_sum > 0.03 ) { + act = true; } else { - gate->is_active = false; + act = 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 = (i - 1) % gate->hist_size; - } -*/ - - for( size_t i = 0; i < frame_size; ++i ) { - if( gate->is_active ) { - gate->cur_gain += gate->attack; - if( gate->cur_gain > 1.0 ) { + if( act ) { + gate->cur_gain += gate->attack; + if( gate->cur_gain > 1.0 ) { gate->cur_gain = 1.0; } - } else { - gate->cur_gain -= gate->attack; - if( gate->cur_gain < 0.0 ) { + } else { + gate->cur_gain -= gate->release; + if( gate->cur_gain < 0.0 ) { gate->cur_gain = 0.0; } - } + } - out[i] = in[i] * gate->cur_gain; - } + out[i] = in[i] * gate->cur_gain; + } } diff --git a/gate.h b/gate.h index c921d1b..7f96d6a 100644 --- a/gate.h +++ b/gate.h @@ -9,13 +9,9 @@ struct gate { bool enable_calibration; unsigned block_size; - - unsigned hist_idx; - unsigned hist_size; - float * hist; - unsigned cur_block_count; float cur_block_sum; + float last_block_sum; bool is_active; float cur_gain; diff --git a/guitfx.c b/guitfx.c index 824310a..11ffe2c 100644 --- a/guitfx.c +++ b/guitfx.c @@ -107,7 +107,7 @@ static void on_process(void *userdata, struct spa_io_position *position) // noise gate calibration if( data->prog == 2 ) { if( midi_data[2] >= 64) { - data->gate.threshold = 0.0;//data->gate.cur_avg; + data->gate.threshold = data->gate.cur_block_sum * 0.8; printf("calibrate noise gate: threshold = %f\n", data->gate.threshold); } } From ce2212708a54cbe6c79bab3165301c4c35206c40 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Thu, 13 Feb 2025 18:00:59 +0100 Subject: [PATCH 05/10] up expr threshold --- guitfx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/guitfx.c b/guitfx.c index 11ffe2c..561156e 100644 --- a/guitfx.c +++ b/guitfx.c @@ -92,11 +92,12 @@ static void on_process(void *userdata, struct spa_io_position *position) // expr pedal float val_f = ((float)midi_data[2]) / 128.0; - float thres = 0.4; + float thres = 0.5; if ( val_f > thres ) { - printf("Expr Pedal %f\n", val_f); - data->delay.mix = (val_f - thres) / (1.0-thres); + float expr_mix = (val_f - thres) / (1.0-thres); + printf("Expr Pedal %f\n", expr_mix); + data->delay.mix = expr_mix; } else { data->delay.mix = 0.0; } From 62acece20421a86bb769128a3bd8df2871e1ff65 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Mon, 17 Feb 2025 17:56:58 +0100 Subject: [PATCH 06/10] gate: decrease attack, increase release --- gate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gate.c b/gate.c index bb11f25..8829c9f 100644 --- a/gate.c +++ b/gate.c @@ -17,8 +17,8 @@ void gate_init( gate->is_active = false; gate->cur_gain = 1.0; - gate->attack = 1.0 / 512.0; - gate->release = 1.0 / 4096.0; + gate->attack = 1.0 / 128.0; + gate->release = 1.0 / 8192.0; } void gate_process( From a6970aeed3b1f28b7f0dfc4ec2d2acec0a707675 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Mon, 17 Feb 2025 18:06:56 +0100 Subject: [PATCH 07/10] clang format --- delay.c | 47 ++++--- delay.h | 19 ++- gate.c | 62 ++++----- gate.h | 33 +++-- guitfx.c | 400 ++++++++++++++++++++++++++----------------------------- sust.c | 78 ++++++----- sust.h | 18 ++- 7 files changed, 315 insertions(+), 342 deletions(-) diff --git a/delay.c b/delay.c index 31f3089..1723ca9 100644 --- a/delay.c +++ b/delay.c @@ -1,12 +1,12 @@ -#include <stdint.h> -#include <stddef.h> -#include <stdlib.h> -#include <stdio.h> #include "delay.h" +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> void delay_init( - struct delay * delay -) { + struct delay* delay) +{ delay->mix = 0.8; delay->feedback = 0.8; delay->duration = 0; @@ -16,39 +16,38 @@ void delay_init( } void delay_set_time( - struct delay * delay, - uint64_t new_duration -) { + struct delay* delay, + uint64_t new_duration) +{ printf("set delay duration to %lu samples\n", new_duration); - if( new_duration > delay->buf_capacity ) { + if (new_duration > delay->buf_capacity) { delay->buf_capacity = new_duration; - delay->buf = realloc( delay->buf, sizeof(float) * new_duration ); + delay->buf = realloc(delay->buf, sizeof(float) * new_duration); } - for( int i = delay->duration; i < new_duration; ++i ) { + for (int i = delay->duration; i < new_duration; ++i) { delay->buf[i] = delay->buf[i - delay->duration]; } delay->duration = new_duration; - if( new_duration > 0 ) { + if (new_duration > 0) { delay->buf_idx %= new_duration; } } void delay_process( - struct delay * delay, + struct delay* delay, size_t frame_size, - float const * in, - float * out -) { - for( size_t i = 0; i < frame_size; ++i ) { - if( delay->duration > 0 ) { - out[i] = - in[i] - + delay->mix * delay->buf[ delay->buf_idx ]; + float const* in, + float* out) +{ + for (size_t i = 0; i < frame_size; ++i) { + if (delay->duration > 0) { + out[i] = in[i] + + delay->mix * delay->buf[delay->buf_idx]; - delay->buf[ delay->buf_idx ] *= delay->feedback; - delay->buf[ delay->buf_idx ] += (1.0 - delay->feedback) * in[i]; + delay->buf[delay->buf_idx] *= delay->feedback; + delay->buf[delay->buf_idx] += (1.0 - delay->feedback) * in[i]; delay->buf_idx = (delay->buf_idx + 1) % delay->duration; } else { out[i] = 0.5 * in[i]; diff --git a/delay.h b/delay.h index 4ed2cf5..499b1cc 100644 --- a/delay.h +++ b/delay.h @@ -1,7 +1,7 @@ #pragma once -#include <stdint.h> #include <stddef.h> +#include <stdint.h> struct delay { uint64_t duration; @@ -10,21 +10,18 @@ struct delay { uint64_t buf_idx; size_t buf_capacity; - float * buf; + float* buf; }; void delay_init( - struct delay * delay -); + struct delay* delay); void delay_set_time( - struct delay * delay, - uint64_t new_duration -); + struct delay* delay, + uint64_t new_duration); void delay_process( - struct delay * delay, + struct delay* delay, size_t frame_size, - float const * in, - float * out -); + float const* in, + float* out); diff --git a/gate.c b/gate.c index 8829c9f..3f13c6a 100644 --- a/gate.c +++ b/gate.c @@ -1,13 +1,13 @@ -#include <stdint.h> -#include <stddef.h> -#include <stdlib.h> -#include <stdio.h> #include "gate.h" #include <math.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> void gate_init( - struct gate * gate -) { + struct gate* gate) +{ gate->threshold = 0.0; gate->enable_calibration = false; @@ -22,42 +22,42 @@ void gate_init( } void gate_process( - struct gate * gate, + struct gate* gate, size_t frame_size, - float const * in, - float * out -) { + float const* in, + float* out) +{ - bool act = false; + bool act = false; - for( size_t i = 0; i < frame_size; ++i ) { - gate->cur_block_sum += fabs( in[i] ); - gate->cur_block_count += 1; + 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 %f, gain = %f\n", gate->cur_block_sum, gate->cur_gain); + if (gate->cur_block_count >= gate->block_size) { + // printf("new block sum %f, gain = %f\n", gate->cur_block_sum, gate->cur_gain); - gate->last_block_sum = gate->cur_block_sum; - gate->cur_block_sum = 0.0; + gate->last_block_sum = gate->cur_block_sum; + gate->cur_block_sum = 0.0; - if( gate->last_block_sum > 0.03 ) { - act = true; - } else { - act = false; - } - } + if (gate->last_block_sum > 0.03) { + act = true; + } else { + act = false; + } + } - if( act ) { - gate->cur_gain += gate->attack; - if( gate->cur_gain > 1.0 ) { + if (act) { + gate->cur_gain += gate->attack; + if (gate->cur_gain > 1.0) { gate->cur_gain = 1.0; } - } else { - gate->cur_gain -= gate->release; - if( gate->cur_gain < 0.0 ) { + } else { + gate->cur_gain -= gate->release; + if (gate->cur_gain < 0.0) { gate->cur_gain = 0.0; } - } + } out[i] = in[i] * gate->cur_gain; } diff --git a/gate.h b/gate.h index 7f96d6a..3773e5c 100644 --- a/gate.h +++ b/gate.h @@ -1,29 +1,28 @@ #pragma once -#include <stdint.h> -#include <stddef.h> #include <stdbool.h> +#include <stddef.h> +#include <stdint.h> struct gate { - float threshold; - bool enable_calibration; + float threshold; + bool enable_calibration; - unsigned block_size; - unsigned cur_block_count; - float cur_block_sum; - float last_block_sum; + unsigned block_size; + unsigned cur_block_count; + float cur_block_sum; + float last_block_sum; - bool is_active; - float cur_gain; + bool is_active; + float cur_gain; - float attack; - float release; + float attack; + float release; }; void gate_init(); void gate_process( - struct gate * gate, - size_t frame_size, - float const * in, - float * out -); + struct gate* gate, + size_t frame_size, + float const* in, + float* out); diff --git a/guitfx.c b/guitfx.c index 561156e..90d2f4f 100644 --- a/guitfx.c +++ b/guitfx.c @@ -2,283 +2,259 @@ #include "pipewire/port.h" #include "spa/pod/iter.h" #include "spa/utils/defs.h" -#include <stdio.h> #include <signal.h> +#include <stdio.h> -#include <spa/pod/pod.h> -#include <spa/pod/builder.h> #include <spa/control/control.h> #include <spa/param/latency-utils.h> +#include <spa/pod/builder.h> +#include <spa/pod/pod.h> -#include <pipewire/pipewire.h> #include <pipewire/filter.h> +#include <pipewire/pipewire.h> #include "delay.h" -#include "sust.h" #include "gate.h" +#include "sust.h" -float envelope( float x ); +float envelope(float x); struct data; struct port { - struct data *data; + struct data* data; }; struct data { - struct pw_main_loop * loop; - struct pw_filter * filter; - struct port * guit_in_port; - struct port * midi_in_port; - struct port * out_port; + struct pw_main_loop* loop; + struct pw_filter* filter; + struct port* guit_in_port; + struct port* midi_in_port; + struct port* out_port; - //! effect data - uint64_t last_tap; - struct delay delay; - struct sust sust; - struct gate gate; + //! effect data + uint64_t last_tap; + struct delay delay; + struct sust sust; + struct gate gate; - unsigned prog; + unsigned prog; - //! elapsed time in number of samples - uint64_t time; + //! elapsed time in number of samples + uint64_t time; }; -static void on_process(void *userdata, struct spa_io_position *position) +static void on_process(void* userdata, struct spa_io_position* position) { - struct data *data = userdata; + struct data* data = userdata; - uint32_t n_samples = position->clock.duration; - uint64_t frame = data->time; - data->time += n_samples; + uint32_t n_samples = position->clock.duration; + uint64_t frame = data->time; + data->time += n_samples; - struct pw_buffer * b = pw_filter_dequeue_buffer(data->midi_in_port); - if( b == NULL ) { - fprintf(stderr, "on_process(): no buffer for midi_in_port\n"); - return; - } + struct pw_buffer* b = pw_filter_dequeue_buffer(data->midi_in_port); + if (b == NULL) { + fprintf(stderr, "on_process(): no buffer for midi_in_port\n"); + return; + } - struct spa_buffer * buf = b->buffer; - spa_assert(buf->n_datas == 1); - struct spa_data * d = &buf->datas[0]; + struct spa_buffer* buf = b->buffer; + spa_assert(buf->n_datas == 1); + struct spa_data* d = &buf->datas[0]; - if( d->data ) { - struct spa_pod * pod = - spa_pod_from_data( - d->data, - d->maxsize, - d->chunk->offset, - d->chunk->size - ); + if (d->data) { + struct spa_pod* pod = spa_pod_from_data(d->data, d->maxsize, + d->chunk->offset, d->chunk->size); - if( pod ) { - if( spa_pod_is_sequence(pod) ) { - struct spa_pod_sequence * pod_seq = (struct spa_pod_sequence*) pod; - struct spa_pod_control * c; - SPA_POD_SEQUENCE_FOREACH(pod_seq, c) { - if( c->type == SPA_CONTROL_Midi ) { - unsigned sec = - (frame + c->offset) - / (float) position->clock.rate.denom; - char * midi_data = SPA_POD_BODY(&c->value); - unsigned size = SPA_POD_BODY_SIZE(&c->value); + if (pod) { + if (spa_pod_is_sequence(pod)) { + struct spa_pod_sequence* pod_seq = (struct spa_pod_sequence*)pod; + struct spa_pod_control* c; + SPA_POD_SEQUENCE_FOREACH(pod_seq, c) + { + if (c->type == SPA_CONTROL_Midi) { + unsigned sec = (frame + c->offset) / (float)position->clock.rate.denom; + char* midi_data = SPA_POD_BODY(&c->value); + unsigned size = SPA_POD_BODY_SIZE(&c->value); - printf("[%d] MIDI message (%d bytes) : %x, %x, %x\n", sec, size, midi_data[0], midi_data[1], midi_data[2]); + printf("[%d] MIDI message (%d bytes) : %x, %x, %x\n", sec, size, + midi_data[0], midi_data[1], midi_data[2]); - switch( midi_data[0] & 0xff ) { - case 0xb0: - switch( midi_data[1] ) { - case 0x0b: - // expr pedal - float val_f = ((float)midi_data[2]) / 128.0; + switch (midi_data[0] & 0xff) { + case 0xb0: + switch (midi_data[1]) { + case 0x0b: + // expr pedal + float val_f = ((float)midi_data[2]) / 128.0; - float thres = 0.5; - - if ( val_f > thres ) { - float expr_mix = (val_f - thres) / (1.0-thres); - printf("Expr Pedal %f\n", expr_mix); - data->delay.mix = expr_mix; - } else { - data->delay.mix = 0.0; - } - break; + float thres = 0.5; - case 0x42: + if (val_f > thres) { + float expr_mix = (val_f - thres) / (1.0 - thres); + printf("Expr Pedal %f\n", expr_mix); + data->delay.mix = expr_mix; + } else { + data->delay.mix = 0.0; + } + break; - // noise gate calibration - if( data->prog == 2 ) { - if( midi_data[2] >= 64) { - data->gate.threshold = data->gate.cur_block_sum * 0.8; - printf("calibrate noise gate: threshold = %f\n", data->gate.threshold); - } - } + case 0x42: - // sust pedal - if( data->prog == 1 ) { - if( midi_data[2] >= 64) { - sust_swap( &data->sust ); - data->sust.playing = true; + // noise gate calibration + if (data->prog == 2) { + if (midi_data[2] >= 64) { + data->gate.threshold = data->gate.cur_block_sum * 0.8; + printf("calibrate noise gate: threshold = %f\n", + data->gate.threshold); + } + } - data->sust.start_idx = data->sust.idx; - data->sust.idx = 0; - } else { - data->sust.playing = false; - } - } + // sust pedal + if (data->prog == 1) { + if (midi_data[2] >= 64) { + sust_swap(&data->sust); + data->sust.playing = true; - // tap tempo - if( data->prog == 0 ) { - uint64_t cur_tap = frame + c->offset; - uint64_t duration = cur_tap - data->last_tap; - data->last_tap = cur_tap; - if( duration < (4*position->clock.rate.denom) ) { - delay_set_time( &data->delay, duration ); - } + data->sust.start_idx = data->sust.idx; + data->sust.idx = 0; + } else { + data->sust.playing = false; + } + } + // tap tempo + if (data->prog == 0) { + uint64_t cur_tap = frame + c->offset; + uint64_t duration = cur_tap - data->last_tap; + data->last_tap = cur_tap; + if (duration < (4 * position->clock.rate.denom)) { + delay_set_time(&data->delay, duration); + } - sust_resize( &data->sust, duration ); - } + sust_resize(&data->sust, duration); + } - break; - } + break; + } - break; + break; - case 0xc0: - // program change - if( midi_data[2] >= 64) { - sust_swap( &data->sust ); - data->sust.playing = true; + 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; - } - } else { - printf("on_process(): non midi-control\n"); - } - } - } else { - fprintf(stderr, "on_process(): unexpected POD that is not a sequence (midi_in_port)\n"); - } - } else { - fprintf(stderr, "on_process(): pod is NULL\n"); - } - } else { - fprintf(stderr, "on_process(): no data in buffer of midi_in_port\n"); - } + 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; + } + } else { + printf("on_process(): non midi-control\n"); + } + } + } else { + fprintf(stderr, "on_process(): unexpected POD that is not a sequence " + "(midi_in_port)\n"); + } + } else { + fprintf(stderr, "on_process(): pod is NULL\n"); + } + } else { + fprintf(stderr, "on_process(): no data in buffer of midi_in_port\n"); + } - pw_filter_queue_buffer(data->midi_in_port, b); + pw_filter_queue_buffer(data->midi_in_port, b); - - float * const in = pw_filter_get_dsp_buffer(data->guit_in_port, 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 ) { - gate_process( &data->gate, n_samples, in, tmp1 ); - sust_process( &data->sust, n_samples, tmp1, tmp2 ); - delay_process( &data->delay, n_samples, tmp2, out ); - } + float* const in = pw_filter_get_dsp_buffer(data->guit_in_port, 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) { + gate_process(&data->gate, n_samples, in, tmp1); + sust_process(&data->sust, n_samples, tmp1, tmp2); + delay_process(&data->delay, n_samples, tmp2, out); + } } static const struct pw_filter_events filter_events = { - PW_VERSION_FILTER_EVENTS, - .process = on_process, + PW_VERSION_FILTER_EVENTS, + .process = on_process, }; -static void do_quit(void *userdata, int signal_number) +static void do_quit(void* userdata, int signal_number) { - struct data *data = userdata; - pw_main_loop_quit(data->loop); + struct data* data = userdata; + pw_main_loop_quit(data->loop); } -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - struct data data = { 0, }; + struct data data = { + 0, + }; - gate_init( &data.gate ); - delay_init( &data.delay ); - sust_init( &data.sust ); - data.prog = 0; + gate_init(&data.gate); + delay_init(&data.delay); + sust_init(&data.sust); + data.prog = 0; - const struct spa_pod *params[1]; - uint8_t buffer[1024]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + const struct spa_pod* params[1]; + uint8_t buffer[1024]; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - pw_init(&argc, &argv); + pw_init(&argc, &argv); - data.loop = pw_main_loop_new(NULL); + data.loop = pw_main_loop_new(NULL); - pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGINT, do_quit, &data); - pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGTERM, do_quit, &data); + pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGINT, do_quit, &data); + pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGTERM, do_quit, &data); - data.filter = pw_filter_new_simple( - pw_main_loop_get_loop(data.loop), - "Guitar FX", - pw_properties_new( - PW_KEY_MEDIA_TYPE, "Audio", - PW_KEY_MEDIA_CATEGORY, "Filter", - PW_KEY_MEDIA_ROLE, "DSP", - NULL), - &filter_events, - &data); + data.filter = pw_filter_new_simple( + pw_main_loop_get_loop(data.loop), "Guitar FX", + pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, + "Filter", PW_KEY_MEDIA_ROLE, "DSP", NULL), + &filter_events, &data); - data.midi_in_port = pw_filter_add_port(data.filter, - PW_DIRECTION_INPUT, - PW_FILTER_PORT_FLAG_MAP_BUFFERS, - sizeof(struct port), - pw_properties_new( - PW_KEY_FORMAT_DSP, "8 bit raw midi", - PW_KEY_PORT_NAME, "midi in", - NULL - ), - NULL, 0 - ); + data.midi_in_port = pw_filter_add_port(data.filter, PW_DIRECTION_INPUT, + PW_FILTER_PORT_FLAG_MAP_BUFFERS, sizeof(struct port), + pw_properties_new(PW_KEY_FORMAT_DSP, "8 bit raw midi", + PW_KEY_PORT_NAME, "midi in", NULL), + NULL, 0); - data.guit_in_port = pw_filter_add_port(data.filter, - PW_DIRECTION_INPUT, - PW_FILTER_PORT_FLAG_MAP_BUFFERS, - sizeof(struct port), - pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit float mono audio", - PW_KEY_PORT_NAME, "guitar in", - NULL), - NULL, 0); + data.guit_in_port = pw_filter_add_port( + data.filter, PW_DIRECTION_INPUT, PW_FILTER_PORT_FLAG_MAP_BUFFERS, + sizeof(struct port), + pw_properties_new(PW_KEY_FORMAT_DSP, "32 bit float mono audio", + PW_KEY_PORT_NAME, "guitar in", NULL), + NULL, 0); - data.out_port = pw_filter_add_port(data.filter, - PW_DIRECTION_OUTPUT, - PW_FILTER_PORT_FLAG_MAP_BUFFERS, - sizeof(struct port), - pw_properties_new( - PW_KEY_FORMAT_DSP, "32 bit float mono audio", - PW_KEY_PORT_NAME, "fx out", - NULL), - NULL, 0); + data.out_port = pw_filter_add_port( + data.filter, PW_DIRECTION_OUTPUT, PW_FILTER_PORT_FLAG_MAP_BUFFERS, + sizeof(struct port), + pw_properties_new(PW_KEY_FORMAT_DSP, "32 bit float mono audio", + PW_KEY_PORT_NAME, "fx out", NULL), + NULL, 0); - params[0] = spa_process_latency_build(&b, - SPA_PARAM_ProcessLatency, - &SPA_PROCESS_LATENCY_INFO_INIT( - .ns = 10 * SPA_NSEC_PER_MSEC - )); + params[0] = spa_process_latency_build( + &b, SPA_PARAM_ProcessLatency, + &SPA_PROCESS_LATENCY_INFO_INIT(.ns = 10 * SPA_NSEC_PER_MSEC)); - if (pw_filter_connect(data.filter, - PW_FILTER_FLAG_RT_PROCESS, - params, 1) < 0) { - fprintf(stderr, "can't connect\n"); - return -1; - } + if (pw_filter_connect(data.filter, PW_FILTER_FLAG_RT_PROCESS, params, 1) < 0) { + fprintf(stderr, "can't connect\n"); + return -1; + } - pw_main_loop_run(data.loop); + pw_main_loop_run(data.loop); - pw_filter_destroy(data.filter); - pw_main_loop_destroy(data.loop); - pw_deinit(); + pw_filter_destroy(data.filter); + pw_main_loop_destroy(data.loop); + pw_deinit(); - return 0; + return 0; } diff --git a/sust.c b/sust.c index d684930..f9d31a2 100644 --- a/sust.c +++ b/sust.c @@ -1,9 +1,10 @@ #include "sust.h" #include <math.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> -void sust_init( struct sust * sust ) { +void sust_init(struct sust* sust) +{ sust->mode = MODE_Sostenuto; sust->playing = false; @@ -12,73 +13,76 @@ void sust_init( struct sust * sust ) { sust->idx = 0; sust->buf_len = 51200; - sust->record_buf = malloc( sizeof(float) * sust->buf_len ); - sust->play_buf = malloc( sizeof(float) * sust->buf_len ); + sust->record_buf = malloc(sizeof(float) * sust->buf_len); + sust->play_buf = malloc(sizeof(float) * sust->buf_len); } -float envelope( float x ) { - if( x < 0.4 ) +float envelope(float x) +{ + if (x < 0.4) return (x / 0.4) * (x / 0.4); - if( x < 0.6 ) + if (x < 0.6) return 1.0; - float v = 1.0 - ((x - 0.6) / 0.4); - return v*v; + float v = 1.0 - ((x - 0.6) / 0.4); + return v * v; } -float softcos( float x ) { - return sin( x * (3.141 / 2.0) ); +float softcos(float x) +{ + return sin(x * (3.141 / 2.0)); } -void sust_resize( struct sust * sust, size_t new_len ) { - sust->buf_len = new_len; - sust->play_buf = realloc( sust->play_buf, sizeof(float) * new_len ); - sust->record_buf = realloc( sust->record_buf, sizeof(float) * new_len ); - sust->idx %= new_len; +void sust_resize(struct sust* sust, size_t new_len) +{ + sust->buf_len = new_len; + sust->play_buf = realloc(sust->play_buf, sizeof(float) * new_len); + sust->record_buf = realloc(sust->record_buf, sizeof(float) * new_len); + sust->idx %= new_len; } void sust_swap( - struct sust * sust -) { - float * tmp = sust->play_buf; + struct sust* sust) +{ + float* tmp = sust->play_buf; sust->play_buf = sust->record_buf; sust->record_buf = tmp; - for( int i = 0; i < sust->buf_len; ++i ) { + for (int i = 0; i < sust->buf_len; ++i) { sust->record_buf[i] = sust->play_buf[i]; } } void sust_process( - struct sust * sust, + struct sust* sust, size_t frame_size, - float const * in, - float * out -) { - for( size_t i = 0; i < frame_size; ++i ) { + float const* in, + float* out) +{ + for (size_t i = 0; i < frame_size; ++i) { - if( sust->mode == MODE_Sustain && sust->idx == 0 ) { - sust_swap( sust ); + if (sust->mode == MODE_Sustain && sust->idx == 0) { + sust_swap(sust); } float out_value = in[i]; - if( sust->playing ) { + if (sust->playing) { int n_voices = 5; - for( int v = 0; v < n_voices; ++v ) { - size_t play_idx = (sust->start_idx + sust->idx + ((v*sust->buf_len)/n_voices)) % sust->buf_len; - float gain = envelope( ((float) play_idx) / ((float)sust->buf_len) ); - //printf("gain = %f\n", gain); - out_value += 0.5 *gain * sust->play_buf[ play_idx ]; + for (int v = 0; v < n_voices; ++v) { + size_t play_idx = (sust->start_idx + sust->idx + ((v * sust->buf_len) / n_voices)) % sust->buf_len; + float gain = envelope(((float)play_idx) / ((float)sust->buf_len)); + // printf("gain = %f\n", gain); + out_value += 0.5 * gain * sust->play_buf[play_idx]; } } - if( sust->mode == MODE_Sostenuto ) { - sust->record_buf[ sust->idx ] = in[i]; + if (sust->mode == MODE_Sostenuto) { + sust->record_buf[sust->idx] = in[i]; } - if( sust->mode == MODE_Sustain ) { - sust->record_buf[ sust->idx ] = 0.5*out_value; + if (sust->mode == MODE_Sustain) { + sust->record_buf[sust->idx] = 0.5 * out_value; } sust->idx = (sust->idx + 1) % sust->buf_len; diff --git a/sust.h b/sust.h index 92bece8..a0472b1 100644 --- a/sust.h +++ b/sust.h @@ -15,18 +15,16 @@ struct sust { size_t start_idx; size_t idx; size_t buf_len; - float * record_buf; - float * play_buf; + float* record_buf; + float* play_buf; }; - -void sust_init( struct sust * sust ); -void sust_resize( struct sust * sust, size_t new_len ); -void sust_swap( struct sust * sust ); +void sust_init(struct sust* sust); +void sust_resize(struct sust* sust, size_t new_len); +void sust_swap(struct sust* sust); void sust_process( - struct sust * sust, + struct sust* sust, size_t frame_size, - float const * in, - float * out -); + float const* in, + float* out); From 752155de328e1407bc486dd9bc5f83f577276160 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Mon, 17 Feb 2025 18:07:53 +0100 Subject: [PATCH 08/10] add gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dee53c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +*~ From 765275ac325e46552700e051615982b936da8a78 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Mon, 17 Feb 2025 18:59:37 +0100 Subject: [PATCH 09/10] move midi-control into separate function&file --- controller.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ guitfx.c | 125 +++++++++++---------------------------------------- guitfx.h | 16 +++++++ meson.build | 1 + 4 files changed, 153 insertions(+), 99 deletions(-) create mode 100644 controller.c create mode 100644 guitfx.h diff --git a/controller.c b/controller.c new file mode 100644 index 0000000..76e38b7 --- /dev/null +++ b/controller.c @@ -0,0 +1,110 @@ +#include "pipewire/keys.h" +#include "pipewire/port.h" +#include "spa/pod/iter.h" +#include "spa/utils/defs.h" +#include <signal.h> +#include <stdio.h> + +#include <spa/control/control.h> +#include <spa/param/latency-utils.h> +#include <spa/pod/builder.h> +#include <spa/pod/pod.h> + +#include <pipewire/filter.h> +#include <pipewire/pipewire.h> + +#include "guitfx.h" +#include "delay.h" +#include "sust.h" +#include "gate.h" + +void midi_control( + struct FxData * data, + + uint64_t frame, + uint64_t offset, + unsigned sec, + unsigned midi_size, + uint8_t * midi_data, + struct spa_io_position* position +) { + printf("[%d] MIDI message (%d bytes) : %x, %x, %x\n", sec, midi_size, + midi_data[0], midi_data[1], midi_data[2]); + + switch (midi_data[0] & 0xff) { + case 0xb0: + switch (midi_data[1]) { + case 0x0b: + // expr pedal + float val_f = ((float)midi_data[2]) / 128.0; + + float thres = 0.5; + + if (val_f > thres) { + float expr_mix = (val_f - thres) / (1.0 - thres); + printf("Expr Pedal %f\n", expr_mix); + + data->delay.mix = expr_mix; + } else { + data->delay.mix = 0.0; + } + break; + + case 0x42: + + // noise gate calibration + if (data->prog == 2) { + if (midi_data[2] >= 64) { + data->gate.threshold = data->gate.cur_block_sum * 0.8; + 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); + data->sust.playing = true; + + data->sust.start_idx = data->sust.idx; + data->sust.idx = 0; + } else { + data->sust.playing = false; + } + } + + // tap tempo + if (data->prog == 0) { + uint64_t cur_tap = frame + offset; + uint64_t duration = cur_tap - data->last_tap; + data->last_tap = cur_tap; + if (duration < (4 * position->clock.rate.denom)) { + delay_set_time(&data->delay, duration); + } + + sust_resize(&data->sust, duration); + } + + break; + } + + break; + + 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; + } +} + diff --git a/guitfx.c b/guitfx.c index 90d2f4f..82b53ca 100644 --- a/guitfx.c +++ b/guitfx.c @@ -16,6 +16,7 @@ #include "delay.h" #include "gate.h" #include "sust.h" +#include "guitfx.h" float envelope(float x); @@ -25,23 +26,24 @@ struct port { struct data* data; }; +void midi_control( + struct FxData * data, + + uint64_t frame, + uint64_t offset, + unsigned sec, + unsigned midi_size, + uint8_t * midi_data, + struct spa_io_position* position); + + struct data { struct pw_main_loop* loop; struct pw_filter* filter; struct port* guit_in_port; struct port* midi_in_port; struct port* out_port; - - //! effect data - uint64_t last_tap; - struct delay delay; - struct sust sust; - struct gate gate; - - unsigned prog; - - //! elapsed time in number of samples - uint64_t time; + struct FxData fx_data; }; static void on_process(void* userdata, struct spa_io_position* position) @@ -49,8 +51,8 @@ static void on_process(void* userdata, struct spa_io_position* position) struct data* data = userdata; uint32_t n_samples = position->clock.duration; - uint64_t frame = data->time; - data->time += n_samples; + uint64_t frame = data->fx_data.time; + data->fx_data.time += n_samples; struct pw_buffer* b = pw_filter_dequeue_buffer(data->midi_in_port); if (b == NULL) { @@ -75,87 +77,12 @@ static void on_process(void* userdata, struct spa_io_position* position) if (c->type == SPA_CONTROL_Midi) { unsigned sec = (frame + c->offset) / (float)position->clock.rate.denom; char* midi_data = SPA_POD_BODY(&c->value); - unsigned size = SPA_POD_BODY_SIZE(&c->value); + unsigned midi_size = SPA_POD_BODY_SIZE(&c->value); - printf("[%d] MIDI message (%d bytes) : %x, %x, %x\n", sec, size, - midi_data[0], midi_data[1], midi_data[2]); - - switch (midi_data[0] & 0xff) { - case 0xb0: - switch (midi_data[1]) { - case 0x0b: - // expr pedal - float val_f = ((float)midi_data[2]) / 128.0; - - float thres = 0.5; - - if (val_f > thres) { - float expr_mix = (val_f - thres) / (1.0 - thres); - printf("Expr Pedal %f\n", expr_mix); - data->delay.mix = expr_mix; - } else { - data->delay.mix = 0.0; - } - break; - - case 0x42: - - // noise gate calibration - if (data->prog == 2) { - if (midi_data[2] >= 64) { - data->gate.threshold = data->gate.cur_block_sum * 0.8; - 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); - data->sust.playing = true; - - data->sust.start_idx = data->sust.idx; - data->sust.idx = 0; - } else { - data->sust.playing = false; - } - } - - // tap tempo - if (data->prog == 0) { - uint64_t cur_tap = frame + c->offset; - uint64_t duration = cur_tap - data->last_tap; - data->last_tap = cur_tap; - if (duration < (4 * position->clock.rate.denom)) { - delay_set_time(&data->delay, duration); - } - - sust_resize(&data->sust, duration); - } - - break; - } - - break; - - 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; - } + midi_control( &data->fx_data, frame, c->offset, sec, midi_size, midi_data, position ); } else { - printf("on_process(): non midi-control\n"); + + printf("on_process(): non midi-control\n"); } } } else { @@ -176,9 +103,9 @@ static void on_process(void* userdata, struct spa_io_position* position) float tmp2[n_samples]; float* out = pw_filter_get_dsp_buffer(data->out_port, n_samples); if (in && 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); + gate_process(&data->fx_data.gate, n_samples, in, tmp1); + sust_process(&data->fx_data.sust, n_samples, tmp1, tmp2); + delay_process(&data->fx_data.delay, n_samples, tmp2, out); } } @@ -199,10 +126,10 @@ int main(int argc, char* argv[]) 0, }; - gate_init(&data.gate); - delay_init(&data.delay); - sust_init(&data.sust); - data.prog = 0; + gate_init(&data.fx_data.gate); + delay_init(&data.fx_data.delay); + sust_init(&data.fx_data.sust); + data.fx_data.prog = 0; const struct spa_pod* params[1]; uint8_t buffer[1024]; diff --git a/guitfx.h b/guitfx.h new file mode 100644 index 0000000..4dedcdd --- /dev/null +++ b/guitfx.h @@ -0,0 +1,16 @@ + +#include "delay.h" +#include "sust.h" +#include "gate.h" + +struct FxData { + uint64_t last_tap; + struct delay delay; + struct sust sust; + struct gate gate; + + unsigned prog; + + //! elapsed time in number of samples + uint64_t time; +}; diff --git a/meson.build b/meson.build index d59ef2b..ab53a04 100644 --- a/meson.build +++ b/meson.build @@ -10,5 +10,6 @@ executable( 'delay.c', 'sust.c', 'gate.c', + 'controller.c', dependencies : [pipewire_dep, m_dep], ) From 703d41aec84d9f0f9f66ab2820b0c7637a3dd3d6 Mon Sep 17 00:00:00 2001 From: Michael Sippel <micha@fragmental.art> Date: Thu, 20 Feb 2025 16:36:10 +0100 Subject: [PATCH 10/10] add .clang-format file & format all --- .clang-format | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++ controller.c | 149 ++++++++++++++------------- guitfx.c | 22 ++-- guitfx.h | 2 +- 4 files changed, 359 insertions(+), 88 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..76e5a44 --- /dev/null +++ b/.clang-format @@ -0,0 +1,274 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: DontAlign +AlignTrailingComments: + Kind: Never + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: All +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: WebKit +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: MultiLine +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: true + AtStartOfFile: true +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: Inner +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: true +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/controller.c b/controller.c index 76e38b7..9de156a 100644 --- a/controller.c +++ b/controller.c @@ -13,98 +13,97 @@ #include <pipewire/filter.h> #include <pipewire/pipewire.h> -#include "guitfx.h" #include "delay.h" -#include "sust.h" #include "gate.h" +#include "guitfx.h" +#include "sust.h" void midi_control( - struct FxData * data, + struct FxData* data, - uint64_t frame, - uint64_t offset, - unsigned sec, - unsigned midi_size, - uint8_t * midi_data, - struct spa_io_position* position -) { - printf("[%d] MIDI message (%d bytes) : %x, %x, %x\n", sec, midi_size, - midi_data[0], midi_data[1], midi_data[2]); + uint64_t frame, + uint64_t offset, + unsigned sec, + unsigned midi_size, + uint8_t* midi_data, + struct spa_io_position* position) +{ + printf("[%d] MIDI message (%d bytes) : %x, %x, %x\n", sec, midi_size, + midi_data[0], midi_data[1], midi_data[2]); - switch (midi_data[0] & 0xff) { - case 0xb0: - switch (midi_data[1]) { - case 0x0b: - // expr pedal - float val_f = ((float)midi_data[2]) / 128.0; + switch (midi_data[0] & 0xff) { + case 0xb0: + switch (midi_data[1]) { + case 0x0b: + // expr pedal + float val_f = ((float)midi_data[2]) / 128.0; - float thres = 0.5; + float thres = 0.5; - if (val_f > thres) { - float expr_mix = (val_f - thres) / (1.0 - thres); - printf("Expr Pedal %f\n", expr_mix); + if (val_f > thres) { + float expr_mix = (val_f - thres) / (1.0 - thres); + printf("Expr Pedal %f\n", expr_mix); - data->delay.mix = expr_mix; - } else { - data->delay.mix = 0.0; - } - break; + data->delay.mix = expr_mix; + } else { + data->delay.mix = 0.0; + } + break; - case 0x42: + case 0x42: - // noise gate calibration - if (data->prog == 2) { - if (midi_data[2] >= 64) { - data->gate.threshold = data->gate.cur_block_sum * 0.8; - printf("calibrate noise gate: threshold = %f\n", - data->gate.threshold); - } - } + // noise gate calibration + if (data->prog == 2) { + if (midi_data[2] >= 64) { + data->gate.threshold = data->gate.cur_block_sum * 0.8; + 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); - data->sust.playing = true; + // sust pedal + if (data->prog == 1) { + 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; - } - } + data->sust.start_idx = data->sust.idx; + data->sust.idx = 0; + } else { + data->sust.playing = false; + } + } - // tap tempo - if (data->prog == 0) { - uint64_t cur_tap = frame + offset; - uint64_t duration = cur_tap - data->last_tap; - data->last_tap = cur_tap; - if (duration < (4 * position->clock.rate.denom)) { - delay_set_time(&data->delay, duration); - } + // tap tempo + if (data->prog == 0) { + uint64_t cur_tap = frame + offset; + uint64_t duration = cur_tap - data->last_tap; + data->last_tap = cur_tap; + if (duration < (4 * position->clock.rate.denom)) { + delay_set_time(&data->delay, duration); + } - sust_resize(&data->sust, duration); - } + sust_resize(&data->sust, duration); + } - break; - } + break; + } - break; + break; - case 0xc0: - // program change - if (midi_data[2] >= 64) { - sust_swap(&data->sust); - data->sust.playing = true; + 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; - } + 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; + } } - diff --git a/guitfx.c b/guitfx.c index 82b53ca..f9afddd 100644 --- a/guitfx.c +++ b/guitfx.c @@ -15,8 +15,8 @@ #include "delay.h" #include "gate.h" -#include "sust.h" #include "guitfx.h" +#include "sust.h" float envelope(float x); @@ -27,15 +27,14 @@ struct port { }; void midi_control( - struct FxData * data, - - uint64_t frame, - uint64_t offset, - unsigned sec, - unsigned midi_size, - uint8_t * midi_data, - struct spa_io_position* position); + struct FxData* data, + uint64_t frame, + uint64_t offset, + unsigned sec, + unsigned midi_size, + uint8_t* midi_data, + struct spa_io_position* position); struct data { struct pw_main_loop* loop; @@ -79,10 +78,9 @@ static void on_process(void* userdata, struct spa_io_position* position) char* midi_data = SPA_POD_BODY(&c->value); unsigned midi_size = SPA_POD_BODY_SIZE(&c->value); - midi_control( &data->fx_data, frame, c->offset, sec, midi_size, midi_data, position ); + midi_control(&data->fx_data, frame, c->offset, sec, midi_size, midi_data, position); } else { - - printf("on_process(): non midi-control\n"); + printf("on_process(): non midi-control\n"); } } } else { diff --git a/guitfx.h b/guitfx.h index 4dedcdd..8c3cb7e 100644 --- a/guitfx.h +++ b/guitfx.h @@ -1,7 +1,7 @@ #include "delay.h" -#include "sust.h" #include "gate.h" +#include "sust.h" struct FxData { uint64_t last_tap;