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

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
Show changes
Showing
with 1812 additions and 13 deletions
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
radspa_t * lowpass_create(uint32_t init_var); radspa_t * lowpass_create(uint32_t init_var);
radspa_descriptor_t lowpass_desc = { radspa_descriptor_t lowpass_desc = {
.name = "lowpass", .name = "lowpass",
.id = 69420, .id = 694202,
.description = "2nd order lowpass lowpass, runs rly sluggish rn, sowy", .description = "[DEPRECATED, replacement: filter]",
.create_plugin_instance = lowpass_create, .create_plugin_instance = lowpass_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy .destroy_plugin_instance = radspa_standard_plugin_destroy
}; };
...@@ -16,79 +16,41 @@ radspa_descriptor_t lowpass_desc = { ...@@ -16,79 +16,41 @@ radspa_descriptor_t lowpass_desc = {
#define LOWPASS_Q 3 #define LOWPASS_Q 3
#define LOWPASS_GAIN 4 #define LOWPASS_GAIN 4
static float apply_lowpass(lowpass_data_t * data, int32_t input){ #define LOWPASS_INTERNAL_SHIFT 14
data->pos++; #define LOWPASS_OUT_COEFF_SHIFT 30
if(data->pos >= 3) data->pos = 0; #define LOWPASS_SUM_SHIFT 25
float out = 0; static void set_lowpass_coeffs(lowpass_data_t * data, int32_t freq, int32_t mq){
float in_acc = input; if(freq < 15.) freq = 15.;
if(freq > 15000.) freq = 15000.;
for(int8_t i = 0; i<2; i++){ if(mq < 140) mq = 140;
int8_t pos = data->pos - i - 1; int32_t K = 15287; // 2*48000/6.28
if(pos < 0) pos += 3; int32_t omega = freq;
in_acc += (2-i)*data->in_history[pos]; int32_t mq_rec = (1UL<<31)/(mq+1);
int32_t A[3];
out -= (data->out_history[pos] * data->out_coeff[i]);
}
out += in_acc * data->in_coeff;
data->in_history[data->pos] = input;
data->out_history[data->pos] = out;
return out;
}
static uint8_t coeff_shift(float coeff) {
int32_t ret = 16;
while(1){
int32_t test_val = (1<<ret) * coeff;
if(test_val < 0) test_val = -test_val;
if(test_val > (1<<12)){
ret -= 3;
} else if (test_val < (1<<8)){
ret += 3;
} else {
break;
}
if(ret > 28) break;
if(ret < 4) break;
}
return ret;
}
static void set_lowpass_coeffs(lowpass_data_t * data, float freq, float q){
//molasses, sorry
if(freq == 0) return;
if(q == 0) return;
float K = 2*48000;
float omega = freq * 6.28;
float A[3];
A[0] = K * K; A[0] = K * K;
A[1] = K*omega/q; A[1] = K * omega * 8;
A[1] = ((int64_t) A[1] * mq_rec) >> 32;
A[1] *= 250;
A[2] = omega*omega; A[2] = omega*omega;
float B = omega*omega; // slow, figure out smth smarther:
int32_t sum_a_rec = (1ULL<<(32 + (LOWPASS_SUM_SHIFT))) / (A[0] + A[1] + A[2]);
float sum_a = A[0] + A[1] + A[2];
float round; int32_t tmp;
//int16_t shift;
round = B / sum_a; tmp = (int64_t) A[2] * sum_a_rec >> 32;
//shift = coeff_shift(round); data->in_coeff = tmp << (32-LOWPASS_SUM_SHIFT);
data->in_coeff = round;// * (1<<shift);
//data->in_coeff_shift = shift;
round = 2.*(A[2]-A[0]) / sum_a; tmp = 2.*(A[2]-A[0]);
//shift = coeff_shift(round); tmp = ((int64_t) tmp * sum_a_rec) >> 32;
data->out_coeff[0] = round;// * (1<<shift); data->out_coeff[0] = tmp<<((LOWPASS_OUT_COEFF_SHIFT) - (LOWPASS_SUM_SHIFT));
//data->out_coeff_shift[0] = shift;
round = (A[0]-A[1]+A[2]) / sum_a; tmp = (A[0]-A[1]+A[2]);
//shift = coeff_shift(round); tmp = ((int64_t) tmp * sum_a_rec) >> 32;
data->out_coeff[1] = round;// * (1<<shift); data->out_coeff[1] = tmp<<((LOWPASS_OUT_COEFF_SHIFT) - (LOWPASS_SUM_SHIFT));
//data->out_coeff_shift[1] = shift;
} }
void lowpass_run(radspa_t * lowpass, uint16_t num_samples, uint32_t render_pass_id){ 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); radspa_signal_t * output_sig = radspa_signal_get_by_index(lowpass, LOWPASS_OUTPUT);
if(output_sig->buffer == NULL) return; if(output_sig->buffer == NULL) return;
...@@ -98,25 +60,44 @@ void lowpass_run(radspa_t * lowpass, uint16_t num_samples, uint32_t render_pass_ ...@@ -98,25 +60,44 @@ void lowpass_run(radspa_t * lowpass, uint16_t num_samples, uint32_t render_pass_
radspa_signal_t * q_sig = radspa_signal_get_by_index(lowpass, LOWPASS_Q); 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); radspa_signal_t * gain_sig = radspa_signal_get_by_index(lowpass, LOWPASS_GAIN);
static int16_t ret = 0;
for(uint16_t i = 0; i < num_samples; i++){ for(uint16_t i = 0; i < num_samples; i++){
int16_t input = input_sig->get_value(input_sig, i, num_samples, render_pass_id); int16_t input = radspa_signal_get_value(input_sig, i, render_pass_id);
int32_t freq = freq_sig->get_value(freq_sig, i, num_samples, render_pass_id); int32_t freq = radspa_signal_get_value(freq_sig, i, render_pass_id);
int16_t q = q_sig->get_value(q_sig, i, num_samples, render_pass_id); int16_t q = radspa_signal_get_value(q_sig, i, render_pass_id);
int16_t gain = gain_sig->get_value(gain_sig, i, num_samples, 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)){ if((freq != data->prev_freq) | (q != data->prev_q)){
set_lowpass_coeffs(data, freq, ((float) q + 1.)/1000.); set_lowpass_coeffs(data, freq, q);
data->prev_freq = freq; data->prev_freq = freq;
data->prev_q = q; data->prev_q = q;
} }
float out = apply_lowpass(data, input) + 0.5; data->pos++;
int16_t ret = radspa_clip(radspa_gain((int32_t) out, gain)); if(data->pos >= 3) data->pos = 0;
(output_sig->buffer)[i] = ret;
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);
} }
output_sig->value = ret;
} }
radspa_t * lowpass_create(uint32_t real_init_var){ radspa_t * lowpass_create(uint32_t real_init_var){
......
...@@ -3,12 +3,10 @@ ...@@ -3,12 +3,10 @@
#include <radspa_helpers.h> #include <radspa_helpers.h>
typedef struct { typedef struct {
float in_history[3]; int32_t in_history[3];
float in_coeff; int32_t in_coeff;
//int16_t in_coeff_shift; int32_t out_history[3];
float out_history[3]; int32_t out_coeff[2];
float out_coeff[2];
//int16_t out_coeff_shift[2];
int32_t prev_freq; int32_t prev_freq;
int16_t prev_q; int16_t prev_q;
......
#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;
}
...@@ -2,7 +2,12 @@ ...@@ -2,7 +2,12 @@
#include <radspa.h> #include <radspa.h>
#include <radspa_helpers.h> #include <radspa_helpers.h>
typedef struct {
int32_t dc;
uint8_t num_inputs;
} mixer_data_t;
extern radspa_descriptor_t mixer_desc; extern radspa_descriptor_t mixer_desc;
radspa_t * mixer_create(uint32_t init_var); radspa_t * mixer_create(uint32_t init_var);
void mixer_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id); 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;
}
...@@ -9,19 +9,21 @@ radspa_descriptor_t noise_desc = { ...@@ -9,19 +9,21 @@ radspa_descriptor_t noise_desc = {
.destroy_plugin_instance = radspa_standard_plugin_destroy .destroy_plugin_instance = radspa_standard_plugin_destroy
}; };
#define NOISE_NUM_SIGNALS 1 #define NOISE_NUM_SIGNALS 2
#define NOISE_OUTPUT 0 #define NOISE_OUTPUT 0
#define NOISE_SPEED 1
void noise_run(radspa_t * noise, uint16_t num_samples, uint32_t render_pass_id){ 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 * output_sig = radspa_signal_get_by_index(noise, NOISE_OUTPUT);
if(output_sig->buffer == NULL) return; radspa_signal_t * speed_sig = radspa_signal_get_by_index(noise, NOISE_SPEED);
static int16_t ret = 0; 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++){ for(uint16_t i = 0; i < num_samples; i++){
(output_sig->buffer)[i] = radspa_random(); radspa_signal_set_value(output_sig, i, radspa_random());
}
} }
output_sig->value = ret;
} }
radspa_t * noise_create(uint32_t init_var){ radspa_t * noise_create(uint32_t init_var){
...@@ -29,5 +31,7 @@ radspa_t * noise_create(uint32_t init_var){ ...@@ -29,5 +31,7 @@ radspa_t * noise_create(uint32_t init_var){
if(noise == NULL) return NULL; if(noise == NULL) return NULL;
noise->render = noise_run; noise->render = noise_run;
radspa_signal_set(noise, NOISE_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0); 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; return noise;
} }
...@@ -20,45 +20,70 @@ radspa_t * noise_burst_create(uint32_t init_var){ ...@@ -20,45 +20,70 @@ radspa_t * noise_burst_create(uint32_t init_var){
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_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_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"; radspa_signal_get_by_index(noise_burst, NOISE_BURST_LENGTH_MS)->unit = "ms";
noise_burst_data_t * data = noise_burst->plugin_data;
data->counter = 15;
data->limit = 15;
return noise_burst; return noise_burst;
} }
#define SAMPLE_RATE_SORRY 48000 #define SAMPLE_RATE_SORRY 48000
void noise_burst_run(radspa_t * noise_burst, uint16_t num_samples, uint32_t render_pass_id){ 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; 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 * output_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_OUTPUT);
if(output_sig->buffer == NULL) return;
radspa_signal_t * trigger_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_TRIGGER); 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); radspa_signal_t * length_ms_sig = radspa_signal_get_by_index(noise_burst, NOISE_BURST_LENGTH_MS);
int16_t ret = output_sig->value; 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));
for(uint16_t i = 0; i < num_samples; i++){ bool output_const = plugin_data->counter == plugin_data->limit;
int16_t trigger = trigger_sig->get_value(trigger_sig, i, num_samples, render_pass_id); // using output_const as proxy if system is running (will no longer be true further down)
int16_t vel = radspa_trigger_get(trigger, &(plugin_data->trigger_prev)); 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 if(vel < 0){ // stop
plugin_data->counter = plugin_data->limit; plugin_data->counter = plugin_data->limit;
} else if(vel > 0 ){ // start } else if(vel > 0 ){ // start
if(output_const){
output_const = false;
radspa_signal_set_values(output_sig, 0, i, out);
}
plugin_data->counter = 0; plugin_data->counter = 0;
int32_t length_ms = trigger_sig->get_value(length_ms_sig, i, num_samples, render_pass_id); int32_t length_ms = radspa_signal_get_value(length_ms_sig, i, render_pass_id);
plugin_data->limit = length_ms * 48; 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){ if(plugin_data->counter < plugin_data->limit){
ret = radspa_random(); out = radspa_random();
plugin_data->counter++; plugin_data->counter++;
} else { } else if(!plugin_data->hold){
ret = 0; out = 0;
} }
if(output_sig->buffer != NULL) (output_sig->buffer)[i] = ret; if(!output_const) radspa_signal_set_value(output_sig, i, out);
} }
output_sig->value = ret; if(output_const) radspa_signal_set_const_value(output_sig, out);
plugin_data->last_out = out;
} }
...@@ -6,6 +6,8 @@ typedef struct { ...@@ -6,6 +6,8 @@ typedef struct {
int32_t counter; int32_t counter;
int32_t limit; int32_t limit;
int16_t trigger_prev; int16_t trigger_prev;
int16_t last_out;
bool hold;
} noise_burst_data_t; } noise_burst_data_t;
extern radspa_descriptor_t noise_burst_desc; extern radspa_descriptor_t noise_burst_desc;
......
#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);
#include "osc_fm.h" #include "osc_fm.h"
static inline int16_t waveshaper(int16_t saw, int16_t shape);
radspa_descriptor_t osc_fm_desc = { radspa_descriptor_t osc_fm_desc = {
.name = "osc_fm", .name = "osc_fm",
.id = 420, .id = 4202,
.description = "simple audio band oscillator with classic waveforms and linear fm input", .description = "[DEPRECATED, replacement: osc] simple audio band oscillator with classic waveforms and linear fm input",
.create_plugin_instance = osc_fm_create, .create_plugin_instance = osc_fm_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy .destroy_plugin_instance = radspa_standard_plugin_destroy
}; };
#define OSC_FM_NUM_SIGNALS 4 #define OSC_FM_NUM_SIGNALS 6
#define OSC_FM_OUTPUT 0 #define OSC_FM_OUTPUT 0
#define OSC_FM_PITCH 1 #define OSC_FM_PITCH 1
#define OSC_FM_WAVEFORM 2 #define OSC_FM_WAVEFORM 2
#define OSC_FM_LIN_FM 3 #define OSC_FM_LIN_FM 3
#define OSC_FM_PITCH_THRU 4
#define OSC_FM_PITCH_OFFSET 5
radspa_t * osc_fm_create(uint32_t init_var){ radspa_t * osc_fm_create(uint32_t init_var){
radspa_t * osc_fm = radspa_standard_plugin_create(&osc_fm_desc, OSC_FM_NUM_SIGNALS, sizeof(osc_fm_data_t), 0); radspa_t * osc_fm = radspa_standard_plugin_create(&osc_fm_desc, OSC_FM_NUM_SIGNALS, sizeof(osc_fm_data_t), 0);
osc_fm->render = osc_fm_run; osc_fm->render = osc_fm_run;
radspa_signal_set(osc_fm, OSC_FM_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0); radspa_signal_set(osc_fm, OSC_FM_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(osc_fm, OSC_FM_PITCH, "pitch", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, 18367); radspa_signal_set(osc_fm, OSC_FM_PITCH, "pitch", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set(osc_fm, OSC_FM_WAVEFORM, "waveform", RADSPA_SIGNAL_HINT_INPUT, -16000); radspa_signal_set(osc_fm, OSC_FM_WAVEFORM, "waveform", RADSPA_SIGNAL_HINT_INPUT, -16000);
radspa_signal_set(osc_fm, OSC_FM_LIN_FM, "lin_fm", RADSPA_SIGNAL_HINT_INPUT, 0); radspa_signal_set(osc_fm, OSC_FM_LIN_FM, "lin_fm", RADSPA_SIGNAL_HINT_INPUT, 0);
return osc_fm; radspa_signal_set(osc_fm, OSC_FM_PITCH_THRU, "fm_pitch_thru", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
} radspa_signal_set(osc_fm, OSC_FM_PITCH_OFFSET, "fm_pitch_offset", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
void osc_fm_run(radspa_t * osc_fm, uint16_t num_samples, uint32_t render_pass_id){
osc_fm_data_t * plugin_data = osc_fm->plugin_data;
radspa_signal_t * output_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_OUTPUT);
radspa_signal_t * pitch_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH);
radspa_signal_t * waveform_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_WAVEFORM);
radspa_signal_t * lin_fm_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_LIN_FM);
if(output_sig->buffer == NULL) return;
int16_t ret = 0;
for(uint16_t i = 0; i < num_samples; i++){
int16_t pitch = pitch_sig->get_value(pitch_sig, i, num_samples, render_pass_id);
int16_t wave = waveform_sig->get_value(waveform_sig, i, num_samples, render_pass_id);
int32_t lin_fm = lin_fm_sig->get_value(lin_fm_sig, i, num_samples, render_pass_id);
if(pitch != plugin_data->prev_pitch){
plugin_data->incr = radspa_sct_to_rel_freq(pitch, 0);
plugin_data->prev_pitch = pitch;
}
plugin_data->counter += plugin_data->incr;
if(lin_fm){
plugin_data->counter += lin_fm * (plugin_data->incr >> 15);
}
int32_t tmp = (plugin_data->counter) >> 17; osc_fm_data_t * data = osc_fm->plugin_data;
tmp = (tmp*2) - 32767; data->output_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_OUTPUT);
ret = waveshaper(tmp, wave); data->pitch_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH);
(output_sig->buffer)[i] = ret; data->waveform_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_WAVEFORM);
} data->lin_fm_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_LIN_FM);
output_sig->value = ret; data->fm_pitch_thru_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH_THRU);
data->fm_pitch_offset_sig = radspa_signal_get_by_index(osc_fm, OSC_FM_PITCH_OFFSET);
data->waveform_sig->unit = "{SINE:-32767} {TRI:-10922} {SQUARE:10922} {SAW:32767}";
return osc_fm;
} }
static inline int16_t triangle(int16_t saw){ static inline int16_t triangle(int32_t saw){
int32_t tmp = saw; saw -= 16384;
tmp += 16384; if(saw < -32767) saw += 65535;
if(tmp > 32767) tmp -= 65535; if(saw > 0) saw = -saw;
if(tmp > 0) tmp = -tmp; return saw * 2 + 32767;
tmp = (2 * tmp) + 32767;
return tmp;
} }
static inline int16_t waveshaper(int16_t saw, int16_t shape){ static inline int16_t waveshaper(int32_t saw, int16_t shape){
int32_t tmp = saw; int32_t tmp = saw;
uint8_t sh = ((uint16_t) shape) >> 14; uint8_t sh = ((uint16_t) shape) >> 14;
sh = (sh + 2)%4; sh = (sh + 2)%4;
...@@ -76,11 +54,11 @@ static inline int16_t waveshaper(int16_t saw, int16_t shape){ ...@@ -76,11 +54,11 @@ static inline int16_t waveshaper(int16_t saw, int16_t shape){
if(tmp > 0){ if(tmp > 0){
tmp = 32767 - tmp; tmp = 32767 - tmp;
tmp = (tmp*tmp)>>15; tmp = (tmp*tmp)>>15;
tmp = 32767. - tmp; tmp = 32767 - tmp;
} else { } else {
tmp = 32767 + tmp; tmp = 32767 + tmp;
tmp = (tmp*tmp)>>15; tmp = (tmp*tmp)>>15;
tmp = tmp - 32767.; tmp = tmp - 32767;
} }
break; break;
case 1: //tri case 1: //tri
...@@ -98,3 +76,54 @@ static inline int16_t waveshaper(int16_t saw, int16_t shape){ ...@@ -98,3 +76,54 @@ static inline int16_t waveshaper(int16_t saw, int16_t shape){
} }
return tmp; return tmp;
} }
void osc_fm_run(radspa_t * osc_fm, uint16_t num_samples, uint32_t render_pass_id){
osc_fm_data_t * data = osc_fm->plugin_data;
int16_t pitch_const = radspa_signal_get_const_value(data->pitch_sig, render_pass_id);
int16_t fm_pitch_offset_const = radspa_signal_get_const_value(data->fm_pitch_offset_sig, render_pass_id);
int16_t wave_const = radspa_signal_get_const_value(data->waveform_sig, render_pass_id);
int16_t lin_fm_const = radspa_signal_get_const_value(data->lin_fm_sig, render_pass_id);
int16_t pitch = pitch_const;
int32_t fm_pitch_offset = fm_pitch_offset_const;
int16_t wave = wave_const;
int32_t lin_fm = lin_fm_const;
if(pitch_const != -32768){
if(pitch != data->prev_pitch){
data->incr = radspa_sct_to_rel_freq(pitch, 0);
data->prev_pitch = pitch;
}
}
bool fm_thru_const = (pitch_const != -32768) && (fm_pitch_offset_const != -32768);
if(fm_thru_const) radspa_signal_set_const_value(data->fm_pitch_thru_sig, pitch_const + fm_pitch_offset_const - RADSPA_SIGNAL_VAL_SCT_A440);
for(uint16_t i = 0; i < num_samples; i++){
if(pitch_const == -32768){
pitch = radspa_signal_get_value(data->pitch_sig, i, render_pass_id);
if(pitch != data->prev_pitch){
data->incr = radspa_sct_to_rel_freq(pitch, 0);
data->prev_pitch = pitch;
}
}
if(wave_const == -32768) wave = radspa_signal_get_value(data->waveform_sig, i, render_pass_id);
if(lin_fm_const == -32768) lin_fm = radspa_signal_get_value(data->lin_fm_sig, i, render_pass_id);
data->counter += data->incr;
if(lin_fm){
data->counter += lin_fm * (data->incr >> 15);
}
int32_t tmp = (data->counter) >> 16;
tmp = tmp - 32767;
tmp = waveshaper(tmp, wave);
radspa_signal_set_value(data->output_sig, i, tmp);
if(fm_pitch_offset_const == -32768) fm_pitch_offset = radspa_signal_get_value(data->fm_pitch_offset_sig, i, render_pass_id);
if(!fm_thru_const) radspa_signal_set_value(data->fm_pitch_thru_sig, i, pitch + fm_pitch_offset - RADSPA_SIGNAL_VAL_SCT_A440);
}
}
...@@ -6,6 +6,12 @@ typedef struct { ...@@ -6,6 +6,12 @@ typedef struct {
uint32_t counter; uint32_t counter;
int16_t prev_pitch; int16_t prev_pitch;
int32_t incr; int32_t incr;
radspa_signal_t * output_sig;
radspa_signal_t * pitch_sig;
radspa_signal_t * waveform_sig;
radspa_signal_t * lin_fm_sig;
radspa_signal_t * fm_pitch_thru_sig;
radspa_signal_t * fm_pitch_offset_sig;
} osc_fm_data_t; } osc_fm_data_t;
extern radspa_descriptor_t osc_fm_desc; extern radspa_descriptor_t osc_fm_desc;
......
#include "poly_squeeze.h"
radspa_descriptor_t poly_squeeze_desc = {
.name = "poly_squeeze",
.id = 172,
.description = "Multiplexes a number of trigger and pitch inputs into a lesser number of trigger pitch output pairs. "
"The latest triggered inputs are forwarded to the output. If such an input receives a stop trigger it is disconnected "
"from its output. If another inputs is in triggered state but not forwarded at the same time it will be connected to that "
"output and the output is triggered. Pitch is constantly streamed to the outputs if they are connected, else the last "
"connected value is being held."
"\ninit_var: lsb: number of outputs, 1..16, default 3; lsb+1: number of inputs, <lsb>..32, default 10; ",
.create_plugin_instance = poly_squeeze_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define NUM_MPX 2
// mpx block 1
#define TRIGGER_INPUT 0
#define PITCH_INPUT 1
// mpx block 2
#define TRIGGER_OUTPUT 0
#define PITCH_OUTPUT 1
static void assign_note_voices(poly_squeeze_data_t * data){
poly_squeeze_note_t * note = data->active_notes_top;
if(note == NULL) return;
uint32_t active_voices = 0xFFFFFFFFUL << data->num_voices;
for(uint8_t i = 0; i < data->num_voices; i++){
if(note == NULL) break;
if(note->voice >= 0) active_voices = active_voices | (1UL<<note->voice);
note = note->lower;
}
while(note != NULL){
note->voice = -1;
note = note->lower;
}
if(active_voices == UINT32_MAX) return;
note = data->active_notes_top;
for(uint8_t i = 0; i < data->num_voices; i++){
if(note == NULL) break;
if(note->voice < 0){
int8_t voice = -1;
for(int8_t v = 0; v < data->num_voices; v++){
if((~active_voices) & (1<<v)){
active_voices = active_voices | (1<<v);
voice = v;
break;
}
}
note->voice = voice;
}
note = note->lower;
}
}
static poly_squeeze_note_t * get_note_with_voice(poly_squeeze_data_t * data, int8_t voice){
poly_squeeze_note_t * note = data->active_notes_top;
for(uint8_t i = 0; i < data->num_voices; i++){
if(note == NULL) break;
if(note->voice == voice) return note;
note = note->lower;
}
return NULL;
}
void take_note(poly_squeeze_data_t * data, poly_squeeze_note_t * note){
if(note == NULL) return;
if(data->free_notes == note) data->free_notes = note->lower;
if(data->active_notes_bottom == note) data->active_notes_bottom = note->higher;
if(data->active_notes_top == note) data->active_notes_top = note->lower;
if(note->higher != NULL) note->higher->lower = note->lower;
if(note->lower != NULL) note->lower->higher = note->higher;
note->higher = NULL;
note->lower = NULL;
}
static int8_t put_note_on_top(poly_squeeze_data_t * data, poly_squeeze_note_t * note){
if(note == NULL) return -1;
if(note == data->active_notes_top) return note->voice;
take_note(data, note);
note->lower = data->active_notes_top;
if(note->lower != NULL) note->lower->higher = note;
data->active_notes_top = note;
if(note->lower == NULL) data->active_notes_bottom = note;
assign_note_voices(data);
return note->voice;
}
static int8_t free_note(poly_squeeze_data_t * data, poly_squeeze_note_t * note){
if(note == NULL) return -1;
take_note(data, note);
int8_t ret = note->voice;
note->voice = -1;
note->lower = data->free_notes;
if(note->lower != NULL) note->lower->higher = note;
data->free_notes = note;
assign_note_voices(data);
return ret;
}
static void voice_start(poly_squeeze_voice_t * voice, int16_t pitch, int16_t vol){
voice->pitch_out = pitch;
int16_t tmp = voice->_start_trigger;
radspa_trigger_start(vol, &tmp);
voice->trigger_out = tmp;
}
static void voice_stop(poly_squeeze_voice_t * voice){
int16_t tmp = voice->_start_trigger;
radspa_trigger_stop(&tmp);
voice->trigger_out = tmp;
}
void poly_squeeze_run(radspa_t * poly_squeeze, uint16_t num_samples, uint32_t render_pass_id){
poly_squeeze_data_t * data = poly_squeeze->plugin_data;
poly_squeeze_note_t * notes = (void *) (&(data[1]));
poly_squeeze_input_t * inputs = (void *) (&(notes[data->num_notes]));
poly_squeeze_voice_t * voices = (void *) (&(inputs[data->num_inputs]));
for(uint8_t j = 0; j < data->num_inputs; j++){
uint16_t pitch_index;
int16_t trigger_in = radspa_trigger_get_const(&poly_squeeze->signals[TRIGGER_INPUT + NUM_MPX*j],
&inputs[j].trigger_in_hist, &pitch_index, num_samples, render_pass_id);
notes[j].pitch = radspa_signal_get_value(&poly_squeeze->signals[PITCH_INPUT + NUM_MPX*j], pitch_index, render_pass_id);
// should order events by pitch index some day maybe
if(trigger_in > 0){
notes[j].vol = trigger_in;
int8_t voice = put_note_on_top(data, &(notes[j]));
if(voice >= 0) voice_start(&(voices[voice]), notes[j].pitch, notes[j].vol);
} else if(trigger_in < 0){
int8_t voice = free_note(data, &(notes[j]));
if(voice >= 0){
poly_squeeze_note_t * note = get_note_with_voice(data, voice);
if(note == NULL){
voice_stop(&(voices[voice]));
} else {
voice_start(&(voices[voice]), note->pitch, note->vol);
}
}
}
}
for(uint8_t j = 0; j < data->num_inputs; j++){
if((notes[j].voice != -1) && (notes[j].voice < data->num_voices)){
voices[notes[j].voice].pitch_out = notes[j].pitch;
}
}
for(uint8_t j = 0; j < data->num_voices; j++){
uint8_t k = data->num_inputs + j;
radspa_signal_set_const_value(&poly_squeeze->signals[TRIGGER_OUTPUT + NUM_MPX * k], voices[j].trigger_out);
radspa_signal_set_const_value(&poly_squeeze->signals[PITCH_OUTPUT + NUM_MPX * k], voices[j].pitch_out);
voices[j]._start_trigger = voices[j].trigger_out;
}
}
radspa_t * poly_squeeze_create(uint32_t init_var){
if(!init_var) init_var = 3 + (1UL<<8) + 9 * (1UL<<16);
uint8_t num_voices = init_var & 0xFF;
if(num_voices > 32) num_voices = 32;
if(num_voices < 1) num_voices = 1;
init_var = init_var >> 8;
uint8_t num_inputs = init_var & 0xFF;
if(num_inputs > 32) num_inputs = 32;
if(num_inputs < num_voices) num_inputs = num_voices;
uint8_t num_notes = num_inputs;
uint32_t num_signals = num_voices * NUM_MPX + num_inputs * NUM_MPX;
size_t data_size = sizeof(poly_squeeze_data_t);
data_size += sizeof(poly_squeeze_voice_t) * num_voices;
data_size += sizeof(poly_squeeze_note_t) * num_notes;
data_size += sizeof(poly_squeeze_input_t) * num_inputs;
radspa_t * poly_squeeze = radspa_standard_plugin_create(&poly_squeeze_desc, num_signals, data_size, 0);
if(poly_squeeze == NULL) return NULL;
poly_squeeze->render = poly_squeeze_run;
radspa_signal_set_group(poly_squeeze, num_inputs, NUM_MPX, TRIGGER_INPUT, "trigger_in",
RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set_group(poly_squeeze, num_inputs, NUM_MPX, PITCH_INPUT, "pitch_in",
RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set_group(poly_squeeze, num_voices, NUM_MPX, TRIGGER_OUTPUT + NUM_MPX*num_inputs, "trigger_out",
RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set_group(poly_squeeze, num_voices, NUM_MPX, PITCH_OUTPUT + NUM_MPX*num_inputs, "pitch_out",
RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
poly_squeeze_data_t * data = poly_squeeze->plugin_data;
data->num_voices = num_voices;
data->num_notes = num_notes;
data->num_inputs = num_inputs;
poly_squeeze_note_t * notes = (void *) (&(data[1]));
poly_squeeze_input_t * inputs = (void *) (&(notes[data->num_notes]));
poly_squeeze_voice_t * voices = (void *) (&(inputs[data->num_inputs]));
data->active_notes_top = NULL;
data->active_notes_bottom = NULL;
data->free_notes = &(notes[0]);
for(uint8_t i = 0; i < num_voices; i++){
voices[i].trigger_out = 0;
voices[i].pitch_out = RADSPA_SIGNAL_VAL_SCT_A440;
voices[i]._start_trigger = voices[i].trigger_out;
}
for(uint8_t i = 0; i < num_notes; i++){
notes[i].pitch = -32768;
notes[i].voice = -1;
if(i){
notes[i].higher = &(notes[i-1]);
} else{
notes[i].higher = NULL;
}
if(i != (num_notes - 1)){
notes[i].lower = &(notes[i+1]);
} else {
notes[i].lower = NULL;
}
}
for(uint8_t i = 0; i < num_inputs; i++){
inputs[i].trigger_in_hist = 0;
}
return poly_squeeze;
}
#pragma once
#include "radspa.h"
#include "radspa_helpers.h"
typedef struct _poly_squeeze_note_t {
int16_t pitch;
int16_t vol;
int8_t voice;
struct _poly_squeeze_note_t * lower;
struct _poly_squeeze_note_t * higher;
} poly_squeeze_note_t;
typedef struct {
int16_t trigger_out;
int16_t pitch_out;
int16_t _start_trigger;
} poly_squeeze_voice_t;
typedef struct {
int16_t trigger_in_hist;
} poly_squeeze_input_t;
typedef struct {
uint8_t num_voices;
uint8_t num_notes;
uint8_t num_inputs;
poly_squeeze_note_t * active_notes_top;
poly_squeeze_note_t * active_notes_bottom;
poly_squeeze_note_t * free_notes;
} poly_squeeze_data_t;
extern radspa_descriptor_t poly_squeeze_desc;
radspa_t * poly_squeeze_create(uint32_t init_var);
void poly_squeeze_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "range_shifter.h"
radspa_t * range_shifter_create(uint32_t init_var);
radspa_descriptor_t range_shifter_desc = {
.name = "range_shifter",
.id = 69,
.description = "saturating multiplication and addition",
.create_plugin_instance = range_shifter_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define RANGE_SHIFTER_NUM_SIGNALS 7
#define RANGE_SHIFTER_OUTPUT 0
#define RANGE_SHIFTER_OUTPUT_A 1
#define RANGE_SHIFTER_OUTPUT_B 2
#define RANGE_SHIFTER_INPUT 3
#define RANGE_SHIFTER_INPUT_A 4
#define RANGE_SHIFTER_INPUT_B 5
#define RANGE_SHIFTER_SPEED 6
#define GET_GAIN { \
output_a = radspa_signal_get_value(output_a_sig, k, render_pass_id); \
output_b = radspa_signal_get_value(output_b_sig, k, render_pass_id); \
input_a = radspa_signal_get_value(input_a_sig, k, render_pass_id); \
input_b = radspa_signal_get_value(input_b_sig, k, render_pass_id); \
output_span = output_b - output_a; \
input_span = input_b - input_a; \
gain = (output_span << 14) / input_span; \
}
#define APPLY_GAIN { \
if(ret == input_a){ \
ret = output_a; \
} else if(ret == input_b){ \
ret = output_b; \
} else { \
ret -= input_a; \
ret = (ret * gain) >> 14; \
ret += output_a; \
} \
}
void range_shifter_run(radspa_t * range_shifter, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT);
radspa_signal_t * output_a_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT_A);
radspa_signal_t * output_b_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_OUTPUT_B);
radspa_signal_t * input_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_INPUT);
radspa_signal_t * input_a_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_INPUT_A);
radspa_signal_t * input_b_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_INPUT_B);
radspa_signal_t * speed_sig = radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_SPEED);
int16_t speed = radspa_signal_get_value(speed_sig, 0, render_pass_id);
int32_t output_a = radspa_signal_get_const_value(output_a_sig, render_pass_id);
int32_t output_b = radspa_signal_get_const_value(output_b_sig, render_pass_id);
int32_t input_a = radspa_signal_get_const_value(input_a_sig, render_pass_id);
int32_t input_b = radspa_signal_get_const_value(input_b_sig, render_pass_id);
int32_t input = radspa_signal_get_const_value(input_sig, render_pass_id);
bool range_const = true;
if(speed >= 10922){
range_const = range_const && (output_a != RADSPA_SIGNAL_NONCONST) && (output_b != RADSPA_SIGNAL_NONCONST);
range_const = range_const && (input_a != RADSPA_SIGNAL_NONCONST) && (input_b != RADSPA_SIGNAL_NONCONST);
}
bool input_const = true;
if(speed > -10922){
input_const = input != RADSPA_SIGNAL_NONCONST;
}
int32_t output_span;
int32_t input_span;
int32_t gain;
if(range_const){
uint16_t k = 0;
GET_GAIN
if(!output_span){
radspa_signal_set_const_value(output_sig, output_a);
} else if(!input_span){
radspa_signal_set_const_value(output_sig, (output_b - output_a)>>1);
} else if(input_const){
int32_t ret = radspa_signal_get_value(input_sig, 0, render_pass_id);
APPLY_GAIN
radspa_signal_set_const_value(output_sig, ret);
} else {
for(uint16_t i = 0; i < num_samples; i++){
int32_t ret = radspa_signal_get_value(input_sig, i, render_pass_id);
APPLY_GAIN
radspa_signal_set_value(output_sig, i, ret);
}
}
} else {
for(uint16_t i = 0; i < num_samples; i++){
uint16_t k = i;
GET_GAIN
if(!output_span){
radspa_signal_set_value(output_sig, i, output_a);
} else if(!input_span){
radspa_signal_set_value(output_sig, i, (output_b - output_a)>>1);
} else {
int32_t ret = radspa_signal_get_value(input_sig, i, render_pass_id);
APPLY_GAIN
radspa_signal_set_value(output_sig, i, ret);
}
}
}
}
radspa_t * range_shifter_create(uint32_t init_var){
radspa_t * range_shifter = radspa_standard_plugin_create(&range_shifter_desc, RANGE_SHIFTER_NUM_SIGNALS, sizeof(char), 0);
if(range_shifter == NULL) return NULL;
range_shifter->render = range_shifter_run;
radspa_signal_set(range_shifter, RANGE_SHIFTER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set_group(range_shifter, 2, 1, RANGE_SHIFTER_OUTPUT_A, "output_range", RADSPA_SIGNAL_HINT_INPUT, -32767);
radspa_signal_set(range_shifter, RANGE_SHIFTER_INPUT, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set_group(range_shifter, 2, 1, RANGE_SHIFTER_INPUT_A, "input_range", RADSPA_SIGNAL_HINT_INPUT, -32767);
radspa_signal_set(range_shifter, RANGE_SHIFTER_SPEED, "speed", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_DEPRECATED, 32767);
radspa_signal_get_by_index(range_shifter, RANGE_SHIFTER_SPEED)->unit = "{SLOW:-32767} {SLOW_RANGE:0} {FAST:32767}";
range_shifter->signals[RANGE_SHIFTER_OUTPUT_B].value = 32767;
range_shifter->signals[RANGE_SHIFTER_INPUT_B].value = 32767;
return range_shifter;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t range_shifter_desc;
radspa_t * range_shifter_create(uint32_t init_var);
void range_shifter_run(radspa_t * osc, uint16_t num_samples, uint32_t render_pass_id);
#include "sampler.h"
radspa_t * sampler_create(uint32_t init_var);
radspa_descriptor_t sampler_desc = {
.name = "sampler",
.id = 696969,
.description = "simple sampler that stores a copy of the sample in ram and has basic recording functionality."
"\ninit_var: length of pcm sample memory\ntable layout: [0:2] read head position (uint32_t), [2:4] write head position (uint32_t), "
"[4:6] sample start (uint32_t), [6:8] sample length (uint32_t), [8:10] sample rate (uint32_t), [10] sampler status "
"(int16_t bitmask), , [11:init_var+11] pcm sample data (int16_t)",
.create_plugin_instance = sampler_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define SAMPLER_NUM_SIGNALS 5
#define SAMPLER_OUTPUT 0
#define SAMPLER_TRIGGER 1
#define SAMPLER_PITCH_SHIFT 2
#define SAMPLER_REC_TRIGGER 3
#define SAMPLER_REC_IN 4
#define READ_HEAD_POS 0
#define WRITE_HEAD_POS 2
#define SAMPLE_START 4
#define SAMPLE_LEN 6
#define SAMPLE_RATE 8
#define STATUS 10
#define STATUS_PLAYBACK_ACTIVE 0
#define STATUS_PLAYBACK_LOOP 1
#define STATUS_RECORD_ACTIVE 2
#define STATUS_RECORD_OVERFLOW 3
#define STATUS_RECORD_NEW_EVENT 4
#define BUFFER_OFFSET 11
void sampler_run(radspa_t * sampler, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(sampler, SAMPLER_OUTPUT);
radspa_signal_t * trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_TRIGGER);
radspa_signal_t * rec_trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_REC_TRIGGER);
radspa_signal_t * rec_in_sig = radspa_signal_get_by_index(sampler, SAMPLER_REC_IN);
radspa_signal_t * pitch_shift_sig = radspa_signal_get_by_index(sampler, SAMPLER_PITCH_SHIFT);
sampler_data_t * data = sampler->plugin_data;
int16_t trigger = radspa_signal_get_const_value(trigger_sig, render_pass_id);
bool trigger_const = trigger != RADSPA_SIGNAL_NONCONST;
if(trigger_const) trigger = radspa_trigger_get(trigger, &(data->trigger_prev));
int16_t rec_trigger = radspa_signal_get_const_value(rec_trigger_sig, render_pass_id);
bool rec_trigger_const = rec_trigger != RADSPA_SIGNAL_NONCONST;
if(rec_trigger_const) rec_trigger = radspa_trigger_get(rec_trigger, &(data->rec_trigger_prev));
/*
if((!data->playback_active) && (!data->rec_active) && (trigger_const) && (rec_trigger_const) && (!rec_trigger) && (!trigger)){
radspa_signal_set_const_value(output_sig, 0);
return;
}
*/
int16_t * buf = sampler->plugin_table;
uint32_t * buf32 = (uint32_t *) buf;
uint32_t sample_len = buf32[SAMPLE_LEN/2];
uint32_t sample_start = buf32[SAMPLE_START/2];
uint32_t sample_rate = buf32[SAMPLE_RATE/2];
if(!sample_rate){
sample_rate = 1;
buf32[SAMPLE_RATE/2] = 1;
}
uint32_t buffer_size = sampler->plugin_table_len - BUFFER_OFFSET;
uint64_t buffer_size_long = buffer_size * 48000;
if(sample_len >= buffer_size) sample_len = buffer_size - 1;
if(sample_start >= buffer_size) sample_start = buffer_size - 1;
bool output_mute = !data->playback_active;
bool output_const = sample_rate < 100;
if(output_const){
sample_rate *= num_samples;
num_samples = 1;
}
int32_t ret = 0;
for(uint16_t i = 0; i < num_samples; i++){
if((!rec_trigger_const) || (!i)){
if(!rec_trigger_const) rec_trigger = radspa_trigger_get(radspa_signal_get_value(rec_trigger_sig, i, render_pass_id), &(data->rec_trigger_prev));
if(rec_trigger > 0){
data->rec_active = true;
data->write_head_pos_long = 0;
data->write_steps = 0;
data->write_head_pos_prev = -1;
data->write_overflow = false;
buf[STATUS] |= 1<<(STATUS_RECORD_NEW_EVENT);
} else if((rec_trigger < 0) && data->rec_active){
data->rec_active = false;
}
}
if(data->rec_active){
int16_t rec_in = radspa_signal_get_value(rec_in_sig, i, render_pass_id);
int32_t write_head_pos = (data->write_head_pos_long * 699) >> 25; // equiv to x/48000 (acc 0.008%)
if(data->write_head_pos_prev == write_head_pos){
if(data->write_steps){
data->rec_acc += rec_in;
} else {
data->rec_acc = buf[write_head_pos + BUFFER_OFFSET];
}
data->write_steps++;
} else {
if(data->write_steps) buf[data->write_head_pos_prev + BUFFER_OFFSET] = data->rec_acc/data->write_steps;
data->write_steps = 0;
if(write_head_pos > data->write_head_pos_prev){
for(uint32_t j = data->write_head_pos_prev + 1; j <= write_head_pos; j++){
buf[j + BUFFER_OFFSET] = rec_in;
}
} else {
uint32_t write_head_max = write_head_pos + buffer_size;
for(uint32_t j = data->write_head_pos_prev + 1; j <= write_head_max; j++){
uint32_t index = j;
if(index >= buffer_size) index -= buffer_size;
buf[index + BUFFER_OFFSET] = rec_in;
}
}
}
if(!data->write_overflow) data->write_overflow = write_head_pos < data->write_head_pos_prev;
data->write_head_pos_prev = write_head_pos;
if(data->write_overflow & (!(buf[STATUS] & (1<<(STATUS_RECORD_OVERFLOW))))){
data->rec_active = false;
} else {
if(data->write_overflow){
sample_start = (data->write_head_pos_long * 699) >> 25;
sample_len = buffer_size;
} else {
sample_start = 0;
sample_len = (data->write_head_pos_long * 699) >> 25;
}
data->write_head_pos_long += sample_rate;
while(data->write_head_pos_long >= buffer_size_long) data->write_head_pos_long -= buffer_size_long;
}
}
if((!trigger_const) || (!i)){
if(!trigger_const) trigger = radspa_trigger_get(radspa_signal_get_value(trigger_sig, i, render_pass_id), &(data->trigger_prev));
if(trigger > 0){
data->playback_active = true;
data->read_head_pos_long = 0;
data->playback_sample_start = sample_start;
data->volume = trigger;
if(output_mute){
radspa_signal_set_values(output_sig, 0, i, 0);
output_mute = false;
}
} else if(trigger < 0){
data->playback_active = false;
}
}
int32_t read_head_pos;
int8_t read_head_pos_subsample;
if(data->playback_active){
read_head_pos = (data->read_head_pos_long * 699) >> (25-6); // equiv to (x<<6)/48000 (acc 0.008%)
read_head_pos_subsample = read_head_pos & 0b111111;
read_head_pos = read_head_pos >> 6;
if(read_head_pos >= sample_len){
if(buf[STATUS] & (1<<(STATUS_PLAYBACK_LOOP))){
while(read_head_pos > sample_len){
if(sample_len){
data->read_head_pos_long -= (uint64_t) sample_len * 48000;
read_head_pos -= sample_len;
} else {
data->read_head_pos_long = 0;
read_head_pos = 0;
break;
}
}
} else {
data->playback_active = false;
}
}
}
if(data->playback_active){
uint32_t sample_offset_pos = read_head_pos + data->playback_sample_start;
while(sample_offset_pos >= sample_len){
if(sample_len){
sample_offset_pos -= sample_len;
} else {
sample_offset_pos = 0;
break;
}
}
ret = buf[sample_offset_pos + BUFFER_OFFSET];
if(read_head_pos_subsample){
ret *= (64 - read_head_pos_subsample);
sample_offset_pos++;
if(sample_offset_pos >= sample_len) sample_offset_pos -= sample_len;
ret += buf[sample_offset_pos + BUFFER_OFFSET] * read_head_pos_subsample;
ret = ret >> 6;
}
ret = radspa_mult_shift(ret, data->volume);
radspa_signal_set_value(output_sig, i, ret);
int32_t pitch_shift = radspa_signal_get_value(pitch_shift_sig, i, render_pass_id);
if(pitch_shift != data->pitch_shift_prev){
data->pitch_shift_mult = radspa_sct_to_rel_freq(radspa_clip(pitch_shift - 18376 - 10986 - 4800), 0);
if(data->pitch_shift_mult > (1<<13)) data->pitch_shift_mult = (1<<13);
data->pitch_shift_prev = pitch_shift;
}
data->read_head_pos_long += (sample_rate * data->pitch_shift_mult) >> 11;
} else {
if(!output_mute) radspa_signal_set_value(output_sig, i, 0);
}
}
if(output_mute || output_const) radspa_signal_set_const_value(output_sig, ret);
buf32[SAMPLE_START/2] = sample_start;
buf32[SAMPLE_LEN/2] = sample_len;
if(data->playback_active){
buf[STATUS] |= 1<<(STATUS_PLAYBACK_ACTIVE);
buf32[READ_HEAD_POS/2] = (data->read_head_pos_long * 699) >> 25;;
} else {
buf[STATUS] &= ~(1<<(STATUS_PLAYBACK_ACTIVE));
buf32[READ_HEAD_POS/2] = 0;
}
if(data->rec_active){
buf[STATUS] |= 1<<(STATUS_RECORD_ACTIVE);
buf32[WRITE_HEAD_POS/2] = (data->write_head_pos_long * 699) >> 25;;
} else {
buf[STATUS] &= ~(1<<(STATUS_RECORD_ACTIVE));
buf32[WRITE_HEAD_POS/2] = 0;
}
}
#define MAX_SAMPLE_LEN (48000UL*300)
radspa_t * sampler_create(uint32_t init_var){
if(init_var == 0) return NULL; //doesn't make sense
if(init_var > MAX_SAMPLE_LEN) init_var = MAX_SAMPLE_LEN;
uint32_t buffer_size = init_var;
radspa_t * sampler = radspa_standard_plugin_create(&sampler_desc, SAMPLER_NUM_SIGNALS, sizeof(sampler_data_t), buffer_size + BUFFER_OFFSET);
if(sampler == NULL) return NULL;
sampler->render = sampler_run;
radspa_signal_set(sampler, SAMPLER_OUTPUT, "playback_output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(sampler, SAMPLER_TRIGGER, "playback_trigger", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
radspa_signal_set(sampler, SAMPLER_PITCH_SHIFT, "playback_speed", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, 18367);
radspa_signal_set(sampler, SAMPLER_REC_IN, "record_input", RADSPA_SIGNAL_HINT_INPUT, 0);
radspa_signal_set(sampler, SAMPLER_REC_TRIGGER, "record_trigger", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
sampler_data_t * data = sampler->plugin_data;
data->pitch_shift_mult = 1<<11;
int16_t * buf = sampler->plugin_table;
uint32_t * buf32 = (uint32_t *) buf;
buf32[SAMPLE_RATE/2] = 48000;
buf[STATUS] = 1<<(STATUS_RECORD_OVERFLOW);
return sampler;
}
...@@ -3,9 +3,20 @@ ...@@ -3,9 +3,20 @@
#include <radspa_helpers.h> #include <radspa_helpers.h>
typedef struct { typedef struct {
uint32_t read_head_position; int64_t write_head_pos_long;
int64_t read_head_pos_long;
uint32_t playback_sample_start;
int16_t pitch_shift_prev;
int16_t trigger_prev; int16_t trigger_prev;
int16_t rec_trigger_prev;
int16_t volume; int16_t volume;
uint32_t pitch_shift_mult;
int32_t rec_acc;
int32_t write_head_pos_prev;
int16_t write_steps;
bool rec_active;
bool write_overflow;
bool playback_active;
} sampler_data_t; } sampler_data_t;
extern radspa_descriptor_t sampler_desc; extern radspa_descriptor_t sampler_desc;
......