Hi Bela users.

I'm fairly new to programming in the Bela IDE and to the Bela API. What is the purpose/idea of the *userData that is passed around.

Best, Hjalte

That is a opaque pointer used to pass arguments around. That pointer is passed to the Bela backend when calling the int Bela_initAudio(BelaInitSettings *settings, void *userData) function. Any Bela project that does not have a custom main.cpp file uses under the hood core/default_main.cpp, which contains the call to Bela_init(), and passes a NULL pointer as userData. This means that if you do not have a custom main.cpp, then userData is not used.
Some of the example projects provide a custom main() function and use userData to pass some data retrieved from the command-ilne to the setup() function:

./04-Audio/FFT-phase-vocoder/render.cpp:	gSampleData = *(SampleData *)userData;
./10-Instruments/d-box/render.cpp:	int oscBankHopSize = *(int *)userData;
./11-Extras/second-pru/render.cpp:	int pruNumber;		 // comes from userData
./11-Extras/second-pru/render.cpp:	// Which PRU to use is in userData, assuming this project
./11-Extras/second-pru/render.cpp:	if(userData == 0) {
./11-Extras/second-pru/render.cpp:	pruNumber = *((int *)userData);
./11-Extras/second-pru/render.cpp:	int pruNumber = *((int *)userData);
./11-Extras/userdata/render.cpp:	if(userData != 0)
./11-Extras/userdata/render.cpp:		gFrequency = *(float *)userData;
./terminal-only/filter-FIR/render.cpp:	gSampleData = *(SampleData *)userData;
./terminal-only/filter-IIR/render.cpp:	gSampleData = *(SampleData *)userData;
./terminal-only/samples/render.cpp:	gSampleData = *(SampleData *)userData;

However, similar results could be achieved - in the context of a Bela project - using global variables.

The most powerful use of userData, however, is when embedding Bela into an other application. For instance, in the code for the Bela backend for SuperCollider, userData is a pointer to a driver object instance:

Bela_initAudio(&settings, this) 

at that point, every time the audio callback function (sc_belaRender()) is called, it is passed a reference to the driver object and it can (after appropriate casting) access its members:

void sc_belaRender(BelaContext *belaContext, void *userData)
{
	SC_BelaDriver *driver = (SC_BelaDriver*)userData;
	driver->BelaAudioCallback(belaContext);
}
    20 days later

    giuliomoro
    From what I understand here, it is possible to modify the userdata in the main.cpp during runtime (say, reading analog inputs in each iteration). So, does sc_belaRender pass the latest userdata to the render function? Or does it pass only the userdata there was during initialization?

    This could be handy because I could implement all the extra logic in the main.cpp and then pass all the parameters through userdata to render in runtime.

    The userData that is passed to setup(), render(), cleanup() is the one that is set in the call to Bela_initAudio: this is normally set just once, typically from the main() function in core/default_main.cpp file.
    If you are calling Bela_initAudio() multiple times (e.g.: if you are start/stopping the audio multiple times), then you can change that userData for every call.
    However, if your objective is to use it to access a portion of memory that is changed somewhere else in the code, keep in mind that the content ofuserData can be of any type, it is just casted to a void* when calling Bela_initAudio() and has to be casted back to the same type in the callback functions. This way, if it actually is a pointer to a location in memory, and you can change the content of the memory it points to, if you want to implement a way of change the data it gives access to for each call to render().

    3 years later

    do you think we could add a setUserData() method?
    (it simply needs to set gUserData, which is currently not exposed)

    I quite like the idea of using it to avoid globals, and so creating a data structure in setup(), and then calling it, and knowing that it would be available in render() and cleanup().

    a setUserData method, would avoid the requirement to copying default_main.cpp, which id prefer to avoid incase subsequent bela release 'change/improve it'

    seems like a good idea, wanted to do something similar for gShouldStop as well. Do you have a Pull Request ready?

    7 days later

    done here. This stuff is going to be merged intomaster next week. However, I thought that maybe the best place to set that would be as a member of the BelaInitSettings structure, which can be set by the user if the define a Bela_userSettings() function, so I may move to that solution later on.