electro-smith / DaisySP

A Powerful DSP Library in C++
https://www.electro-smith.com/daisy
Other
836 stars 131 forks source link

Add alternate MIT-licensed ladder filter module #200

Closed ndonald2 closed 5 months ago

ndonald2 commented 5 months ago

Description

Adds a new, MIT-licensed ladder filter implementation with additional features and stability compared to the previous DaisySP moogladder (now in LGPL modules).

This implementation is ported from MIT-licensed code in the Teensy Audio Library, with the implementation derived from work in this paper from Computer Music Journal by Välimäki and Huovilainen.

This version brings the following advantages:

However it is a little bit more computationally expensive without additional optimizations not included here (block-based processing helps a bit). Still plenty fast enough to run multiple instances on a Seed.

I believe the OSS license stuff is all in order (preserved MIT license in header with original copyright, added copyright for modifications, and documentation of modifications).

Testing

I've used this code extensively in my own projects

Demos / Example Code

I don't have any audio or video demos handy but I could make some on request.

Example program

#include "daisysp.h"
#include "daisy_seed.h"

using namespace daisysp;
using namespace daisy;

static DaisySeed  hw;
static Oscillator osc, lfo;
static LadderFilter ladder;

static void AudioCallback(AudioHandle::InterleavingInputBuffer  in,
                          AudioHandle::InterleavingOutputBuffer out,
                          size_t                                size)
{
    float sig;
    float cutoff;
    for(size_t i = 0; i < size; i += 2)
    {
        cutoff = 2000.0f;
        cutoff *= exp2f(lfo.Process() * 2.0f);
        ladder.SetFreq(cutoff);

        sig = osc.Process();
        sig = ladder.Process(sig);

        // left out
        out[i] = sig;

        // right out
        out[i + 1] = sig;
    }
}

int main(void)
{
    // initialize seed hardware and oscillator daisysp module
    float sample_rate;
    hw.Configure();
    hw.Init();
    hw.SetAudioBlockSize(4);
    sample_rate = hw.AudioSampleRate();

    osc.Init(sample_rate);
    lfo.Init(sample_rate);
    ladder.Init(sample_rate);

    // Set parameters for oscillator
    osc.SetWaveform(osc.WAVE_SAW);
    osc.SetFreq(220.0f);
    osc.SetAmp(0.5f);

    // Set parameters for filter
    ladder.SetRes(0.5f);
    ladder.SetInputDrive(2.0f);
    //ladder.SetFilterMode(LadderFilter::FilterMode::BP12); // set alt filter mode

    // Set parameters for lfo
    lfo.SetWaveform(lfo.WAVE_SIN);
    lfo.SetFreq(0.5f);
    lfo.SetAmp(1.0f);

    // start callback
    hw.StartAudio(AudioCallback);

    while(1) {}
}
stephenhensley commented 5 months ago

This is awesome! We'll get this reviewed and merged within the next week!

Thanks for the contribution, @ndonald2 !!

beserge commented 5 months ago

Sounds great! Tested the module with your example code, tried a bunch of different settings. Did a quick code review as well, looks great!

Nice work! Thanks as always for the well documented PR and the phenomenal code. 🚀