ZicBox is a versatile C++ framework designed to simplify the development of music applications, with a primary focus on creating grooveboxes and drum machines for custom hardware running on Raspberry Pi. However, it is not limited to embedded devices, it also runs on Linux desktops, making it a basic foundation for building full-fledged music production software.
If you have any questions, feel free to ask on Discord:
ZicBox is built around a highly modular system that ensures flexibility and extensibility:
- UI Components as Modules β Every UI element is encapsulated as a module, allowing for easy customization and expansion.
- Audio Processing as Modules β Synth engines (such as drum synthesizers, sample players, ...) and effect processors (like filters, distortion, etc.) are also modular, enabling seamless integration of new sound-processing capabilities.
- Hardware Interfaces as Modules β The system abstracts hardware interactions into modules, making it simple to add support for new devices without modifying the core application.
This modular design allows developers to extend ZicBox effortlessly by adding new modules without altering the frameworkβs core logic.
ZicBox efficiently manages system resources to ensure low-latency audio performance. It achieves this by:
- Running the UI in a dedicated thread to ensure smooth rendering and interaction.
- Routing all control data between the UI and the audio engine efficiently.
- Running each audio track in a separate thread, ensuring optimal real-time processing.
- Handling audio thread synchronization to maintain precise timing and tempo accuracy.
For configuring the framework, ZicBox use JSON. However, instead of writing pure JSON, developers can use TypeScript to generate the configuration file. This allows for a strongly typed configuration system while still benefiting from JSON lightweight runtime.
Additionally, ZicBox leverages JSX (React-style syntax) for UI configuration, making it intuitive to define interface components. Unlike traditional React, there is no component state management involved, JSX is used purely for declarative UI structure.
- π₯οΈ Designed for Custom Hardware β Optimized for Raspberry Pi but also runs on Linux desktop.
- 𧩠Extensible & Modular β Easily add new UI components, synth engines, effects, and hardware integrations.
- β‘ High-Performance Audio β Multi-threaded design ensures real-time audio processing with precise synchronization.
- π‘ Type-Safe Configuration β Use TypeScript instead of Lua for a structured, maintainable setup.
- π¨ JSX-Based UI β Define interfaces declaratively with React-style syntax.
ZicBox is an ideal solution for developers looking to build custom music applications, whether for standalone hardware or full desktop music production environments.
Clone the repo and start building with ZicBox! π΅
git clone --recurse-submodules https://github.com/apiel/zicBox.git
cd zicBox
Note: If the repository has already been cloned but submodules are missing, run the following command to pull them:
git submodule update --initFor SSH submodules, use:
git submodule update --init .gitmodules_ssh
Update package lists and install required dependencies:
apt-get update
apt-get install build-essential librtmidi-dev libsndfile1-dev pulseaudio alsa-utils -y
If you are setting up on a desktop, install SDL2 development libraries:
sudo apt-get install libsdl2-dev
For Raspberry Pi, a setup script is available. Run the following commands:
cd hardware/rpi
sudo ./setup.sh
Once everything is set up, you can run the demo project using:
make pixel
Now you should get something like:
Yes, I know, it sounds boring! But before we complicate things, let's take a moment to understand how everything works. First, let's take a look at the code:
import * as React from '@/libs/react';
import { writeFileSync } from 'fs';
import 'tsconfig-paths/register'; // To solve imported alias
import { audioPlugin } from '@/libs/audio';
import { Keyboard } from '@/libs/nativeComponents/Keyboard';
import { KnobValue } from '@/libs/nativeComponents/KnobValue';
import { List } from '@/libs/nativeComponents/List';
import { Rect } from '@/libs/nativeComponents/Rect';
import { Text } from '@/libs/nativeComponents/Text';
import { Value } from '@/libs/nativeComponents/Value';
import { View } from '@/libs/nativeComponents/View';
const ScreenWidth = 240;
const ScreenHeight = 320;
const demoView = (
<View name="Demo">
<Text fontSize={16} text="title" bounds={[0, 0, ScreenWidth, 16]} centered />
<Rect color="tertiary" filled={false} bounds={[10, 30, 100, 50]} />
<Rect color="primary" bounds={[120, 30, 110, 20]} />
<Value
audioPlugin="Tempo"
param="BPM"
bounds={[120, 60, 110, 20]}
encoderId={0}
barColor="quaternary"
/>
<KnobValue
audioPlugin="Tempo"
param="BPM"
bounds={[10, 90, 70, 70]}
encoderId={1}
color="secondary"
/>
<List items={['item1', 'item2', 'item3']} bounds={[120, 100, 110, 60]} />
<Keyboard bounds={[0, 175, ScreenWidth, 120]} />
</View>
);
const output = JSON.stringify(
{
audio: { tracks: [{ id: 0, plugins: [audioPlugin('Tempo')] }] },
pixelController: 'rpi3A_4enc_11btn',
screen: { screenSize: { width: ScreenWidth, height: ScreenHeight } },
views: [demoView],
},
null,
2
);
writeFileSync('config.json', output);
console.log('done');
If you prefer not to use TypeScript for the configuration file, you directly edit the JSON file or use any scripting language, Lua, Python, or even define everything directly in C++. However, I personally find TypeScript/JSX to be the most convenient option due to its strong typing, ease of use, and developer-friendly tooling (and maybe also because I am orginally web developer ^^).
Now, you might be wondering about performance, donβt worry! The configuration process is purely declarative, meaning TypeScript is only used to define settings and structure. Once the JSON configurations are initialized, the actual execution happens entirely in C++, ensuring optimal performance.
In short, you get the best of both worlds, TypeScript for a clean and manageable configuration setup, and C++ for high-performance execution.
More documentation here.
π§ Built for musicians & developers
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |