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 916 additions and 426 deletions
#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){
radspa_signal_t * output_sig = radspa_signal_get_by_index(mixer, 0);
if(output_sig->buffer == NULL) return;
radspa_signal_t * gain_sig = radspa_signal_get_by_index(mixer, 1);
uint8_t num_inputs = mixer->len_signals - 2;
radspa_signal_t * input_sigs[num_inputs];
for(uint8_t i = 0; i < num_inputs; i++){
input_sigs[i] = radspa_signal_get_by_index(mixer, 2 + i);
}
int32_t * dc_acc = mixer->plugin_data;
static int32_t ret = 0;
for(uint16_t i = 0; i < num_samples; i++){
int16_t gain = gain_sig->get_value(gain_sig, i, num_samples, render_pass_id);
ret = 0;
for(uint8_t j = 0; j < num_inputs; j++){
ret += input_sigs[j]->get_value(input_sigs[j], i, num_samples, render_pass_id);
}
// remove dc
(* dc_acc) = (ret + (* dc_acc)*1023) >> 10;
ret -= (* dc_acc);
(output_sig->buffer)[i] = radspa_clip(radspa_gain(ret, gain));
}
output_sig->value = ret;
}
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, 2 + init_var, sizeof(int32_t), 0);
if(mixer == NULL) return NULL;
mixer->render = mixer_run;
radspa_signal_set(mixer, 0, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
int16_t gain = RADSPA_SIGNAL_VAL_UNITY_GAIN/init_var;
radspa_signal_set(mixer, 1, "gain", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_GAIN, gain);
radspa_signal_set_group(mixer, init_var, 1, 2, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
int32_t * dc_acc = mixer->plugin_data;
(* dc_acc) = 0;
return mixer;
}
#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",
.create_plugin_instance = multipitch_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
void multipitch_run(radspa_t * multipitch, uint16_t num_samples, uint32_t render_pass_id){
bool output_request = false;
radspa_signal_t * thru_sig = radspa_signal_get_by_index(multipitch, 0);
if(thru_sig->buffer != NULL) output_request = true;
radspa_signal_t * input_sig = radspa_signal_get_by_index(multipitch, 1);
uint8_t num_outputs = (multipitch->len_signals - 2)/2;
radspa_signal_t * output_sigs[num_outputs];
radspa_signal_t * pitch_sigs[num_outputs];
for(uint8_t j = 0; j < num_outputs; j++){
output_sigs[j] = radspa_signal_get_by_index(multipitch, 2 + j);
pitch_sigs[j] = radspa_signal_get_by_index(multipitch, 3 + j);
if(output_sigs[j]->buffer != NULL) output_request = true;
}
if(!output_request) return;
int32_t ret = 0;
int32_t rets[num_outputs];
for(uint16_t i = 0; i < num_samples; i++){
int32_t input = input_sig->get_value(input_sig, i, num_samples, render_pass_id);
ret = input;
if(thru_sig->buffer != NULL) (thru_sig->buffer)[i] = ret;
int32_t pitch;
for(uint8_t j = 0; j < num_outputs; j++){
pitch = pitch_sigs[j]->get_value(pitch_sigs[j], i, num_samples, render_pass_id);
rets[j] = pitch + input - RADSPA_SIGNAL_VAL_SCT_A440;
if(output_sigs[j]->buffer != NULL) (output_sigs[j]->buffer)[i] = rets[j];
}
}
// clang-tidy only, num_samples is always nonzero
if(!num_samples){
for(uint8_t j = 0; j < num_outputs; j++){
rets[j] = 0;
}
}
for(uint8_t j = 0; j < num_outputs; j++){
output_sigs[j]->value = rets[j];
}
thru_sig->value = ret;
}
radspa_t * multipitch_create(uint32_t init_var){
if(init_var > 127) init_var = 127;
radspa_t * multipitch = radspa_standard_plugin_create(&multipitch_desc, 2 + 2*init_var, sizeof(int32_t), 0);
if(multipitch == NULL) return NULL;
multipitch->render = multipitch_run;
radspa_signal_set(multipitch, 0, "thru", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set(multipitch, 1, "input", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT, RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set_group(multipitch, init_var, 2, 2, "output", RADSPA_SIGNAL_HINT_OUTPUT | RADSPA_SIGNAL_HINT_SCT,
RADSPA_SIGNAL_VAL_SCT_A440);
radspa_signal_set_group(multipitch, init_var, 2, 3, "shift", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_SCT,
RADSPA_SIGNAL_VAL_SCT_A440);
return multipitch;
}
#include "sampler.h"
radspa_t * sampler_create(uint32_t init_var);
radspa_descriptor_t sampler_desc = {
.name = "_sampler_ram",
.id = 696969,
.description = "simple sampler that stores a copy of the sample in ram",
.create_plugin_instance = sampler_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
#define SAMPLER_NUM_SIGNALS 2
#define SAMPLER_OUTPUT 0
#define SAMPLER_TRIGGER 1
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);
if(output_sig->buffer == NULL) return;
sampler_data_t * data = sampler->plugin_data;
int16_t * buf = sampler->plugin_table;
radspa_signal_t * trigger_sig = radspa_signal_get_by_index(sampler, SAMPLER_TRIGGER);
static int32_t ret = 0;
uint32_t buffer_size = sampler->plugin_table_len;
for(uint16_t i = 0; i < num_samples; i++){
int16_t trigger = trigger_sig->get_value(trigger_sig, i, num_samples, render_pass_id);
int16_t vel = radspa_trigger_get(trigger, &(data->trigger_prev));
if(vel > 0){
data->read_head_position = 0;
data->volume = vel;
} else if(vel < 0){
data->read_head_position = buffer_size;
}
if(data->read_head_position < buffer_size){
ret = radspa_mult_shift(buf[data->read_head_position], data->volume);
data->read_head_position++;
} else {
//ret = (ret * 255)>>8; // avoid dc clicks with bad samples
ret = 0;
}
(output_sig->buffer)[i] = ret;
}
output_sig->value = ret;
}
radspa_t * sampler_create(uint32_t init_var){
if(init_var == 0) return NULL; //doesn't make sense
uint32_t buffer_size = init_var;
radspa_t * sampler = radspa_standard_plugin_create(&sampler_desc, SAMPLER_NUM_SIGNALS, sizeof(sampler_data_t), buffer_size);
if(sampler == NULL) return NULL;
sampler->render = sampler_run;
radspa_signal_set(sampler, SAMPLER_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(sampler, SAMPLER_TRIGGER, "trigger", RADSPA_SIGNAL_HINT_INPUT | RADSPA_SIGNAL_HINT_TRIGGER, 0);
return sampler;
}
......@@ -4,7 +4,7 @@
// this file, kindly append "-modified" to the version string below so it is not mistaken
// for an official release.
// Version 0.1.0+
// Version 0.2.1
/* Realtime Audio Developer's Simple Plugin Api
*
......@@ -42,6 +42,7 @@
#define RADSPA_SIGNAL_HINT_OUTPUT (1<<1)
#define RADSPA_SIGNAL_HINT_TRIGGER (1<<2)
#define RADSPA_SIGNAL_HINT_GAIN (1<<3)
#define RADSPA_SIGNAL_HINT_DEPRECATED (1<<4)
#define RADSPA_SIGNAL_HINT_SCT (1<<5)
#define RADSPA_SIGNAL_VAL_SCT_A440 (INT16_MAX - 6*2400)
......@@ -51,6 +52,8 @@ struct _radspa_descriptor_t;
struct _radspa_signal_t;
struct _radspa_t;
typedef void (* radspa_render_t)(struct _radspa_t * plugin, uint16_t num_samples, uint32_t render_pass_id);
typedef struct _radspa_descriptor_t{
char * name;
uint32_t id; // unique id number
......@@ -60,41 +63,48 @@ typedef struct _radspa_descriptor_t{
} radspa_descriptor_t;
typedef struct _radspa_signal_t{
// this bitfield determines the type of the signal, see RADSPA_SIGNAL_HINTS_*
uint32_t hints;
// this is the name of the signal as shown to the user.
// allowed characters: lowercase, numbers, underscore, may not start with number
// if name_multplex >= 0: may not end with number
char * name;
// arbitrary formatted string to describe what the signal is for
char * description;
// unit that corresponds to value, may be empty. note: some RADSPA_SIGNAL_HINTS_*
// imply units. field may be empty.
char * unit;
// -1 to disable signal multiplexing
int8_t name_multiplex;
int16_t * buffer; // full buffer of num_samples. may be NULL.
// used for input channels only
int16_t value; //static value, should be used if buffer is NULL.
// buffer full of samples, may be NULL.
int16_t * buffer;
// static value to be used when buffer is NULL for input signals only
int16_t value;
// when the signal has last requested to render its source
uint32_t render_pass_id;
// function to retrieve value. radspa_helpers provides an example.
int16_t (* get_value)(struct _radspa_signal_t * sig, int16_t index, uint16_t num_samples, uint32_t render_pass_id);
struct _radspa_signal_t * next; //signals are in a linked list
} radspa_signal_t;
typedef struct _radspa_t{
const radspa_descriptor_t * descriptor;
// linked list of all i/o signals of the module and length of list
radspa_signal_t * signals;
uint8_t len_signals;
void * parent;
// renders all signal outputs for num_samples if render_pass_id has changed
// since the last call, else does nothing.
void (* render)(struct _radspa_t * plugin, uint16_t num_samples, uint32_t render_pass_id);
radspa_render_t render;
// stores id number of render pass.
uint32_t render_pass_id;
// init var that was used for creating the plugin. if the plugin needs to modify the value to
// a valid range it may do so at any point in time.
uint32_t init_var;
void * plugin_data; // internal data for the plugin to use. should not be accessed from outside.
uint32_t plugin_table_len;
int16_t * plugin_table;
uint8_t len_signals;
radspa_signal_t signals[];
} radspa_t;
/* REQUIREMENTS
......@@ -108,19 +118,7 @@ typedef struct _radspa_t{
extern uint32_t radspa_sct_to_rel_freq(int16_t sct, int16_t undersample_pow);
// Return 1 if the buffer wasn't rendered already, 0 otherwise.
extern bool radspa_host_request_buffer_render(int16_t * buf, uint16_t num_samples);
// limit a to -32767..32767
extern int16_t radspa_clip(int32_t a);
// saturating int16 addition
extern int16_t radspa_add_sat(int32_t a, int32_t b);
// (a*b)>>15
extern int32_t radspa_mult_shift(int32_t a, int32_t b);
// (a*b)>>12
extern int32_t radspa_gain(int32_t a, int32_t b);
extern int16_t radspa_trigger_start(int16_t velocity, int16_t * hist);
extern int16_t radspa_trigger_stop(int16_t * hist);
extern int16_t radspa_trigger_get(int16_t trigger_signal, int16_t * hist);
extern bool radspa_host_request_buffer_render(int16_t * buf);
extern int16_t radspa_random();
//SPDX-License-Identifier: CC0-1.0
#include "radspa_helpers.h"
// #define RADSPA_SIGNAL_CACHING
extern inline int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uint32_t render_pass_id);
extern inline int16_t radspa_signal_get_const_value(radspa_signal_t * sig, uint32_t render_pass_id);
extern inline void radspa_signal_set_value(radspa_signal_t * sig, int16_t index, int32_t value);
extern inline void radspa_signal_set_value_check_const(radspa_signal_t * sig, int16_t index, int32_t value);
extern inline void radspa_signal_set_const_value(radspa_signal_t * sig, int32_t value);
extern inline int16_t radspa_clip(int32_t a);
extern inline int16_t radspa_add_sat(int32_t a, int32_t b);
extern inline int32_t radspa_mult_shift(int32_t a, int32_t b);
extern inline int32_t radspa_gain(int32_t a, int32_t b);
extern inline int16_t radspa_trigger_start(int16_t velocity, int16_t * hist);
extern inline int16_t radspa_trigger_stop(int16_t * hist);
extern inline int16_t radspa_trigger_get(int16_t trigger_signal, int16_t * hist);
extern inline radspa_signal_t * radspa_signal_get_by_index(radspa_t * plugin, uint16_t signal_index);
radspa_signal_t * radspa_signal_get_by_index(radspa_t * plugin, uint16_t signal_index){
radspa_signal_t * ret = NULL;
if(plugin == NULL) return ret; // clang-tidy
#ifdef RADSPA_SIGNAL_CACHING
static radspa_signal_t * cache_s = NULL;
static radspa_t * cache_p = NULL;
static uint16_t cache_i = 0;
if((plugin == cache_p) && (signal_index == cache_i + 1) && (cache_s != NULL)){
ret = cache_s->next;
}
if(ret == NULL){
#endif
ret = plugin->signals;
for(uint16_t i = 0; i < signal_index; i++){
ret = ret->next;
if(ret == NULL) break;
}
#ifdef RADSPA_SIGNAL_CACHING
}
cache_s = ret;
cache_p = plugin;
cache_i = signal_index;
#endif
return ret;
}
void radspa_signal_set(radspa_t * plugin, uint8_t signal_index, char * name, uint32_t hints, int16_t value){
radspa_signal_t * radspa_signal_set(radspa_t * plugin, uint8_t signal_index, char * name, uint32_t hints, int16_t value){
radspa_signal_t * sig = radspa_signal_get_by_index(plugin, signal_index);
if(sig == NULL) return;
if(sig == NULL) return NULL;
sig->name = name;
sig->hints = hints;
sig->value = value;
return sig;
}
void radspa_signal_set_description(radspa_t * plugin, uint8_t signal_index, char * description){
......@@ -44,16 +30,17 @@ void radspa_signal_set_description(radspa_t * plugin, uint8_t signal_index, char
sig->description = description;
}
void radspa_signal_set_group(radspa_t * plugin, uint8_t group_len, uint8_t step, uint8_t signal_index, char * name,
radspa_signal_t * radspa_signal_set_group(radspa_t * plugin, uint8_t group_len, uint8_t step, uint8_t signal_index, char * name,
uint32_t hints, int16_t value){
for(uint8_t i = 0; i < group_len; i++){
radspa_signal_t * sig = radspa_signal_get_by_index(plugin, signal_index + i * step);
if(sig == NULL) return;
if(sig == NULL) return NULL;
sig->name = name;
sig->hints = hints;
sig->value = value;
sig->name_multiplex = i;
}
return radspa_signal_get_by_index(plugin, signal_index);
}
void radspa_signal_set_group_description(radspa_t * plugin, uint8_t group_len, uint8_t step, uint8_t signal_index,
......@@ -65,50 +52,18 @@ void radspa_signal_set_group_description(radspa_t * plugin, uint8_t group_len, u
}
}
int16_t radspa_signal_add(radspa_t * plugin, char * name, uint32_t hints, int16_t value){
radspa_signal_t * sig = calloc(1,sizeof(radspa_signal_t));
if(sig == NULL) return -1; // allocation failed
sig->name = name;
sig->hints = hints;
static void radspa_signal_init(radspa_signal_t * sig){
sig->name = "UNINITIALIZED";
sig->hints = 0;
sig->unit = "";
sig->description = "";
sig->buffer = NULL;
sig->next = NULL;
sig->value = value;
sig->value = 0;
sig->name_multiplex = -1;
sig->get_value = radspa_signal_get_value;
//find end of linked list
uint16_t list_index = 0;
if(plugin->signals == NULL){
plugin->signals = sig;
} else {
radspa_signal_t * sigs = plugin->signals;
list_index++;
while(sigs->next != NULL){
sigs = sigs->next;
list_index++;
}
sigs->next = sig;
}
if(plugin->len_signals != list_index){ abort(); }
plugin->len_signals++;
return list_index;
}
int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uint16_t num_samples, uint32_t render_pass_id){
if(sig->buffer != NULL){
if(sig->render_pass_id != render_pass_id){
radspa_host_request_buffer_render(sig->buffer, num_samples); //, render_pass_id);
sig->render_pass_id = render_pass_id;
}
return sig->buffer[index];
}
return sig->value;
sig->buffer = NULL;
}
radspa_t * radspa_standard_plugin_create(radspa_descriptor_t * desc, uint8_t num_signals, size_t plugin_data_size, uint32_t plugin_table_size){
radspa_t * ret = calloc(1, sizeof(radspa_t));
radspa_t * ret = calloc(1, sizeof(radspa_t) + num_signals * sizeof(radspa_signal_t));
if(ret == NULL) return NULL;
if(plugin_data_size){
ret->plugin_data = calloc(1,plugin_data_size);
......@@ -117,20 +72,16 @@ radspa_t * radspa_standard_plugin_create(radspa_descriptor_t * desc, uint8_t num
return NULL;
}
}
ret->signals = NULL;
ret->len_signals = 0;
ret->len_signals = num_signals;
ret->render = NULL;
ret->descriptor = desc;
ret->plugin_table_len = plugin_table_size;
bool init_failed = false;
for(uint8_t i = 0; i < num_signals; i++){
if(radspa_signal_add(ret,"UNINITIALIZED",0,0) == -1){
init_failed = true;
break;
}
radspa_signal_init(&(ret->signals[i]));
}
bool init_failed = false;
if(ret->plugin_table_len){
ret->plugin_table = calloc(plugin_table_size, sizeof(int16_t));
if(ret->plugin_table == NULL) init_failed = true;
......@@ -146,12 +97,6 @@ radspa_t * radspa_standard_plugin_create(radspa_descriptor_t * desc, uint8_t num
}
void radspa_standard_plugin_destroy(radspa_t * plugin){
radspa_signal_t * sig = plugin->signals;
while(sig != NULL){
radspa_signal_t * sig_next = sig->next;
free(sig);
sig = sig_next;
}
if(plugin->plugin_table != NULL) free(plugin->plugin_table);
if(plugin->plugin_data != NULL) free(plugin->plugin_data);
free(plugin);
......
......@@ -2,20 +2,20 @@
#pragma once
#include "radspa.h"
#define RADSPA_SIGNAL_NONCONST (-32768)
#define RADSPA_EVENT_MASK (0b11111)
#define RADSPA_EVENT_POW (5)
// adds signal to plugin instance struct. typically used to initiate a plugin instance.
int16_t radspa_signal_add(radspa_t * plugin, char * name, uint32_t hints, int16_t value);
// as above, but sets parameters of an already existing signal with at list position signal_index
void radspa_signal_set(radspa_t * plugin, uint8_t signal_index, char * name, uint32_t hints, int16_t value);
void radspa_signal_set_group(radspa_t * plugin, uint8_t group_len, uint8_t step, uint8_t signal_index, char * name,
radspa_signal_t * radspa_signal_set(radspa_t * plugin, uint8_t signal_index, char * name, uint32_t hints, int16_t value);
radspa_signal_t * radspa_signal_set_group(radspa_t * plugin, uint8_t group_len, uint8_t step, uint8_t signal_index, char * name,
uint32_t hints, int16_t value);
void radspa_signal_set_description(radspa_t * plugin, uint8_t signal_index, char * description);
void radspa_signal_set_group_description(radspa_t * plugin, uint8_t group_len, uint8_t step, uint8_t signal_index,
char * description);
// get signal struct from a signal index
radspa_signal_t * radspa_signal_get_by_index(radspa_t * plugin, uint16_t signal_index);
radspa_t * radspa_standard_plugin_create(radspa_descriptor_t * desc, uint8_t num_signals, size_t plugin_data_size,
uint32_t plugin_table_size);
void radspa_standard_plugin_destroy(radspa_t * plugin);
......@@ -23,8 +23,168 @@ void radspa_standard_plugin_destroy(radspa_t * plugin);
// frees all signal structs. typically used to destroy a plugin instance.
void radspa_signals_free(radspa_t * plugin);
inline int16_t radspa_clip(int32_t a){
if(a > 32767){
return 32767;
} else if(a < -32767){
return -32767;
}
return a;
}
inline int16_t radspa_add_sat(int32_t a, int32_t b){ return radspa_clip(a+b); }
inline int32_t radspa_mult_shift(int32_t a, int32_t b){ return radspa_clip((a*b)>>15); }
inline int32_t radspa_gain(int32_t a, int32_t b){ return radspa_clip((a*b)>>12); }
inline int16_t radspa_trigger_start(int16_t velocity, int16_t * hist){
if(!velocity) velocity = 1;
if(velocity == -32768) velocity = 1;
if(velocity < 0) velocity = -velocity;
(* hist) = ((* hist) > 0) ? -velocity : velocity;
return * hist;
}
inline int16_t radspa_trigger_stop(int16_t * hist){
(* hist) = 0;
return * hist;
}
inline int16_t radspa_trigger_get(int16_t trigger_signal, int16_t * hist){
// might wanna remove that safeguard soon
if(trigger_signal == RADSPA_SIGNAL_NONCONST) return 0;
if((* hist) == trigger_signal) return 0;
(* hist) = trigger_signal;
if(!trigger_signal){
return -1;
} else if(trigger_signal < 0 ){
return -trigger_signal;
} else {
return trigger_signal;
}
}
inline radspa_signal_t * radspa_signal_get_by_index(radspa_t * plugin, uint16_t signal_index){
return &(plugin->signals[signal_index]);
}
/* returns the value that a signal has at a given moment in time. time is
* represented as the buffer index. requests rendering from host and requires implementation
* of radspa_host_request_buffer_render.
*/
int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uint16_t num_samples, uint32_t render_pass_id);
inline int16_t radspa_signal_get_value(radspa_signal_t * sig, int16_t index, uint32_t render_pass_id){
if(sig->buffer){
if(sig->render_pass_id != render_pass_id) radspa_host_request_buffer_render(sig->buffer);
if(sig->buffer[1] == -32768) return sig->buffer[0];
return sig->buffer[index];
}
return sig->value;
}
inline void radspa_signal_set_value_noclip(radspa_signal_t * sig, int16_t index, int16_t val){
if(sig->buffer != NULL){
sig->buffer[index] = val;
} else if(!index){
sig->value = val;
}
}
inline void radspa_signal_set_value(radspa_signal_t * sig, int16_t index, int32_t val){
if(sig->buffer != NULL){
sig->buffer[index] = radspa_clip(val);
} else if(!index){
sig->value = radspa_clip(val);
}
}
inline void radspa_signal_copy(radspa_signal_t * input, radspa_signal_t * output, uint32_t buffer_len, uint32_t render_pass_id){
if(!output->buffer){
output->value = radspa_signal_get_value(input, 0, render_pass_id);
} else if(!input->buffer){
output->buffer[0] = input->value;
output->buffer[1] = -32768;
} else {
if(input->render_pass_id != render_pass_id) radspa_host_request_buffer_render(input->buffer);
if(input->buffer[1] == -32768){
memcpy(output->buffer, input->buffer, sizeof(int16_t) * 2);
} else {
memcpy(output->buffer, input->buffer, sizeof(int16_t) * buffer_len);
}
}
}
inline void radspa_signal_set_value_check_const(radspa_signal_t * sig, int16_t index, int32_t val){
// disabled for now, causes issues somewhere, no time to track it down
radspa_signal_set_value(sig, index, val);
return;
if(sig->buffer == NULL){
if(!index) sig->value = radspa_clip(val);
return;
}
val = radspa_clip(val);
if(index == 0){
sig->buffer[0] = val;
} else if(index == 1){
if(val == sig->buffer[0]) sig->buffer[1] = -32768;
} else {
if((sig->buffer[1] == -32768) && (val != sig->buffer[0])) sig->buffer[1] = sig->buffer[0];
sig->buffer[index] = val;
}
}
inline int16_t radspa_signal_set_value_check_const_result(radspa_signal_t * sig){
if(sig->buffer != NULL){
if(sig->buffer[1] == -32768) return sig->buffer[0];
return RADSPA_SIGNAL_NONCONST;
}
return sig->value;
}
inline void radspa_signal_set_const_value(radspa_signal_t * sig, int32_t val){
if(sig->buffer == NULL){
sig->value = radspa_clip(val);
} else {
sig->buffer[0] = radspa_clip(val);
sig->buffer[1] = -32768;
}
}
inline void radspa_signal_set_values(radspa_signal_t * sig, uint16_t start, uint16_t stop, int32_t val){
if(sig->buffer == NULL){
if((!start) && stop) sig->value = radspa_clip(val);
} else {
val = radspa_clip(val);
for(uint16_t i = start; i < stop; i++){
sig->buffer[i] = val;
}
}
}
inline int16_t radspa_signal_get_const_value(radspa_signal_t * sig, uint32_t render_pass_id){
if(sig->buffer != NULL){
if(sig->render_pass_id != render_pass_id){
radspa_host_request_buffer_render(sig->buffer);
sig->render_pass_id = render_pass_id;
}
if(sig->buffer[1] == -32768) return sig->buffer[0];
return RADSPA_SIGNAL_NONCONST;
}
return sig->value;
}
inline int16_t radspa_trigger_get_const(radspa_signal_t * sig, int16_t * hist, uint16_t * index, uint16_t num_samples, uint32_t render_pass_id){
(* index) = 0;
int16_t ret_const = radspa_signal_get_const_value(sig, render_pass_id);
if(ret_const != RADSPA_SIGNAL_NONCONST) return radspa_trigger_get(ret_const, hist);
int16_t ret = 0;
for(uint16_t i = 0; i< num_samples; i++){
int16_t tmp = radspa_trigger_get(radspa_signal_get_value(sig, i, render_pass_id), hist);
if(tmp){
ret = tmp;
(* index) = i;
}
}
return ret;
}
......@@ -5,8 +5,8 @@
radspa_t * ampliverter_create(uint32_t init_var);
radspa_descriptor_t ampliverter_desc = {
.name = "ampliverter",
.id = 69,
.description = "saturating multiplication and addition",
.id = 68,
.description = "[DEPRECATED, replaced by `mixer` or `range_shifter`] saturating multiplication and addition",
.create_plugin_instance = ampliverter_create,
// with this we can only use radspa_standard_plugin_create to allocate memory.
// this restricts data layout flexibility for large buffers, but in return it offers
......@@ -37,23 +37,17 @@ void ampliverter_run(radspa_t * ampliverter, uint16_t num_samples, uint32_t rend
// step 2: render the outputs. most of the time a simple for loop will be fine.
// using {*radspa_signal_t}->get_value is required to automatically switch between
// static values and streamed data at various sample rates, don't access the data directly
int16_t bias = bias_sig->get_value(bias_sig, i, num_samples, render_pass_id);
int16_t gain = gain_sig->get_value(gain_sig, i, num_samples, render_pass_id);
int16_t bias = radspa_signal_get_value(bias_sig, i, render_pass_id);
int16_t gain = radspa_signal_get_value(gain_sig, i, render_pass_id);
if(gain == 0){
// make sure that the output buffer exists by comparing to NULL!
// (here done earlier outside of the loop)
ret = bias;
} else {
ret = input_sig->get_value(input_sig, i, num_samples, render_pass_id);
// the helper functions make sure that potential future float versions behave
// as intended
ret = radspa_signal_get_value(input_sig, i, render_pass_id);
ret = radspa_mult_shift(ret, gain);
ret = radspa_add_sat(ret, bias);
}
(output_sig->buffer)[i] = ret;
radspa_signal_set_value(output_sig, i, ret);
}
output_sig->value = ret;
}
radspa_t * ampliverter_create(uint32_t init_var){
......
#include "buffer.h"
radspa_descriptor_t buffer_desc = {
.name = "buffer",
.id = 22,
.description = "forwards input signal to output signal",
.create_plugin_instance = buffer_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id){
// note: this could be more lightweight by simply forwarding the buffer,
// however at this point the radspa protocol has no built-in flag for this.
// a host may still choose to simply do so to save CPU.
// for the future, since this is a common use case, we should add some sort of
// buffer forwarding flag. but it's okay. still lighter than the old approach
// (running a single channel mixer).
radspa_signal_t * output = radspa_signal_get_by_index(buffer, 0);
radspa_signal_t * input = radspa_signal_get_by_index(buffer, 1);
radspa_signal_copy(input, output, num_samples, render_pass_id);
}
radspa_t * buffer_create(uint32_t init_var){
radspa_t * buffer = radspa_standard_plugin_create(&buffer_desc, 2, 0, 0);
if(!buffer) return NULL;
buffer->render = buffer_run;
radspa_signal_set(buffer, 0, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
radspa_signal_set(buffer, 1, "input", RADSPA_SIGNAL_HINT_INPUT, 0);
return buffer;
}
#pragma once
#include <radspa.h>
#include <radspa_helpers.h>
extern radspa_descriptor_t buffer_desc;
radspa_t * buffer_create(uint32_t init_var);
void buffer_run(radspa_t * buffer, uint16_t num_samples, uint32_t render_pass_id);
......@@ -2,9 +2,10 @@
radspa_t * delay_create(uint32_t init_var);
radspa_descriptor_t delay_desc = {
.name = "delay",
.name = "delay_static",
.id = 42069,
.description = "simple delay with ms input and feedback",
.description = "simple delay with ms input and feedback\n"
"init_var: delay buffer length in ms, default 500",
.create_plugin_instance = delay_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
......@@ -20,7 +21,6 @@ radspa_descriptor_t delay_desc = {
void delay_run(radspa_t * delay, uint16_t num_samples, uint32_t render_pass_id){
radspa_signal_t * output_sig = radspa_signal_get_by_index(delay, DELAY_OUTPUT);
if(output_sig->buffer == NULL) return;
delay_data_t * data = delay->plugin_data;
int16_t * buf = delay->plugin_table;
radspa_signal_t * input_sig = radspa_signal_get_by_index(delay, DELAY_INPUT);
......@@ -32,34 +32,32 @@ void delay_run(radspa_t * delay, uint16_t num_samples, uint32_t render_pass_id){
static int16_t ret = 0;
uint32_t buffer_size = delay->plugin_table_len;
for(uint16_t i = 0; i < num_samples; i++){
uint32_t time = time_sig->get_value(time_sig, i, num_samples, render_pass_id);
int32_t buffer_size = delay->plugin_table_len;
int32_t time = radspa_signal_get_value(time_sig, 0, render_pass_id);
if(time < 0) time = -time;
if(time > data->max_delay) time = data->max_delay;
data->write_head_position++;
while(data->write_head_position >= buffer_size) data->write_head_position -= buffer_size; // maybe faster than %
if(time != data->time_prev){
data->read_head_position = data->write_head_position;
data->read_head_position = - time * (48000/1000);
data->read_head_position -= time * (48000/1000);
if(data->read_head_position < 0) data->read_head_position += buffer_size;
data->time_prev = time;
} else {
data->read_head_position++;
}
while(data->read_head_position >= buffer_size) data->read_head_position -= buffer_size;
int16_t fb = radspa_signal_get_value(feedback_sig, 0, render_pass_id);
int16_t level = radspa_signal_get_value(level_sig, 0, render_pass_id);
//int16_t * buf = &(data->buffer);
int16_t dry_vol = radspa_signal_get_value(dry_vol_sig, 0, render_pass_id);
int16_t rec_vol = radspa_signal_get_value(rec_vol_sig, 0, render_pass_id);
int16_t dry = input_sig->get_value(input_sig, i, num_samples, render_pass_id);
int16_t wet = buf[data->read_head_position];
int16_t fb = feedback_sig->get_value(feedback_sig, i, num_samples, render_pass_id);
int16_t level = level_sig->get_value(level_sig, i, num_samples, render_pass_id);
for(uint16_t i = 0; i < num_samples; i++){
int16_t dry_vol = dry_vol_sig->get_value(dry_vol_sig, i, num_samples, render_pass_id);
int16_t rec_vol = rec_vol_sig->get_value(rec_vol_sig, i, num_samples, render_pass_id);
data->write_head_position++;
while(data->write_head_position >= buffer_size) data->write_head_position -= buffer_size; // maybe faster than %
data->read_head_position++;
while(data->read_head_position >= buffer_size) data->read_head_position -= buffer_size;
int16_t dry = radspa_signal_get_value(input_sig, i, render_pass_id);
int16_t wet = buf[data->read_head_position];
if(rec_vol){
buf[data->write_head_position] = radspa_add_sat(radspa_mult_shift(rec_vol, dry), radspa_mult_shift(wet,fb));
......@@ -67,9 +65,8 @@ void delay_run(radspa_t * delay, uint16_t num_samples, uint32_t render_pass_id){
ret = radspa_add_sat(radspa_mult_shift(dry_vol,dry), radspa_mult_shift(wet,level));
(output_sig->buffer)[i] = ret;
radspa_signal_set_value(output_sig, i, ret);
}
output_sig->value = ret;
}
radspa_t * delay_create(uint32_t init_var){
......@@ -80,7 +77,7 @@ radspa_t * delay_create(uint32_t init_var){
if(delay == NULL) return NULL;
delay_data_t * plugin_data = delay->plugin_data;
plugin_data->time_prev = UINT32_MAX;
plugin_data->time_prev = -1;
plugin_data->max_delay = init_var;
delay->render = delay_run;
radspa_signal_set(delay, DELAY_OUTPUT, "output", RADSPA_SIGNAL_HINT_OUTPUT, 0);
......
......@@ -4,9 +4,9 @@
typedef struct {
int32_t read_head_position;
uint32_t write_head_position;
uint32_t max_delay;
uint32_t time_prev;
int32_t write_head_position;
int32_t max_delay;
int32_t time_prev;
} delay_data_t;
extern radspa_descriptor_t delay_desc;
......
......@@ -2,7 +2,7 @@
radspa_t * distortion_create(uint32_t init_var);
radspa_descriptor_t distortion_desc = {
.name = "_distortion",
.name = "distortion",
.id = 9000,
.description = "distortion with linear interpolation between int16 values in plugin_table[129]",
.create_plugin_instance = distortion_create,
......@@ -13,29 +13,36 @@ radspa_descriptor_t distortion_desc = {
#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);
static int32_t ret = 0;
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 = input_sig->get_value(input_sig, i, num_samples, render_pass_id);
input += 32768;
uint8_t index = input>>9;
int32_t blend = input & ((1<<7)-1);
ret = dist[index]*((1<<7)-blend) + dist[index+1]*blend;
ret = ret >> 7;
(output_sig->buffer)[i] = ret;
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));
}
}
output_sig->value = ret;
}
radspa_t * distortion_create(uint32_t init_var){
radspa_t * distortion = radspa_standard_plugin_create(&distortion_desc, DISTORTION_NUM_SIGNALS, 0, (1<<7) + 1);
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);
......@@ -50,6 +57,7 @@ radspa_t * distortion_create(uint32_t init_var){
dist[i] = -((128-i)*(128-i)*32767>>12) + 32767;
}
}
dist[129] = 0;
return distortion;
}
#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;
}
......@@ -4,19 +4,23 @@
typedef struct {
uint32_t env_counter;
uint32_t attack;
uint32_t decay;
uint32_t sustain;
uint32_t release;
uint32_t release_init_val;
uint16_t attack_prev_ms;
uint16_t decay_prev_ms;
uint16_t release_prev_ms;
uint32_t gate;
uint32_t velocity;
uint8_t env_phase;
uint8_t skip_hold;
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;
......
#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);
......@@ -4,8 +4,7 @@ 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.\
does not come with lfo.",
.description = "flanger with subsample interpolation and negative mix/resonance capability.",
.create_plugin_instance = flanger_create,
.destroy_plugin_instance = radspa_standard_plugin_destroy
};
......@@ -14,73 +13,109 @@ radspa_descriptor_t flanger_desc = {
#define FIXED_POINT_DIGITS 4
#define VARIABLE_NAME ((FLANGER_BUFFER_SIZE)<<(FIXED_POINT_DIGITS))
#define FLANGER_NUM_SIGNALS 6
#define FLANGER_NUM_SIGNALS 7
#define FLANGER_OUTPUT 0
#define FLANGER_INPUT 1
#define FLANGER_MANUAL 2
#define FLANGER_RESONANCE 3
#define FLANGER_LEVEL 4
#define FLANGER_MIX 5
#define FLANGER_DECAY 4
#define FLANGER_LEVEL 5
#define FLANGER_MIX 6
static int16_t fixed_point_list_access(int32_t * buf, uint32_t fp_index, uint32_t buf_len){
uint32_t index = (fp_index) >> (FIXED_POINT_DIGITS);
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;
uint32_t next_index = index + 1;
int32_t next_index = index + 1;
while(next_index >= buf_len) next_index -= buf_len;
uint32_t subindex = (fp_index) & ((1<<(FIXED_POINT_DIGITS)) - 1);
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 = flanger->plugin_table;
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);
static int16_t ret = 0;
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
for(uint16_t i = 0; i < num_samples; i++){
int32_t manual = manual_sig->get_value(manual_sig, i, num_samples, render_pass_id);
int32_t manual = radspa_signal_get_value(manual_sig, 0, render_pass_id);
if(manual != data->manual_prev){
// index propto 1/radspa_sct_to_rel_freq(manual) -> signflip faster
int32_t invert = ((2400*(FIXED_POINT_DIGITS)) - 7572) - manual;
uint32_t rho = radspa_sct_to_rel_freq(radspa_clip(invert), 0);
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
int32_t dry = input_sig->get_value(input_sig, i, num_samples, render_pass_id);
int16_t reso = reso_sig->get_value(reso_sig, i, num_samples, render_pass_id);
int16_t level = level_sig->get_value(level_sig, i, num_samples, render_pass_id);
int16_t mix = mix_sig->get_value(mix_sig, i, num_samples, render_pass_id);
buf[data->write_head_position] = dry;
int32_t wet = fixed_point_list_access(buf, data->read_head_position, FLANGER_BUFFER_SIZE);
buf[data->write_head_position] += radspa_mult_shift(wet, reso);
int16_t dry_vol = (mix>0) ? (32767-mix) : (32767+mix); //always pos polarity
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;
}
ret = radspa_add_sat(radspa_mult_shift(dry, dry_vol), radspa_mult_shift(radspa_clip(wet), mix));
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));
(output_sig->buffer)[i] = ret;
radspa_signal_set_value(output_sig, i, ret);
}
output_sig->value = ret;
}
radspa_t * flanger_create(uint32_t init_var){
......@@ -93,29 +128,11 @@ radspa_t * flanger_create(uint32_t init_var){
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_HINT_GAIN,
RADSPA_SIGNAL_VAL_UNITY_GAIN/2);
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;
}
#undef FLANGER_DLY_GAIN
#undef FLANGER_BUFFER_SIZE
#undef FLANGER_NUM_SIGNALS
#undef FLANGER_OUTPUT
#undef FLANGER_INPUT
#undef FLANGER_MANUAL
#undef FLANGER_RESONANCE
#undef FLANGER_LEVEL
#undef FLANGER_MIX
#undef FIXED_POINT_DIGITS
/* 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)
*/
......@@ -7,6 +7,8 @@ typedef struct {
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;
......