Yeah, you were trying to solve your problem with what programmers call an “anti-pattern.” I think what might be useful is to step back and think about how you are managing state on a broader level. The Daisy code is designed around a callback model, and if you try to work with that code in a non-callback fashion you are likely going to encounter anti-pattern problems.
Think of a callback function kind of like an alarm clock, and your code is a narcoleptic dude who can only stay awake long enough to finish a simple job. The purpose of the call back function is to kick the dude in the butt every so often and say, “HEY! WAKE UP! TIME TO DO YOUR JOB!” The Daisy library is the clock where you set the alarm. It will trigger the alarm regularly to remind you it’s time to wake up, but it has no idea why you want to wake up or what you need to do. The purpose of the Daisy code is to let you know when it is time to do whatever it is you need to do. It does this by running your callback code.
The Daisy code doesn’t know anything about what you are trying to do. It doesn’t know if you are trying to play a synthesizer oscillator, or access a delay buffer, or turn on a servo motor to flip the waffles in your breakfast pan.
It is the sleepy dude who needs to remember what he is supposed to do and how he is supposed to do it, so that sleepy dude is where you need to maintain all of your state. The sleepy dude is your main code file – the one that has both the main function and the audio callback function code. Those are the tools that you have to maintain state and remember what you are trying to do every time the alarm clock goes off.
This is where you can start thinking of strategies for maintaining state. The main problem for you to solve is how to share information between your “main” function and your callback function. One way to do this is to put your callback function inside an object that exists in the main function. I think that is what JCRiggs is showing you how to do.
Another way to do this is to create a state holder object at the global level. You can initialize it in main, and the access it in your callback. This second approach is is what most of the Daisy library examples do:
#include "daisy_seed.h"
#include "daisysp.h"
#include "MyKillerSynthesizer.h" // <--- That is a file you create for your synth. You also create the cpp file.
using namespace daisy;
using namespace daisysp;
DaisySeed hw;
// Here is the object you create that manages state and also knows how to do synth stuff
MyKillerSynthesizer theSynth;
// Here is how the Daisy tells your synth dude to WAKE UP!!!!
void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{
// This is the function you create where synth dude does something amazing:
theSynth.Process(in, out, size);
} // <--- Now synth dude goes back to sleep until Daisy wakes him up again.
int main(void)
{
hw.Init();
hw.SetAudioBlockSize(48); // number of samples handled per callback
hw.SetAudioSampleRate(SaiHandle::Config::SampleRate::SAI_48KHZ);
theSynth.Init(hw.AudioSampleRate()); // <-- This is a function you make that tells how to set up the synth.
hw.StartAdc();
hw.StartAudio(AudioCallback);
while(1)
{
// This infinite loop prevents the program from exiting so that the Daisy library can keep calling your callback and telling sleepyhead to WAKE UP over and over. How rude!
}
}
That takes us to the next step, which is creating MyKillerSynthesizer.h and MyKillerSynthesizer.cpp…