C++

C++ is the original language for Bela projects, and remains the core of Bela language support. C++ is a multi-purpose language and has a big presence in music and audio programming. Many people are already familiar with C++ though they might not know it - Arduino’s programming language is a simplified version of C++.

Though C++ can be used to make LEDs blink and sense button pushes, it can do much, much more. This article discusses the details of Bela’s C++ support, and how you can use it to work with sensors and sound.

Table of contents

  1. C++ and Bela
  2. The Bela API for C++
    1. setup()
    2. render()
    3. cleanup()
  3. Writing real-time safe C++
    1. Bela C++ must be real-time safe
  4. Resources

C++ and Bela

C++ is the native lanugage for programming Bela. Though Pure Data, SuperCollider and Csound are also well supported, C++ was the first language for Bela projects. The core Bela software is mostly written in C++.

Bela fully supports C++14. Bela’s version of C++ is not simplified or limited; instead, you have full access to all the affordances of C++14 to write your code (with some considerations for real-time safety that we outline below).

The Bela API for C++

Bela has a simple API for C++ projects. It’s made up of three functions:

#include <Bela.h>

bool setup(BelaContext *context, void *userData) {
	return true;
}

void render(BelaContext *context, void *userData) {

}

void cleanup(BelaContext *context, void *userData) {

}

setup()

The setup() function runs once at the beginning of your project’s execution (just like the Arduino setup() function). Because it runs once before the audio processing starts, it’s the place to do things like initialise hardware, allocate memory, and set up any other resources you will need in render().

The setup() function should return false if an error occurred, otherwise it should return true. Returning false will stop the program.

render()

The render() function is called at regular intervals as Bela runs (similar to the loop() function in the Arduino environment).

The render() function is where all of Bela’s real-time processing takes place. The render() function is called for each block of samples. The block size is specified in the Settings tab of the IDE.

A typical program in render() might process each audio frame in sequence using a loop like this:

void render(BelaContext *context, void *userData) {
	for(unsigned int n = 0; n < context->audioFrames; n++) {
		// Code to process each sample
	}
}

cleanup()

The cleanup() function runs at the end of the program before it exits, to do tasks like freeing up any memory that was allocated in setup().

Writing real-time safe C++

Tip

Want to learn about writing C++ for real-time applications? Check out Bela's free course on YouTube, C++ Real-Time Audio Programming with Bela.

Bela is a hard real-time system. This means that in order for Bela to run, all code must complete in time, and nothing can slow down the real-time thread. This commitment to completing tasks on time is what makes interaction with Bela feel so natural and responsive. (To find out about how Bela processes audio and sensor data, check out the article on Bela software.)

Bela C++ must be real-time safe

All the code that happens in render() is on a real-time thread (specifically, a real-time task in Xenomai Linux), and there are some things to keep in mind to make sure your code is real-time safe.

The code in the render() function operates in “primary” mode. Everything that the operating system does is at a lower priority - such as connecting to the network, printing to the console, reading from the SD card, and so on - also called “secondary” mode.

Switching from the primary real-time mode of the render() thread to the secondary system functions is called a mode switch, and will interfere with Bela’s performance.

There are ways around mode switches. As a general rule, avoid running any code that requires access to specific features of the Linux system. For instance, instead of using the usual C++ methods of printing to the console such as cout or printf(), Bela has a real-time safe print function: rt_printf(). Additionally, when a process needs more time to complete or may involve switching modes, you can use the AuxiliaryTask API (see the example Sensors -> MPR121 in the Examples to run the code in a different, lower-priority thread.

Be aware that this concept of real-time safety also applies to allocating memory, which should only be done in the setup() function and not in render().

Resources

  • There are dozens of examples demonstrating techniques with C++ in the Examples tab of the IDE. Check those out for in-depth demonstrations of real-time safe Bela projects

  • If you’re new to C++ and want to learn some techniques, the C++ Reference is a great place to start.