No description
  • C++ 95.2%
  • Makefile 1.9%
  • CMake 1.5%
  • C 1.4%
Find a file
Julien Mazari Garcia e962e86576 Restructure README: three-component layout + fix ASCII art rendering
- Split into CLI / CMake library / Cardputer ADV firmware sections
- Wrap ASCII art in code block (Forgejo renders bare lines as single paragraph)
- Add component overview table at the top

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:50:02 +02:00
esp32 Add ESP32 port for M5Stack Cardputer ADV + extend Linux engine 2026-04-17 18:44:12 +02:00
lib Add static library with C API for CMake integration 2026-04-17 13:00:09 +02:00
.gitignore Initial commit: bytebeat synthesizer over PipeWire 2026-04-16 22:54:42 +02:00
audio_pipewire.cpp Initial commit: bytebeat synthesizer over PipeWire 2026-04-16 22:54:42 +02:00
audio_pipewire.h Initial commit: bytebeat synthesizer over PipeWire 2026-04-16 22:54:42 +02:00
bb8 Initial commit: bytebeat synthesizer over PipeWire 2026-04-16 22:54:42 +02:00
bb8_engine.cpp Add ESP32 port for M5Stack Cardputer ADV + extend Linux engine 2026-04-17 18:44:12 +02:00
bb8_engine.h Add ESP32 port for M5Stack Cardputer ADV + extend Linux engine 2026-04-17 18:44:12 +02:00
main.cpp Initial commit: bytebeat synthesizer over PipeWire 2026-04-16 22:54:42 +02:00
Makefile Initial commit: bytebeat synthesizer over PipeWire 2026-04-16 22:54:42 +02:00
README.md Restructure README: three-component layout + fix ASCII art rendering 2026-04-17 18:50:02 +02:00

888888b.  888888b.   .d8888b.
888  "88b 888  "88b d88P  Y88b
888  .88P 888  .88P Y88b. d88P
8888888K. 8888888K.  "Y88888"
888  "Y88b888  "Y88b.d8P""Y8b.
888    888888    888888    888
888   d88P888   d88PY88b  d88P
8888888P" 8888888P"  "Y8888P"

Bytebeat synthesizer — generate audio from arithmetic expressions over a time variable t. Each sample is the low 8 bits of the expression evaluated at t = 0, 1, 2, …

This repository contains three components sharing the same engine:

Component Target Directory
CLI Linux / PipeWire ./
Static library Any CMake project lib/
Firmware M5Stack Cardputer ADV (ESP32-S3) esp32/

Supported operators: + - * / % & | ^ ~ << >> < <= > >= == != ?: ( )


Linux CLI

Command-line tool that streams audio through PipeWire.

Dependencies

  • C++17 compiler, libpipewire-0.3, pkg-config
sudo pacman -S pipewire pkg-config   # Arch Linux

Build

make
sudo make install   # optional, installs to /usr/local/bin/bb8

Usage

bb8 -expr <expression> [options]

  -expr <expr>   Bytebeat expression (variable: t)   [required]
  -rate <hz>     Sample rate in Hz                   (default: 8000)
  -time <sec>    Stop after N seconds                (default: infinite)
  -loop          Run indefinitely (default behaviour)

Press Ctrl-C to stop.

bb8 -expr "t*(t>>8|t>>9)&46&t>>8"
bb8 -expr "t*(t>>5&t>>8)" -time 30
bb8 -expr "2*(t>>5&t)-(t>>5)+t*(t>>14&14)" -rate 44100

CMake Library

lib/ exposes a minimal C API for embedding bytebeat audio in CMake projects.

API

#include <bb8.h>

void bb8_play(const char *expr, int sampleRate, float duration); // duration <= 0 → infinite
void bb8_stop(void);

Integration

add_subdirectory(/path/to/bb8/lib bb8)
target_link_libraries(your_target PRIVATE bb8)
#include <bb8.h>

bb8_play("t*(t>>8|t>>9)&46&t>>8", 8000, -1);  // start (background thread)
bb8_stop();                                      // stop + join

Cardputer ADV Firmware

esp32/ is a full port for the M5Stack Cardputer ADV (ESP32-S3 + ES8311 codec).

Features

  • Real-time audio via ES8311 / I2S DMA
  • Live expression editing on the Cardputer keyboard
  • Waveform display (~10 Hz refresh)
  • Instant hot-swap on Enter (lock-free, audio never glitches)
  • BtnA toggles playback

Build & flash

Requires PlatformIO.

cd esp32
pio run              # compile
pio run -t upload    # flash
pio device monitor   # serial output

How it works

The engine is re-implemented with ESP32 constraints: int32_t arithmetic (native 32-bit), fixed-size bytecode array (no heap allocation), IRAM_ATTR evaluate() to avoid flash cache misses.

Two FreeRTOS tasks run in parallel:

  • Core 0 — audio task (max priority): fills 256-sample chunks via evaluate(), feeds Speaker.playRaw()
  • Core 1 — UI task: keyboard input, display, expression compilation

Engine hot-swap uses std::atomic acquire/release so the audio path never takes a lock.


License

MIT