Skip to content

Commit

Permalink
lichen-community-systemsgh-63: Adds parameters for passband gain and …
Browse files Browse the repository at this point in the history
…overdrive.

Adds an output tap after the second stage of the ladder lpf.
  • Loading branch information
colinbdclark committed May 25, 2023
1 parent 6e9946f commit 57bbbd0
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ void buildSignalGraph(struct sig_SignalContext* context,

leftFilter = sig_dsp_LadderLPF_new(&allocator, context);
sig_List_append(&signals, leftFilter, status);
leftFilter->parameters.overdrive = 1.1f;
leftFilter->parameters.passbandGain = 0.5f;
leftFilter->inputs.source = leftIn->outputs.main;
leftFilter->inputs.frequency = leftFrequency->outputs.main;
leftFilter->inputs.resonance = resonanceKnob->outputs.main;
Expand All @@ -157,6 +159,8 @@ void buildSignalGraph(struct sig_SignalContext* context,

rightFilter = sig_dsp_LadderLPF_new(&allocator, context);
sig_List_append(&signals, rightFilter, status);
rightFilter->parameters.overdrive = 1.1f;
leftFilter->parameters.passbandGain = 0.5f;
rightFilter->inputs.source = rightIn->outputs.main;
rightFilter->inputs.frequency = rightFrequency->outputs.main;
rightFilter->inputs.resonance = resonanceKnob->outputs.main;
Expand Down
30 changes: 28 additions & 2 deletions libsignaletic/include/libsignaletic.h
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,7 @@ struct sig_dsp_Filter_Inputs {
float_array_ptr resonance;
};


/**
* @brief Miller Pucket's 24dB Moog-style ladder low pass filter.
* Imitates a Moog resonant filter by Runge-Kutte numerical integration
Expand Down Expand Up @@ -1689,7 +1690,32 @@ void sig_dsp_BobLPF_destroy(struct sig_Allocator* allocator,
struct sig_dsp_BobLPF* self);


struct sig_dsp_LadderLPF_Parameters {
/**
* @brief The passband gain of the filter (best between 0.0-0.5),
* helps to offset the drop in low frequencies when resonance is high.
*/
float passbandGain;

/**
* @brief Gain prior to the filter, allowing for greater saturation levels.
*/
float overdrive;
};

struct sig_dsp_LadderLPF_Outputs {
float_array_ptr main;
float_array_ptr twoPole;
};

void sig_dsp_LadderLPF_Outputs_newAudioBlocks(
struct sig_Allocator* allocator,
struct sig_AudioSettings* audioSettings,
struct sig_dsp_LadderLPF_Outputs* outputs);

void sig_dsp_LadderLPF_Outputs_destroyAudioBlocks(
struct sig_Allocator* allocator,
struct sig_dsp_LadderLPF_Outputs* outputs);
/**
* @brief Valimaki and Huovilainen's Moog-style Ladder Filter
* Ported from Infrasonic Audio LLC's adaptation of
Expand All @@ -1704,8 +1730,9 @@ void sig_dsp_BobLPF_destroy(struct sig_Allocator* allocator,
struct sig_dsp_LadderLPF {
struct sig_dsp_Signal signal;
struct sig_dsp_Filter_Inputs inputs;
struct sig_dsp_LadderLPF_Parameters parameters;
// TODO: Add outputs for the other filter poles.
struct sig_dsp_Signal_SingleMonoOutput outputs;
struct sig_dsp_LadderLPF_Outputs outputs;

uint8_t interpolation;
float interpolationRecip;
Expand All @@ -1716,7 +1743,6 @@ struct sig_dsp_LadderLPF {
float k;
float fBase;
float qAdjust;
float pbg;
float prevFrequency;
float prevInput;
};
Expand Down
43 changes: 34 additions & 9 deletions libsignaletic/src/libsignaletic.c
Original file line number Diff line number Diff line change
Expand Up @@ -2347,13 +2347,27 @@ void sig_dsp_BobLPF_destroy(struct sig_Allocator* allocator,
}


void sig_dsp_LadderLPF_Outputs_newAudioBlocks(
struct sig_Allocator* allocator,
struct sig_AudioSettings* audioSettings,
struct sig_dsp_LadderLPF_Outputs* outputs) {
outputs->main = sig_AudioBlock_newSilent(allocator, audioSettings);
outputs->twoPole = sig_AudioBlock_newSilent(allocator, audioSettings);
}

void sig_dsp_LadderLPF_Outputs_destroyAudioBlocks(
struct sig_Allocator* allocator,
struct sig_dsp_LadderLPF_Outputs* outputs) {
sig_AudioBlock_destroy(allocator, outputs->main);
sig_AudioBlock_destroy(allocator, outputs->twoPole);
}

struct sig_dsp_LadderLPF* sig_dsp_LadderLPF_new(
struct sig_Allocator* allocator, struct sig_SignalContext* context) {
struct sig_dsp_LadderLPF* self = sig_MALLOC(allocator,
struct sig_dsp_LadderLPF);
sig_dsp_LadderLPF_init(self, context);
sig_dsp_Signal_SingleMonoOutput_newAudioBlocks(allocator,
sig_dsp_LadderLPF_Outputs_newAudioBlocks(allocator,
context->audioSettings, &self->outputs);

return self;
Expand All @@ -2364,6 +2378,12 @@ void sig_dsp_LadderLPF_init(
struct sig_SignalContext* context) {
sig_dsp_Signal_init(self, context, *sig_dsp_LadderLPF_generate);

struct sig_dsp_LadderLPF_Parameters parameters = {
.passbandGain = 0.5f,
.overdrive = 1.0f
};
self->parameters = parameters;

self->interpolation = 2;
self->interpolationRecip = 1.0f / self->interpolation;
self->alpha = 1.0f;
Expand All @@ -2373,7 +2393,6 @@ void sig_dsp_LadderLPF_init(
self->k = 1.0f;
self->fBase = 1000.0f;
self->qAdjust = 1.0f;
self->pbg = 0.5f;
self->prevFrequency = -1.0f;
self->prevInput = 0.0f;

Expand Down Expand Up @@ -2406,12 +2425,15 @@ inline float sig_dsp_LadderLPF_calcStage(
void sig_dsp_LadderLPF_generate(void* signal) {
struct sig_dsp_LadderLPF* self =
(struct sig_dsp_LadderLPF*) signal;
float interpolationRecip = self->interpolationRecip;

for (size_t i = 0; i < self->signal.audioSettings->blockSize; i++) {
float input = FLOAT_ARRAY(self->inputs.source)[i];
float input = FLOAT_ARRAY(self->inputs.source)[i] *
self->parameters.overdrive;
float frequency = FLOAT_ARRAY(self->inputs.frequency)[i];
float resonance = FLOAT_ARRAY(self->inputs.resonance)[i];
float total = 0.0f;
float total12db = 0.0f;
float total24db = 0.0f;
float interp = 0.0f;

// Recalculate coefficients if the frequency has changed.
Expand All @@ -2425,27 +2447,30 @@ void sig_dsp_LadderLPF_generate(void* signal) {

for (size_t os = 0; os < self->interpolation; os++) {
float u = (interp * self->prevInput + (1.0f - interp) * input) -
(self->z1[3] - self->pbg * input) * self->k * self->qAdjust;
(self->z1[3] - self->parameters.passbandGain * input) *
self->k * self->qAdjust;
u = sig_fastTanhf(u);
float stage1 = sig_dsp_LadderLPF_calcStage(self,
u, 0);
float stage2 = sig_dsp_LadderLPF_calcStage(self,
stage1, 1);
total12db += stage2 * interpolationRecip;
float stage3 = sig_dsp_LadderLPF_calcStage(self,
stage2, 2);
float stage4 = sig_dsp_LadderLPF_calcStage(self,
stage3, 3);
total += stage4 * self->interpolationRecip;
interp += self->interpolationRecip;
total24db += stage4 * interpolationRecip;
interp += interpolationRecip;
}
self->prevInput = input;
FLOAT_ARRAY(self->outputs.main)[i] = total;
FLOAT_ARRAY(self->outputs.main)[i] = total24db;
FLOAT_ARRAY(self->outputs.twoPole)[i] = total12db;
}
}

void sig_dsp_LadderLPF_destroy(struct sig_Allocator* allocator,
struct sig_dsp_LadderLPF* self) {
sig_dsp_Signal_SingleMonoOutput_destroyAudioBlocks(allocator,
sig_dsp_LadderLPF_Outputs_destroyAudioBlocks(allocator,
&self->outputs);
sig_dsp_Signal_destroy(allocator, self);
}
Expand Down

0 comments on commit 57bbbd0

Please sign in to comment.