Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 89-apps-should-be-able-to-specify-if-they-want-wifi-to-be-disabled-when-entering-them
  • 9Rmain
  • allow-reloading-sunmenu
  • always-have-a-wifi-instance
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • app_text_viewer
  • audio_input
  • audio_io
  • blm_dev_chan
  • ch3/bl00mbox_docs
  • ci-1690580595
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dx/dldldld
  • dx/fb-save-restore
  • dx/hint-hint
  • dx/jacksense-headset-mic-only
  • events
  • fil3s-limit-filesize
  • fil3s-media
  • fpletz/flake
  • gr33nhouse-improvements
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • led_fix_fix
  • main
  • main+schneider
  • media_has_video_has_audio
  • micropython_api
  • mixer2
  • moon2_demo_temp
  • moon2_migrate_apps
  • more-accurate-battery
  • pippin/ctx_sprite_sheet_support
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/more-accurate-battery
  • pippin/tcp_redirect_hack
  • pippin/tune_ctx_config_update_from_upstream
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • py_only_update_fps_overlay_when_changing
  • q3k/doom-poc
  • q3k/render-to-texture
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • release/1.2.0
  • release/1.3.0
  • release/1.4.0
  • restore_blit
  • return_of_melodic_demo
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • sector_size_512
  • shoegaze-fps
  • smaller_gradient_lut
  • store_delta_ms_and_ins_as_class_members
  • task_cleanup
  • uctx-wip
  • w1f1-in-sim
  • widgets_draw
  • wifi-json-error-handling
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
  • v1.4.0
94 results

Target

Select target project
  • flow3r/flow3r-firmware
  • Vespasian/flow3r-firmware
  • alxndr42/flow3r-firmware
  • pl/flow3r-firmware
  • Kari/flow3r-firmware
  • raimue/flow3r-firmware
  • grandchild/flow3r-firmware
  • mu5tach3/flow3r-firmware
  • Nervengift/flow3r-firmware
  • arachnist/flow3r-firmware
  • TheNewCivilian/flow3r-firmware
  • alibi/flow3r-firmware
  • manuel_v/flow3r-firmware
  • xeniter/flow3r-firmware
  • maxbachmann/flow3r-firmware
  • yGifoom/flow3r-firmware
  • istobic/flow3r-firmware
  • EiNSTeiN_/flow3r-firmware
  • gnudalf/flow3r-firmware
  • 999eagle/flow3r-firmware
  • toerb/flow3r-firmware
  • pandark/flow3r-firmware
  • teal/flow3r-firmware
  • x42/flow3r-firmware
  • alufers/flow3r-firmware
  • dos/flow3r-firmware
  • yrlf/flow3r-firmware
  • LuKaRo/flow3r-firmware
  • ThomasElRubio/flow3r-firmware
  • ai/flow3r-firmware
  • T_X/flow3r-firmware
  • highTower/flow3r-firmware
  • beanieboi/flow3r-firmware
  • Woazboat/flow3r-firmware
  • gooniesbro/flow3r-firmware
  • marvino/flow3r-firmware
  • kressnerd/flow3r-firmware
  • quazgar/flow3r-firmware
  • aoid/flow3r-firmware
  • jkj/flow3r-firmware
  • naomi/flow3r-firmware
41 results
Select Git revision
  • 9Rmain
  • anon/gpndemo
  • anon/update-sim
  • anon/webflasher
  • audio_input
  • audio_io
  • bl00mbox
  • bl00mbox_old
  • captouch-threshold
  • ch3/bl00mbox_docs
  • ci-1690580595
  • compressor
  • dev_p4
  • dev_p4-iggy
  • dev_p4-iggy-rebased
  • dos
  • dos-main-patch-50543
  • events
  • fm_fix
  • fm_fix2
  • fpletz/flake
  • history-rewrite
  • icon-flower
  • iggy/stemming
  • iggy/stemming_merge
  • json-error
  • main
  • main+schneider
  • media-buf
  • micropython_api
  • moon2_applications
  • moon2_demo_temp
  • moon2_gay_drums
  • passthrough
  • phhw
  • pippin/display-python-errors-on-display
  • pippin/make_empty_drawlists_skip_render_and_blit
  • pippin/media_framework
  • pippin/uhm_flash_access_bust
  • pressable_bugfix
  • q3k/doom-poc
  • rahix/big-flow3r
  • rahix/flow3rseeds
  • raw_captouch_new
  • raw_captouch_old
  • release/1.0.0
  • release/1.1.0
  • release/1.1.1
  • rev4_micropython
  • schneider/application-remove-name
  • schneider/bhi581
  • schneider/factory_test
  • schneider/recovery
  • scope
  • scope_hack
  • sdkconfig-spiram-tinyusb
  • sec/auto-nick
  • sec/blinky
  • simtest
  • slewtest
  • t
  • test
  • test2
  • uctx-wip
  • view-think
  • vm-pending
  • vsync
  • wave
  • wip-docs
  • wip-tinyusb
  • v1.0.0
  • v1.0.0+rc1
  • v1.0.0+rc2
  • v1.0.0+rc3
  • v1.0.0+rc4
  • v1.0.0+rc5
  • v1.0.0+rc6
  • v1.1.0
  • v1.1.0+rc1
  • v1.1.1
  • v1.2.0
  • v1.2.0+rc1
  • v1.3.0
83 results
Show changes
Showing
with 1401 additions and 0 deletions
#include "buffer.h"
radspa_descriptor_t buffer_desc = {
.name = "buffer",
.id = 22,
.description = "forwards input signal to output signal",
.create_plugin_instance = buffer_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id){
// note: this could be more lightweight by simply forwarding the buffer,
// however at this point the radspa protocol has no built-in flag for this.
// a host may still choose to simply do so to save CPU.
// for the future, since this is a common use case, we should add some sort of
// buffer forwarding flag. but it's okay. still lighter than the old approach
// (running a single channel mixer).
radspa_signal_t * output = radspa_signal_get_by_index(buffer, 0);
radspa_signal_t * input = radspa_signal_get_by_index(buffer, 1);
radspa_signal_copy(input, output, num_samples, render_pass_id);
}
radspa_t * buffer_create(uint32_t init_var){
radspa_t * buffer = radspa_standard_plugin_create(&buffer_desc, 2, 0, 0);
if(!buffer) return NULL;
buffer->render = buffer_run;
radspa_signal_set(buffer, 0, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(buffer, 1, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
return buffer;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t buffer_desc;
radspa_t * buffer_create(uint32_t init_var);
void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id);
#include "delay.h"
radspa_t * delay_create(uint32_t init_var);
radspa_descriptor_t delay_desc = {
.name = "delay_static",
.id = 42069,
.description = "simple delay with ms input and feedback\n"
"init_var: delay buffer length in ms, default 500",
.create_plugin_instance = delay_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define DELAY_NUM_SIGNALS 7
#define DELAY_OUTPUT 0
#define DELAY_INPUT 1
#define DELAY_TIME 2
#define DELAY_FEEDBACK 3
#define DELAY_LEVEL 4
#define DELAY_DRY_VOL 5
#define DELAY_REC_VOL 6
void delay_run(radspa_t * delay, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(delay, DELAY_OUTPUT);
delay_data_t * data = delay->plugin_data;
int16_t * buf = delay->plugin_table;
radspa_signal_t * input_sig = radspa_signal_get_by_index(delay, DELAY_INPUT);
radspa_signal_t * time_sig = radspa_signal_get_by_index(delay, DELAY_TIME);
radspa_signal_t * feedback_sig = radspa_signal_get_by_index(delay, DELAY_FEEDBACK);
radspa_signal_t * level_sig = radspa_signal_get_by_index(delay, DELAY_LEVEL);
radspa_signal_t * dry_vol_sig = radspa_signal_get_by_index(delay, DELAY_DRY_VOL);
radspa_signal_t * rec_vol_sig = radspa_signal_get_by_index(delay, DELAY_REC_VOL);
static int16_t ret = 0;
int32_t buffer_size = delay->plugin_table_len;
int32_t time = radspa_signal_get_value(time_sig, 0, render_pass_id);
if(time < 0) time = -time;
if(time > data->max_delay) time = data->max_delay;
if(time != data->time_prev){
data->read_head_position = data->write_head_position;
data->read_head_position -= time * (48000/1000);
if(data->read_head_position < 0) data->read_head_position += buffer_size;
data->time_prev = time;
}
int16_t fb = radspa_signal_get_value(feedback_sig, 0, render_pass_id);
int16_t level = radspa_signal_get_value(level_sig, 0, render_pass_id);
int16_t dry_vol = radspa_signal_get_value(dry_vol_sig, 0, render_pass_id);
int16_t rec_vol = radspa_signal_get_value(rec_vol_sig, 0, render_pass_id);
for(uint16_t i = 0; i < num_samples; i++){
data->write_head_position++;
while(data->write_head_position >= buffer_size) data->write_head_position -= buffer_size; // maybe faster than %
data->read_head_position++;
while(data->read_head_position >= buffer_size) data->read_head_position -= buffer_size;
int16_t dry = radspa_signal_get_value(input_sig, i, render_pass_id);
int16_t wet = buf[data->read_head_position];
if(rec_vol){
buf[data->write_head_position] = radspa_add_sat(radspa_mult_shift(rec_vol, dry), radspa_mult_shift(wet,fb));
}
ret = radspa_add_sat(radspa_mult_shift(dry_vol,dry), radspa_mult_shift(wet,level));
radspa_signal_set_value(output_sig, i, ret);
}
}
radspa_t * delay_create(uint32_t init_var){
if(init_var == 0) init_var = 500;
if(init_var > 10000) init_var = 10000;
uint32_t buffer_size = init_var*(48000/1000);
radspa_t * delay = radspa_standard_plugin_create(&delay_desc, DELAY_NUM_SIGNALS, sizeof(delay_data_t), buffer_size);
if(delay == NULL) return NULL;
delay_data_t * plugin_data = delay->plugin_data;
plugin_data->time_prev = -1;
plugin_data->max_delay = init_var;
delay->render = delay_run;
radspa_signal_set(delay, DELAY_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(delay, DELAY_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(delay, DELAY_TIME, "time", RADSPA_SIGNAL_HINT_INPUT, 200);
radspa_signal_set(delay, DELAY_FEEDBACK, "feedback", RADSPA_SIGNAL_HINT_INPUT, 16000);
radspa_signal_set(delay, DELAY_LEVEL, "level", RADSPA_SIGNAL_HINT_INPUT, 16000);
radspa_signal_set(delay, DELAY_DRY_VOL, "dry_vol", RADSPA_SIGNAL_HINT_INPUT, 32767);
radspa_signal_set(delay, DELAY_REC_VOL, "rec_vol", RADSPA_SIGNAL_HINT_INPUT, 32767);
return delay;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
typedef struct {
int32_t read_head_position;
int32_t write_head_position;
int32_t max_delay;
int32_t time_prev;
} delay_data_t;
extern radspa_descriptor_t delay_desc;
radspa_t * delay_create(uint32_t init_var);
void delay_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "distortion.h"
radspa_t * distortion_create(uint32_t init_var);
radspa_descriptor_t distortion_desc = {
.name = "distortion",
.id = 9000,
.description = "distortion with linear interpolation between int16 values in plugin_table[129]",
.create_plugin_instance = distortion_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define DISTORTION_NUM_SIGNALS 2
#define DISTORTION_OUTPUT 0
#define DISTORTION_INPUT 1
static inline int32_t distort(int32_t input, int16_t * dist, uint8_t lerp_glitch){
// lerp glitch is a legacy feature from a math error of the 0th gen
// pass 9 normally, pass 7 for legacy glitch
input += 32768;
uint8_t index = input >> 9;
int32_t blend = input & ((1<<lerp_glitch)-1);
int32_t ret = dist[index]*((1<<lerp_glitch)-blend) + dist[index+1]*blend;
return ret >> lerp_glitch;
}
void distortion_run(radspa_t * distortion, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(distortion, DISTORTION_OUTPUT);
if(output_sig->buffer == NULL) return;
int16_t * dist = distortion->plugin_table;
radspa_signal_t * input_sig = radspa_signal_get_by_index(distortion, DISTORTION_INPUT);
int32_t input = radspa_signal_get_const_value(input_sig, render_pass_id);
uint8_t lerp_glitch = 9 - ((dist[129]) & 7); // legacy glitch
if(input != RADSPA_SIGNAL_NONCONST){
radspa_signal_set_const_value(output_sig, distort(input, dist, lerp_glitch));
} else {
for(uint16_t i = 0; i < num_samples; i++){
int32_t input = radspa_signal_get_value(input_sig, i, render_pass_id);
radspa_signal_set_value(output_sig, i, distort(input, dist, lerp_glitch));
}
}
}
radspa_t * distortion_create(uint32_t init_var){
radspa_t * distortion = radspa_standard_plugin_create(&distortion_desc, DISTORTION_NUM_SIGNALS, 0, (1<<7) + 2);
if(distortion == NULL) return NULL;
distortion->render = distortion_run;
radspa_signal_set(distortion, DISTORTION_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(distortion, DISTORTION_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
// prefill table with mild saturation
int16_t * dist = distortion->plugin_table;
for(int32_t i = 0; i < ((1<<7)+1) ; i++){
if(i < 64){
dist[i] = ((i*i)*32767>>12) - 32767;
} else {
dist[i] = -((128-i)*(128-i)*32767>>12) + 32767;
}
}
dist[129] = 0;
return distortion;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t distortion_desc;
radspa_t * distortion_create(uint32_t init_var);
void distortion_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "env_adsr.h"
radspa_descriptor_t env_adsr_desc = {
.name = "env_adsr",
.id = 42,
.description = "simple ADSR envelope",
.create_plugin_instance = env_adsr_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define ENV_ADSR_NUM_SIGNALS 9
#define ENV_ADSR_OUTPUT 0
#define ENV_ADSR_INPUT 1
#define ENV_ADSR_ENV_OUTPUT 2
#define ENV_ADSR_TRIGGER 3
#define ENV_ADSR_ATTACK 4
#define ENV_ADSR_DECAY 5
#define ENV_ADSR_SUSTAIN 6
#define ENV_ADSR_RELEASE 7
#define ENV_ADSR_GAIN 8
#define ENV_ADSR_PHASE_OFF 0
#define ENV_ADSR_PHASE_ATTACK 1
#define ENV_ADSR_PHASE_DECAY 2
#define ENV_ADSR_PHASE_SUSTAIN 3
#define ENV_ADSR_PHASE_RELEASE 4
#define SAMPLE_RATE_SORRY 48000
static inline uint32_t env_adsr_time_ms_to_val_rise(int16_t time_ms, uint32_t val, uint16_t num_samples){
if(!time_ms) return UINT32_MAX;
if(time_ms < 0) time_ms = -time_ms;
uint32_t div = time_ms * ((SAMPLE_RATE_SORRY)/1000);
uint32_t input = val/div;
if(((uint64_t) input * num_samples) >> 32){
return UINT32_MAX; // sat
} else {
return input * num_samples;
}
}
static inline void update_attack_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){
env_adsr_data_t * data = env_adsr->plugin_data;
int16_t attack = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_ATTACK], 0, render_pass_id);
if((data->attack_prev_ms != attack) || (data->num_samples_prev != num_samples)){
data->attack_raw = env_adsr_time_ms_to_val_rise(attack, UINT32_MAX, num_samples);
data->attack_prev_ms = attack;
}
}
static inline void update_release_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){
env_adsr_data_t * data = env_adsr->plugin_data;
int16_t release = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_RELEASE], 0, render_pass_id);
if((data->release_prev_ms != release) || (data->num_samples_prev != num_samples) || data->release_init_val_prev != data->release_init_val){
data->release_raw = env_adsr_time_ms_to_val_rise(release, data->release_init_val, num_samples);
data->release_prev_ms = release;
if(data->release_init_val_prev != data->release_init_val){;
uint8_t phase = ENV_ADSR_PHASE_RELEASE;
data->square_min[phase] = 0;
uint32_t delta = data->release_init_val >> 17;;
if(delta){
data->square_mult[phase] = (1UL<<31) / delta;
} else {
data->square_mult[phase] = 0;
}
data->release_init_val_prev = data->release_init_val;
}
}
}
static inline void update_sustain_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){
env_adsr_data_t * data = env_adsr->plugin_data;
int16_t sustain = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_SUSTAIN], 0, render_pass_id);
sustain = sustain < 0 ? -sustain : sustain;
data->sustain = ((uint32_t) sustain) << 17UL;
}
static inline void update_decay_coeffs(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){
update_sustain_coeffs(env_adsr, num_samples, render_pass_id);
env_adsr_data_t * data = env_adsr->plugin_data;
int32_t decay = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_DECAY], 0, render_pass_id);
if((data->decay_prev_ms != decay) || (data->sustain_prev != data->sustain) || (data->num_samples_prev != num_samples)){
data->decay_raw = env_adsr_time_ms_to_val_rise(decay, UINT32_MAX - data->sustain, num_samples);
data->decay_prev_ms = decay;
if(data->sustain_prev != data->sustain){
uint8_t phase = ENV_ADSR_PHASE_DECAY;
data->square_min[phase] = data->sustain >> 17;
uint32_t delta = 32767 - data->square_min[phase];
if(delta){
data->square_mult[phase] = (1UL<<31) / delta;
} else {
data->square_mult[phase] = 0 ;
}
data->sustain_prev = data->sustain;
}
}
}
void env_adsr_run(radspa_t * env_adsr, uint16_t num_samples, uint32_t render_pass_id){
env_adsr_data_t * data = env_adsr->plugin_data;
uint16_t throwaway;
int16_t vel = radspa_trigger_get_const(&env_adsr->signals[ENV_ADSR_TRIGGER], &data->trigger_prev, &throwaway, num_samples, render_pass_id);
if(vel > 0 ){ // start
data->env_phase = ENV_ADSR_PHASE_ATTACK;
data->velocity = vel;
} else if(vel < 0){ // stop
if(data->env_phase != ENV_ADSR_PHASE_OFF){
data->env_phase = ENV_ADSR_PHASE_RELEASE;
data->release_init_val = data->env_counter;
}
}
uint32_t tmp;
switch(data->env_phase){
case ENV_ADSR_PHASE_OFF:
data->env_counter = 0;;
break;
case ENV_ADSR_PHASE_ATTACK:
update_attack_coeffs(env_adsr, num_samples, render_pass_id);
tmp = data->env_counter + data->attack_raw;
if(tmp < data->env_counter){ // overflow
tmp = ~((uint32_t) 0); // max out
data->env_phase = ENV_ADSR_PHASE_DECAY;
}
data->env_counter = tmp;
break;
case ENV_ADSR_PHASE_DECAY:
update_decay_coeffs(env_adsr, num_samples, render_pass_id);
tmp = data->env_counter - data->decay_raw;
if(tmp > data->env_counter){ // underflow
tmp = 0; //bottom out
}
if(tmp <= data->sustain){
tmp = data->sustain;
data->env_phase = ENV_ADSR_PHASE_SUSTAIN;
}
data->env_counter = tmp;
break;
case ENV_ADSR_PHASE_SUSTAIN:
update_sustain_coeffs(env_adsr, num_samples, render_pass_id);
if(data->sustain == 0) data->env_phase = ENV_ADSR_PHASE_OFF;
data->env_counter = data->sustain;
break;
case ENV_ADSR_PHASE_RELEASE:
update_release_coeffs(env_adsr, num_samples, render_pass_id);
tmp = data->env_counter - data->release_raw;
if(tmp > data->env_counter){ // underflow
tmp = 0; //bottom out
data->env_phase = ENV_ADSR_PHASE_OFF;
}
data->env_counter = tmp;
break;
}
data->num_samples_prev = num_samples;
int32_t gain = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_GAIN], 0, render_pass_id);
if((data->env_phase == ENV_ADSR_PHASE_OFF) || (!gain)){
data->env_prev = 0;
radspa_signal_set_const_value(&env_adsr->signals[ENV_ADSR_OUTPUT], 0);
radspa_signal_set_const_value(&env_adsr->signals[ENV_ADSR_ENV_OUTPUT], 0);
return;
}
int32_t env = data->env_counter >> 17;
env = (env * data->velocity) >> 15;
env = (env * gain) >> 15;
radspa_signal_set_const_value(&env_adsr->signals[ENV_ADSR_ENV_OUTPUT], env);
if(data->square_mult[data->env_phase]){
uint32_t env_sq = (data->env_counter >> 17) - data->square_min[data->env_phase];
env_sq *= env_sq << 1;
env_sq = ((uint64_t) data->square_mult[data->env_phase] * env_sq) >> 32;;
env_sq += data->square_min[data->env_phase];
env = env_sq;
env = (env * data->velocity) >> 15;
env = (env * gain) >> 15;
}
int16_t ret = radspa_signal_get_const_value(&env_adsr->signals[ENV_ADSR_INPUT], render_pass_id);
if(ret == RADSPA_SIGNAL_NONCONST){
int32_t env_slope = ((env - data->env_prev) << 15) / num_samples;
for(uint16_t i = 0; i < num_samples; i++){
ret = radspa_signal_get_value(&env_adsr->signals[ENV_ADSR_INPUT], i, render_pass_id);
int32_t env_inter = data->env_prev + ((env_slope * i)>>15);
ret = (ret * env_inter) >> 12;
radspa_signal_set_value(&env_adsr->signals[ENV_ADSR_OUTPUT], i, ret);
}
} else {
ret = (ret * env) >> 12;
radspa_signal_set_const_value(&env_adsr->signals[ENV_ADSR_OUTPUT], ret);
}
data->env_prev = env;
}
radspa_t * env_adsr_create(uint32_t init_var){
radspa_t * env_adsr = radspa_standard_plugin_create(&env_adsr_desc, ENV_ADSR_NUM_SIGNALS, sizeof(env_adsr_data_t), 0);
env_adsr->render = env_adsr_run;
radspa_signal_set(env_adsr, ENV_ADSR_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(env_adsr, ENV_ADSR_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 32767);
radspa_signal_set(env_adsr, ENV_ADSR_ENV_OUTPUT, "env_output", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_GAIN, 0);
radspa_signal_set(env_adsr, ENV_ADSR_TRIGGER, "trigger", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(env_adsr, ENV_ADSR_ATTACK, "attack", RADSPA_SIGNAL_HINT_INPUT, 100);
radspa_signal_set(env_adsr, ENV_ADSR_DECAY, "decay", RADSPA_SIGNAL_HINT_INPUT, 250);
radspa_signal_set(env_adsr, ENV_ADSR_SUSTAIN, "sustain", RADSPA_SIGNAL_HINT_INPUT, 16000);
radspa_signal_set(env_adsr, ENV_ADSR_RELEASE, "release", RADSPA_SIGNAL_HINT_INPUT, 50);
radspa_signal_set(env_adsr, ENV_ADSR_GAIN, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN, RADSPA_SIGNAL_VAL_UNITY_GAIN);
radspa_signal_get_by_index(env_adsr, ENV_ADSR_ATTACK)->unit = "ms";
radspa_signal_get_by_index(env_adsr, ENV_ADSR_DECAY)->unit = "ms";
radspa_signal_get_by_index(env_adsr, ENV_ADSR_SUSTAIN)->unit = "ms";
env_adsr_data_t * data = env_adsr->plugin_data;
data->trigger_prev = 0;
data->env_phase = ENV_ADSR_PHASE_OFF;
data->release_prev_ms = -1;
data->release_init_val_prev = -1;
data->attack_prev_ms = -1;
data->sustain_prev = -1;
data->decay_prev_ms = -1;
data->env_prev = 0;
data->square_min[ENV_ADSR_PHASE_ATTACK] = 0;
data->square_mult[ENV_ADSR_PHASE_ATTACK] = (1UL<<31) / 32767;
data->square_mult[ENV_ADSR_PHASE_OFF] = 0;
data->square_mult[ENV_ADSR_PHASE_SUSTAIN] = 0;
return env_adsr;
}
#pragma once
#include "radspa.h"
#include "radspa_helpers.h"
typedef struct {
uint32_t env_counter;
uint32_t velocity;
uint32_t square_mult[5];
uint32_t square_min[5];
int16_t trigger_prev;
uint16_t num_samples_prev;
int32_t env_prev;
uint8_t env_phase;
int16_t attack_prev_ms;
uint32_t attack_raw;
int16_t decay_prev_ms;
uint32_t decay_raw;
uint32_t sustain;
uint32_t sustain_prev;
int16_t release_prev_ms;
uint32_t release_raw;
uint32_t release_init_val;
uint32_t release_init_val_prev;
} env_adsr_data_t;
extern radspa_descriptor_t env_adsr_desc;
radspa_t * env_adsr_create(uint32_t init_var);
void env_adsr_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "filter.h"
radspa_t * filter_create(uint32_t init_var);
radspa_descriptor_t filter_desc = {
.name = "filter",
.id = 69420,
.description = "biquad filter. use negative q for allpass variations.",
.create_plugin_instance = filter_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define FILTER_NUM_SIGNALS 7
#define FILTER_OUTPUT 0
#define FILTER_INPUT 1
#define FILTER_PITCH 2
#define FILTER_RESO 3
#define FILTER_GAIN 4
#define FILTER_MIX 5
#define FILTER_MODE 6
#define FILTER_MODE_LOWPASS 0
#define FILTER_MODE_BANDPASS 1
#define FILTER_MODE_HIGHPASS 2
#define INV_NORM_BOOST 5
static inline int32_t approx_cos(uint32_t x){
// x: full circle: 1<<32
// return val: 1<<30 <=> 1
uint32_t sq = x & (~(1UL<<31));
if(sq > (1UL<<30)) sq = (1UL<<31) - sq;
sq = ((uint64_t) sq * sq) >> 32;
int32_t ret = (((1<<28) - (uint64_t) sq)<<32) / (((1UL<<30) + sq));
if((x > (1UL<<30)) && (x < (3UL<<30))) ret = -ret;
return ret;
}
static inline void get_mode_coeffs(uint8_t mode, filter_data_t * data, int32_t * coeffs){
switch(mode){
case FILTER_MODE_LOWPASS:
coeffs[1] = ((((1L<<21) - data->cos_omega)>>INV_NORM_BOOST) * data->inv_norm)>>1;
coeffs[0] = coeffs[1]>>1;
coeffs[2] = coeffs[0];
break;
case FILTER_MODE_BANDPASS:
coeffs[0] = (data->alpha>>INV_NORM_BOOST) * data->inv_norm;
coeffs[1] = 0;
coeffs[2] = -coeffs[0];
break;
case FILTER_MODE_HIGHPASS:
coeffs[1] = ((-((1L<<21) + data->cos_omega)>>INV_NORM_BOOST) * data->inv_norm)>>1;
coeffs[0] = -coeffs[1]/2;
coeffs[2] = coeffs[0];
break;
}
}
static inline void get_coeffs(filter_data_t * data, int16_t pitch, int16_t reso, int16_t mode){
if((pitch != data->pitch_prev) || (reso != data->reso_prev)){
int32_t mqi = reso>>2;
if(mqi < 0) mqi = -mqi;
if(mqi < 171) mqi = 171;
uint32_t freq = radspa_sct_to_rel_freq(pitch, 0);
if(freq > (3UL<<29)) freq = 3UL<<29;
// unit: 1<<21 <=> 1, range: [0..1<<21]
int32_t cos_omega = approx_cos(freq)>>9;
// unit: 1<<21 <=> 1, range: [0..3<<21]
int32_t alpha = approx_cos(freq + (3UL<<30))/mqi;
// unit transform from 1<<21 to 1<<30 <=> 1
int32_t inv_norm = (1L<<30)/(((1L<<(21)) + alpha)>>INV_NORM_BOOST);
data->cos_omega = cos_omega;
data->alpha = alpha;
data->inv_norm = inv_norm;
}
if((pitch != data->pitch_prev) || (reso != data->reso_prev) || (mode != data->mode_prev)){
// unit for {in/out}_coeffs: 1<<29 <=> 1, range: full
data->out_coeffs[1] = (-data->cos_omega>>INV_NORM_BOOST) * data->inv_norm;
data->out_coeffs[2] = ((((1<<21) - data->alpha)>>INV_NORM_BOOST) * data->inv_norm) >> 1;
if(mode == -32767){
get_mode_coeffs(FILTER_MODE_LOWPASS, data, data->in_coeffs);
} else if(mode == 0){
get_mode_coeffs(FILTER_MODE_BANDPASS, data, data->in_coeffs);
} else if(mode == 32767){
get_mode_coeffs(FILTER_MODE_HIGHPASS, data, data->in_coeffs);
} else {
int32_t a[3];
int32_t b[3];
int32_t blend = mode;
if(mode < 0){
get_mode_coeffs(FILTER_MODE_LOWPASS, data, a);
get_mode_coeffs(FILTER_MODE_BANDPASS, data, b);
blend += 32767;
} else {
get_mode_coeffs(FILTER_MODE_BANDPASS, data, a);
get_mode_coeffs(FILTER_MODE_HIGHPASS, data, b);
}
blend = blend << 16;
for(uint8_t i = 0; i<3; i++){
data->in_coeffs[i] = ((int64_t) b[i] * blend) >> 32;
data->in_coeffs[i] += ((int64_t) a[i] * ((1L<<31) - blend)) >> 32;
data->in_coeffs[i] = data->in_coeffs[i] << 1;
}
data->const_output = RADSPA_SIGNAL_NONCONST;
}
/*
printf("cos_omega: %ld alpha: %ld inv_norm: %ld\n",data->cos_omega, data->alpha, data->inv_norm);
printf("in_coeffs: %ld %ld %ld\n",data->in_coeffs[0], data->in_coeffs[1], data->in_coeffs[2]);
printf("out_coeffs: %ld %ld\n", data->out_coeffs[1], data->out_coeffs[2]);
*/
}
data->pitch_prev = pitch;
data->reso_prev = reso;
data->mode_prev = mode;
}
void filter_run(radspa_t * filter, uint16_t num_samples, uint32_t render_pass_id){
filter_data_t * data = filter->plugin_data;
radspa_signal_t * output_sig = radspa_signal_get_by_index(filter, FILTER_OUTPUT);
radspa_signal_t * mode_sig = radspa_signal_get_by_index(filter, FILTER_MODE);
radspa_signal_t * input_sig = radspa_signal_get_by_index(filter, FILTER_INPUT);
radspa_signal_t * pitch_sig = radspa_signal_get_by_index(filter, FILTER_PITCH);
radspa_signal_t * gain_sig = radspa_signal_get_by_index(filter, FILTER_GAIN);
radspa_signal_t * reso_sig = radspa_signal_get_by_index(filter, FILTER_RESO);
radspa_signal_t * mix_sig = radspa_signal_get_by_index(filter, FILTER_MIX);
int16_t input_const = radspa_signal_get_const_value(input_sig, render_pass_id);
int16_t pitch_const = radspa_signal_get_const_value(pitch_sig, render_pass_id);
int16_t gain_const = radspa_signal_get_const_value(gain_sig, render_pass_id);
int16_t reso_const = radspa_signal_get_const_value(reso_sig, render_pass_id);
int16_t mode_const = radspa_signal_get_const_value(mode_sig, render_pass_id);
int16_t mix_const = radspa_signal_get_const_value(mix_sig, render_pass_id);
int16_t pitch = pitch_const;
int16_t gain = gain_const;
int16_t reso = reso_const;
int16_t mode = mode_const;
int16_t mix = mix_const;
int32_t input = input_const;
bool always_update_coeffs = true;
if((pitch_const != RADSPA_SIGNAL_NONCONST) && (reso_const != RADSPA_SIGNAL_NONCONST) && (mode_const != RADSPA_SIGNAL_NONCONST)){
always_update_coeffs = false;
get_coeffs(data, pitch, reso, mode);
}
if((input_const != RADSPA_SIGNAL_NONCONST) && (mix_const != RADSPA_SIGNAL_NONCONST) && (gain_const != RADSPA_SIGNAL_NONCONST)
&& (data->const_output != RADSPA_SIGNAL_NONCONST)){
radspa_signal_set_const_value(output_sig, data->const_output);
return;
}
int16_t out[num_samples];
for(uint16_t i = 0; i < num_samples; i++){
if(!(i & (RADSPA_EVENT_MASK))){
if(always_update_coeffs){
if(pitch_const == RADSPA_SIGNAL_NONCONST) pitch = radspa_signal_get_value(pitch_sig, i, render_pass_id);
if(reso_const == RADSPA_SIGNAL_NONCONST) reso = radspa_signal_get_value(reso_sig, i, render_pass_id);
if(mode_const == RADSPA_SIGNAL_NONCONST) mode = radspa_signal_get_value(mode_sig, i, render_pass_id);
get_coeffs(data, pitch, reso, mode);
}
if(gain_const == RADSPA_SIGNAL_NONCONST) gain = radspa_signal_get_value(gain_sig, i, render_pass_id);
if(mix_const == RADSPA_SIGNAL_NONCONST) mix = radspa_signal_get_value(mix_sig, i, render_pass_id);
}
if(input_const == RADSPA_SIGNAL_NONCONST) input = radspa_signal_get_value(input_sig, i, render_pass_id);
data->pos++;
if(data->pos >= 3) data->pos = 0;
data->in_history[data->pos] = input << 12;
int32_t ret = ((int64_t) data->in_coeffs[0] * data->in_history[data->pos]) >> 32;
for(int8_t i = 1; i < 3; i++){
int8_t pos = data->pos - i;
if(pos < 0) pos += 3;
ret += ((int64_t) data->in_history[pos] * data->in_coeffs[i]) >> 32;
ret -= ((int64_t) data->out_history[pos] * data->out_coeffs[i]) >> 32;
}
if(ret >= (1L<<28)){
ret = (1L<<28) - 1;
} else if(ret <= -(1L<<28)){
ret = 1-(1L<<28);
}
data->out_history[data->pos] = ret << 3;
ret = ret >> 9;
if(reso < 0) ret = input - (ret<<1); //allpass mode
if(mix == -32767){
ret = -ret;
} else if (mix == 0){
ret = input;
} else if(mix != 32767){
ret *= mix;
int32_t dry_vol = mix > 0 ? 32767 - mix : 32767 + mix;
ret += dry_vol * input;
ret = ret >> 15;
}
out[i] = radspa_clip(radspa_gain(ret, gain));
}
if(input_const == RADSPA_SIGNAL_NONCONST){
for(uint16_t i = 0; i < num_samples; i++){
radspa_signal_set_value(output_sig, i, out[i]);
}
} else if(data->const_output == RADSPA_SIGNAL_NONCONST){
for(uint16_t i = 0; i < num_samples; i++){
radspa_signal_set_value_check_const(output_sig, i, out[i]);
}
data->const_output = radspa_signal_set_value_check_const_result(output_sig);
} else {
radspa_signal_set_const_value(output_sig, data->const_output);
}
}
radspa_t * filter_create(uint32_t real_init_var){
radspa_t * filter = radspa_standard_plugin_create(&filter_desc, FILTER_NUM_SIGNALS, sizeof(filter_data_t), 0);
if(filter == NULL) return NULL;
filter->render = filter_run;
filter_data_t * data = filter->plugin_data;
radspa_signal_set(filter, FILTER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(filter, FILTER_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(filter, FILTER_PITCH, "cutoff", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT,
RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set(filter, FILTER_RESO, "reso", RADSPA_SIGNAL_HINT_INPUT, RADSPA_SIGNAL_VAL_UNITY_GAIN);
radspa_signal_set(filter, FILTER_GAIN, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN,
RADSPA_SIGNAL_VAL_UNITY_GAIN);
radspa_signal_set(filter, FILTER_MIX, "mix", RADSPA_SIGNAL_HINT_INPUT, 32767);
radspa_signal_set(filter, FILTER_MODE, "mode", RADSPA_SIGNAL_HINT_INPUT, -32767);
radspa_signal_t * sig;
sig = radspa_signal_get_by_index(filter, FILTER_MODE);
sig->unit = "{LOWPASS:-32767} {BANDPASS:0} {HIGHPASS:32767}";
sig = radspa_signal_get_by_index(filter, FILTER_RESO);
sig->unit = "4096*Q";
data->pos = 0;
data->pitch_prev = RADSPA_SIGNAL_NONCONST;
data->mode_prev = RADSPA_SIGNAL_NONCONST;
data->reso_prev = RADSPA_SIGNAL_NONCONST;
data->const_output = RADSPA_SIGNAL_NONCONST;
for(uint8_t i = 0; i < 3;i++){
data->in_history[i] = 0;
data->out_history[i] = 0;
}
get_coeffs(data, RADSPA_SIGNAL_VAL_SCT_A440, RADSPA_SIGNAL_VAL_UNITY_GAIN, -32767);
return filter;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
typedef struct {
int32_t in_coeffs[3];
int32_t out_coeffs[3]; // 0th entry is a dummy and never used, just for comfy indexing
int32_t in_history[3];
int32_t out_history[3];
int8_t pos;
int16_t pitch_prev;
int16_t reso_prev;
int16_t mode_prev;
int16_t const_output;
int32_t cos_omega;
int32_t alpha;
int32_t inv_norm;
} filter_data_t;
extern radspa_descriptor_t filter_desc;
radspa_t * filter_create(uint32_t init_var);
void filter_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#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;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
typedef struct {
uint32_t write_head_position;
int32_t read_head_position;
int32_t read_head_offset;
int32_t manual_prev;
int32_t decay_reso;
int16_t abs_decay_prev;
} flanger_data_t;
extern radspa_descriptor_t flanger_desc;
radspa_t * flanger_create(uint32_t init_var);
void flanger_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "lowpass.h"
radspa_t * lowpass_create(uint32_t init_var);
radspa_descriptor_t lowpass_desc = {
.name = "lowpass",
.id = 694202,
.description = "[DEPRECATED, replacement: filter]",
.create_plugin_instance = lowpass_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define LOWPASS_NUM_SIGNALS 5
#define LOWPASS_OUTPUT 0
#define LOWPASS_INPUT 1
#define LOWPASS_FREQ 2
#define LOWPASS_Q 3
#define LOWPASS_GAIN 4
#define LOWPASS_INTERNAL_SHIFT 14
#define LOWPASS_OUT_COEFF_SHIFT 30
#define LOWPASS_SUM_SHIFT 25
static void set_lowpass_coeffs(lowpass_data_t * data, int32_t freq, int32_t mq){
if(freq < 15.) freq = 15.;
if(freq > 15000.) freq = 15000.;
if(mq < 140) mq = 140;
int32_t K = 15287; // 2*48000/6.28
int32_t omega = freq;
int32_t mq_rec = (1UL<<31)/(mq+1);
int32_t A[3];
A[0] = K * K;
A[1] = K * omega * 8;
A[1] = ((int64_t) A[1] * mq_rec) >> 32;
A[1] *= 250;
A[2] = omega*omega;
// slow, figure out smth smarther:
int32_t sum_a_rec = (1ULL<<(32 + (LOWPASS_SUM_SHIFT))) / (A[0] + A[1] + A[2]);
int32_t tmp;
tmp = (int64_t) A[2] * sum_a_rec >> 32;
data->in_coeff = tmp << (32-LOWPASS_SUM_SHIFT);
tmp = 2.*(A[2]-A[0]);
tmp = ((int64_t) tmp * sum_a_rec) >> 32;
data->out_coeff[0] = tmp<<((LOWPASS_OUT_COEFF_SHIFT) - (LOWPASS_SUM_SHIFT));
tmp = (A[0]-A[1]+A[2]);
tmp = ((int64_t) tmp * sum_a_rec) >> 32;
data->out_coeff[1] = tmp<<((LOWPASS_OUT_COEFF_SHIFT) - (LOWPASS_SUM_SHIFT));
}
void lowpass_run(radspa_t * lowpass, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(lowpass, LOWPASS_OUTPUT);
if(output_sig->buffer == NULL) return;
lowpass_data_t * data = lowpass->plugin_data;
radspa_signal_t * input_sig = radspa_signal_get_by_index(lowpass, LOWPASS_INPUT);
radspa_signal_t * freq_sig = radspa_signal_get_by_index(lowpass, LOWPASS_FREQ);
radspa_signal_t * q_sig = radspa_signal_get_by_index(lowpass, LOWPASS_Q);
radspa_signal_t * gain_sig = radspa_signal_get_by_index(lowpass, LOWPASS_GAIN);
for(uint16_t i = 0; i < num_samples; i++){
int16_t input = radspa_signal_get_value(input_sig, i, render_pass_id);
int32_t freq = radspa_signal_get_value(freq_sig, i, render_pass_id);
int16_t q = radspa_signal_get_value(q_sig, i, render_pass_id);
int32_t gain = radspa_signal_get_value(gain_sig, i, render_pass_id);
if((freq != data->prev_freq) | (q != data->prev_q)){
set_lowpass_coeffs(data, freq, q);
data->prev_freq = freq;
data->prev_q = q;
}
data->pos++;
if(data->pos >= 3) data->pos = 0;
data->in_history[data->pos] = input;
int32_t in_acc = input;
int32_t ret = 0;
for(int8_t i = 0; i<2; i++){
int8_t pos = data->pos - i - 1;
if(pos < 0) pos += 3;
in_acc += (2-i)*data->in_history[pos];
ret -= (((int64_t) data->out_history[pos]) * data->out_coeff[i]) >> 32;
}
ret = ret << (32 - LOWPASS_OUT_COEFF_SHIFT);
in_acc = in_acc << (LOWPASS_INTERNAL_SHIFT);
in_acc = ((int64_t) in_acc * data->in_coeff) >> 32;
ret += in_acc;
data->out_history[data->pos] = ret;
ret = ret >> (LOWPASS_INTERNAL_SHIFT);
ret = radspa_clip(radspa_gain(ret, gain));
radspa_signal_set_value(output_sig, i, ret);
}
}
radspa_t * lowpass_create(uint32_t real_init_var){
radspa_t * lowpass = radspa_standard_plugin_create(&lowpass_desc, LOWPASS_NUM_SIGNALS, sizeof(lowpass_data_t), 0);
if(lowpass == NULL) return NULL;
lowpass->render = lowpass_run;
radspa_signal_set(lowpass, LOWPASS_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(lowpass, LOWPASS_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(lowpass, LOWPASS_FREQ, "freq", RADSPA_SIGNAL_HINT_INPUT, 500);
radspa_signal_set(lowpass, LOWPASS_Q, "reso", RADSPA_SIGNAL_HINT_INPUT, 1000);
radspa_signal_set(lowpass, LOWPASS_GAIN, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN,
RADSPA_SIGNAL_VAL_UNITY_GAIN);
lowpass_data_t * data = lowpass->plugin_data;
data->pos = 0;
data->prev_freq = 1<<24;
for(uint8_t i = 0; i < 3;i++){
data->in_history[i] = 0.;
data->out_history[i] = 0.;
}
return lowpass;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
typedef struct {
int32_t in_history[3];
int32_t in_coeff;
int32_t out_history[3];
int32_t out_coeff[2];
int32_t prev_freq;
int16_t prev_q;
int8_t pos;
} lowpass_data_t;
extern radspa_descriptor_t lowpass_desc;
radspa_t * lowpass_create(uint32_t init_var);
void lowpass_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "mixer.h"
radspa_descriptor_t mixer_desc = {
.name = "mixer",
.id = 21,
.description = "sums input and applies output gain\n init_var: number of inputs, 1-127, default 4",
.create_plugin_instance = mixer_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id){
mixer_data_t * data = mixer->plugin_data;
int32_t ret[num_samples];
bool ret_init = false;
bool ret_const_init = false;
radspa_signal_t * input_sigs[data->num_inputs];
radspa_signal_t * input_gain_sigs[data->num_inputs];
for(uint8_t j = 0; j < data->num_inputs; j++){
input_sigs[j] = radspa_signal_get_by_index(mixer, 3+2*j);
input_gain_sigs[j] = radspa_signal_get_by_index(mixer, 4+2*j);
}
for(uint8_t j = 0; j < data->num_inputs; j++){
int32_t input_gain_const = radspa_signal_get_const_value(input_gain_sigs[j], render_pass_id);
if(!input_gain_const) continue;
int32_t input_const = radspa_signal_get_const_value(input_sigs[j], render_pass_id);
if(!input_const) continue;
if((input_const != RADSPA_SIGNAL_NONCONST) && (input_gain_const != RADSPA_SIGNAL_NONCONST)){
if(ret_init){
for(uint16_t i = 0; i < num_samples; i++){
ret[i] += (input_gain_const * input_const) >> 12;
}
} else if(ret_const_init){
ret[0] += (input_gain_const * input_const) >> 12;
} else {
ret[0] = (input_gain_const * input_const) >> 12;
ret_const_init = true;
}
} else {
if(ret_const_init){
for(uint16_t i = 0; i < num_samples; i++){
ret[i] = ret[0];
}
ret_const_init = false;
}
if(input_gain_const == RADSPA_SIGNAL_VAL_UNITY_GAIN){
if(ret_init){
for(uint16_t i = 0; i < num_samples; i++){
ret[i] += radspa_signal_get_value(input_sigs[j], i, render_pass_id);
}
} else {
for(uint16_t i = 0; i < num_samples; i++){
ret[i] = radspa_signal_get_value(input_sigs[j], i, render_pass_id);
}
ret_init = true;
}
} else if(input_gain_const == -RADSPA_SIGNAL_VAL_UNITY_GAIN){
if(ret_init){
for(uint16_t i = 0; i < num_samples; i++){
ret[i] -= radspa_signal_get_value(input_sigs[j], i, render_pass_id);
}
} else {
for(uint16_t i = 0; i < num_samples; i++){
ret[i] = -radspa_signal_get_value(input_sigs[j], i, render_pass_id);
}
ret_init = true;
}
} else if(input_gain_const == RADSPA_SIGNAL_NONCONST){
if(ret_init){
for(uint16_t i = 0; i < num_samples; i++){
int32_t input_gain = radspa_signal_get_value(input_gain_sigs[j], i, render_pass_id);
ret[i] += (input_gain * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12;
}
} else {
for(uint16_t i = 0; i < num_samples; i++){
int32_t input_gain = radspa_signal_get_value(input_gain_sigs[j], i, render_pass_id);
ret[i] = (input_gain * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12;
}
ret_init = true;
}
} else {
if(ret_init){
for(uint16_t i = 0; i < num_samples; i++){
ret[i] += (input_gain_const * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12;
}
} else {
for(uint16_t i = 0; i < num_samples; i++){
ret[i] = (input_gain_const * radspa_signal_get_value(input_sigs[j], i, render_pass_id)) >> 12;
}
ret_init = true;
}
}
}
}
radspa_signal_t * output_sig = radspa_signal_get_by_index(mixer, 0);
radspa_signal_t * gain_sig = radspa_signal_get_by_index(mixer, 1);
radspa_signal_t * block_dc_sig = radspa_signal_get_by_index(mixer, 2);
bool block_dc = radspa_signal_get_value(block_dc_sig, 0, render_pass_id) > 0;
if(block_dc){
if(ret_init){
for(uint16_t i = 0; i < num_samples; i++){
bool invert = data->dc < 0;
if(invert) data->dc = -data->dc;
data->dc = ((uint64_t) data->dc * (((1UL<<12) - 1)<<20)) >> 32;
if(invert) data->dc = -data->dc;
data->dc += ret[i];
ret[i] -= (data->dc >> 12);
}
} else {
if(data->dc){
for(uint16_t i = 0; i < num_samples; i++){
bool invert = data->dc < 0;
if(invert) data->dc = -data->dc;
data->dc = ((uint64_t) data->dc * (((1UL<<12) - 1)<<20)) >> 32;
if(invert) data->dc = -data->dc;
ret[i] = -(data->dc >> 12);
ret_init = true;
}
}
}
}
if(ret_init){
int16_t gain_const = radspa_signal_get_const_value(gain_sig, render_pass_id);
int32_t gain = gain_const;
if(gain_const != RADSPA_SIGNAL_VAL_UNITY_GAIN){
if(gain_const == RADSPA_SIGNAL_NONCONST){
for(uint16_t i = 0; i < num_samples; i++){
gain = radspa_signal_get_value(gain_sig, i, render_pass_id);
ret[i] = (ret[i] * gain) >> 12;
}
} else {
for(uint16_t i = 0; i < num_samples; i++){
ret[i] = (ret[i] * gain) >> 12;
}
}
}
for(uint16_t i = 0; i < num_samples; i++){
radspa_signal_set_value(output_sig, i, ret[i]);
}
} else if(ret_const_init){
int16_t gain_const = radspa_signal_get_const_value(gain_sig, render_pass_id);
int32_t gain = gain_const;
if(gain_const != RADSPA_SIGNAL_VAL_UNITY_GAIN){
if(gain_const == RADSPA_SIGNAL_NONCONST){
for(uint16_t i = 0; i < num_samples; i++){
gain = radspa_signal_get_value(gain_sig, i, render_pass_id);
ret[i] = (ret[0] * gain) >> 12;
}
} else {
ret[0] = (ret[0] * gain) >> 12;
}
}
if(gain_const == RADSPA_SIGNAL_NONCONST){
for(uint16_t i = 0; i < num_samples; i++){
radspa_signal_set_value(output_sig, i, ret[i]);
}
} else {
radspa_signal_set_const_value(output_sig, ret[0]);
}
} else {
radspa_signal_set_const_value(output_sig, 0);
}
}
radspa_t * mixer_create(uint32_t init_var){
if(init_var == 0) init_var = 4;
if(init_var > 127) init_var = 127;
radspa_t * mixer = radspa_standard_plugin_create(&mixer_desc, 3 + 2* init_var, sizeof(mixer_data_t), 0);
if(mixer == NULL) return NULL;
mixer->render = mixer_run;
mixer_data_t * data = mixer->plugin_data;
data->num_inputs = init_var;
radspa_signal_set(mixer, 0, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(mixer, 1, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN, RADSPA_SIGNAL_VAL_UNITY_GAIN/init_var);
radspa_signal_set(mixer, 2, "block_dc", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_DEPRECATED, -32767);
radspa_signal_set_group(mixer, init_var, 2, 3, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set_group(mixer, init_var, 2, 4, "input_gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN,
RADSPA_SIGNAL_VAL_UNITY_GAIN);
radspa_signal_get_by_index(mixer, 2)->unit = "{OFF:-32767} {ON:32767}";
return mixer;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
typedef struct {
int32_t dc;
uint8_t num_inputs;
} mixer_data_t;
extern radspa_descriptor_t mixer_desc;
radspa_t * mixer_create(uint32_t init_var);
void mixer_run(radspa_t * mixer, uint16_t num_samples, uint32_t render_pass_id);
#include "multipitch.h"
radspa_descriptor_t multipitch_desc = {
.name = "multipitch",
.id = 37,
.description = "takes a pitch input and provides a number of shifted outputs."
"\ninit_var: number of outputs, default 0, max 127",
.create_plugin_instance = multipitch_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define NUM_SIGNALS 8
#define INPUT 0
#define THRU 1
#define TRIGGER_IN 2
#define TRIGGER_THRU 3
#define MOD_IN 4
#define MOD_SENS 5
#define MAX_PITCH 6
#define MIN_PITCH 7
#define NUM_MPX 2
#define OUTPUT 8
#define SHIFT 9
typedef struct {
int16_t trigger_in_prev;
int16_t trigger_thru_prev;
} multipitch_data_t;
static inline int32_t pitch_limit(int32_t pitch, int32_t min, int32_t max){
if(pitch > max){
int32_t estimate = (13981*(pitch - max))>>25;
pitch -= 2400 * estimate;
while(pitch > max) pitch -= 2400;
} else if(pitch < min){
int32_t estimate = (13891*(min - pitch))>>25;
pitch += 2400 * estimate;
while(pitch < min) pitch += 2400;
}
return pitch;
}
void multipitch_run(radspa_t * multipitch, uint16_t num_samples, uint32_t render_pass_id){
uint8_t num_outputs = (multipitch->len_signals - (NUM_SIGNALS))/2;
multipitch_data_t * data = multipitch->plugin_data;
uint16_t i;
int16_t trigger_in = radspa_trigger_get_const(&multipitch->signals[TRIGGER_IN], &data->trigger_in_prev, &i, num_samples, render_pass_id);
if(trigger_in > 0) radspa_trigger_start(trigger_in, &(data->trigger_thru_prev));
if(trigger_in < 0) radspa_trigger_stop(&(data->trigger_thru_prev));
radspa_signal_set_const_value(&multipitch->signals[TRIGGER_THRU], data->trigger_thru_prev);
int32_t max_pitch = radspa_signal_get_value(&multipitch->signals[MAX_PITCH], 0, render_pass_id);
int32_t min_pitch = radspa_signal_get_value(&multipitch->signals[MIN_PITCH], 0, render_pass_id);
if(max_pitch < min_pitch){
int32_t a = max_pitch;
max_pitch = min_pitch;
min_pitch = a;
}
int32_t input = radspa_signal_get_value(&multipitch->signals[INPUT], i, render_pass_id);
int32_t mod = radspa_signal_get_value(&multipitch->signals[MOD_IN], i, render_pass_id);
mod *= radspa_signal_get_value(&multipitch->signals[MOD_SENS], i, render_pass_id);
mod = ((int64_t) mod * 76806) >> 32;
input += mod;
radspa_signal_set_const_value(&multipitch->signals[THRU], pitch_limit(input, min_pitch, max_pitch));
for(uint8_t j = 0; j < num_outputs; j++){
int32_t shift = input + radspa_signal_get_value(&multipitch->signals[(SHIFT) + (NUM_MPX)*j], i, render_pass_id) - RADSPA_SIGNAL_VAL_SCT_A440;
radspa_signal_set_const_value(&multipitch->signals[(OUTPUT) + (NUM_MPX)*j], pitch_limit(shift, min_pitch, max_pitch));
}
}
radspa_t * multipitch_create(uint32_t init_var){
if(init_var > 127) init_var = 127;
radspa_t * multipitch = radspa_standard_plugin_create(&multipitch_desc, NUM_SIGNALS + 2*init_var, sizeof(multipitch_data_t), 0);
if(multipitch == NULL) return NULL;
multipitch->render = multipitch_run;
radspa_signal_set(multipitch, INPUT, "input", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set(multipitch, THRU, "thru", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set(multipitch, TRIGGER_IN, "trigger_in", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(multipitch, TRIGGER_THRU, "trigger_thru", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(multipitch, MOD_IN, "mod_in", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(multipitch, MOD_SENS, "mod_sens", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN, RADSPA_SIGNAL_VAL_UNITY_GAIN);
radspa_signal_set(multipitch, MAX_PITCH, "max_pitch", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440 + 2400 * 4);
radspa_signal_set(multipitch, MIN_PITCH, "min_pitch", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440 - 2400 * 4);
radspa_signal_set_group(multipitch, init_var, NUM_MPX, OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT,
RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set_group(multipitch, init_var, NUM_MPX, SHIFT, "shift", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT,
RADSPA_SIGNAL_VAL_SCT_A440);
return multipitch;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t multipitch_desc;
radspa_t * multipitch_create(uint32_t init_var);
void multipitch_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "noise.h"
radspa_t * noise_create(uint32_t init_var);
radspa_descriptor_t noise_desc = {
.name = "noise",
.id = 0,
.description = "random data",
.create_plugin_instance = noise_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define NOISE_NUM_SIGNALS 2
#define NOISE_OUTPUT 0
#define NOISE_SPEED 1
void noise_run(radspa_t * noise, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(noise, NOISE_OUTPUT);
radspa_signal_t * speed_sig = radspa_signal_get_by_index(noise, NOISE_SPEED);
if(radspa_signal_get_value(speed_sig, 0, render_pass_id) < 0){
radspa_signal_set_const_value(output_sig, radspa_random());
} else {
for(uint16_t i = 0; i < num_samples; i++){
radspa_signal_set_value(output_sig, i, radspa_random());
}
}
}
radspa_t * noise_create(uint32_t init_var){
radspa_t * noise = radspa_standard_plugin_create(&noise_desc, NOISE_NUM_SIGNALS, sizeof(char), 0);
if(noise == NULL) return NULL;
noise->render = noise_run;
radspa_signal_set(noise, NOISE_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(noise, NOISE_SPEED, "speed", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_DEPRECATED, 32767);
radspa_signal_get_by_index(noise, NOISE_SPEED)->unit = "{LFO:-32767} {AUDIO:32767}";
return noise;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t noise_desc;
radspa_t * noise_create(uint32_t init_var);
void noise_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);