Passing arguments to AudioCallback()

Is there a way to pass arguments (besides the default InputBuffer in, OutputBuffer out, size_t size parameters).
Theoretically, I can define a callback with custom parameters:

	void MyCallback(
					daisy::AudioHandle::InputBuffer in,
					daisy::AudioHandle::OutputBuffer out,
					size_t size,
					int myVar0,
					float myVar1
				   ) {...}

but am not sure how to start this callback and pass it the arguments in main().
If I try to specify these arguments in the StartAudio() function …

int a = 0;
float b = 0.f;
hw.StartAudio(MyCallBack(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size, a, b))

… I get an error stating “no instance of overloaded function ‘daisy::DaisySeed::StartAudio’ matches the argument list.”
Is there a different way I should be using to pass arguments to the callback?

I’m trying to pass variables to the callback to try to eliminate some global variables that I am accessing in the callback and would prefer to declare them in main() and pass them to AudioCallback().

I’m brand new to daisy and haven’t even set up the code yet… but that error message tells me that StartAudio is defined elsewhere as having only the initial 3 arguments.

When I hunt down StartAudio in the Github repository, I found the header file below

There the definition is:

typedef void (*AudioCallback)(InputBuffer  in,
                              OutputBuffer out,
                              size_t       size);

My admittedly superficial search tells me that’s why you get that message.

Function overloading should do the job: declare another function with the same name, but with the additional two parameters, and see what happens.

Thanks for your replies.

Maybe I’m doing something incorrectly but I’m getting the same error message when overloading AudioCallback. As far as I understand your first answer, linking the audio.h, seems to point to argument passing not being possible.
Here’s how I’m trying to overload the callback.


void AudioCallback(
    daisy::AudioHandle::InputBuffer in, 
    daisy::AudioHandle::OutputBuffer out, 
    size_t size,
    int j
) 
{
    // callback
}
// in main...
hw.StartAudio(AudioCallback);

I’m still unable to pass any arguments to AudioCallback even when using the initial three arguments, i.e. hw.StartAudio(AudioCallback(in, out, size)). This gives the same error “no instance of overloaded function…” As far as I can tell int j is being initialized and theoretically could be used in the callback, but I am still unable to pass an argument to AudioCallback.

I also tried

daisy::AudioHandle::InputBuffer in;
daisy::AudioHandle::OutputBuffer out;
size_t size;
int j;
hw.StartAudio(AudioCallback(in, out, size, j));

which won’t even compile. (same error).

I don’t know if I should talk without even having the code set up yet… but I can tell you my thinking…

StartAudio has one argument - AudioCallback. When I looked up AudioCallback, I found that definition in the Audio.h file that I linked earlier.

typedef void (*AudioCallback)(InputBuffer  in,
                              OutputBuffer out,
                              size_t       size);

What I would do is I would add this to Audio.h (not modify the existing definition, add the one below):

typedef void (*AudioCallback)(InputBuffer  in,
                              OutputBuffer out,
                              size_t       size,
                              int j);

I’m not that familiar with C++, but I know this would work in C#. It’s a small, quick change that can be tested right away and can be reverted.

I thought about adding an overload of AudioCallback to the Audio.h file as you suggested, but I’m still not sure how I would pass an argument to this overloaded callback. This method would only initialize a variable every time AudioCallback is called.
The only way to avoid the error:

hw.StartAudio(AudioCallback);

which still doesn’t allow me to pass arguments, even if I am calling the overloaded AudioCallback with int j initialized.
It might help if I explain further. I need a class object that persists across the lifetime of the callback and it needs to be initialized (for some setup) before the callback is started. The way I was hoping to accomplish this was declaring the object in main and then passing it to the AudioCallback as an argument. However, because I have not been able to successfully pass the callback any arguments, I’ve had to globally declare the object to be able to manipulate it both in main() and in AudioCallback(). I’d prefer to avoid the global but it doesn’t seem like I can.

After you add the overload to Audio.h you would add your other overload in the .cpp file where you make the hw.StartAudio(AudioCallback) call.

void AudioCallback(
				daisy::AudioHandle::InputBuffer in,
				daisy::AudioHandle::OutputBuffer out,
				size_t size,
				int myVar0
			   ) {...}

Oh ok.
I guess I’m confused though. So would I be calling an overload of StartAudio?

hw.StartAudio(AudioCallback(in, out, size, j));

I’m still unsure how the arguments would get passed to the callback.

Hmm… Good point. Yeah, I would try

hw.StartAudio(AudioCallback(in, out, size, j));

If that doesn’t work… I don’t have enough knowledge of the libraries, but I’m wondering how complex it would be to implement your own custom function instead of an overload in Audio.h.

Something like

typedef void (*MyCustomAudioCallback)(InputBuffer in,
OutputBuffer out,
size_t size,
int j);

I did try that, with and without additional variables.

I think implementing a custom callback and StartAudio is beyond my knowledge to be honest lol. I may just have to accept the globals.

I’m working on setting up the entire daisy framework on my computer. Once it’s up and running, I’ll play with your exact same scenario and see what smart or stupid stuff I can come up with.

I like learning/exploring a new library while working on an actual issue, rather than browsing through it and reading. I’m waiting for my daisy pod anyway.

Ok, let me know if you find anything. Thank you.

Good luck! The daisy has been pretty fun for me so far!

I think you have a bit of a misunderstanding of how the AudioCallback method works. When you call hw.StartAudio(AudioCallback), you are not invoking the callback code but rather passing a pointer to this code to the hw object via the StartAudio method. The hw object will use this pointer to call your callback code from within its own code, populating the arguments at that time. To add arguments by overloading, you would need to modify the code of the hw object class to accommodate these new arguments as well.
If you absolutely must avoid global scope, you could make your new values private variables of a new class and make the AudioCallback a method of that class. Then you would initialize the variables when you construct an instance of that class and pass that object’s AudioCallback method to StartAudio. You will have to manage scope for the object now though - if the instance gets deleted while still being called on by the hw object, your code will likely crash.
Hopefully that is clear - let me know if any of it does not makes sense to you. There are probably other ways to do this that may be more appropriate to Daisy, so hopefully someone with more savvy will weigh in if that is the case. I am a C++ guy with a Daisy Pod I have yet to set up.
Regards,
John

That makes sense. Thanks for the explanation. I’m doing some reading about function pointers now.

This seems like an example of when avoiding a global is not worth the hoops I’d have to jump through.

Not really a misunderstanding… it’s pretty clear how AudioCallback works. The overloading part is what doesn’t work so far.

I should talk less and work with the code. So far I’m still struggling to make VisualGDB see the toolchain.

My point was that you cannot just overload a callback without also adjusting the code that invokes it - that is the misunderstanding. Just trying to help.

Regards,
John

No offense was taken, any help is appreciated. Only that we did discuss adding an overload in the definition header file and then calling it accordingly in the .cpp file. It didn’t work so far… but it has to eventually

The call to hw.StartAudio(AudioCallback) does not call the code in AudioCallback - it merely passes a pointer to that method to the hw object. Overloading AudioCallback and adding arguments to this call will not do anything useful (or even compile) unless you modify the code of the hw object to deal with the new overloaded version of the AudioCallback at the points where it uses the pointer passed to it in StartAudio (and even then, passing the arguments in the StartAudio call is not correct)
Overloading - at least the way it is discussed here - is not the way to approach this problem. There are probably several ways to deal with it - the simplest is to just live with global variables, the next is probably an object wrapper, as I proposed.

Regards,
John

I’ll tell you what I did and I don’t seem to get errors, but can’t tell for sure since my daisy setup has been a pain and isn’t complete. I’m simply mimicking the current behavior, not doing anything smart.

In blockquotes below is all the new stuff I created.

audio.h:

typedef void (*CustomInterleavingAudioCallback)(InterleavingInputBuffer  in,
                                          InterleavingOutputBuffer out,
                                          size_t                   size,
                                          int myint);

This is just below the existing
typedef void (*InterleavingAudioCallback)(InterleavingInputBuffer in,
InterleavingOutputBuffer out,
size_t size);

audio.cpp:

In the Public declaration section at the top:

AudioHandle::Result StartCustom(AudioHandle::CustomInterleavingAudioCallback callback);

Below the existing
AudioHandle::Result Start(AudioHandle::InterleavingAudioCallback callback);

then

AudioHandle::Result
AudioHandle::Impl::StartCustom(AudioHandle::CustomInterleavingAudioCallback callback)
{
// Get instance of object
sai1_.StartDma(buff_rx_[0],
buff_tx_[0],
config_.blocksize * 2 * 2,
audio_handle.InternalCallback);
interleaved_callback_ = (void*)callback;
callback_ = nullptr;
return Result::OK;
}

Below the existing
AudioHandle::Result
AudioHandle::Impl::Start(AudioHandle::InterleavingAudioCallback callback)
{…

audio.h:

Result StartCustom(CustomInterleavingAudioCallback callback);

Below the existing
Result Start(InterleavingAudioCallback callback);

audio.cpp again:

AudioHandle::Result AudioHandle::StartCustom(CustomInterleavingAudioCallback callback)
{
return pimpl_->StartCustom(callback);
}

Below the existing
AudioHandle::Result AudioHandle::Start(InterleavingAudioCallback callback)
{
return pimpl_->Start(callback);
}

daisy_seed.cpp:

void DaisySeed::StartAudioCustom(AudioHandle::CustomInterleavingAudioCallback cb)
{
audio_handle.StartCustom(cb);
}

Below the existing
void DaisySeed::StartAudio(AudioHandle::InterleavingAudioCallback cb)
{
audio_handle.Start(cb);
}

daisy_seed.h:

void StartAudioCustom(AudioHandle::CustomInterleavingAudioCallback cb);

Below the existing
void StartAudio(AudioHandle::InterleavingAudioCallback cb);

daisy_pod.cpp:

void DaisyPod::StartAudioCustom(AudioHandle::CustomInterleavingAudioCallback cb)
{
seed.StartAudioCustom(cb);
}

Below the existing
void DaisyPod::StartAudio(AudioHandle::InterleavingAudioCallback cb)
{
seed.StartAudio(cb);
}

daisy_pod.h:

void StartAudioCustom(AudioHandle::CustomInterleavingAudioCallback cb);

Below the existing
void StartAudio(AudioHandle::InterleavingAudioCallback cb);

Finally, in your .cpp project file

void AudioCallbackCustom(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size,
int myint)
{…

and also change the call in

int main(void)

to

pod.StartAudioCustom(AudioCallbackCustom);

First of all, your code modifies the code for the class that provides the hw object in the original example so that your new type can be passed (which I noted would be required), but none of your code populates the new myint parameter. The value for this parameter has to come from somewhere. The original example passed the value for myint in the call to StartAudio - this will not work, since making that change alters the code to pass the result of the AudioCallback method rather than a pointer to it. This is all pretty standard C++.
Your code will compile but will not do anything useful with the myint parameter you have added. It looks to me like a lot of work for no real result - all you’ve really done is create a parallel callback with a new parameter that is actually unused (i.e. never populated by the code that actually invokes the callback).
Regards,
John