Firmware

libpo32

Loud82/100

C99 library for PO-32 acoustic transfers and drum synthesis.

libpo32 is custom firmware for the Teenage Engineering PO-32 tonic, by @ericlewis. Open source under MIT, latest release 1.0.0 (November 2026), 212 stars on GitHub.

forTeenage Engineering PO-32 tonic·by@ericlewis

Unclaimed. Is this yours? Sign in with GitHub as @ericlewis to claim it.

Downloads
0
Stars
212
Forks
13
Commits
97
Last commit
Get the source

No release files yet. Build from source.

MIT· ericlewis/libpo·downloads come from the creator’s GitHub releases

62
Commits
4
Releases
62 commits and 4 releases in the last year
Activity · last 12 months

libpo

Tests FOSSA Status

Decode, edit and encode Teenage Engineering Pocket Operator backups, convert samples, and synthesize drum and speech audio. libpo provides a freestanding C99 core, command-line WAV tools, and one Go module covering all supported families.

Supported families

DevicesBackup transportData and audio APIs
PO-32 tonicMono DPSK encode/decodeDrum patches, patterns, state and drum synthesis
PO-33 K.O! / PO-133 Street FighterStereo DQPSK encode/decodeSample conversion, patterns, settings and sample-pool editing
PO-35 speak / PO-137 Rick and MortyStereo DQPSK encode/decodeSpeech analysis and synthesis, drum patches, patterns and settings

The C core uses caller-owned memory, with no heap allocation or calls to libc, libm, filesystem or device APIs. Hosted tools handle WAV files and allocation; applications handle playback and device I/O. See the freestanding contract for compiler and target requirements.

PO-35/137 speech analysis and synthesis are approximate models. Some pattern and metadata fields remain uninterpreted and are preserved as raw bytes. Software loopbacks verify transfer-byte preservation; generated stereo-family backups and speech output have not been validated on physical devices.

Build and try

Requires CMake 3.16 or newer and a C99 compiler. Go is optional.

git clone https://github.com/ericlewis/libpo.git
cd libpo
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
(cd build && ctest --output-on-failure)
(cd build && ./core/po32_demo)

The demo builds a PO-32 transfer, renders and decodes it, verifies the roundtrip, and synthesizes a drum hit. It writes build/demo_modem.wav and build/demo_kick.wav.

Work with backups

The stereo tools read PCM16, PCM24, PCM32 or float32 WAV captures at 32–192 kHz. Keep both channels: mixing a backup to mono loses data. Output directories and WAV files must not already exist. The PO-33/35 edit selectors below are zero-based.

PO-33 / PO-133 samples

Extract a backup, rebuild it, and check that the decoded frame is unchanged:

./build/core/po33_decode_capture backup.wav decoded-po33
./build/core/po33_encode_capture decoded-po33/frame.bin rebuilt-po33.wav
./build/core/po33_decode_capture rebuilt-po33.wav checked-po33
cmp decoded-po33/frame.bin checked-po33/frame.bin

Exports include the frame, packet list, settings, patterns, sound headers and sample WAVs. The sample WAVs contain entire stored pools; trim and slice references are preserved in the raw records, not applied to the exported audio.

To replace an existing sample pool with a mono WAV:

./build/core/po33_encode_capture decoded-po33/frame.bin edited-po33.wav \
  --sample 0 replacement.wav

Replacement audio can use 8–192 kHz sample rates and different lengths. Shorter audio is padded; longer audio grows the allocation. Existing trim coordinates, slice references, patterns and other metadata are preserved, so appended audio may lie outside the retained playback range. The tool cannot create a missing pool or infer new trim settings. Larger allocations remain unverified on hardware.

Raw pattern edits are also supported:

./build/core/po33_encode_capture decoded-po33/frame.bin edited-pattern.wav \
  --pattern 0 edited-pattern-00.bin

These are structural record edits, not a complete musical-note editor. See PO-33/133 editing for byte edits, shared pools and conversion details.

PO-35 / PO-137 speech

Extract speech records and playable previews, then replace an existing slot:

./build/core/po35_decode_capture backup.wav decoded-po35
./build/core/po35_encode_capture decoded-po35/frame.bin edited-po35.wav \
  --speech 0 spoken-intro.wav --fps 80
./build/core/po35_decode_capture edited-po35.wav checked-po35

Slots 0..14 must already exist in the template. Replacement speech can use 8–192 kHz WAV input. The default 80 fps permits up to eight seconds per replacement; the tool also supports 20, 40 and 60 fps. Unselected speech, drum patches, patterns, settings and opaque sample metadata are retained.

Previews are approximate and normalized per slot. They do not reproduce every device voice or effect. See speech replacement for duration limits, normalization and model details.

For either family's replacement audio, stereo WAVs require --channel left, --channel right or --channel mix. Without edit options, the encoders rebuild the original frame unchanged. --rate 44100|48000|96000 selects the transfer WAV rate, defaulting to 48000; it does not select the sample or speech rate.

PO-32 patches and patterns

./build/core/po32_example
./build/core/po32_pattern_editor
./build/core/po32_decode_capture backup.wav decoded-po32

The example demonstrates a complete codec/modem loopback. The interactive pattern editor supports four trigger lanes, accents and transfer-WAV export. PO-32 transfers carry patch, pattern and state data for the device's own synth; po32_synth renders drum audio locally. See the example guide.

Use the C library

Install the built archive, public headers, CMake packages and pkg-config files:

cmake --install build --prefix "$PWD/install"

In a consuming CMake project:

find_package(LibPO CONFIG REQUIRED)
target_link_libraries(app PRIVATE LibPO::po)

Pass the installation prefix in CMAKE_PREFIX_PATH when configuring that project. For pkg-config consumers, put the installed pkg-config directory on PKG_CONFIG_PATH if it is outside the system search path:

cc app.c $(pkg-config --cflags --libs po) -o app

Include <po.h> for all families or select individual headers:

HeadersAPIs
po32.h, po32_synth.hDrum patches, patterns, framing, mono modem and drum synthesis
po33.hPO-33/133 framing, records and PCM sample conversion
po35.h, po35_analysis.h, po35_synth.hPO-35/137 framing, records, PCM analysis and speech synthesis
po_stereo.hShared stereo transmission and offline reception
po_common.hShared status and packet types

The build target and archive retain the names po32 and libpo32.a for compatibility. LibPO32::po32, pkg-config po32 and existing public PO-32 C names remain available. New consumers can use LibPO::po and pkg-config po.

Use from Go

One module provides all families. It requires Go 1.26.1 or newer, cgo and a C99 compiler, and bundles the C sources so consumers do not need a separate CMake installation. The module retains its historical libpo32 import path despite the repository rename.

To use the current development branch from your Go project:

go get github.com/ericlewis/libpo32/bindings/go@main
PackageAPIs
github.com/ericlewis/libpo32/bindings/goShared packets and status errors; package name libpo
github.com/ericlewis/libpo32/bindings/go/po32Drum patches, patterns, synthesis and mono modem
github.com/ericlewis/libpo32/bindings/go/po33PO-33/133 samples, patterns and framing
github.com/ericlewis/libpo32/bindings/go/po35PO-35/137 speech, patterns and framing
github.com/ericlewis/libpo32/bindings/go/stereoShared stereo modem

The former root PO-32 API moved to /po32. Call Close on objects that own native resources. See the Go binding guide for examples, ownership, migration and nested-module release tags.

Documentation

GuideContents
C APIFunctions, memory ownership and error contracts
ArchitectureFreestanding core, hosted adapters and shared code
Backup formatsFamily layouts, raw fields and evidence limits
PO-32 protocolPO-32 packet and modem format
Drum synthesisPO-32 synthesis behavior
Patch parametersThe 21 drum-patch parameters
ExamplesCLI options, replacement audio and offline capture checks
Go bindingModel packages and integration
FuzzingFuzz harnesses and differential checks

Canonical C sources and headers live in core/src and core/include. Hosted tools are in core/examples, native tests in core/tests, and the Go module in bindings/go. The Go C bundle is generated from the canonical core.

Projects using libpo

ProjectWhat it does
Libpo32 for SchwungA 16-voice drum synthesizer for Schwung on Ableton Move, built on the PO-32 engine

Contributing

See CONTRIBUTING.md for verification commands, clang-format 18, optional Git hooks and the Conventional Commits policy. Changes to canonical C sources must also update the generated Go bundle.

License

Copyright (c) 2026 Eric Lewis. Licensed under the MIT License. See LICENSE.