Basic step sequencer

Hi
I’m new to daisy and I’ve bought a Pod like a year ago. Now I’ve decided to give a try and try to build a basic step sequencer (just sequence a sine wave), change note for each step and hopefully have 16 steps. I’ve looked at the Pod sequencer example, but there’s a lot of stuff I don’t understand what it does, just wanted to check if there’s a simpler version of this sequencer or what are the important parts in that code I should be considering for this first project.

Thanks!

@Ulozilla,

Hi, happy to help where I can here… I am reasonably new to the platform as well, so I am happy to share some of things I have learned. There is a good primer around here (somewhere) on how the basics of the core work in the Daisy.

I’ll put a few things in here and if some of you know and you are looking for other items, please feel free to let me know and i’ll do what I can to help. :slight_smile:

Some thoughts:

  1. The Audio Callback is called on a timer to ensure good audio throughput and no skipped / broken up audio. Thus, you will see that the number of audio block sizes can be set… the small, the faster and more immediate the response / less audio lag. pod.SetAudioBlockSize(4);

  2. This audio callback is always running once you call: pod.StartAudio(AudioCallback); - this is why the main program loop is nothing more than a “while(1) {}” in this app. All of the setup is done before the audio callbacks start and there all the work is done insides of the audio callback function. You do have to be careful not to overload the time it takes to complete work in this audio callback function. Thus, it may be necessary to off load things that can be interrupted in the main loop.

  3. the main app loop can, and will be, interrupted by the audio callback as noted above to ensure that audio stays flowing without breakups.

  4. it is good to understand that the Metro(nome) is a time that when it gets to the next appropriate “tick” the metro.process() will return true. This is effectively the way to know you are at the next time signal. This is where you would, for example, advance the step count and setup the next audio out.

  5. When you setup items such as oscillators, metronomes, etc. the functions need the audio rate in order to properly calculate the next signal step so that you can have a the proper output for your chosen audio rate. Under the hood of the code it will keep everything in sync for you. This is also why you see the .process() for these function inside of the audio callback.

  6. To extend what I spoke bout above: in the audio callback you will notice there is a “size” sent in and a loop is created around the “size” so that a frame of audio can be calculated and sent out to the audio device. Thus, the callback will create a small piece of the waveform that will be played while the program is doing the rest of the work such as setting LEDs, getting control data, etc.

  7. This function is where the audio is created and I added a few comments. Although maybe it was already obvious I thought it was best to just add it for clarity just in case it helps. Hopefully it is not insulting to have done this for you.

void NextSamples(float &sig)
{
    env_out = env.Process(); // get the next envelope for the next auio sample  
    osc.SetAmp(env_out); // update the audio amplitude for the oscillator based on the envelope update 
    sig = osc.Process(); // Get the next sample from the oscillator 
    sig = flt.Process(sig); // apply the filter to the oscillator sample

    if(tick.Process() && !edit)  // Check to se if we hit another time maker for the metronome and that we are not editing to keep the step sequencer running 
    {
        step++;  
        step %= 8;
        if(active[step])
        {
            env.Trigger();  // restart the envelope if we are on an active step 
        }
    }

I wanted to cover a few ideas for you here, sorry if some of them are obvious and/or this is not quite what you were looking for. Please feel free to keep asking question as I know it has taken me some time to ramp up on the platform as well.

I hope some of this helps, and if not, again, feel free to keep asking more questions.

Thanks,
Brett

2 Likes

Brett
Thank you for replying, this explanation is great. I will try to make a simpler version of the step sequencer and see if I can make it work during the week.

1 Like

Actually it’s a callback to SAI DMA that is triggered when half of DMA data is available. Audio codec is sending and receiving data constantly once you call ::startAudio. Whenever buffer gets half full, a hardware interrupt is raised that executes your audio callback. So it preempts whatever code is called in main loop. Once it’s done the main loop resumes its code execution.

There are actual hardware timers on this MCU that could be used for running code periodically. And you also could have custom callbacks for them.

1 Like

@antisvin,

Ah, yes, thank you for the correction/clarification on what I wrote above.

this would be really nice to have it as an example! :slight_smile:
would you mind providing us with one?