diff --git a/guitfx.c b/guitfx.c index 02f8a12..4ab88e1 100644 --- a/guitfx.c +++ b/guitfx.c @@ -14,7 +14,9 @@ #include #include "delay.h" +#include "sust.h" +float envelope( float x ); struct data; struct port { @@ -31,6 +33,7 @@ struct data { //! effect data uint64_t last_tap; struct delay delay; + struct sust sust; //! elapsed time in number of samples uint64_t time; @@ -90,7 +93,17 @@ static void on_process(void *userdata, struct spa_io_position *position) case 0x42: // sust pedal + 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 uint64_t cur_tap = frame + c->offset; uint64_t duration = cur_tap - data->last_tap; data->last_tap = cur_tap; @@ -126,7 +139,8 @@ 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 * out = pw_filter_get_dsp_buffer(data->out_port, n_samples); if( in && out ) { - delay_process( &data->delay, n_samples, in, out ); + //delay_process( &data->delay, n_samples, in, out ); + sust_process( &data->sust, n_samples, in, out ); } } @@ -146,6 +160,7 @@ int main(int argc, char *argv[]) struct data data = { 0, }; delay_init( &data.delay ); + sust_init( &data.sust ); const struct spa_pod *params[1]; uint8_t buffer[1024]; diff --git a/meson.build b/meson.build index 5f61c36..9fc0dd8 100644 --- a/meson.build +++ b/meson.build @@ -1,8 +1,13 @@ project('guitfx', 'c') pipewire_dep = dependency('libpipewire-0.3') + +cc = meson.get_compiler('c') +m_dep = cc.find_library('m', required : false) + executable( 'guitfx', 'guitfx.c', 'delay.c', - dependencies : [pipewire_dep], + 'sust.c', + dependencies : [pipewire_dep, m_dep], ) diff --git a/sust.c b/sust.c new file mode 100644 index 0000000..c836b2a --- /dev/null +++ b/sust.c @@ -0,0 +1,80 @@ +#include "sust.h" +#include +#include +#include + +void sust_init( struct sust * sust ) { + sust->mode = MODE_Sostenuto; + + sust->playing = false; + + sust->start_idx = 0; + sust->idx = 0; + + sust->buf_len = 12800; + 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 ) + return (x / 0.4) * (x / 0.4); + if( x < 0.6 ) + return 1.0; + + float v = 1.0 - ((x - 0.6) / 0.4); + return v*v; +} + +float softcos( float x ) { + return sin( x * (3.141 / 2.0) ); +} + +void sust_swap( + 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 ) { + sust->record_buf[i] = sust->play_buf[i]; + } +} + +void sust_process( + struct sust * sust, + size_t frame_size, + 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 ); + } + + float out_value = in[i]; + + 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 ]; + } + } + + 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; + } + + sust->idx = (sust->idx + 1) % sust->buf_len; + out[i] = out_value; + } +} diff --git a/sust.h b/sust.h new file mode 100644 index 0000000..23c6f67 --- /dev/null +++ b/sust.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +enum sust_mode { + MODE_Sustain = 0, + MODE_Sostenuto = 1 +}; + +struct sust { + enum sust_mode mode; + bool playing; + + size_t start_idx; + size_t idx; + size_t buf_len; + float * record_buf; + float * play_buf; +}; + + +void sust_init( struct sust * sust ); +void sust_swap( struct sust * sust ); + +void sust_process( + struct sust * sust, + size_t frame_size, + float const * in, + float * out +);