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
Loading items

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
Loading items
Show changes
Showing
with 1847 additions and 0 deletions
#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);
#include "noise_burst.h"
radspa_descriptor_t noise_burst_desc = {
.name = "noise_burst",
.id = 7,
.description = "outputs flat noise upon trigger input for an amount of milliseconds",
.create_plugin_instance = noise_burst_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define NOISE_BURST_NUM_SIGNALS 3
#define NOISE_BURST_OUTPUT 0
#define NOISE_BURST_TRIGGER 1
#define NOISE_BURST_LENGTH_MS 2
radspa_t * noise_burst_create(uint32_t init_var){
radspa_t * noise_burst = radspa_standard_plugin_create(&noise_burst_desc, NOISE_BURST_NUM_SIGNALS, sizeof(noise_burst_data_t),0);
noise_burst->render = noise_burst_run;
radspa_signal_set(noise_burst, NOISE_BURST_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(noise_burst, NOISE_BURST_TRIGGER, "trigger", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(noise_burst, NOISE_BURST_LENGTH_MS, "length", RADSPA_SIGNAL_HINT_INPUT, 100);
radspa_signal_get_by_index(noise_burst, NOISE_BURST_LENGTH_MS)->unit = "ms";
return noise_burst;
}
#define SAMPLE_RATE_SORRY 48000
void noise_burst_run(radspa_t * noise_burst, uint16_t num_samples, uint32_t render_pass_id){
noise_burst_data_t * plugin_data = noise_burst->plugin_data;
radspa_signal_t * output_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_OUTPUT);
radspa_signal_t * trigger_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_TRIGGER);
radspa_signal_t * length_ms_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_LENGTH_MS);
int16_t trigger = radspa_signal_get_const_value(trigger_sig, render_pass_id);
bool trigger_const = trigger != RADSPA_SIGNAL_NONCONST;
int16_t vel = radspa_trigger_get(trigger, &(plugin_data->trigger_prev));
bool output_const = plugin_data->counter == plugin_data->limit;
// using output_const as proxy if system is running (will no longer be true further down)
if((trigger_const) && ((vel < 0) || ((!vel) && output_const))){
if(!plugin_data->hold) plugin_data->last_out = 0;
plugin_data->counter = plugin_data->limit;
radspa_signal_set_const_value(output_sig, plugin_data->last_out);
return;
}
int16_t out = plugin_data->last_out;
for(uint16_t i = 0; i < num_samples; i++){
if(!(i && trigger_const)){
if(!trigger_const){
trigger = radspa_signal_get_value(trigger_sig, i, render_pass_id);
vel = radspa_trigger_get(trigger, &(plugin_data->trigger_prev));
}
if(vel < 0){ // stop
plugin_data->counter = plugin_data->limit;
} else if(vel > 0 ){ // start
if(output_const){
output_const = false;
radspa_signal_set_values(output_sig, 0, i, out);
}
plugin_data->counter = 0;
int32_t length_ms = radspa_signal_get_value(length_ms_sig, i, render_pass_id);
if(length_ms > 0){
plugin_data->hold = false;
plugin_data->limit = length_ms * ((SAMPLE_RATE_SORRY) / 1000);
} else {
plugin_data->hold = true;
if(length_ms){
plugin_data->limit = -length_ms * ((SAMPLE_RATE_SORRY) / 1000);
} else {
plugin_data->limit = 1;
}
}
}
}
if(plugin_data->counter < plugin_data->limit){
out = radspa_random();
plugin_data->counter++;
} else if(!plugin_data->hold){
out = 0;
}
if(!output_const) radspa_signal_set_value(output_sig, i, out);
}
if(output_const) radspa_signal_set_const_value(output_sig, out);
plugin_data->last_out = out;
}
#pragma once
#include "radspa.h"
#include "radspa_helpers.h"
typedef struct {
int32_t counter;
int32_t limit;
int16_t trigger_prev;
int16_t last_out;
bool hold;
} noise_burst_data_t;
extern radspa_descriptor_t noise_burst_desc;
radspa_t * noise_burst_create(uint32_t init_var);
void noise_burst_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "osc.h"
radspa_descriptor_t osc_desc = {
.name = "osc",
.id = 420,
.description = "simple oscillator with waveshaping, linear fm and hardsync",
.create_plugin_instance = osc_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define OSC_NUM_SIGNALS 9
#define OSC_OUT 0
#define OSC_PITCH 1
#define OSC_WAVEFORM 2
#define OSC_MORPH 3
#define OSC_FM 4
#define OSC_SYNC_IN 5
#define OSC_SYNC_IN_PHASE 6
#define OSC_SYNC_OUT 7
#define OSC_SPEED 8
#pragma GCC push_options
#pragma GCC optimize ("-O3")
/* The oscillator receives a lot of control signals that
* can be useful either as constant buffers or at full
* resolution. This results in a lot of if(_const) in the
* for loop, dragging down performance. We could split
* the oscillator up in seperate less general purpose
* plugins, but we wouldn't change the UI anyways so
* instead we allow ourselves to generate a bunch of
* code here by manually unswitching the for loop.
*
* If all conditionals are removed the code size explodes
* a bit too much, but we can group them into blocks so that
* if either element of a block receives a fast signal it takes
* the performance hit for all of them:
*
* pitch, morph and waveform are grouped together since they
* typically are constant and only need fast signals for ring
* modulation like effects. We call this the RINGMOD group.
*
* fm and sync_in are grouped together for similar reasons
* into the OSCMOD group.
*
* out and sync_out should be switched seperately, but we can
* ignore the option of them both being disconnected and switch
* to LFO mode in this case instead. This generates slightly
* different antialiasing but that is okay, especially since
* hosts are advised to not render a plugin at all if no
* output is connected to anything.
*
* the index for OSC_MEGASWITCH is defined as follows:
* ringmod_const + (oscmod_const<<1) + (out_const<<2) + (sync_out_const<<3);
*
* this limits the index range to [0..11], a reasonable amount
* of extra code size in our opinion given the importance of a
* fast and flexible basic oscillator building block.
*/
#define OSC_MEGASWITCH \
case 0: \
for(; i < num_samples; i++){ \
RINGMOD_READ \
FM_READ \
OSCILLATE \
SYNC_IN_READ \
OUT_WRITE \
SYNC_OUT_WRITE \
} \
break; \
case 1: \
for(; i < num_samples; i++){ \
FM_READ \
OSCILLATE \
SYNC_IN_READ \
OUT_WRITE \
SYNC_OUT_WRITE \
} \
break; \
case 2: \
for(; i < num_samples; i++){ \
RINGMOD_READ \
OSCILLATE \
OUT_WRITE \
SYNC_OUT_WRITE \
} \
break; \
case 3: \
for(; i < num_samples; i++){ \
OSCILLATE \
OUT_WRITE \
SYNC_OUT_WRITE \
} \
break; \
case 4: \
for(; i < num_samples; i++){ \
RINGMOD_READ \
FM_READ \
OSCILLATE \
SYNC_IN_READ \
SYNC_OUT_WRITE \
} \
break; \
case 5: \
for(; i < num_samples; i++){ \
FM_READ \
OSCILLATE \
SYNC_IN_READ \
SYNC_OUT_WRITE \
} \
break; \
case 6: \
for(; i < num_samples; i++){ \
RINGMOD_READ \
OSCILLATE \
SYNC_OUT_WRITE \
} \
break; \
case 7: \
for(; i < num_samples; i++){ \
OSCILLATE \
SYNC_OUT_WRITE \
} \
break; \
case 8: \
for(; i < num_samples; i++){ \
RINGMOD_READ \
FM_READ \
OSCILLATE \
SYNC_IN_READ \
OUT_WRITE \
} \
break; \
case 9: \
for(; i < num_samples; i++){ \
FM_READ \
OSCILLATE \
SYNC_IN_READ \
OUT_WRITE \
} \
break; \
case 10: \
for(; i < num_samples; i++){ \
RINGMOD_READ \
OSCILLATE \
OUT_WRITE \
} \
break; \
case 11: \
for(; i < num_samples; i++){ \
OSCILLATE \
OUT_WRITE \
} \
break; \
/*
int16_t poly_blep_saw(int32_t input, int32_t incr){
input += 32767;
incr = incr >> 16;
incr_rec = (1<<(16+14)) / incr;
if (input < incr){
input = ((input * incr_rec) >> (14-1);
input -= ((input*input)>>18);
return input - 65536;
} else if(input > 65535 - incr) {
input = input - 65535;
input = ((input * incr_rec) >> (14-1);
input += ((input*input)>>18);
return input + 65536;
}
return 0;
}
*/
static inline void get_ringmod_coeffs(osc_data_t * data, int16_t pitch, int32_t morph, int32_t waveform){
int32_t morph_gate = data->morph_gate_prev;
bool morph_no_pwm = data->morph_no_pwm_prev;
if(pitch != data->pitch_prev){
data->pitch_coeffs[0] = radspa_sct_to_rel_freq(pitch, 0);
morph_gate = 30700 - (data->pitch_coeffs[0]>>12); // "anti" "aliasing"
if(morph_gate < 0) morph_gate = 0;
data->pitch_prev = pitch;
}
if(waveform != data->waveform_prev){
data->waveform_prev = waveform;
data->waveform_coeffs[0] = waveform + 32767;
//if(waveform_coeffs[0] == (32767*2)){ data->waveform_coeffs[1] = UINT32_MAX; return; }
data->waveform_coeffs[1] = (((uint32_t) data->waveform_coeffs[0]) * 196616);
morph_no_pwm = waveform != 10922;
}
if(morph != data->morph_prev || (morph_gate != data->morph_gate_prev)){
if(morph > morph_gate){
morph = morph_gate;
} else if(morph < -morph_gate){
morph = -morph_gate;
}
data->morph_gate_prev = morph_gate;
if((morph != data->morph_prev) || (morph_no_pwm != data->morph_no_pwm_prev)){
data->morph_prev = morph;
data->morph_no_pwm_prev = morph_no_pwm;
data->morph_coeffs[0] = morph + 32767;
if(morph && morph_no_pwm){;
data->morph_coeffs[1] = (1L<<26)/((1L<<15) + morph);
data->morph_coeffs[2] = (1L<<26)/((1L<<15) - morph);
} else {
data->morph_coeffs[1] = 0; //always valid for pwm, speeds up modulation
data->morph_coeffs[2] = 0;
}
}
}
}
static inline int16_t triangle(int32_t saw){
saw -= 16384;
saw += 65535 * (saw < -32767);
saw -= 2*saw * (saw > 0);
return saw * 2 + 32767;
}
static inline int16_t fake_sine(int16_t tri){
int16_t sign = 2 * (tri > 0) - 1;
tri *= sign;
tri = 32767 - tri;
tri = (tri*tri)>>15;
tri = 32767 - tri;
tri *= sign;
return tri;
}
// <bad code>
// blepping is awfully slow atm but we don't have time to fix it before the next release.
// we believe it's important enough to keep it in even though it temporarily drags down
// performance. we see some low hanging fruits but we can't justify spending any more time
// on this until flow3r 1.3 is done.
static inline int16_t saw(int16_t saw, osc_data_t * data){
int16_t saw_sgn = saw > 0 ? 1 : -1;
int16_t saw_abs = saw * saw_sgn;
if(saw_abs > data->blep_coeffs[0]){
int32_t reci = (1<<15) / (32767 - data->blep_coeffs[0]);
int32_t blep = (saw_abs - data->blep_coeffs[0]) * reci;
blep = (blep * blep) >> 15;
return saw - (blep * saw_sgn);
}
return saw;
}
static inline int16_t square(int16_t saw, osc_data_t * data){
int16_t saw_sgn = saw >= 0 ? 1 : -1;
return 32767 * saw_sgn;
int16_t saw_abs = saw * saw_sgn;
saw_abs = (saw_abs >> 14) ? saw_abs : 32767 - saw_abs;
if(saw_abs > data->blep_coeffs[0]){
int32_t reci = (1<<15) / (32767 - data->blep_coeffs[0]);
int32_t blep = (saw_abs - data->blep_coeffs[0]) * reci;
blep = (blep * blep) >> 15;
return (32767 - blep) * saw_sgn;
}
return 32767 * saw_sgn;
}
static inline void get_blep_coeffs(osc_data_t * data, int32_t incr){
// if antialiasing is false we externally write INT16_MAX to blep_coeffs[0]
if(incr == data->incr_prev || (!data->antialiasing)) return;
int32_t incr_norm = ((int64_t) incr * 65535) >> 32; // max 65534
incr_norm = incr_norm > 0 ? incr_norm : -incr_norm;
data->blep_coeffs[0] = 32767 - incr_norm;
data->incr_prev = incr;
}
// </bad code>
static inline int16_t apply_morph(osc_data_t * data, uint32_t counter){
counter = counter << 1;
int32_t input = ((uint64_t) counter * 65535) >> 32; // max 65534
if(data->morph_coeffs[0] == 32767) return input - 32767; // fastpass
if(input < data->morph_coeffs[0]){
input = ((input * data->morph_coeffs[1]) >> 11);
input -= 32767;
} else {
input -= data->morph_coeffs[0];
input = ((input * data->morph_coeffs[2]) >> 11);
}
return input;
}
static inline int16_t apply_waveform(osc_data_t * data, int16_t input, int32_t incr){
int16_t a, b;
if(data->waveform_coeffs[0] < (32767-10922)){
b = triangle(input);
a = fake_sine(b);
} else if(data->waveform_coeffs[0] < (32767+10922)){
a = triangle(input);
if(data->waveform_coeffs[0] == 32767-10922) return a;
get_blep_coeffs(data, incr);
b = square(input, data);
} else if(data->waveform_coeffs[0] < (32767+32767)){
get_blep_coeffs(data, incr);
a = square(input, data);
if(data->waveform_coeffs[0] == 32767+10922) return a;
b = saw(input, data);
} else {
get_blep_coeffs(data, incr);
return saw(input, data);
}
int32_t ret = (((int64_t) (b-a) * data->waveform_coeffs[1]) >> 32);
return ret + a;
}
#define RINGMOD_READ { \
if(!pitch_const) pitch = radspa_signal_get_value(pitch_sig, i, render_pass_id); \
if(!morph_const) morph = radspa_signal_get_value(morph_sig, i, render_pass_id); \
if(!waveform_const) waveform = radspa_signal_get_value(waveform_sig, i, render_pass_id); \
get_ringmod_coeffs(data, pitch, morph, waveform); \
}
#define FM_READ { \
if(!fm_const) fm_mult = (((int32_t)radspa_signal_get_value(fm_sig, i, render_pass_id)) << 15) + (1L<<28); \
}
#define OSCILLATE \
int32_t incr = ((int64_t) data->pitch_coeffs[0] * (fm_mult)) >> 32; \
data->counter += incr * 8;
#define SYNC_IN_APPLY { \
data->counter = data->counter & (1<<31); \
data->counter += (sync_in_phase + 32767) * 32769; \
}
#define SYNC_IN_READ { \
if(!sync_in_const){ \
sync_in = radspa_signal_get_value(sync_in_sig, i, render_pass_id); \
if(radspa_trigger_get(sync_in, &(data->sync_in)) > 0){ \
if(!sync_in_phase_const){ \
sync_in_phase = radspa_signal_get_value(sync_in_phase_sig, i, render_pass_id); \
} \
SYNC_IN_APPLY \
}\
}\
}
#define OUT_APPLY \
int32_t out = apply_morph(data, data->counter); \
out = apply_waveform(data, out, incr); \
#define OUT_WRITE { \
OUT_APPLY \
radspa_signal_set_value_noclip(out_sig, i, out); \
}
#define SYNC_OUT_WRITE { \
radspa_signal_set_value_noclip(sync_out_sig, i, data->counter > (1UL<<31) ? 32767 : -32767); \
}
#define ANTIALIASING_INDEX 64
void osc_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id){
osc_data_t * data = osc->plugin_data;
int8_t * table = (int8_t * ) osc->plugin_table;
radspa_signal_t * speed_sig = radspa_signal_get_by_index(osc, OSC_SPEED);
radspa_signal_t * out_sig = radspa_signal_get_by_index(osc, OSC_OUT);
radspa_signal_t * pitch_sig = radspa_signal_get_by_index(osc, OSC_PITCH);
radspa_signal_t * waveform_sig = radspa_signal_get_by_index(osc, OSC_WAVEFORM);
radspa_signal_t * morph_sig = radspa_signal_get_by_index(osc, OSC_MORPH);
radspa_signal_t * fm_sig = radspa_signal_get_by_index(osc, OSC_FM);
radspa_signal_t * sync_in_sig = radspa_signal_get_by_index(osc, OSC_SYNC_IN);
radspa_signal_t * sync_in_phase_sig = radspa_signal_get_by_index(osc, OSC_SYNC_IN_PHASE);
radspa_signal_t * sync_out_sig = radspa_signal_get_by_index(osc, OSC_SYNC_OUT);
int16_t pitch = radspa_signal_get_const_value(pitch_sig, render_pass_id);
int16_t sync_in = radspa_signal_get_const_value(sync_in_sig, render_pass_id);
int32_t sync_in_phase = radspa_signal_get_const_value(sync_in_phase_sig, render_pass_id);
int16_t morph = radspa_signal_get_const_value(morph_sig, render_pass_id);
int16_t waveform = radspa_signal_get_const_value(waveform_sig, render_pass_id);
int16_t fm = radspa_signal_get_const_value(fm_sig, render_pass_id);
int32_t fm_mult = (((int32_t)radspa_signal_get_value(fm_sig, 0, render_pass_id)) << 15) + (1L<<28);
int16_t speed = radspa_signal_get_value(speed_sig, 0, render_pass_id);
bool out_const = out_sig->buffer == NULL;
bool sync_out_const = sync_out_sig->buffer == NULL;
data->antialiasing = table[ANTIALIASING_INDEX];
if(!data->antialiasing) data->blep_coeffs[0] = INT16_MAX;
bool lfo = speed < -10922; // manual setting
lfo = lfo || (out_const && sync_out_const); // unlikely, host should ideally prevent that case
{
get_ringmod_coeffs(data, pitch, morph, waveform);
lfo = lfo || ((speed < 10922) && (data->pitch_coeffs[0] < 1789569)); // auto mode below 20Hz
OSCILLATE
if(lfo) data->counter += incr * ((num_samples - 1) << 3);
if(radspa_trigger_get(sync_in, &(data->sync_in)) > 0){
SYNC_IN_APPLY
}
OUT_APPLY
radspa_signal_set_const_value(out_sig, out);
// future blep concept for hard sync: encode subsample progress in the last 5 bit of the
// trigger signal? would result in "auto-humanize" when attached to any other consumer
// but that's fine we think.
radspa_signal_set_const_value(sync_out_sig, data->counter > (1UL<<31) ? 32767 : -32767);
// max index 63
table[(data->counter<<1)>>(32-6)] = out >> 8;
}
if(!lfo){
uint16_t i = 1; // incrementing variable for megaswitch for loop
bool waveform_const = waveform != RADSPA_SIGNAL_NONCONST;
bool morph_const = morph != RADSPA_SIGNAL_NONCONST;
bool sync_in_phase_const = sync_in_phase != RADSPA_SIGNAL_NONCONST;
bool fm_const = fm != RADSPA_SIGNAL_NONCONST;
bool pitch_const = pitch != RADSPA_SIGNAL_NONCONST;
bool sync_in_const = sync_in != RADSPA_SIGNAL_NONCONST;
bool ringmod_const = pitch_const && morph_const && waveform_const;
bool oscmod_const = fm_const && sync_in_const;
{ // generate rest of samples with megaswitch
uint8_t fun_index = ringmod_const + (oscmod_const<<1) + (out_const<<2) + (sync_out_const<<3);
switch(fun_index){
OSC_MEGASWITCH
}
}
}
}
#pragma GCC pop_options
radspa_t * osc_create(uint32_t init_var){
radspa_t * osc = radspa_standard_plugin_create(&osc_desc, OSC_NUM_SIGNALS, sizeof(osc_data_t), 33);
int8_t * table = (int8_t * ) osc->plugin_table;
table[ANTIALIASING_INDEX] = true;
osc->render = osc_run;
radspa_signal_set(osc, OSC_OUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(osc, OSC_PITCH, "pitch", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set(osc, OSC_WAVEFORM, "waveform", RADSPA_SIGNAL_HINT_INPUT, -10922);
radspa_signal_set(osc, OSC_MORPH, "morph", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(osc, OSC_FM, "fm", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(osc, OSC_SYNC_IN, "sync_input", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(osc, OSC_SYNC_IN_PHASE, "sync_input_phase", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(osc, OSC_SYNC_OUT, "sync_output", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(osc, OSC_SPEED, "speed", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_DEPRECATED, 0);
radspa_signal_get_by_index(osc, OSC_WAVEFORM)->unit = "{SINE:-32767} {TRI:-10922} {SQUARE:10922} {SAW:32767}";
radspa_signal_get_by_index(osc, OSC_SPEED)->unit = "{LFO:-32767} {AUTO:0} {AUDIO:32767}";
osc_data_t * data = osc->plugin_data;
data->pitch_prev = -32768;
data->morph_prev = -32768;
data->waveform_prev = -32768;
data->morph_gate_prev = -32768;
return osc;
}
#pragma once
#include "radspa.h"
#include "radspa_helpers.h"
typedef struct {
uint32_t counter;
int16_t sync_in;
int16_t sync_out;
int16_t pitch_prev;
uint32_t pitch_coeffs[1];
int32_t waveform_prev;
uint32_t waveform_coeffs[2];
int32_t blep_coeffs[1];
int32_t incr_prev;
int32_t morph_prev;
int32_t morph_coeffs[3];
int16_t morph_gate_prev;
bool morph_no_pwm_prev;
bool antialiasing;
} osc_data_t;
extern radspa_descriptor_t osc_desc;
radspa_t * osc_create(uint32_t init_var);
void osc_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);