Browse Source

Ladder filter frequency modulation in "volts per octave"

dds
PaulStoffregen 3 years ago
parent
commit
8f0829c845
3 changed files with 51 additions and 9 deletions
  1. +15
    -4
      examples/Synthesis/LadderFilter/LadderFilter.ino
  2. +34
    -5
      filter_ladder.cpp
  3. +2
    -0
      filter_ladder.h

+ 15
- 4
examples/Synthesis/LadderFilter/LadderFilter.ino View File

// By Richard van Hoesel // By Richard van Hoesel
// https://forum.pjrc.com/threads/60488?p=269756&viewfull=1#post269756 // https://forum.pjrc.com/threads/60488?p=269756&viewfull=1#post269756


// Ladder filter demo with continuous 3-saw drone into the filter
// with separate LFOs modulating filter frequency and resonance.
// By Richard van Hoesel
// https://forum.pjrc.com/threads/60488?p=269756&viewfull=1#post269756

#include <Audio.h> #include <Audio.h>


AudioSynthWaveform waveform1; AudioSynthWaveform waveform1;
sgtl5000_1.enable(); sgtl5000_1.enable();
sgtl5000_1.volume(0.6); sgtl5000_1.volume(0.6);


filter1.resonance(0.55);
filter1.frequency(4000);
filter1.resonance(0.55); // "lfo2" waveform overrides this setting
filter1.frequency(800); // "lfo1" modifies this 800 Hz setting
filter1.octaveControl(2.6); // up 2.6 octaves (4850 Hz) & down 2.6 octaves (132 Hz)
waveform1.frequency(50); waveform1.frequency(50);
waveform2.frequency(100.1); waveform2.frequency(100.1);
waveform3.frequency(150.3); waveform3.frequency(150.3);
waveform2.begin(WAVEFORM_BANDLIMIT_SAWTOOTH); waveform2.begin(WAVEFORM_BANDLIMIT_SAWTOOTH);
waveform3.begin(WAVEFORM_BANDLIMIT_SAWTOOTH); waveform3.begin(WAVEFORM_BANDLIMIT_SAWTOOTH);
lfo1.frequency(0.2); lfo1.frequency(0.2);
lfo1.amplitude(0.985);
lfo1.amplitude(0.99);
lfo1.phase(270); lfo1.phase(270);
lfo1.begin(WAVEFORM_TRIANGLE);
lfo2.frequency(0.07); lfo2.frequency(0.07);
lfo2.amplitude(0.55); lfo2.amplitude(0.55);
lfo2.phase(270); lfo2.phase(270);
lfo2.begin(WAVEFORM_SINE);
} }


void loop() { void loop() {
Serial.print("CPU Usage: ");
Serial.print("Filter CPU Usage: ");
Serial.print(filter1.processorUsageMax());
Serial.print("%, Total CPU Usage: ");
Serial.print(AudioProcessorUsageMax()); Serial.print(AudioProcessorUsageMax());
Serial.println("%"); Serial.println("%");
filter1.processorUsageMaxReset();
AudioProcessorUsageMaxReset(); AudioProcessorUsageMaxReset();
delay(1000); delay(1000);
} }

+ 34
- 5
filter_ladder.cpp View File

#define MOOG_PI ((float)3.14159265358979323846264338327950288) #define MOOG_PI ((float)3.14159265358979323846264338327950288)


#define MAX_RESONANCE ((float)1.1) #define MAX_RESONANCE ((float)1.1)
#define MAX_FREQUENCY ((float)(AUDIO_SAMPLE_RATE_EXACT * 0.49f))


float AudioFilterLadder::LPF(float s, int i) float AudioFilterLadder::LPF(float s, int i)
{ {
compute_coeffs(c); compute_coeffs(c);
} }


void AudioFilterLadder::octaveControl(float octaves)
{
if (octaves > 7.0f) {
octaves = 7.0f;
} else if (octaves < 0.0f) {
octaves = 0.0f;
}
octaveScale = octaves / 32768.0f;
}

void AudioFilterLadder::compute_coeffs(float c) void AudioFilterLadder::compute_coeffs(float c)
{ {
if (c > 0.49f * AUDIO_SAMPLE_RATE_EXACT) {
c = 0.49f * AUDIO_SAMPLE_RATE_EXACT;
if (c > MAX_FREQUENCY) {
c = MAX_FREQUENCY;
} else if (c < 1.0f) { } else if (c < 1.0f) {
c = 1.0f; c = 1.0f;
} }
return false; return false;
} }


static inline float fast_exp2f(float x)
{
float i;
float f = modff(x, &i);
f *= 0.693147f / 256.0f;
f += 1.0f;
f *= f;
f *= f;
f *= f;
f *= f;
f *= f;
f *= f;
f *= f;
f *= f;
f = ldexpf(f, i);
return f;
}

static inline float fast_tanh(float x) static inline float fast_tanh(float x)
{ {
float x2 = x * x; float x2 = x * x;
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) { for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
float input = blocka->data[i] * (1.0f/32768.0f); float input = blocka->data[i] * (1.0f/32768.0f);
if (FCmodActive) { if (FCmodActive) {
float FCmod = blockb->data[i] * (1.0f/32768.0f);
// TODO: should this be "volts per octave"?
float ftot = Fbase + Fbase * FCmod;
float FCmod = blockb->data[i] * octaveScale;
float ftot = Fbase * fast_exp2f(FCmod);
if (ftot > MAX_FREQUENCY) ftot = MAX_FREQUENCY;
if (FCmod != 0) compute_coeffs(ftot); if (FCmod != 0) compute_coeffs(ftot);
} }
if (QmodActive) { if (QmodActive) {

+ 2
- 0
filter_ladder.h View File

AudioFilterLadder() : AudioStream(3, inputQueueArray) {}; AudioFilterLadder() : AudioStream(3, inputQueueArray) {};
void frequency(float FC); void frequency(float FC);
void resonance(float reson); void resonance(float reson);
void octaveControl(float octaves);
virtual void update(void); virtual void update(void);
private: private:
float LPF(float s, int i); float LPF(float s, int i);
float z1[4] = {0.0, 0.0, 0.0, 0.0}; float z1[4] = {0.0, 0.0, 0.0, 0.0};
float K = 1.0; float K = 1.0;
float Fbase = 1000; float Fbase = 1000;
float octaveScale = 1.0f/32768.0f;
//float Qbase = 0.5; //float Qbase = 0.5;
//float overdrive = 1.0; //float overdrive = 1.0;
audio_block_t *inputQueueArray[3]; audio_block_t *inputQueueArray[3];

Loading…
Cancel
Save