1---2name: disting-nt-cpp-plugin-writer3description: Build and maintain Expert Sleepers disting NT C++ plugins with API v13, deliberate routing and polyphonic CV/gate design, click-safe voice transitions, tests, fact-checked player documentation, and verified GitHub releases. Use for new plugins, plugin fixes, hardware builds, nt_emu work, release preparation, or documentation audits.4---56<objective>7Develop disting NT C++ plugins that are musically reliable, preset-compatible, documented for players, and releasable as verified ARM objects.89The current verified baseline is API v13: 64 logical buses (12 input, 8 output, 44 aux). Pin the `distingNT_API` submodule and verify the target firmware/API from official Expert Sleepers sources before each release; do not assume this baseline will remain current.10</objective>1112<working_method>131. Inspect the real repository before designing: current branch/status, API submodule commit, build targets, tests, release workflow, docs, and existing parameter indices.142. Define behavior as observable contracts. For instruments, specify voice ownership, allocation/stealing, gate thresholds, pitch conversion, retrigger behavior, sustain/panic handling, and reconfiguration behavior before changing DSP.153. Keep the public control surface small. Expose dedicated inputs only when a signal is inherently audio-rate or per-voice. Prefer the disting NT mapping system for ordinary modulation rather than adding redundant CV input parameters.164. Implement with fixed memory and bounded audio-thread work. Avoid allocation, blocking I/O, logging, and unbounded scans in `step()`.175. Add native behavioral tests while implementing. Exercise state transitions and discontinuities, not only steady-state audio.186. Update player documentation in the same development slice as the behavior it describes.197. Before a release, run the fact-check, automated verification, ARM inspection, and release checklist in [production-workflow.md](production-workflow.md).208. Treat emulator/native checks, CI, and physical disting NT acceptance as separate evidence. Never report one as proof of another.21</working_method>2223<design_rules>24- Use `numFramesBy4 * 4`; convert host bus numbers to buffer indices exactly once at the boundary.25- Treat bus parameter value `0` as `None` when the parameter allows it. Never subtract one before validating the value.26- Respect Add/Replace output mode. State whether a voltage ceiling applies to this plugin's contribution or to the final shared bus.27- Clamp all externally derived indices, voltages, notes, frequencies, and counts before using them. Extremely out-of-range CV must not crash or produce invalid oscillator increments.28- Preserve parameter indices in released plugins. Append new parameters to the underlying parameter array; page arrays may present those appended parameters on the correct UI page.29- When a parameter changes the legal range of another parameter, mutate the instance-owned definition, call `NT_updateParameterDefinition()`, and synchronize the value with the callback-safe host setter. Guard recursive updates.30- Declare derived bus usage to the host when one routing parameter implies additional buses. Runtime reads and routing metadata must use the same derivation.31- Reset complete musical state on the supported panic messages, including MIDI realtime Stop (`0xFC`), System Reset (`0xFF`), and channel-mode All Sound Off/All Notes Off (CC 120/123) when the plugin consumes them.32</design_rules>3334<memory_budgeting>35When object sections, loader errors, or plug-in memory pressure matter, read [memory-budgeting.md](memory-budgeting.md).3637- Treat pool sizes and loader placement as dated firmware facts, not API guarantees; inspect the pinned firmware and the real ARM object.38- Put persistent per-instance data in memory requested by `calculateRequirements()` rather than static DTC allocations.39- Use `NT_globals.workBuffer` only for non-persistent scratch that fits `workBufferSizeBytes`; it resides in DTC.40- Do not assume cold plug-in code can run from flash or that proposed relocation changes exist until the target firmware proves they do.41</memory_budgeting>4243<polyphonic_cv_gate>44For a polyphonic gate/CV instrument, read and apply [polyphonic-cv-gate.md](polyphonic-cv-gate.md). Its core model is:4546- A gate group owns one gate bus and `Count` consecutive pitch buses immediately after it: pitch voice `i` reads `gateBus + i + 1` in host numbering.47- Validate the highest derived pitch bus against `kNT_lastBus`, the configured voice ceiling, and all other groups' reservations.48- Allocate fixed, non-overlapping voice partitions in group order. Reserve the remainder for MIDI; do not let MIDI steal a CV-owned slot or one CV group borrow another group's slot.49- Use Schmitt hysteresis, explicit sample-and-hold semantics, fresh-edge activation after count increases, and short transition fades for removal/reassignment.50- Retrigger an audible release tail in place when logical voice identity is unchanged; stealing/reassignment should fade the old sound before resetting phase/filter/envelope state.51</polyphonic_cv_gate>5253<documentation_and_fact_check>54Documentation is part of implementation, not release cleanup.5556- Keep the public guide player-focused: purpose, installation, controls, defaults, ranges, routing, ownership, S&H behavior, panic behavior, compatibility, and practical examples. Keep build/developer commands in developer docs.57- Audit every numeric or behavioral claim against code and tests. Audit firmware, API, installation, and hardware claims against current primary sources.58- Label ambiguous pitch anchors with both MIDI note number and frequency; do not rely on octave-name conventions.59- Distinguish user envelope Release from internal safety fades, a plugin's own output limiting from the final Add-mode bus, and MIDI channel messages from system/realtime messages.60- Record unresolved or time-sensitive claims instead of smoothing over uncertainty.6162Use the claim inventory and release gate in [production-workflow.md](production-workflow.md).63</documentation_and_fact_check>6465<verification>66Minimum evidence before release:67681. Native unit/behavior tests, including worst-case voice counts and state transitions.692. Strict compile warnings and available static analysis.703. ARM hardware build with `-fPIC` and no exceptions/RTTI.714. Object inspection: ELF32 little-endian ARM relocatable object, exported `pluginEntry`, section/size review, and an understood undefined-symbol set.725. Documentation fact-check against the release commit.736. nt_emu and/or physical hardware testing appropriate to the change, reported separately.747. Clean repository status and a reviewed release diff.7576Use [testing.md](testing.md) for desktop/emulator setup and [production-workflow.md](production-workflow.md) for the release gate.77</verification>7879<release_process>80- Use semantic version intent: breaking change = major, user-visible compatible feature = minor, compatible fix/reliability change = patch. A documentation-only correction normally does not need a version tag.81- Require explicit user approval at the production tag/release boundary.82- Use [templates/release.yaml](templates/release.yaml): Linux runner, pinned major action versions, recursive submodules, ARM toolchain, hardware build plus inspection, exact `programs/plug-ins/<name>.o` archive layout, downloadable workflow artifact, and tag-only GitHub Release creation.83- After pushing the tag, watch the hosted workflow to a terminal result. Then inspect the live GitHub Release, download the published archive, verify its digest and contents, and inspect the shipped `.o` rather than trusting only the workspace build.84</release_process>8586<reference_guides>87- [production-workflow.md](production-workflow.md) — design through release, including fact-check and post-publish verification88- [memory-budgeting.md](memory-budgeting.md) — dated loader placement, pool, `calculateRequirements()`, and `workBuffer` facts89- [polyphonic-cv-gate.md](polyphonic-cv-gate.md) — reusable gate/CV voice architecture and click-safe transitions90- [reference.md](reference.md) — API v13 structures and callbacks91- [examples.md](examples.md) — DSP and API patterns92- [quick-start.md](quick-start.md) — project setup and first build93- [testing.md](testing.md) — native, nt_emu, and hardware testing94- [GUID-CONVENTION.md](GUID-CONVENTION.md) — GUID allocation rules95- [templates/](templates/) — source, Makefile, and GitHub Actions templates96</reference_guides>9798<final_polish>99Before handoff or publication:1001011. Fix warnings rather than suppressing them unless the exception is documented.1022. Run `clang-tidy` with the actual compile database when available and `cppcheck --enable=warning,style,performance,portability --std=c++17 --suppress=missingIncludeSystem .` when appropriate.1033. Inspect `arm-none-eabi-size -A`, `arm-none-eabi-nm -S --size-sort`, and `arm-none-eabi-readelf -h`. Do not encode a timeless fixed plugin-size limit: firmware memory availability changes, including an increase in firmware 1.16.1044. Confirm immutable tables and metadata are actually const, enum strings exactly match their ranges, hot callbacks allocate nothing, and every array/index path is bounded.1055. Review the user-facing diff for stale defaults, renamed controls, changed behavior, missing compatibility notes, or developer-only clutter.1066. Check `git status`; preserve completed work in the repository's normal durable flow.107</final_polish>108109<success_criteria>110- The requested behavior is covered by deterministic tests and works in the relevant live environment.111- ARM output is a valid relocatable plugin object exporting `pluginEntry`.112- Routing metadata matches runtime bus access, including derived polyphonic buses.113- Voice transitions and configuration changes do not introduce avoidable clicks, stuck notes, or cross-owner stealing.114- Panic clears every voice and controller state the plugin owns.115- Player docs match code, tests, packaged defaults, and current official platform facts.116- The release archive has the exact MicroSD layout and the published artifact has been independently rechecked.117- The repository is clean, committed, and pushed unless the user explicitly requests otherwise.118</success_criteria>