Migrating to Bela Gem

Port your projects from Bela to Gem

Bela Gem is our most recent embedded audio and sensor platform built around PocketBeagle 2 (PB2). If you have an existing project running on first-gen Bela board (Bela, Bela Mini, CTAG, or any combination of these), this guide will help you adapt it to a Gem Stereo or Gem Multi. Make sure you go through the Gem getting started guide to get your board working first.

Table of contents

  1. Introduction
  2. Hardware
  3. Software
    1. Analog outputs are now audio outputs
    2. PureData: abstractions for accessing I/Os
    3. C++: the default analog sampling rate has changed
    4. C++: threads and parallelism
    5. The IDE
    6. The Linux image

Introduction

The Bela Gem Stereo and Bela Gem Multi boards, which started shipping in early 2026, consolidate our lineup of maker boards, which had sprawled up during the 10 years of existence of the boards based around the Beaglebone Black and PocketBeagle single-board computers. Gem is based on the PocketBeagle 2 (PB2), delivering much more power in a compact form factor than the previous boards based on the BeagleBone Black (BBB) and PocketBeagle (PB).

Product Salient specs
Bela Gem Stereo Based on PB2
2 audio in (microphone/line)
2 audio out (line/headphone)
8 DC-coupled analog in
Bela Gem Multi Based on PB2
10 audio in (microphone/line, optionally up to 8 PDM mic)
10 audio out (2 with line/headphone, 8 DC-coupled line ±5V)
8 DC-coupled analog in

In broad strokes, the Bela Gem Stereo is meant as a direct replacement for the Bela Mini, while the Bela Gem Multi is the one-stop shop to replace the Bela cape and all multichannel offering, although it is not a one-to-one replacement for any of those. The table below provides summary specs and suggests replacement for legacy products.

Product Salient specs Suggested replacement Salient differences
Bela Based on BBB
2 audio in (microphone/line)
2 audio out (line/headphone)
8 DC-coupled analog in
8 DC-coupled analog out
Stereo speaker amp
Bela Gem Multi More input channels, no speaker amp, analog out are now audio out, no ethernet
Bela Mini Based on PB
2 audio in (microphone/line)
2 audio out (line/headphone)
8 DC-coupled analog in
Bela Gem Stereo  
Bela Mini with Multi-channel expander Based on BBB
8 audio in (microphone/line)
8 audio out (line/headphone)
8 DC-coupled analog in
Bela Gem Multi More input and output channels, no headphone amp on 6 channels
CTAG Face Based on BBB
4 audio in (line)
8 audio out (line)
Bela Gem Multi More audio channels, analog inputs, no ethernet
CTAG Beast Based on BBB
8 audio in (line)
16 audio out (line)
Bela Gem Multi More audio input channels, analog inputs, fewer audio output channels, no ethernet

Hardware

In general, form factor and pinout differ between the legacy boards and the Gem family. That’s true even when moving from Bela Mini to Bela Gem Stereo, even if they look remarkably similar: while the analog input header remains in the same place, the pinout of P1 and P2 has changed between the two, most crucially swapping the 5V and 3v3 pins, so most anything you connect to the boards will need to change place.

If you have previously designed a PCB to go on top of your legacy Bela product, you may find the KiCAD symbols and footprints for Bela Gem useful. If you haven’t designed a PCB but instead relied on jumper wires or perfboards, check out the new pinout in the Bela IDE, and if you were tempted to design a PCB for your next project, it will be much easier now that symbols and footprints are available.

Software

Most of the software written for the legacy Bela boards that was correctly using the Bela API should work mostly unchanged on the new boards. Here we highlight some of the adjustments you’ll have to make.

Analog outputs are now audio outputs

The Bela cape, throughout its revisions, provided 8 DC-coupled analog outputs whose output ranged between 0V and 5V. These were sampled at the same rate as the analog inputs (typically 22.05kHz) and could be used for a variety of applications, including driving LEDs or controlling synthesizers via control voltage.

In the Gem Multi we are using an audio DAC (ES9080Q) for channels 2 through 9 which can output a DC-coupled signal and whose output is amplified to reach ±5V. This means that it can be used both for audio purposes (when driving audio-frequency bipolar signals) and for replacing the functionality of the analog outputs of the Bela cape.

We are now retiring the old notion of “analog outputs” and treat all non-digital output channels as audio. So if your code was using the analog outputs, it should now use the audio outputs instead.

If, in C++, you were using analogWrite() or analogWriteOnce(), it won’t be, in general, as easy as replacing the function with audioOut() :

  • you should pay particular attention to the frame index (the second argument), as previously it was bound to context->analogFrames, but now it will have to be bound to context->audioFrames
  • persistence is no longer handled for you by the backend, so if you were using analogWrite() to update the output value every time an event took place and were relying on the backend to hold it for you until the next time you’d write it, that will no longer work and you’ll have to take care of managing persistence yourself.
  • you will need to upgrade the channel number by adding + 2 to it. For instance, if you were writing to analog out 0 you should now write to audio out 2.

PureData: abstractions for accessing I/Os

Accessing audio, analog, digital and scope channels in Pure Data patches using the legacy API requires some wrangling to get the channels right. We were using Pd’s own [adc~] and [dac~] wherever possible, with the following rules to determine channel numbers, which, as per Pd convention, are 1-based):

  • audio channels: every [adc~] or [dac~] starting from 1 through the number of input or output audio channels was an audio channel. If the number of inputs and outputs differ, then padding dummy channels would be append to the whichever stream (input or output) had fewer. For instance, a CTAG Face with 4 inputs and 8 outputs would have dac~ 1 through 8 for the outputs and adc~ 1 through 4 for the inputs, with four additional empty adc~ channels 5 through 8
  • analog channels: analog channels start at the first [adc~] or [dac~] following the audio channels. Because of the padding in the audio channels, both analog inputs and outputs would start at the same number. For instance, with a Bela or BelaMini cape, they would start at [adc~ 3], with a CTAG Face (4 audio in, 8 audio out) or a Bela Mini + Multichannel (8 audio in, 8 audio out), they would start at [adc~ 9]. Again, if there is a different number of analog inputs and outputs (typically 0 analog outputs on Bela Mini), the deficient stream would be padd up with dummy channels.
  • digital channels: digital channels start at the first number after the analog channels. Additionally, they need a message to [send bela_setDigital] to be set up as an input or an output, at audio rate or message rate. When used at audio rate, you’d use a [adc~] or [dac~], whereas if used at message rate, you’d use a [receive bela_digitalInXY] or [send bela_digitalOutXY].
  • scope channels: the scope has four channels, accesible via a [dac~] starting at the first number after the last digital channel.

As if this set of rules wasn’t complex enough, changing the number of analog channels or disabling analog or digital channels also causes a renumbering all following channels, making patches even more complex to maintain. Using Gem boards, this would mean that the analog and digital cchannels would have different [adc~] numbers depending on whether the code ran on a Stereo or a Multi, wihich would have made writing the examples very complicated.

To simplfiy things, Gem boards now ship with Pd abstractions that allow to access Bela’s I/O channels with unambiguous numbering that matches the markings on the board itself, doesn’t require calculations and is invariant to changing number of audio, analog or digital channels. These abstractions can be downloaded from here for developing on the host and examples of how to use them are available through the IDE on your Bela Gem.

C++: the default analog sampling rate has changed

Since the very first Bela cape was introduced, the sampling rate of the analog channels was limited to a maximum of 250 kHz across all channels. This means that when using 8 channels the maximum sampling rate of each channel is 31.25 kHz, but in order to keep it at a fixed ratio to the audio sample rate, which was fixed at 44.1 kHz, we would cap it at 22.05 kHz. That sampling rate could be increased to 44.1 kHz or 88.2 kHz by reducing the number of analog channels to 4 or 2, respectively. Each of these ratios also affects the ratio between the number of analog frames and audio frames within a given block of audio: 0.5 for 8 channels, 1 for 4 channels, 2 for 2 channels.

In C++, the BelaContext structure contained sampling rate and number of frames for each of the audio, analog and digital streams. While the digital and audio always coincided, the analog sampling rate and number of frames would be affected by the above mentioned ratios. This made for a slight awkwardness in the code, where in the audio processing loop the user had to compute the analog frame index based on the audio frame and the ratio between the two rates. The programmer could have requested uniformSampleRate (see), which resampled the analog chanels in the backend and make them available to the user callback with a uniform sampling rate, making code easier to write, but that feature was not widely advertised or used.

With Gem, which can reach audio sampling rates up to 96 kHz, things would become even more complex, as at that frequency the ratio between analog and audio frames would be 0.25 when running with 8 analog channels. Most critically, running the project at different audio sampling rates would yield different ratios, which could make code break when changing the audio sample rate if it didn’t account for this correctly. For these reasons, the uniformSampleRate is now enabled by default and is also available as a toggle in the Bela IDE (and as a command line option --uniform-sample-rate).

As long as your old project correctly dynamically accounted for the ratio between audio and analog frames, it should still work correctly. However, a lot of code would have relied on the old default ratio of 0.5, which won’t work with the new defaults. If your code contains lines like analogRead(context, n / 2, c) (i.e.: it assumes a 1 / 2 ratio), it probably needs fixing. If your legacy code’s analog inputs are misbehaving on Gem, try disabling the Uniform sample rate in the project settings; if that fixes it, it will give you a hint of where to look for solutions.

C++: threads and parallelism

Bela Gem boards are based on the PocketBeagle 2, which sports a quad-core Cortex-A53 ARM-v8 64-bit processor, while the legacy boards were based on a single-core Cortex-A8 ARM-v7 32-bit processor. The audio thread is pinned to the third core, but any additional thread, for instance std::thread or the AuxiliaryTask provided by the Bela API can run on any other thread. This means inter-thread communication has become more complex and potentially unsafe. You may want to consider atomic types and lock-free queues for inter-thread communication. Where locking or condition variables are required and the audio thread is involved, you should probably be using the classes provided by the RtLock.h, RtMsgFifo.h and RtThread.h headers.

The IDE

Gem ships with an entirely new IDE, written in typecript and vue over a couple of intense years. Project settings from legacy projects should be migrated neatly to the new format, but occasional issues may arise, so double check your project settings, especially if you had gain applied to the audio I/Os or were using custom command line options or custom make parameters.

The Linux image

Gem is released with a Debian 12 Bookworm image, whereas the latest stable image for legacy Bela images was based on Debian 9 Stretch. As such, several things will have changed on the Linux side as well. We will update relevant tutorials as time allows, but in the meantime if Linux things that you were doing on a previous Bela image stopped working and there’s no updated tutorial, consider searching for that on the wider internet appending “Debian Bullseye” to the search string.