Compare commits

...

3 commits

5 changed files with 168 additions and 12 deletions

View file

@ -44,8 +44,8 @@ void delay_process(
for( size_t i = 0; i < frame_size; ++i ) {
if( delay->duration > 0 ) {
out[i] =
0.5 * in[i]
+ 0.5 * delay->mix * delay->buf[ delay->buf_idx ];
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];

View file

@ -14,7 +14,9 @@
#include <pipewire/filter.h>
#include "delay.h"
#include "sust.h"
float envelope( float x );
struct data;
struct port {
@ -31,6 +33,9 @@ struct data {
//! effect data
uint64_t last_tap;
struct delay delay;
struct sust sust;
unsigned prog;
//! elapsed time in number of samples
uint64_t time;
@ -84,26 +89,49 @@ static void on_process(void *userdata, struct spa_io_position *position)
// expr pedal
float val_f = ((float)midi_data[2]) / 128.0;
printf("Expr Pedal %f\n", val_f);
data->delay.mix = val_f;
if ( val_f > 0.1 ) {
data->delay.mix = val_f;
} else {
data->delay.mix = 0.0;
}
break;
case 0x42:
// 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 );
}
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/4 );
}
break;
}
break;
case 0xc0:
// program change
printf("program change: %u\n", midi_data[1]);
data->prog = midi_data[1];
break;
}
} else {
@ -124,9 +152,11 @@ 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 * out = pw_filter_get_dsp_buffer(data->out_port, n_samples);
if( in && out ) {
delay_process( &data->delay, n_samples, in, out );
sust_process( &data->sust, n_samples, in, tmp );
delay_process( &data->delay, n_samples, tmp, out );
}
}
@ -146,6 +176,8 @@ int main(int argc, char *argv[])
struct data data = { 0, };
delay_init( &data.delay );
sust_init( &data.sust );
data.prog = 0;
const struct spa_pod *params[1];
uint8_t buffer[1024];

View file

@ -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],
)

87
sust.c Normal file
View file

@ -0,0 +1,87 @@
#include "sust.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
void sust_init( struct sust * sust ) {
sust->mode = MODE_Sostenuto;
sust->playing = false;
sust->start_idx = 0;
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 );
}
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_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;
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;
}
}

32
sust.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
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_resize( struct sust * sust, size_t new_len );
void sust_swap( struct sust * sust );
void sust_process(
struct sust * sust,
size_t frame_size,
float const * in,
float * out
);