Skip to content

Repository files navigation

Pi-Pico-Random-Looping-Sequencer-Firmware

C++ firmware for a new 4-voice polyphonic generative sequencer Eurorack module, built on a Raspberry Pi Pico 2 (RP2350). Despite the repo name, this is not a port of the MicroPython firmware in Pi-Pico-Random-Looping-Sequencer's Software/ — it's a from-scratch engine for a new module that happens to share the spirit (random looping per-step CV/trig). The original MicroPython module remains its own thing.

The code runs on two hosts that share the same C++17 engine and App layer:

  • playground — a macOS sim (GLFW + Dear ImGui + PortAudio audition synth). Develop without hardware.
  • firmware/ — a Pico-SDK host that boots on a real Pico 2 driving an SSD1306 OLED + 8 buttons over USB-C power.

Engine features

4-voice polyphony with independent per-voice state. Each voice has:

  • Per-step CV + trigger sequences (16 steps, but step count is variable)
  • Scale-quantised pitch from one of 46 scale presets, configurable octave range and starting note
  • Per-step CV / trigger mutability locks (freeze individual steps)
  • Glide / portamento, euclidean rhythm, step direction (Fwd/Rev/Pend/Rand), swing/shuffle, neighbour-weighted CV picking, pattern rotate, and one-shot Randomize

Engine-wide: internal clock with tap tempo, or external clock-in (jack not wired yet — see "Hardware status" below).

Sim build (macOS)

One-time:

brew install glfw portaudio pkg-config

Then from the repo root:

make            # first run clones Dear ImGui v1.91.0 into ./imgui/
./playground
# or
make run

The sim mirrors the pattern from the vault note Quick Tips/Simulating module UI on macOS and the reference implementation in DIYSynthMNL/vcdo-daisy. A std::chrono tick thread (ClockThreadMain) replaces the external Eurorack clock when the engine is in INT-clock mode; PortAudio drives the 4-voice audition synth so you can hear what the module would output.

Sim windows

Window Contents
Simulated OLED (128×64) Header bar, body, status footer. PlaybackViews + menus render here exactly as on the firmware OLED.
Encoder / buttons On-screen mirrors of the 8 hardware buttons + encoder.
Audition Per-voice mute toggles (V1–V4) and master gain for the summed PortAudio output.
Engine inspector Live state dump (per-voice CV/trig, clock period, locks) for debugging.

Keymap (sim)

Key Action
/ Encoder rotate (−1 / +1)
Space Encoder press (Click)
Backspace Encoder long-press (Back / cancel)
19 Jump to numbered submenu (root list only)
P Play / stop
T Tap tempo
Tab Cycle active voice (V1 → V2 → V3 → V4)
V Cycle PlaybackView layout
M Open main menu
H Go home (back to PlaybackView)
X Randomize active voice
S Toggle clock source Ext ↔ Int
G Manual external-clock pulse
D Manual digital-in pulse
R Reset engine to defaults
A Toggle audition audio on/off
Esc / Q Quit

Hardware

The firmware targets a Raspberry Pi Pico 2 (RP2350) driving:

  • an SSD1306 OLED (128×64, I²C, address 0x3C) — the menu/UI display
  • 8 momentary switches — menu navigation + transport + per-voice actions

Pinout

Signal Pico 2 pin GPIO Notes
OLED VCC 36 3V3 OUT (most SSD1306 modules also accept 5 V on VSYS)
OLED GND 38 any GND pin
OLED SDA 6 GP4 I²C0 SDA
OLED SCL 7 GP5 I²C0 SCL
Up button 9 GP6 rotate −1 (each button: one leg to GPIO, other leg to GND)
Down button 10 GP7 rotate +1
Click button 11 GP8 encoder press
Back button 12 GP9 long-press / cancel
Play button 14 GP10 transport toggle
Tap button 15 GP11 tap tempo
Voice button 16 GP12 cycle active voice (V1 → V2 → V3 → V4)
Random button 17 GP13 scramble the active voice's pattern (CV + triggers; respects step locks)
USB-C Power + USB-CDC serial for boot/debug prints
LED onboard GP25 heartbeat

No external resistors needed for the buttons — the Pico's internal pull-ups (~50 kΩ) are enabled in software. For the OLED, the Pico's internal pull-ups on SDA/SCL are usually fine at 400 kHz over short jumper wires; if you see bus errors over longer runs, add external 4.7 kΩ pull-ups from SDA/SCL to 3V3.

External Eurorack jacks (clock in, digital in, CV out, gate out) are not wired yet — see Hardware status below for the entry points each will hook into.

Dev environment setup (macOS)

One-time setup for building + flashing the Pico 2 firmware.

# 1. VS Code (skip if already installed)
brew install --cask visual-studio-code

# 2. Optional but handy: install the `code` CLI shim so `code .` works
#    from the terminal. From inside VS Code:
#      Cmd+Shift+P  ->  "Shell Command: Install 'code' command in PATH"

# 3. Install the official Raspberry Pi Pico extension
code --install-extension raspberry-pi.raspberry-pi-pico

# 4. Optional: a CLI serial reader for the USB-CDC logs
brew install picocom         # nicer than the built-in `screen`

The Pico extension bundles the Pico SDK, the ARM toolchain (arm-none-eabi-gcc), OpenOCD, CMake, Ninja, and picotool — so you don't need to brew-install any of those separately. On first project import it downloads everything into ~/.pico-sdk/ (takes a few minutes — watch the progress in VS Code's bottom-right corner).

If you'd rather build from the command line without VS Code, see the header comment in firmware/CMakeLists.txt for the bare brew install

  • cmake / make recipe.

Firmware build (Pico 2)

Open the repo and let the Pico extension take it from there:

code .

Then in VS Code:

  1. Cmd+Shift+P"Raspberry Pi Pico: Import Project" → pick the firmware/ subfolder; board type pico2; SDK 2.x.
  2. Click Compile Project in the Pico sidebar (raspberry icon on the left).
  3. Hold the BOOTSEL button on the Pico while plugging in USB → the board mounts as a USB drive called RPI-RP2 → drag firmware/build/seq_firmware.uf2 onto it. The Pico reboots automatically and starts running the firmware.

USB-CDC serial prints boot status + button events to the host:

screen /dev/cu.usbmodem* 115200            # macOS built-in (Ctrl-A K to quit)
# or
brew install picocom
picocom -b 115200 --imap lfcrlf /dev/cu.usbmodem*

Direct (no VS Code): see header comment in firmware/CMakeLists.txt for the cmake / make commands.

Files

Engine + shared App layer (portable C++17, linked by both hosts):

File Purpose
Voice.{h,cpp} One voice's full state — CV/trig sequences, scale, locks, glide, euclidean, swing, RNG, etc. Voice::Randomize, RotatePattern, Tick.
Sequencer.{h,cpp} Multi-voice orchestrator. Owns kVoiceCount = 4 voices, internal clock generator with tap tempo, external-edge dispatch, transport.
Menu.{h,cpp} OLED menu framework — items, sections, edit views, render. Host-agnostic.
App.{h,cpp} Shared App layer between sim + firmware. Owns the engine instance, all menu items, the BuildMenu + OnMenuCommit wiring, PlaybackView (7 layouts), AppMutex / AppLock (std::mutex on sim, pico/mutex.h on firmware).
Scales.h 46 scale intervals + BuildScale() helper.
FakeOled.h 128×64 monochrome framebuffer with line/rect/text primitives + 6×8 inline bitmap font. Used directly by the sim; the firmware Ssd1306 driver consumes the same buffer.

Sim host:

File Purpose
playground.cpp GLFW + Dear ImGui window, clock thread, key handling, OLED window, audition audio via PortAudio. Provides App with NowMs() + file-backed SaveStateLocked / LoadStateLocked.
Makefile macOS-only build recipe (clones ImGui on first run).

Firmware host (firmware/):

File Purpose
main.cpp Pico-SDK init, I²C0 + button GPIO setup, run loop (poll buttons → dispatch Do* helpers → Sequencer::Tick → render g_views into the SSD1306 framebuffer).
Ssd1306.{h,cpp} Minimal I²C driver for SSD1306; pushes a 128×64 framebuffer per frame.
Buttons.{h,cpp} Software-debounced 8-button polling.
CMakeLists.txt Pico-SDK build; links App + engine sources from the repo root.
pico_sdk_import.cmake Canonical SDK import shim.

Hardware status

What the firmware drives today and what's still pending wiring:

Feature Status
SSD1306 OLED over I²C0 Working
8 buttons (Up/Down/Click/Back/Play/Tap/Voice/Random) Working
Engine + all UI from the sim Working
Onboard LED heartbeat Working
USB-CDC boot/debug logs Working
CV outputs (4× to a DAC over SPI; DAC8568 candidate) Not wired. Engine exposes voice(i).last_dac().
Gate / trigger outputs (4× GPIO) Not wired. Engine exposes voice(i).trig_active().
External clock-in jack Not wired. Sequencer::OnClockEdge is the entry point.
Digital-in / reset jack Not wired. Sequencer::OnDigitalEdge is the entry point.
Flash-backed persistence SaveStateLocked / LoadStateLocked are no-ops on firmware. Sim uses a text file (playground.state); the firmware version will use the Pico's onboard flash sector.

Tested on

  • Sim: macOS 25.3 (Darwin), Apple clang 17, glfw 3.4, portaudio 19.7, Dear ImGui v1.91.0.
  • Firmware: Raspberry Pi Pico 2 (RP2350), Pico SDK 2.2.0, ARM toolchain 14_2_Rel1, picotool 2.2.0-a4.

Contributing

Bug reports, build problems, and PRs are welcome.

Filing an issue — please include:

  • Which host hit the problem (sim or firmware-on-Pico-2).
  • For firmware: the relevant USB-CDC log output (screen /dev/cu.usbmodem* 115200) — boot lines have [BOOT] tags and button presses log [BTN] …, both of which usually pinpoint where things went sideways.
  • For sim: macOS version + how you built (plain make, or something custom).
  • Steps to reproduce. "Press X, see Y, expected Z" beats "doesn't work".

Scope — this repo is firmware (engine + sim + Pico-SDK host) for a new polyphonic module. The hardware schematic / PCB for the original MicroPython single-voice module lives in Pi-Pico-Random-Looping-Sequencer; file hardware issues there. PCB/panel for this new poly module is still TBD.

Pull requests — match surrounding style (2-space indent, clang-format not enforced but consistent with the existing tree). Keep changes focused; one logical change per PR. The engine is host-agnostic (Voice/Sequencer/Menu/App) — please don't pull pico/stdlib.h, GLFW, or PortAudio into those translation units; that boundary is what lets the sim and firmware share code.

License — undecided. Until a LICENSE file lands in the repo, the code is all-rights-reserved by default. If you'd like to fork, build, or redistribute in the meantime, open an issue and we can figure it out.

About

C++ firmware for a 4-voice polyphonic generative sequencer Eurorack module — runs on Raspberry Pi Pico 2, with a macOS sim sharing the same engine

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages