Skip to content

DaisySP Audio Callback Recipes & Blueprints

This reference document contains production-ready C++ DSP recipes for libDaisy and DaisySP.


Recipe 1: Monophonic Subtractive Synth Voice

Components: Oscillator, LadderFilter, Adsr, and Overdrive.

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

using namespace daisy;
using namespace daisysp;

static DaisySeed    hw;
static Oscillator   osc;
static LadderFilter flt;
static Adsr         amp_env;
static Adsr         flt_env;
static Overdrive    drive;

void AudioCallback(AudioHandle::InputBuffer in, 
                   AudioHandle::OutputBuffer out, 
                   size_t size)
{
    for (size_t i = 0; i < size; i++)
    {
        // 1. Evaluate control envelopes (gate held true)
        float a_env = amp_env.Process(true);
        float f_env = flt_env.Process(true);

        // 2. Modulate ladder filter cutoff dynamically
        flt.SetFreq(120.0f + f_env * 3800.0f);

        // 3. Audio generation, filtering, and saturation
        float sig = osc.Process();
        sig = flt.Process(sig);
        sig = drive.Process(sig);

        // 4. Output with VCA scaling
        float final_out = sig * a_env;
        out[0][i] = final_out; // Left
        out[1][i] = final_out; // Right
    }
}

int main(void)
{
    hw.Init();
    float sr = hw.AudioSampleRate();

    osc.Init(sr);
    osc.SetWaveform(Oscillator::WAVE_POLYBLEP_SAW);
    osc.SetFreq(mtof(36)); // C2 bass
    osc.SetAmp(0.85f);

    flt.Init(sr);
    flt.SetFilterMode(LadderFilter::FilterMode::LP24);
    flt.SetRes(0.65f);
    flt.SetPassbandGain(0.3f);

    drive.Init();
    drive.SetDrive(0.25f);

    amp_env.Init(sr);
    amp_env.SetAttackTime(0.01f);
    amp_env.SetDecayTime(0.25f);
    amp_env.SetSustainLevel(0.3f);
    amp_env.SetReleaseTime(0.3f);

    flt_env.Init(sr);
    flt_env.SetAttackTime(0.04f);
    flt_env.SetDecayTime(0.35f);
    flt_env.SetSustainLevel(0.1f);
    flt_env.SetReleaseTime(0.2f);

    hw.StartAudio(AudioCallback);
    while (1) {}
}

Recipe 2: Ambient Stereo Guitar Multi-FX Chain

Components: Overdrive, Chorus, DelayLine, and ReverbSc.

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

#ifdef USE_DAISYSP_LGPL
#include "daisysp-lgpl.h"
#endif

using namespace daisy;
using namespace daisysp;

static DaisySeed hw;
static Overdrive drive;
static Chorus    chorus;

// High-capacity delay line and Reverb mapped to SDRAM
#define MAX_DELAY (48000 * 2) // 2 seconds @ 48 kHz
static DelayLine<float, MAX_DELAY> DSY_SDRAM_BSS delay_line;

#ifdef USE_DAISYSP_LGPL
static ReverbSc DSY_SDRAM_BSS reverb;
#endif

void AudioCallback(AudioHandle::InputBuffer in, 
                   AudioHandle::OutputBuffer out, 
                   size_t size)
{
    for (size_t i = 0; i < size; i++)
    {
        float mono_in = in[0][i];

        // 1. Soft saturation
        float sig = drive.Process(mono_in);

        // 2. Stereo chorus
        chorus.Process(sig);
        float ch_l = chorus.GetLeft();
        float ch_r = chorus.GetRight();

        // 3. Ping-pong delay line with Hermite cubic interpolation
        float del_sig = delay_line.ReadHermite(36000.0f); // 750 ms
        delay_line.Write(ch_l + del_sig * 0.45f);

        float wet_l = ch_l + del_sig * 0.5f;
        float wet_r = ch_r + del_sig * 0.5f;

#ifdef USE_DAISYSP_LGPL
        // 4. Algorithmic stereo reverberation
        float verb_l, verb_r;
        reverb.Process(wet_l, wet_r, &verb_l, &verb_r);
        out[0][i] = wet_l * 0.65f + verb_l * 0.35f;
        out[1][i] = wet_r * 0.65f + verb_r * 0.35f;
#else
        out[0][i] = wet_l;
        out[1][i] = wet_r;
#endif
    }
}

Recipe 3: Algorithmic Techno Drum Sequencer

Components: Metro, Maytrig, AnalogBassDrum, AnalogSnareDrum, HiHat.

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

using namespace daisy;
using namespace daisysp;

static DaisySeed       hw;
static Metro           clock;
static Maytrig         prob;
static AnalogBassDrum  kick;
static AnalogSnareDrum snare;
static HiHat           hat;
static uint32_t        step = 0;

void AudioCallback(AudioHandle::InputBuffer in, 
                   AudioHandle::OutputBuffer out, 
                   size_t size)
{
    for (size_t i = 0; i < size; i++)
    {
        // 16th-note clock tick (8 Hz @ 120 BPM)
        if (clock.Process())
        {
            if (step % 4 == 0)
                kick.Trig();

            if (step % 8 == 4)
                snare.Trig();

            if (step % 2 != 0 || prob.Process(0.35f))
                hat.Process(true);

            step = (step + 1) % 16;
        }

        // Sum drum voices
        float k = kick.Process(false);
        float s = snare.Process(false);
        float h = hat.Process(false);

        float mix = (k * 0.8f) + (s * 0.6f) + (h * 0.4f);
        out[0][i] = SoftClip(mix);
        out[1][i] = SoftClip(mix);
    }
}

int main(void)
{
    hw.Init();
    float sr = hw.AudioSampleRate();

    clock.Init(8.0f, sr); // 120 BPM 16th notes
    kick.Init(sr);
    kick.SetFreq(52.0f);
    kick.SetTone(0.6f);
    kick.SetDecay(0.45f);

    snare.Init(sr);
    snare.SetFreq(185.0f);
    snare.SetSnappy(0.7f);

    hat.Init(sr);
    hat.SetTone(0.85f);
    hat.SetDecay(0.2f);

    hw.StartAudio(AudioCallback);
    while (1) {}
}