Firmware (pico-cp/code.py): on every click, send a USB-MIDI note-on per firing lane —
GM drum note by voice (SOUND_GM), velocity by level (accent/normal/ghost) — via the
default-enabled usb_midi.ports[1]. Polyphonic, so the computer plays the full groove.
New CONFIG: MIDI_ENABLED (default on), MUTE_BUZZER (silence the buzzer when using
computer audio).
Editor (editor.html): a '🎹 Device audio' toggle uses the Web MIDI API
(requestMIDIAccess) to voice incoming notes through the existing synth — Note-On ->
GM_NUM[note] / velocity-to-gain -> playInstrument(). The device is the clock; the
browser is the sound module, locked in sync. Chrome/Edge.
Verified: firmware emits the right notes (kick+hat on beat 1 of four-on-the-floor,
snare's rest skipped); editor loads clean with the toggle + handlers present. Docs
(info-kit, both READMEs) updated. The on-device buzzer/screen still work standalone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
4.5 KiB
Markdown
74 lines
4.5 KiB
Markdown
# PM_K‑1 "Kit" — CircuitPython edition (USB drive + editor)
|
||
|
||
The **CircuitPython** firmware for the 52Pi EP‑0172 Pico kit. Unlike the MicroPython version
|
||
(`../pico/main.py`), this makes the Pico mount as a **USB drive (`CIRCUITPY`)** that carries the
|
||
firmware and your tracks — so you can edit on the web and reprogram it without Thonny. It runs the
|
||
same program‑string language as <https://metronome.varasys.io>.
|
||
|
||
> **Status: experimental, phase 1.** This drives the screen/touch/joystick/buzzer and reads your
|
||
> grooves from `programs.json`. The editor's one‑click "Save to device" and USB‑MIDI audio‑to‑computer
|
||
> are landing in later phases. The simpler **MicroPython** firmware (`../pico/main.py`) remains the
|
||
> rock‑solid fallback — and the Pico can't be bricked (BOOTSEL → drag a MicroPython `.uf2` back).
|
||
|
||
## Install
|
||
|
||
1. **Flash CircuitPython:** hold **BOOTSEL**, plug in, and drop the CircuitPython `.uf2` for your board
|
||
onto the `RPI‑RP2` drive (<https://circuitpython.org/board/raspberry_pi_pico/> — or the Pico 2 / W
|
||
build). It reboots and a **`CIRCUITPY`** drive appears.
|
||
2. **Copy everything from the bundle** onto `CIRCUITPY` (drag‑and‑drop — it's a normal drive now):
|
||
- `code.py` (this firmware — runs on boot)
|
||
- `programs.json` (your grooves)
|
||
- `font_s.bin`, `font_m.bin`, `font_l.bin` (the anti‑aliased fonts — kept as files to save RAM)
|
||
- `editor.html` (an offline copy of the web editor, so the drive carries its own programmer)
|
||
3. It starts immediately. Editing `programs.json` (or re‑saving it from the editor) makes CircuitPython
|
||
**auto‑reload** with the new tracks.
|
||
|
||
## Play through the computer's speakers (USB-MIDI)
|
||
|
||
The board also shows up as a **USB-MIDI** device and sends a note on every click (a GM drum note per
|
||
lane, velocity by accent). Open the [editor](https://metronome.varasys.io/editor.html) in **Chrome/Edge**,
|
||
click **🎹 Device audio**, grant MIDI access, then press play *on the device* — the editor voices the
|
||
groove through its full synth, out your computer's speakers, locked to the device's clock. Set
|
||
`MUTE_BUZZER = True` in `code.py` if you'd rather silence the on-board buzzer while doing this.
|
||
|
||
## Controls (same as the MicroPython build)
|
||
|
||
- **Touch:** on‑screen `◀◀ / ▶ / ▶▶` (prev · play/stop · next) and `− / TAP / +`.
|
||
- **Joystick:** up/down = tempo, left/right = previous/next groove.
|
||
- **Button A (GP15)** play/stop · **Button B (GP14)** tap tempo.
|
||
- **RGB LED** flashes each beat; **buzzer** clicks (accent/normal/ghost).
|
||
|
||
## programs.json
|
||
|
||
```json
|
||
{ "title": "PolyMeter",
|
||
"programs": [ { "name": "Four on the floor", "prog": "t120;kick:4;snare:4=.x.x;hatClosed:4/2" } ] }
|
||
```
|
||
|
||
Each `prog` is a program string from the web editor. Add/replace entries and save — the device reloads.
|
||
|
||
**Easiest way to (re)program it:** in the editor (the web app, or the `editor.html` on the drive), build a
|
||
set list, then the set‑list **⋯** menu → **📟 Save to device** → pick the `CIRCUITPY` drive. In Chrome/Edge it
|
||
writes `programs.json` straight onto the drive (the Pico auto‑reloads); elsewhere it downloads the file to drag
|
||
on. **📥 Load from device** reads a `programs.json` back into a new set list.
|
||
|
||
## Calibration (flip flags at the top of `code.py`)
|
||
|
||
- **Red/blue swapped:** flip `MADCTL` between `0x48` (default) and `0x40`.
|
||
- **Colours look negative:** toggle `INVERT_COLORS`.
|
||
- **Taps land wrong:** set `TOUCH_DEBUG = True`, watch the serial output, then set
|
||
`TOUCH_SWAP_XY` / `TOUCH_INVERT_X` / `TOUCH_INVERT_Y`.
|
||
- **Joystick reversed:** toggle `JOY_INVERT_X` / `JOY_INVERT_Y`.
|
||
- **Computer audio:** `MIDI_ENABLED` (default on) sends the MIDI notes; `MUTE_BUZZER` silences the buzzer.
|
||
- **LED too bright / too dim:** change `LED_BRIGHTNESS` (0..1, default 0.15).
|
||
- **Screen tearing:** the SPI panel has no tearing-effect sync; `SPI_BAUD` (default 62.5 MHz) is pushed fast
|
||
to minimise it — lower it only if the display is unstable.
|
||
- **Screen blank / garbled:** the panel lot may differ; drop `SPI_BAUD`, and if it's a 240×320 ILI9341
|
||
instead of the 320×480 ST7796, the init/size need changing (this targets the 320×480 you have).
|
||
- **RGB LED** is driven by the core `neopixel_write` module — no library to install. If it stays dark,
|
||
your CircuitPython build is unusually missing that module (everything else still works).
|
||
|
||
If `code.py` ever errors, CircuitPython prints the traceback **on the screen and over USB serial** —
|
||
copy that to me and I'll fix it.
|
||
|
||
The fonts are the same baked anti‑aliased blobs as the MicroPython build (see `../pico/gen_font.py`).
|