#include #include #include #include #include #include #include "jl_mem.h" #include "soundfile.h" #include "sample.h" #include "fx.h" static bool starts_with(char *s, char *prefix) { int n = strlen(prefix); if(n > strlen(s)) { return false; } for(int i = 0; i < n; ++i) { if(s[i] != prefix[i]) { return false; } } return true; } static void fsample_apply_effect(FSample *s, char *txt) { // Attempt to parse each effect until one works. if(starts_with(txt, "amp(")) { double gain; if(sscanf(txt, "amp(%lf)", &gain) != 1) { goto apply_fx_err; } fx_amp(s, gain); } else if(starts_with(txt, "balance(")) { double balance; if(sscanf(txt, "balance(%lf)", &balance) != 1) { goto apply_fx_err; } fx_balance(s, balance); } else if(starts_with(txt, "divide_rms(")) { double t_ms; if(sscanf(txt, "divide_rms(%lf)", &t_ms) != 1) { goto apply_fx_err; } fx_divide_rms(s, t_ms); } else if(starts_with(txt, "fade_in(")) { double t_ms; if(sscanf(txt, "fade_in(%lf)", &t_ms) != 1) { goto apply_fx_err; } fx_fade_in(s, t_ms); } else if(starts_with(txt, "ir(")) { char path[MAX_FX_LINE]; double mix; if(sscanf(txt, "ir(%[^,], %lf)", path, &mix) != 2) { goto apply_fx_err; } fx_ir(s, path, mix); } else if(starts_with(txt, "mono()")) { fx_mono(s); } else if(starts_with(txt, "pan(")) { double pan; if(sscanf(txt, "pan(%lf)", &pan) != 1) { goto apply_fx_err; } fx_pan(s, pan); } else if(starts_with(txt, "pre_cut(")) { double pct, fade_ms; if(sscanf(txt, "pre_cut(%lf, %lf)", &pct, &fade_ms) != 2) { goto apply_fx_err; } fx_pre_cut(s, pct, fade_ms); } else if(starts_with(txt, "playback_speed(")) { double speed; if(sscanf(txt, "playback_speed(%lf)", &speed) != 1) { goto apply_fx_err; } fx_playback_speed(s, speed); } else if(starts_with(txt, "pre_delay(")) { double left_ms, right_ms; if(sscanf(txt, "pre_delay(%lf, %lf)", &left_ms, &right_ms) != 2) { goto apply_fx_err; } fx_pre_delay(s, left_ms, right_ms); } else if(starts_with(txt, "rc_highpass(")) { double freq; int order; if(sscanf(txt, "rc_highpass(%lf, %d)", &freq, &order) != 2) { goto apply_fx_err; } fx_rc_highpass(s, freq, order); } else if(starts_with(txt, "rc_lowpass(")) { double freq; int order; if(sscanf(txt, "rc_lowpass(%lf, %d)", &freq, &order) != 2) { goto apply_fx_err; } fx_rc_lowpass(s, freq, order); } else if(starts_with(txt, "rc_highshelf(")) { double freq, gain; int order; if(sscanf(txt, "rc_highshelf(%lf, %d, %lf)", &freq, &order, &gain) != 3) { goto apply_fx_err; } fx_rc_highshelf(s, freq, order, gain); } else if(starts_with(txt, "rc_lowshelf(")) { double freq, gain; int order; if(sscanf(txt, "rc_lowshelf(%lf, %d, %lf)", &freq, &order, &gain) != 3) { goto apply_fx_err; } fx_rc_lowshelf(s, freq, order, gain); } else if(starts_with(txt, "stereo_width(")) { double width; if(sscanf(txt, "stereo_width(%lf)", &width) != 1) { goto apply_fx_err; } fx_stereo_width(s, width); } else { printf("Unknown effect: %s\n", txt); } return; apply_fx_err: printf("Parsing error: %s\n", txt); exit(1); } void fsample_load(FSample *s, char *path, SoundConfig *conf, int buf_size) { s->len = soundfile_load_stereo(path, &s->L, &s->R); // Apply global pre effects. for(int i = 0; conf->global_fx_pre[i][0] != '\0'; ++i) { fsample_apply_effect(s, conf->global_fx_pre[i]); } // Apply pre effects. for(int i = 0; conf->fx_pre[i][0] != '\0'; ++i) { fsample_apply_effect(s, conf->fx_pre[i]); } // Apply post effets. for(int i = 0; conf->fx_post[i][0] != '\0'; ++i) { fsample_apply_effect(s, conf->fx_post[i]); } // Apply global post effects. for(int i = 0; conf->global_fx_post[i][0] != '\0'; ++i) { fsample_apply_effect(s, conf->global_fx_post[i]); } } void fsample_set_data(FSample *s, float *L, float *R, int len) { jl_free(s->L); jl_free(s->R); s->L = L; s->R = R; s->len = len; } double fsample_max_amp(FSample *s) { double max = 0; for(int i = 0; i < s->len; i++) { if(max < s->L[i]) { max = s->L[i]; } else if(max < -s->L[i]) { max = -s->L[i]; } if(max < s->R[i]) { max = s->R[i]; } else if(max < -s->R[i]) { max = -s->R[i]; } } return max; } void fsample_free(FSample *s) { jl_free(s->L); jl_free(s->R); s->R = s->L = NULL; s->len = 0; }