Looper only getting loud noise

Trying to create a multitrack loopstation
Buttons are working perfectly as they should (encoders arent fully soldered yet and leds arent working)
But the issue is with the audio

Default is output (line out) equals input (line in)
But when a loop (audio buffer) is created, it should play that (after the recording is finished)
What comes out is a loud noise

Disabling the other loops didnt change anything
No clue how to print the audio buffer to console, therefore not able to debug it that way

No clue what the issue is or how to debug it

Any help is greatly appreciated

Here is the code
(loop2 is currently disabled bc of a hardware issue)

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

// Use the daisy namespace to prevent having to type
// daisy:: before all libdaisy functions
using namespace daisy;
using namespace daisy::seed;
using namespace std;

// Declare a DaisySeed object called hardware
DaisySeed hw;

// PUBLIC Variables
#define MAX_SIZE (48000 * 60 * 1) // 1 minutes of floats at 48 khz
float DSY_SDRAM_BSS buffer1[MAX_SIZE];
float DSY_SDRAM_BSS buffer2[MAX_SIZE];
float DSY_SDRAM_BSS buffer3[MAX_SIZE];
float DSY_SDRAM_BSS buffer4[MAX_SIZE];
float DSY_SDRAM_BSS buffer5[MAX_SIZE];
GPIO buttonFn1, buttonFn2, buttonFn3;

// Classes
class Loop
{
private:
    enum buttonFunction {first, second, third, fourth, fifth, sixth, seventh, eight};
    enum loopModes {loop, oneshot, replace};
    loopModes loopMode = loop;
    bool firstLoop = true;
    bool recording = false;
    bool playing = false;
    bool overdubing = false;
    int position = 0;
    int length = 0;
    int loopNumber;
    GPIO button;
    bool buttonPressed = false;
    GPIO led;
    GPIO encoder1;
    GPIO encoder2;
    float *buffer;
public:
    // Initialize Hardware for Loop
    Loop(Pin buttonPin, Pin encoderPin1, Pin encoderPin2, Pin ledPin, int no, float *buf) {
        button.Init(buttonPin, GPIO::Mode::INPUT, GPIO::Pull::PULLUP);
        encoder1.Init(encoderPin1, GPIO::Mode::INPUT, GPIO::Pull::PULLUP);
        encoder2.Init(encoderPin2, GPIO::Mode::INPUT, GPIO::Pull::PULLUP);
        led.Init(ledPin, GPIO::Mode::OUTPUT);
        loopNumber = no;
        buffer = buf;
        
    }
    // ~Loop();
    loopModes getLoopMode() {
        return loopMode;
    }
    void setLoopMode(loopModes mode) {
        loopMode = mode;
    }
    void checkButton() {
        if (!button.Read() && !buttonPressed)
        {
            buttonPressed = true;
            hw.PrintLine("======");
            hw.PrintLine(to_string(loopNumber).data());
            ButtonPressed(determineButtonFunction());
        } else if (button.Read() && buttonPressed) {
            buttonPressed = false;
        }
        hw.SetLed(buttonPressed);
    }
    buttonFunction determineButtonFunction() {
        if (!buttonFn1.Read() && !buttonFn2.Read() && !buttonFn3.Read())
        { return eight; } 
        else if (!buttonFn1.Read() && !buttonFn3.Read())
        { return seventh; } 
        else if (!buttonFn2.Read() && !buttonFn3.Read())
        { return sixth; } 
        else if (!buttonFn1.Read() && !buttonFn2.Read())
        { return fifth; } 
        else if (!buttonFn3.Read())
        { return fourth; } 
        else if (!buttonFn2.Read())
        { return third; } 
        else if (!buttonFn1.Read())
        { return second; } 
        else { return first; }
    }
    void ButtonPressed(buttonFunction funct) {
        switch (funct)
        {
        case first:
            hw.PrintLine("first");
            // record / play/oneshot/replace / pause
            if (firstLoop) {
                recording = true;
                firstLoop = false;
                hw.PrintLine("recording");
            // stop recording and play
            } else if (recording) {
                recording = false;
                playing = true;
                hw.PrintLine("rec -> play");
            // pause
            } else if (playing) {
                playing = false;
                hw.PrintLine("paused");
            // play
            } else if (!playing) {
                playing = true;
                hw.PrintLine("playing");
            // stop overdubing
            } else if (overdubing) {
                overdubing = false;
                hw.PrintLine("stoped overdub");
            }
            break;
        case second:
            hw.PrintLine("second");
            // overdub
            if (loopMode = loop) {
                overdubing = true;
                hw.PrintLine("overdub");
            }
            break;
        case third:
            hw.PrintLine("third");
            break;
        case fourth:
            hw.PrintLine("fourth");
            break;
        case fifth:
            hw.PrintLine("fifth");
            break;
        case sixth:
            hw.PrintLine("sixth");
            break;
        case seventh:
            hw.PrintLine("seventh");
            break;
        case eight:
            hw.PrintLine("eight");
            // delete loop
            DeleteLoop();
            hw.PrintLine("deleted");
            break;
        }
    }
    void DeleteLoop() {
        loopMode = loop;
        firstLoop = true;
        recording = false;
        playing = false;
        overdubing = false;
        position = 0;
        length = 0;
        for(int i = 0; i < length; i++)
        {
            buffer[i] = 0;
        }
    }
    void WriteBuffer(AudioHandle::InterleavingInputBuffer in, size_t i) {
        if (recording)
        {
            buffer[position] = in[i];
            length++;
        } else {
            buffer[position] = buffer[position] * 0.5 + in[i] * 0.5;
        }
    }
    void NextSamples(float& output, AudioHandle::InterleavingInputBuffer in, size_t i)
    {
        if (recording || overdubing)
        {
            WriteBuffer(in, i);
        }
        
        //automatic looptime
        if (length >= MAX_SIZE)
        {
            firstLoop = false;
            recording = false;
            playing = true;
        }
        
        if (playing)
        {
            position++;
            position %= length;
            output = buffer[position];
        }
    }
};

    Loop    loop1(D27, D26, D2, D1, 1, buffer1),
            // loop2(D25, D24, D5, D3, buffer2),
            loop3(D23, D22, D8, D6, 3, buffer3),
            loop4(D21, D20, D11, D9, 4, buffer4),
            loop5(D19, D18, D15, D12, 5, buffer5);

void AudioCallback(AudioHandle::InterleavingInputBuffer in, AudioHandle::InterleavingOutputBuffer out, size_t size) {
    float output = 0;
    for (size_t i = 0; i < size; i += 2) {
        loop1.NextSamples(output, in, i);
        // loop2.NextSamples(output, in, i);
        loop3.NextSamples(output, in, i);
        loop4.NextSamples(output, in, i);
        loop5.NextSamples(output, in, i);
        out[i] = out[i + 1] = output + in[i] + in[i + 1];
    }
}

int main(void)
{
    // Configure and Initialize the Daisy Seed
    // These are separate to allow reconfiguration of any of the internal
    // components before initialization.
    hw.Configure();
    hw.Init();
    hw.SetAudioBlockSize(4);

    // Wait for Debugger
    hw.StartLog(true);

    // Initialize FN Buttons
    buttonFn1.Init(D17, GPIO::Mode::INPUT, GPIO::Pull::PULLUP);
    buttonFn2.Init(D15, GPIO::Mode::INPUT, GPIO::Pull::PULLUP);
    buttonFn3.Init(D16, GPIO::Mode::INPUT, GPIO::Pull::PULLUP);

    hw.StartAudio(AudioCallback);

    while (1)
    {
        loop1.checkButton();
        // loop2.checkButton();
        loop3.checkButton();
        loop4.checkButton();
        loop5.checkButton();
    }
}

It’s possible that your audio buffer is underflowing because you’re running at a small block size, and reading / writing often from the (slower) SDRAM. Try increasing the audio block size to something like 64 or 128, or removing some of the loop*.NextSamples calls.

Also, unrelated to your noise issue, only the last Loop object (loop5) is going to contribute to the output sound, since the output variable passed by reference is overwritten on each loop*.NextSamples() call.

There’s a nice documentation article about logging / debug printing, hope that helps!

is it possible to check that somehow?
tried increasing the blocksize to 64, 128 and 265 and only activated 1 loop*.NextSamples() call
also tried deleting the hw.SetAudioBlocksize() again, bc only included that bc of example
nothing is making any difference, thou for some reason, theres no loud noise today (no clue why) and also when something is playing, it makes some pop noises in regular intervals, which feels like there is actually something playing

deleted some commented things and didnt notice that the playing portion of NextSamples() was a temporary trial and error
original is like this, which should add the buffer to the output, making all loops contribute to the output (unless somethings wrong with that)

if (playing)
        {
            position++;
            position %= length;
            output = output + buffer[position];
        }

reallized the debugging issue
it somehow dosnt work when it is run in a function that was called by the AudioCallback
it instantly freezes/crashes the seed

Oh yeah, you definitely don’t want to call the logging functions from inside the audio thread. Generally speaking, i/o operations (like the serial communication for debugging) can take an uncertain amount of time to complete and shouldn’t be called from the audio callback, which needs to complete in a specified amount of time whenever it’s called.

Glad that at least the loud noise is gone. I’m not sure I can help with the pop noises – it’s possible you’ll need some sort of envelope to modulate the signal you write the buffer (so that you don’t get clicks at the beginnings of record regions).

wanted to print an audio buffer (float*) to console within the while(1) loop, but no clue how to convert it
still not getting any looping audio, appart from the clicking noises

hmm… guess that makes somewhat sense

is it possible that the issue is somehow with the audiocallback and it might work when the function gets called in the while loop? thou it would probably desync?

just an idea, currently no IDE around to test it

didnt even do anything, but the noise is back

atleast having a better input source now and wow, the audio of this thing is completely clean!

I won’t debug this, but my guess is that you are indexing the in and out arrays in the callback incorrectly.
I’d suggest converting this to use the non-Interleaved form of audio buffer, it seems a bit more intuitive.

dont think thats it, as currently trying to get it working, building ontop of the pod looper example and it produces the same error

any clue on how to print the buffer? wanna see if anything gets written into it

here’s the code

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

#define MAX_SIZE (48000 * 60 * 1) // 1 minute of floats at 48 khz

using namespace daisysp;
using namespace daisy;
using namespace daisy::seed;
using namespace std;

static DaisySeed hw;

float DSY_SDRAM_BSS buf[MAX_SIZE];
int pos = 0;

class Loop {
    private:
        bool first = true;  //first loop (sets length)
        bool rec   = false; //currently recording
        bool play  = false; //currently playing
        // int                 pos    = 0;
        int                 mod    = MAX_SIZE;
        int                 len    = 0;
        float               drywet = 1;
        Encoder button, button2;
    public:
        Loop() {
            button.Init(D26, D30, D27);
            button2.Init(D24, D29, D25);
        }
        //Resets the buffer
        void ResetBuffer()
        {
            play  = false;
            rec   = false;
            first = true;
            pos   = 0;
            len   = 0;
            for(int i = 0; i < mod; i++)
            {
                buf[i] = 0;
            }
            mod = MAX_SIZE;
        }
        void UpdateButtons()
        {
            button.Debounce();
            button2.Debounce();
            //button1 pressed
            if(button.RisingEdge())
            {
                if(first && rec)
                {
                    first = false;
                    rec = false;
                    mod   = len;
                    len   = 0;
                    play = true;
                } else if (first)
                {
                    rec = true;
                } 
                if (!first)
                {
                    play = !play;
                }
            }

            //button1 held
            if(button.TimeHeldMs() >= 1000) // && res)
            {
                ResetBuffer();
                first = true;
                rec = false;
                mod = MAX_SIZE;
                len = 0;
            }

            //button2 pressed
            if(button2.RisingEdge())
            {
                play = false;
                rec  = false;
            }
        }
        void WriteBuffer(AudioHandle::InterleavingInputBuffer in, size_t i)
        {
            buf[pos] = buf[pos] + in[i];
            if(first)
            {
                len++;
            }
        }
        void NextSamples(float&                               output,
                    AudioHandle::InterleavingInputBuffer in,
                    size_t                               i)
        {
            if(rec)
            {
                WriteBuffer(in, i);
            }

            output = buf[pos];

            //automatic looptime
            if(len >= MAX_SIZE)
            {
                first = false;
                mod   = MAX_SIZE;
                len   = 0;
            }

            if(play)
            {
                pos++;
                pos %= mod;
            }

            if(!rec)
            {
                output = output + in[i];
            } else {
                output = in[i];
            }
        }
};

Loop loop1;

static void AudioCallback(AudioHandle::InterleavingInputBuffer  in,
                          AudioHandle::InterleavingOutputBuffer out,
                          size_t                                size)
{
    float output = 0;

    for(size_t i = 0; i < size; i += 2)
    {
        loop1.NextSamples(output, in, i);

        // left and right outs
        out[i] = out[i + 1] = output;
    }
}

int main(void)
{
    hw.Init();
    hw.SetAudioBlockSize(4);
    hw.StartLog();
    
    loop1.ResetBuffer();
    
    hw.StartAudio(AudioCallback);

    while(1) {
        loop1.UpdateButtons();
    }
}

Practically speaking, you can’t print the audio buffer.

is there any way to see if something gets written to it or if it stays all 0?

Im sure you could do something to set a flag in the callback, and print a message in main.
I don’t understand your statement about the Pod looper. You can’t get Pod looper to work?

how to do it without crashing the daisy?

the pod looper example works
but when trying to modify it (see code), it ends up with the same error

ok, tried printing a single position of the buffer after button press, but printing anything to do with the buffer instantly crashes the daisy

okay, rewritten everything and it mostly works
only issue is adding the buffers to output, but opened a new topic for that

1 Like