Skip to content
Snippets Groups Projects
Select Git revision
  • 65f14260d6e70264651fcfe82173ad0a96e155fc
  • main default protected
  • phhw
  • captouch-threshold
  • t
  • dos
  • test2
  • test
  • slewtest
  • simtest
  • view-think
  • vm-pending
  • media-buf
  • scope
  • passthrough
  • wave
  • vsync
  • dos-main-patch-50543
  • json-error
  • rahix/big-flow3r
  • pippin/media_framework
  • v1.3.0
  • v1.2.0
  • v1.2.0+rc1
  • v1.1.1
  • v1.1.0
  • v1.1.0+rc1
  • v1.0.0
  • v1.0.0+rc6
  • v1.0.0+rc5
  • v1.0.0+rc4
  • v1.0.0+rc3
  • v1.0.0+rc2
  • v1.0.0+rc1
34 results

flanger.c

Blame
  • Forked from flow3r / flow3r firmware
    Source project has a limited visibility.
    flanger.c 6.47 KiB
    #include "flanger.h"
    
    radspa_t * flanger_create(uint32_t init_var);
    radspa_descriptor_t flanger_desc = {
        .name = "flanger",
        .id = 123,
        .description = "flanger with subsample interpolation and negative mix/resonance capability.",
        .create_plugin_instance = flanger_create,
        .destroy_plugin_instance = radspa_standard_plugin_destroy
    };
    
    #define FLANGER_BUFFER_SIZE 4800
    #define FIXED_POINT_DIGITS 4
    #define VARIABLE_NAME ((FLANGER_BUFFER_SIZE)<<(FIXED_POINT_DIGITS))
    
    #define FLANGER_NUM_SIGNALS 7
    #define FLANGER_OUTPUT 0
    #define FLANGER_INPUT 1
    #define FLANGER_MANUAL 2
    #define FLANGER_RESONANCE 3
    #define FLANGER_DECAY 4
    #define FLANGER_LEVEL 5
    #define FLANGER_MIX 6
    
    static inline int32_t fixed_point_list_access(int32_t * buf, int32_t fp_index, uint32_t buf_len){
        int32_t index = (fp_index) >> (FIXED_POINT_DIGITS);
        while(index >= buf_len) index -= buf_len;
        int32_t next_index = index + 1;
        while(next_index >= buf_len) next_index -= buf_len;
    
        int32_t subindex = (fp_index) & ((1<<(FIXED_POINT_DIGITS)) - 1);
        int32_t ret =  buf[index] * ((1<<(FIXED_POINT_DIGITS)) - subindex);
        ret += (buf[next_index]) * subindex;
        ret = ret >> (FIXED_POINT_DIGITS);
        return radspa_clip(ret);
    }
    
    /* delay_time = 1/freq
     * delay_samples = delay_time * SAMPLE_RATE
     * freq(sct) = pow(2, (sct + 2708)/2400))
     * freq = sct_to_rel_freq(sct) * SAMPLE_RATE / UINT32_MAX
     * delay_samples = UINT32_MAX / sct_to_rel_freq(sct)
     * delay_samples = sct_to_rel_freq(-7572-sct + 2400 * FIXED_POINT_DIGITS)
     *
     * decay_reso_float = 2**(-delay_time_ms/decay_ms_per_6dB)
     * rho = (delay_time_ms * 48) * (1<<FIXED_POINT_DIGITS)
     * delay_time_ms * 2400 = (rho >> FIXED_POINT_DIGITS) * 50
     * delay_reso_int = sct_to_rel_freq(offset - (delay_time_ms * 2400)/decay_ms_per_6dB)
     */
    
    void flanger_run(radspa_t * flanger, uint16_t num_samples, uint32_t render_pass_id){
        radspa_signal_t * output_sig = radspa_signal_get_by_index(flanger, FLANGER_OUTPUT);
        if(output_sig->buffer == NULL) return;
        flanger_data_t * data = flanger->plugin_data;
        int32_t * buf = (int32_t *) flanger->plugin_table;
        radspa_signal_t * input_sig = radspa_signal_get_by_index(flanger, FLANGER_INPUT);
        radspa_signal_t * manual_sig = radspa_signal_get_by_index(flanger, FLANGER_MANUAL);
        radspa_signal_t * reso_sig = radspa_signal_get_by_index(flanger, FLANGER_RESONANCE);
        radspa_signal_t * decay_sig = radspa_signal_get_by_index(flanger, FLANGER_DECAY);
        radspa_signal_t * level_sig = radspa_signal_get_by_index(flanger, FLANGER_LEVEL);
        radspa_signal_t * mix_sig = radspa_signal_get_by_index(flanger, FLANGER_MIX);
    
        int32_t reso = radspa_signal_get_value(reso_sig, 0, render_pass_id);
        reso = reso << 14;
        int32_t level = radspa_signal_get_value(level_sig, 0, render_pass_id);
        int32_t mix = radspa_signal_get_value(mix_sig, 0, render_pass_id);
        int32_t decay = radspa_signal_get_value(decay_sig, 0, render_pass_id);
        int32_t dry_vol = (mix>0) ? (32767-mix) : (32767+mix); //always pos polarity
    
        int32_t manual = radspa_signal_get_value(manual_sig, 0, render_pass_id);
        if(manual != data->manual_prev){
            int32_t manual_invert = ((2400*(FIXED_POINT_DIGITS)) - 7572) - manual; // magic numbers
            uint32_t rho = radspa_sct_to_rel_freq(radspa_clip(manual_invert), 0);
            if(rho > VARIABLE_NAME) rho = VARIABLE_NAME;
            data->read_head_offset = rho;
        }
        if(decay){
            int32_t sgn_decay = decay > 0 ? 1 : -1;
            int32_t abs_decay = decay * sgn_decay;
            if((abs_decay != data->abs_decay_prev) || (manual != data->manual_prev)){
                int32_t decay_invert = - ((data->read_head_offset * 50) >> FIXED_POINT_DIGITS)/abs_decay;
                decay_invert += 34614 - 4800 - 2400; // magic number
                data->decay_reso = radspa_sct_to_rel_freq(radspa_clip(decay_invert), 0);
            }
            int32_t tmp = reso + sgn_decay * data->decay_reso;
            if((sgn_decay == 1) && (tmp < reso)){
                    tmp = INT32_MAX;
            } else if((sgn_decay == -1) && (tmp > reso)){
                    tmp = INT32_MIN;
            }
            reso = tmp;
            data->abs_decay_prev = abs_decay;
        }
        data->manual_prev = manual;
    
        for(uint16_t i = 0; i < num_samples; i++){
            int32_t dry = radspa_signal_get_value(input_sig, i, render_pass_id);
    
            data->write_head_position++;
            while(data->write_head_position >= FLANGER_BUFFER_SIZE) data->write_head_position -= FLANGER_BUFFER_SIZE;
            data->read_head_position = ((data->write_head_position)<<(FIXED_POINT_DIGITS));
            data->read_head_position -= data->read_head_offset;
            while(data->read_head_position < 0) data->read_head_position += VARIABLE_NAME; //underflow
    
            buf[data->write_head_position] = dry;
            int32_t wet = fixed_point_list_access(buf, data->read_head_position, FLANGER_BUFFER_SIZE) << 3;
            bool sgn_wet = wet > 0;
            bool sgn_reso = reso > 0;
            if(sgn_wet != sgn_reso){
                buf[data->write_head_position] -= ((int64_t) (-wet) * reso) >> 32;
            } else {
                buf[data->write_head_position] += ((int64_t) wet * reso) >> 32;
            }
    
            int32_t ret = radspa_add_sat(radspa_mult_shift(dry, dry_vol), radspa_mult_shift(radspa_clip(wet), mix));
            ret = radspa_clip(radspa_gain(ret, level));
            radspa_signal_set_value(output_sig, i, ret);
        }
    }
    
    radspa_t * flanger_create(uint32_t init_var){
        radspa_t * flanger = radspa_standard_plugin_create(&flanger_desc, FLANGER_NUM_SIGNALS, sizeof(flanger_data_t),
                                                                2 * FLANGER_BUFFER_SIZE);
        if(flanger == NULL) return NULL;
        flanger_data_t * plugin_data = flanger->plugin_data;
        plugin_data->manual_prev = 40000;
        flanger->render = flanger_run;
        radspa_signal_set(flanger, FLANGER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
        radspa_signal_set(flanger, FLANGER_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
        radspa_signal_set(flanger, FLANGER_MANUAL, "manual", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, 18367);
        radspa_signal_set(flanger, FLANGER_RESONANCE, "resonance", RADSPA_SIGNAL_HINT_INPUT, RADSPA_SIGNAL_VAL_UNITY_GAIN/2);
        radspa_signal_set(flanger, FLANGER_DECAY, "decay", RADSPA_SIGNAL_HINT_INPUT, 0);
        radspa_signal_set(flanger, FLANGER_LEVEL, "level", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN,
                                RADSPA_SIGNAL_VAL_UNITY_GAIN);
        radspa_signal_set(flanger, FLANGER_MIX, "mix", RADSPA_SIGNAL_HINT_INPUT, 1<<14);
        flanger->signals[FLANGER_DECAY].unit = "ms/6dB";
        return flanger;
    }