o1nk as a CLAP for sndstation handhelds; one UDG-defined UI for CLAP and AUv3 #4

Merged
peterswimm merged 6 commits from feat/clap-handheld into main 2026-10-14 01:18:34 +00:00
Owner

o1nk as a CLAP instrument for the sndstation Linux handhelds, alongside the AUv3, with one parameter UI defined in UDG and rendered by both.

Scope

  • clap/: o1nk as a CLAP, vendor FUX CAPACITY, id com.toilville.o1nk.
    • core/ is a C++ port of O1NKDSPKernel.swift that renders the same samples. tests/parity.sh checks Swift against C++, and the largest difference is at most 6e-8.
    • plugin/o1nk_clap.cpp provides params (the AU's 26 parameters plus wavetable.bank), saved state, notes as CLAP or MIDI, and 8 remote-controls pages.
    • Builds for macOS, and for Linux arm64 via clap/linux/build.sh, which uses Docker with Debian trixie.
  • Handheld screen. On hosts with Paul Walker's draft game-controller extensions, o1nk draws its own screen and takes the d-pad.
    • It shows the UDG pages in LittleGPTracker's stock look and palette.
    • The font comes from the BSD-3 original, so o1nk's licence is unaffected.
    • Hosts without those extensions are unaffected.
  • AUv3 view. The SwiftUI view renders the same 8 UDG pages. Its wavetable banks now use the CLAP's order.
  • scripts/udg_parity.py checks o1nk's UDG definition (toilville-design udg/products/fux-capacity/o1nk.forgeblock.json, merged in Toilville/toilville-design#210) against these, and against each other:
    • the OPSL device and movemap
    • the CLAP's page table
    • the AU's page table
    • the two bank lists

Testing

  • Swift/C++ parity: all 6 scenarios pass at a tolerance of 1e-5. The largest difference is 6e-8, and a zero-tolerance run fails as expected.
  • clapcheck (sndstation) at its conformant level, on Linux arm64: score 100, 27 params, 8 pages. All 7 applicable checks pass, including param fuzzing and chunked state.
  • Smoke host: a note renders audio. The bank lookup works, and a missing bank folder gives a warning.
  • Paul's disposable_emulator --selftest:
    • o1nk loads as a game-controller-aware plugin.
    • A d-pad press steps Sample from 0 to 1 on screen.
    • Suspend and resume work.
    • MENU quits to the launcher.
  • udg_parity.py --udg <toilville-design>/udg: passes. Injected faults fail it: a dropped parameter, a wrong control kind, an unknown parameter, page order, a CLAP or AU page mismatch, and the old bank order. A missing UDG file exits with code 2.
  • AUv3: xcodebuild succeeds for the iOS Simulator. The view has not yet been looked at inside a host app.

Impact Statement

  • Existing features:
    • The AU view's tabs are now the 8 UDG pages: Crusher is split from Volume, and controls appear in UDG order.
    • The bank picker moved from a header button that cycled banks to a chip row on the Sample page.
    • The AU's DSP and parameters are unchanged.
  • Public APIs / contracts: a new CLAP plugin id, com.toilville.o1nk. Its parameter ids are the AU addresses, plus 100 for wavetable.bank.
  • Schemas: a new CLAP state format: "O1NK", version 1, then (id, value) pairs.
  • Data / artifacts:
    • The CLAP ships the wavetable WAVs: inside the macOS bundle, and in o1nk-banks/ beside the plugin on Linux.
    • Vendored: Paul Walker's draft extension header (MIT) and LittleGPTracker's 8x8 font (BSD-3).
  • Integrations: sndstation and Gyre, as a CLAP on ~/.clap. The UDG definition lives in toilville-design.
  • Mappings: no change to OPSL.
  • Backward compatibility: AU presets are unaffected. The AU never saved the bank as a parameter, so reordering its bank list changes no saved data.

Docs

clap/README.md covers building, banks, parity, the UDG definition, the handheld screen controls, and the differences from the AU.

o1nk as a CLAP instrument for the sndstation Linux handhelds, alongside the AUv3, with one parameter UI defined in UDG and rendered by both. ## Scope - **`clap/`: o1nk as a CLAP**, vendor FUX CAPACITY, id `com.toilville.o1nk`. - `core/` is a C++ port of `O1NKDSPKernel.swift` that renders the same samples. `tests/parity.sh` checks Swift against C++, and the largest difference is at most 6e-8. - `plugin/o1nk_clap.cpp` provides params (the AU's 26 parameters plus `wavetable.bank`), saved state, notes as CLAP or MIDI, and 8 remote-controls pages. - Builds for macOS, and for Linux arm64 via `clap/linux/build.sh`, which uses Docker with Debian trixie. - **Handheld screen.** On hosts with Paul Walker's draft game-controller extensions, o1nk draws its own screen and takes the d-pad. - It shows the UDG pages in LittleGPTracker's stock look and palette. - The font comes from the BSD-3 original, so o1nk's licence is unaffected. - Hosts without those extensions are unaffected. - **AUv3 view.** The SwiftUI view renders the same 8 UDG pages. Its wavetable banks now use the CLAP's order. - **`scripts/udg_parity.py`** checks o1nk's UDG definition (toilville-design `udg/products/fux-capacity/o1nk.forgeblock.json`, merged in Toilville/toilville-design#210) against these, and against each other: - the OPSL device and movemap - the CLAP's page table - the AU's page table - the two bank lists ## Testing - **Swift/C++ parity:** all 6 scenarios pass at a tolerance of 1e-5. The largest difference is 6e-8, and a zero-tolerance run fails as expected. - **clapcheck** (sndstation) at its conformant level, on Linux arm64: score 100, 27 params, 8 pages. All 7 applicable checks pass, including param fuzzing and chunked state. - **Smoke host:** a note renders audio. The bank lookup works, and a missing bank folder gives a warning. - **Paul's `disposable_emulator --selftest`:** - o1nk loads as a game-controller-aware plugin. - A d-pad press steps Sample from 0 to 1 on screen. - Suspend and resume work. - MENU quits to the launcher. - **`udg_parity.py --udg <toilville-design>/udg`:** passes. Injected faults fail it: a dropped parameter, a wrong control kind, an unknown parameter, page order, a CLAP or AU page mismatch, and the old bank order. A missing UDG file exits with code 2. - **AUv3:** `xcodebuild` succeeds for the iOS Simulator. The view has not yet been looked at inside a host app. ## Impact Statement - **Existing features:** - The AU view's tabs are now the 8 UDG pages: Crusher is split from Volume, and controls appear in UDG order. - The bank picker moved from a header button that cycled banks to a chip row on the Sample page. - The AU's DSP and parameters are unchanged. - **Public APIs / contracts:** a new CLAP plugin id, `com.toilville.o1nk`. Its parameter ids are the AU addresses, plus 100 for `wavetable.bank`. - **Schemas:** a new CLAP state format: "O1NK", version 1, then (id, value) pairs. - **Data / artifacts:** - The CLAP ships the wavetable WAVs: inside the macOS bundle, and in `o1nk-banks/` beside the plugin on Linux. - Vendored: Paul Walker's draft extension header (MIT) and LittleGPTracker's 8x8 font (BSD-3). - **Integrations:** sndstation and Gyre, as a CLAP on `~/.clap`. The UDG definition lives in toilville-design. - **Mappings:** no change to OPSL. - **Backward compatibility:** AU presets are unaffected. The AU never saved the bank as a parameter, so reordering its bank list changes no saved data. ## Docs `clap/README.md` covers building, banks, parity, the UDG definition, the handheld screen controls, and the differences from the AU.
- clap/core: C++ port of O1NKDSPKernel and the O1NKParam table (same ids,
  identifiers, ranges, defaults, value strings, sections)
- clap/plugin: CLAP wrapper, vendor FUX CAPACITY, id com.toilville.o1nk;
  audio/note ports, params, state, remote-controls page per OPSL section,
  wavetable.bank param with banks loaded off the audio thread
- clap/tests/parity.sh: renders six scenarios through the Swift and C++
  kernels; max difference 6e-8
- clap/linux: Debian trixie arm64 build; --check rates it with
  sndstation-clapcheck (100, conformant)
o1nk's UI is defined once in toilville-design
(udg/products/fux-capacity/o1nk.forgeblock.json) and rendered by both the AU
view and the CLAP's handheld screen. The check confirms every OPSL parameter
sits on exactly one page, pages match the movemap layout in order, control
kinds fit parameter types, and the page strip lists every page. wavetable.bank
is the one allowed non-OPSL binding (the CLAP's kWavetableBank). A missing UI
file exits 2, not 0.
Eight pages instead of seven: the CLAP's remote-controls pages are now the
param_page list in toilville-design's o1nk.forgeblock.json (the OPSL movemap
pages, with Crusher split from Volume), in the same order with the same
controls, so a host's generic pages match the designed UI. Section names are
the OPSL sections. udg_parity.py now also checks kPages against the UDG
pages control for control.

clapcheck conformant: 100, 27 params, 8 pages.
On hosts offering Paul Walker's game-controller extensions (display + event
ports), o1nk now draws the UDG parameter pages itself and takes the d-pad:
up/down move, left/right step, A + up/down large steps, A flips on/off values,
L1/R1 change page, MENU quits to the launcher. Other hosts are unaffected.

- plugin/o1nk_ui: host-free screen, 320x240 canvas scaled up by the host, drawn
  with LittleGPTracker's stock 8x8 font and the djdiskmachine fork's default
  palette.
- Edits from the screen pass to the audio thread through a lock-free queue and
  reach the host as CLAP_EVENT_PARAM_VALUE, via process() or flush().
- core/o1nk_pages.h: the page table, shared by remote controls and the screen;
  udg_parity.py now reads it there. valueText() shared by params and screen.
- third_party/game_controller: the draft header, vendored unchanged (MIT).
- third_party/lgpt: the font, from the BSD-3 original LittleGPTracker (identical
  bit for bit to the GPLv3 fork's default), repacked one byte per row.
- tools/o1nk_screens: renders every page to PPM without a host.

Checked: Paul's disposable_emulator selftest loads it as game-controller aware,
a d-pad press steps Sample 0 -> 1 on screen, MENU quits to the launcher;
clapcheck conformant 100 on Linux arm64; udg_parity PASS.
The SwiftUI view now follows the same eight pages as the CLAP's screen and
remote controls, from UDG's o1nk.forgeblock.json: O1NKPage.all lists them,
the tab bar shows one tab per page (Crusher split from Volume), and each page
draws its controls in UDG order: named values as chip rows (param_enum,
param_toggle), numbers as knobs (param_knob), consecutive knobs sharing a grid.
The wavetable bank moves from a header button that cycled banks to a chip row
in its UDG place on the Sample page.

udg_parity.py now checks O1NKPage.all against UDG as it does the CLAP's
kPages. Builds for the iOS Simulator; not yet looked at in a host.
The AU view listed PPG last; the CLAP's kBanks has it fifth, and there the bank
is a saved parameter whose order can't change. The AU now uses the CLAP's order,
so the bank chips read the same on the AU and the handheld, and udg_parity.py
checks the two lists stay equal (it fails on the old order).
peterswimm deleted branch feat/clap-handheld 2026-10-14 01:18:34 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
peterswimm/01nk!4
No description provided.