Added DelayLine to my synth, now it crackles

Hi,

newbie here, I am making my first little synth: osc, env, filter.

Now I added the DelayLine and it crackles.

Most probably the cpu is cooking.

How could I optimize this?

I already successfully implemented the mux, and the oled, but the oled also dragged the performance down (no sound).

Maybe the adc could be read more slowly, but I don´t know how.

Here is the code:

#include “daisysp.h”
#include <stdio.h>
#include <string.h>
#include “daisy_seed.h”
#include “dev/oled_ssd130x.h”
#include “dev/mpr121.h”

#define MAX_DELAY static_cast<size_t>(48000 * 0.75f)

using namespace daisysp;
using namespace daisy;

using MyOledDisplay = OledDisplay;

dsy_gpio ledR_1_pin, ledG_1_pin, ledB_1_pin;

uint16_t currTouched;
uint16_t lastTouched;

// Define the frequencies for the two octaves surrounding middle C
double scale[12] = {
// Octave below middle C
{130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94},
// Middle C and the octave above
{261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88},
// Octave above middle C
{523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77}};

DaisySeed hw;
MyOledDisplay display;
Mpr121I2C mpr121;

static Oscillator osc;
static Svf filt;
static Metro clock;
static Adsr env;
bool gate;
float envout;
float finalF;
float trig;

// Declare a DelayLine of MAX_DELAY number of floats.
static DelayLine<float, MAX_DELAY> del;

static void AudioCallback(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size)

{
// Declare a DelayLine of MAX_DELAY number of floats.
float delout;
float feedback;
float sig;
float sigout;
for(size_t i = 0; i < size; i += 2)
{
del.SetDelay(hw.adc.GetMuxFloat(10, 1) * 20000 );
float fb = (hw.adc.GetMuxFloat(10, 2) * .99);
// Use envelope to control the amplitude of the oscillator.
envout = env.Process(trig);
osc.SetAmp(envout);

    filt.Process(sig);

    // Read from delay line
    delout = del.Read();

    // Calculate output and feedback
    sig = osc.Process();
    sigout = delout + filt.Low();
    feedback = (delout * fb) + filt.Low();

    // Write to the delay
    del.Write(feedback);

    // left out
    out[i] = sigout;

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

}

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

//init metro object
clock.Init(2, sample_rate);

//Set envelope parameters
env.Init(sample_rate);
env.SetTime(ADSR_SEG_ATTACK, .1);
env.SetTime(ADSR_SEG_DECAY, .5);
env.SetTime(ADSR_SEG_RELEASE, .5);  
env.SetSustainLevel(0);

// Set parameters for oscillator
osc.SetWaveform(osc.WAVE_POLYBLEP_SAW);
osc.SetFreq(440);
osc.SetAmp(0.5);

// Initialize Filter, and set parameters.
filt.Init(sample_rate);
filt.SetFreq(500.0);
filt.SetRes(0.85);
filt.SetDrive(0.8);

del.Init();


// R 1 on pin 27
ledR_1_pin.pin = hw.GetPin(12);
ledR_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
ledR_1_pin.pull = DSY_GPIO_NOPULL;
dsy_gpio_init(&ledR_1_pin);
dsy_gpio_write(&ledR_1_pin, false);

// G 1 on pin 26
ledG_1_pin.pin = hw.GetPin(13);
ledG_1_pin.pull = DSY_GPIO_NOPULL;
ledG_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
dsy_gpio_init(&ledG_1_pin);
dsy_gpio_write(&ledG_1_pin, false);

// B 1 on pin 25
ledB_1_pin.pin = hw.GetPin(14);
ledB_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
ledB_1_pin.pull = DSY_GPIO_NOPULL;
dsy_gpio_init(&ledB_1_pin);
dsy_gpio_write(&ledB_1_pin, false);
/** Initialize the ADC with our configuration */
//hw.adc.Init(&adc_cfg, 1);
//Configure pin 21 as an ADC input. This is where we'll read the knob.

// Create an array of two AdcChannelConfig objects
const int num_adc_channels = 11;
AdcChannelConfig my_adc_config[num_adc_channels];

// Initialize the first one connected to A0
my_adc_config[0].InitSingle(hw.GetPin(21));
my_adc_config[1].InitSingle(hw.GetPin(20));
my_adc_config[2].InitSingle(hw.GetPin(19));
my_adc_config[3].InitSingle(hw.GetPin(18));
my_adc_config[4].InitSingle(hw.GetPin(17));
my_adc_config[5].InitSingle(hw.GetPin(16));
my_adc_config[6].InitSingle(hw.GetPin(15));
my_adc_config[7].InitSingle(hw.GetPin(22));
my_adc_config[8].InitSingle(hw.GetPin(23));
my_adc_config[9].InitSingle(hw.GetPin(24));
my_adc_config[10].InitMux(seed::A10, 8, seed::D0, seed::D1, seed::D2);


//Initialize the adc with the config we just made

hw.adc.Init(my_adc_config, num_adc_channels);



//Start reading values
hw.adc.Start();


// start callback
hw.StartAudio(AudioCallback);

// touch works
// Initialize MPR121 with I2C configuration
Mpr121I2C::Config mprConfig;
mprConfig.transport_config.periph = I2CHandle::Config::Peripheral::I2C_1;
mprConfig.transport_config.speed = I2CHandle::Config::Speed::I2C_400KHZ;
mprConfig.transport_config.scl = Pin(PORTB,8);  // Replace with your SCL pin
mprConfig.transport_config.sda = Pin(PORTB,9);  // Replace with your SDA pin

// Set additional MPR121 configuration if needed
mprConfig.touch_threshold = 12;
mprConfig.release_threshold = 6;

if(mpr121.Init(mprConfig) != Mpr121I2C::OK)
{
    // Handle initialization error
    while(1)
    {
        // Error handling code (blinking LED, etc.)
    }
}
// Setup to print 
hw.StartLog();
// oled
// Configure the Display 
/*MyOledDisplay::Config disp_cfg;
disp_cfg.driver_config.transport_config.i2c_address               = 0x3C;
disp_cfg.driver_config.transport_config.i2c_config.periph         = I2CHandle::Config::Peripheral::I2C_1;
disp_cfg.driver_config.transport_config.i2c_config.speed          = I2CHandle::Config::Speed::I2C_100KHZ;
disp_cfg.driver_config.transport_config.i2c_config.mode           = I2CHandle::Config::Mode::I2C_MASTER;
disp_cfg.driver_config.transport_config.i2c_config.pin_config.scl = {DSY_GPIOB, 8};    
disp_cfg.driver_config.transport_config.i2c_config.pin_config.sda = {DSY_GPIOB, 9};
// And Initialize
display.Init(disp_cfg);
float finalFO = 440;
int te = 1;
bool we = false;
//oled end
*/

// Touch Stuff
//bool test = false;

int step = 0;
int cnt = 0;

while(1) {
    


    float baseF=hw.adc.GetFloat(0)*200;

    // Read touch status
    currTouched = mpr121.Touched();

    // Process the touch status as needed
    for(int i = 0; i < 12; i++)
    {
        if((currTouched & (1 << i)) && !(lastTouched& (1 << i)))
        {
            // Channel i is touched, print the channel number
            hw.PrintLine("Channel %d touched", i);
            osc.SetFreq(scale[0][i] + baseF);
            trig = 1;
            hw.SetLed(true);
            dsy_gpio_write(&ledR_1_pin, true );
            dsy_gpio_write(&ledG_1_pin, true );
            dsy_gpio_write(&ledB_1_pin, true );
            
        }
        if(!(currTouched & (1 << i)) && (lastTouched& (1 << i)))
        {
            // Channel i is released, print the channel number
            hw.PrintLine("Channel %d released", i);
            trig = 0;
            hw.SetLed(false);
            //
            dsy_gpio_write(&ledR_1_pin, false ); 
            dsy_gpio_write(&ledG_1_pin, false );
            dsy_gpio_write(&ledB_1_pin, false ); 
        }
    }
    lastTouched = currTouched;

    if (clock.Process()){
        if(cnt == 0) {
            gate = 1;
            if (step == 2){
                step=0;
            }
            else{
                step++;
            }
        } else if(cnt == 3) {
            gate = 0;
        }

        if (cnt < 4) {
            cnt++;
        } else {
            cnt = 0;
        }
    }

    
    
    /*if (step==0){
        finalF =  baseF + hw.adc.GetFloat(3);
    }
    else if (step==1){
        finalF =  baseF + hw.adc.GetFloat(4);
    }
    else if (step==2){
        finalF =  baseF + hw.adc.GetFloat(5);
    }*/

    if(finalF > 1.0) {
        finalF = 1.0;
    }
    
    //OlED Stuff
    /*if (finalF != finalFO) {
        //display.Fill(false);
        //display.SetCursor(10, 10);
        //display.DrawRect(4, 4, 124, 60, true, false);
        //display.WriteString(strbuff, Font_11x18, true);
        //display.SetCursor(10, 32);
        //display.WriteString("test2", Font_11x18, true);
        //display.Update();
        //oled
    }*/
    /*if (cnt==0) {
        display.SetCursor(10, 10);
        if (we == true) {
            display.WriteString("1test", Font_11x18, true);
            we = false;
        } else {
            display.WriteString("2test", Font_11x18, true);
            we = true;
        }
        display.Update();
    }
    finalFO = finalF;*/



    //osc.SetFreq(finalF * 1200 + 45);
    float peak = hw.adc.GetFloat(9) * envout;
    float Cut = hw.adc.GetFloat(1);
    filt.SetFreq((Cut * Cut + peak) * 4500 + 45);
    filt.SetRes(hw.adc.GetFloat(2) * 1.1f);
    osc.SetWaveform(hw.adc.GetMuxFloat(10, 0)*4+4);

    clock.SetFreq(4 * (hw.adc.GetFloat(6) * 1.9f + .1f));

     //Set envelope parameters
    env.SetTime(ADSR_SEG_ATTACK, hw.adc.GetFloat(7));
    float dec = hw.adc.GetFloat(8);
    env.SetTime(ADSR_SEG_DECAY, dec * dec);
    env.SetTime(ADSR_SEG_RELEASE, dec * dec);
    env.SetSustainLevel(trig);

    

    
    
    

}

}

It’s all a bit hard to read withthe lack of proper code formatting but I think the problem is passing the values directly into SetDelay(). You might want to smooth that a bit using fonepole(smoothed, time, coefficient).

Check out Smoodge Delay for an example:

I built a 8tap multidelay based on the stuff I learned from that example.

1 Like