VSCode DSP delayline example, modified for input.... ceiling on delay time?

I’m modifying the DaisyExamples\seed\DSP\delayline example to make a basic delay pedal, and have successfully done everything as far as I can tell… Except that I can’t figure out why there seems to be a ceiling on the MAX_DELAY value, up there in the defines. If I put it any higher than 63962, the thing won’t build, and says build/delayline.bin can’t be found. Anyone have any idea why? Code below…

I’m a little new to C++ (used to C) so forgive me

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

// Interleaved audio definitions
#define LEFT (i)
#define RIGHT (i + 1)

// Set delay time range in samples.
#define MIN_DELAY 24
#define MAX_DELAY 63962

using namespace daisysp;
using namespace daisy;

// Set up Daisy hardware seed
static DaisySeed hw;

// Declare the button
Switch button1;

// Declare DelayLines of MAX_DELAY number of floats.
static DelayLine<float, static_cast<size_t>(MAX_DELAY)> delL;
static DelayLine<float, static_cast<size_t>(MAX_DELAY)> delR;

// Setup..
const int num_adc_channels = 3;
const int blockSize = 1;

// Scale the feedback signal
const float feedbackScalar=1.0;


//
// Audio Callback function  (the audio loop)
//
static void AudioCallback(AudioHandle::InterleavingInputBuffer  in,
                          AudioHandle::InterleavingOutputBuffer out,
                          size_t                                size)
{
    float feedbackL, feedbackR, delL_out, delR_out, sigL_out, sigR_out, del;
    
    for(size_t i = 0; i < size; i += 2)
    {
        
        float knob= hw.adc.GetFloat(0);
        float knob2= hw.adc.GetFloat(1);
        float knob3= hw.adc.GetFloat(2);

        knob *= knob;
        del = ((MAX_DELAY - MIN_DELAY) * knob)+(MIN_DELAY);
        delL.SetDelay(del);
        delR.SetDelay(del);

        button1.Debounce();
        float btn = button1.Pressed();

        // Read from delay line
        delL_out = delL.Read();
        delR_out = delR.Read();

        // Calculate output mix
        if(btn){
            if (knob3 <= .5){
                sigL_out  = ((in[LEFT]) + (delL_out * (knob3*2.0f)));
                sigR_out  = ((in[RIGHT]) + (delR_out * (knob3*2.0f)));
            }else{
                sigL_out  = (((in[LEFT])*(1-((knob3-0.5f)*2.0f)))) + (delL_out);
                sigR_out  = (((in[RIGHT])*(1-((knob3-0.5f)*2.0f)))) + (delR_out);
            }
        }else{
            sigL_out = in[LEFT];
            sigR_out = in[RIGHT];
        }

        // Calculate feedback
        feedbackL = (delL_out * knob2 * feedbackScalar) + in[LEFT];
        feedbackR = (delR_out * knob2 * feedbackScalar) + in[RIGHT];

        // Write to the delay
        delL.Write(feedbackL * btn);
        delR.Write(feedbackR * btn);
        
        // Output
        out[LEFT]  = sigL_out;
        out[RIGHT] = sigR_out;
    }
}

int main(void)
{
    // initialize seed hardware and daisysp modules
    float sample_rate;
    hw.Configure();
    hw.Init();
    hw.SetAudioBlockSize(blockSize);
    sample_rate = hw.AudioSampleRate();
    delL.Init();
    delR.Init();

    //This is our ADC configuration
    AdcChannelConfig adcConfig[num_adc_channels];
    
    //Configure pin 21 as an ADC input. This is where we'll read the knob.
    adcConfig[0].InitSingle(hw.GetPin(21));
    adcConfig[1].InitSingle(hw.GetPin(22));
    adcConfig[2].InitSingle(hw.GetPin(23));

    //Initialize the adc with the config we just made
    hw.adc.Init(adcConfig, num_adc_channels);

    //Initialize the button
    button1.Init(hw.GetPin(28),1000);

    // Set Default Delay time
    delL.SetDelay(sample_rate * 0.75f);
    delR.SetDelay(sample_rate * 0.75f);

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

    // Start audio loop    
    hw.StartAudio(AudioCallback);

    while(1) {}
}

oh and here’s the console output if I use MAXDELAY 63963

*  Executing task: make clean; make; make program-dfu 

rm -fR build
mkdir build
arm-none-eabi-gcc -c -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard -DUSE_HAL_DRIVER -DSTM32H750xx -DHSE_VALUE=16000000  -DCORE_CM7 -DSTM32H750IB -DARM_MATH_CM7 -DUSE_FULL_LL_DRIVER -include stm32h7xx.h -I../../../libDaisy -I../../../libDaisy/src/ -I../../../libDaisy/src/sys -I../../../libDaisy/src/usbd -I../../../libDaisy/src/usbh -I../../../libDaisy/Drivers/CMSIS/Include/ -I../../../libDaisy/Drivers/CMSIS/DSP/Include -I../../../libDaisy/Drivers/CMSIS/Device/ST/STM32H7xx/Include -I../../../libDaisy/Drivers/STM32H7xx_HAL_Driver/Inc/ -I../../../libDaisy/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../../../libDaisy/Middlewares/ST/STM32_USB_Host_Library/Core/Inc -I../../../libDaisy/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc -I../../../libDaisy/core/ -I../../../DaisySP/Source -I../../../libDaisy/Middlewares/Third_Party/FatFs/src -O2 -Wall -Wno-missing-attributes -fasm -fdata-sections -ffunction-sections -Wno-stringop-overflow -g -ggdb -MMD -MP -MF"build/startup_stm32h750xx.d" -std=gnu11 -Wa,-a,-ad,-alms=build/startup_stm32h750xx.lst ../../../libDaisy/core/startup_stm32h750xx.c -o build/startup_stm32h750xx.o
arm-none-eabi-g++ -c -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard -DUSE_HAL_DRIVER -DSTM32H750xx -DHSE_VALUE=16000000  -DCORE_CM7 -DSTM32H750IB -DARM_MATH_CM7 -DUSE_FULL_LL_DRIVER -include stm32h7xx.h -I../../../libDaisy -I../../../libDaisy/src/ -I../../../libDaisy/src/sys -I../../../libDaisy/src/usbd -I../../../libDaisy/src/usbh -I../../../libDaisy/Drivers/CMSIS/Include/ -I../../../libDaisy/Drivers/CMSIS/DSP/Include -I../../../libDaisy/Drivers/CMSIS/Device/ST/STM32H7xx/Include -I../../../libDaisy/Drivers/STM32H7xx_HAL_Driver/Inc/ -I../../../libDaisy/Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../../../libDaisy/Middlewares/ST/STM32_USB_Host_Library/Core/Inc -I../../../libDaisy/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc -I../../../libDaisy/core/ -I../../../DaisySP/Source -I../../../libDaisy/Middlewares/Third_Party/FatFs/src -O2 -Wall -Wno-missing-attributes -fasm -fdata-sections -ffunction-sections -Wno-stringop-overflow -g -ggdb -MMD -MP -MF"build/delayline.d" -fno-exceptions -fasm -finline -finline-functions-called-once -fshort-enums -fno-move-loop-invariants -fno-unwind-tables -fno-rtti -Wno-register -std=gnu++14 -Wa,-a,-ad,-alms=build/delayline.lst delayline.cpp -o build/delayline.o
arm-none-eabi-g++ build/startup_stm32h750xx.o build/delayline.o  -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard --specs=nano.specs --specs=nosys.specs -T../../../libDaisy/core/STM32H750IB_flash.lds -L../../../libDaisy/build -L ../../../DaisySP/build -ldaisy -lc -lm -lnosys -ldaisysp -Wl,-Map=build/delayline.map,--cref -Wl,--gc-sections -Wl,--print-memory-usage -o build/delayline.elf      
c:/program files/daisytoolchain/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: build/delayline.elf section `.bss' will not fit in region `SRAM'
c:/program files/daisytoolchain/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld.exe: region `SRAM' overflowed by 4 bytes
Memory region         Used Size  Region Size  %age Used
           FLASH:       70216 B       128 KB     53.57%
         DTCMRAM:          0 GB       128 KB      0.00%
            SRAM:      524292 B       512 KB    100.00%
          RAM_D2:       16704 B       288 KB      5.66%
          RAM_D3:          0 GB        64 KB      0.00%
     BACKUP_SRAM:          12 B         4 KB      0.29%
         ITCMRAM:          0 GB        64 KB      0.00%
           SDRAM:          0 GB        64 MB      0.00%
       QSPIFLASH:          0 GB         8 MB      0.00%
collect2.exe: error: ld returned 1 exit status
make: *** [../../../libDaisy/core/Makefile:291: build/delayline.elf] Error 1
dfu-util -a 0 -s 0x08000000:leave -D build/delayline.bin -d ,0483:df11
dfu-util 0.10

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2020 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

No such file or directory: Could not open file build/delayline.bin for reading
make: *** [../../../libDaisy/core/Makefile:344: program-dfu] Error 74

 *  The terminal process "C:\Program Files\Git\bin\bash.exe '--login', '-i', '-c', 'make clean; make; make program-dfu'" terminated with exit code: 2. 
 *  Terminal will be reused by tasks, press any key to close it. 

The program has to allocate a float array whose size is the max delay time in samples. That array is completely filling up SDRAM in your second forum post. Any larger and it won’t fit, so the thing won’t compile.

1 Like

You can force the delay lines into the SDRAM by using the DSY_SDRAM_BSS attribute like such:

static DelayLine<float, MAX_DELAY> DSY_SDRAM_BSS dell;
static DelayLine<float, MAX_DELAY> DSY_SDRAM_BSS delr;

Then you should be able to increase the max delay.

Cheers

2 Likes

That did the trick! Wow thanks for the quick response!

A tip to other newcomers who find this… make sure to smooth the knob values before you apply them to the delay time… noise on that will cause weird distortion in playback!

1 Like

I’m writing my first effect as well in C++. Also an extended delayline line.

I see you are reading the knobs and button during the AudioCallback. As far as I can tell that should be done in the while loop in main(), as you don’t need to read that button at audio rate.

1 Like

So… the while loop runs slower? I wondered why that was down there :stuck_out_tongue:

I would have thought the while loop ran faster honestly… I still need to get a firmer grasp on timing. Not used to having to think about processor speed and timer interrupts, coming from puredata. I’ll look more into it later today!

My instinct tells me though, that it runs faster, because the while loop would run constantly at the maximum possible speed, but then every 1/48000 of a second the timer interrupt triggers the audio callback and puts the while loop on hold until that processes, then goes back to the while loop

But I haven’t looked deeply into how the audio callback works yet, or even how timer interrupts work… so I have some research to do

The ‘while’ loop in main() runs faster than the AudioCallback(), but you’d typically put a delay in the ‘while’ loop to run much slower.

The point is, you have to be careful to not put anything in the callback which will ever take more the amount of time available, or you’ll get overruns and underruns.

For example, at 48khz sample rate, with buffer size of 48, AudioCallback runs 1000 times per second, and MUST always complete in under 1ms.

The simplest way to meet that constraint is usually to use the callback only for what absolutely must be done at audio rate, or with fast, precise timing, and do everything else in main(), but it’s not a rule.

Ah thanks for the clarification, learning as I go.