Port Potato Chips to the disting NT plug-in API #1
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
peterswimm/potatochips!1
Loading…
Reference in a new issue
No description provided.
Delete branch "claude/port-distong-nt-native-c-2yibw6"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Description
Ports all sixteen Potato Chips modules to the Expert Sleepers disting NT plug-in API as native C++ algorithms, one
.oper chip.The emulators are reused as-is: everything under
src/dspis header-only and already independent of VCV Rack, so the port re-implements only the module layer — the part that reads a panel and drives the chip's registers. Two small pieces bridge the gap to a bare-metal Cortex-M7 target:distingNT/include/nt_potatochips/compat.hpp— supplies inert stand-ins for the three exception types the emulators name on their out-of-range paths (the NT builds with-fno-exceptions) and definesrack::dsp::FREQ_C4, the one Rack constant the DSP layer reads.distingNT/include/nt_potatochips/chip.hpp— stands in for the Rack build'sChipModule: bus resolution, coarse/fine pitch conversion,BLIPBufferrendering at the 768kHz chip clock, the /16 control-rate divider, and the output normalling that mixes an unpatched output into the next patched one.The API headers are vendored as the
dep/distingNT_APIsubmodule somake -C distingNTworks out of the box.distingNT/README.mddocuments the build, the install, the parameter conventions, the memory each algorithm asks for, and every departure from the Rack build.Nothing in the port allocates. The built plug-ins reference no allocator and no C++ ABI runtime — only
NT_globalsand standard library symbols the firmware provides (memcpy,memmove,memset,cos,sin,pow,powf,log,log2f).Memory errors fixed in shared code
distingNT/test(below) runs every algorithm under ASan and UBSan. Getting all sixteen to pass turned up memory errors in the emulators. Every one of these affects the Rack build too:BLIPBuffer::read_sample()moved one element too many and cleared one element past the end of its buffer — on every sample, of every buffer. In the Rack build that write lands in the next buffer's first field; on the NT it landed in the chip emulator that follows the buffers and zeroed an oscillator's output pointer, crashing Mega Tone on its first block.BLIPSynthesizer::adjust_impulse()ran its phase loop one step wide at both ends, reading before and writing past its impulse table (into the adjacentkernel_unitmember) — and, from the same off-by-one, never reached thep == p2case that halves the error correction for the phase-0.5 impulse.Ricoh2A03::Oscillator::reset()was missing its= 0: it copied the uninitialised fourth register across the other three instead of clearing them, and left thereg_writtenbools holding whatever was in memory.NintendoGBSsized its register array asADDR_END - ADDR_START, one short of the inclusive range its ownwrite()accepts, so writing the last wave-RAM byte wrote past the array.DigitalOscillatortook the note that selects its band-limited wave-table straight from an unbounded pitch. A zero frequency or a large control voltage indexed past the 16-entry table and segfaulted on the resulting pointer.Also, for the port's own needs: the 13KB built-in sample moves off
SuperSampler's stack intodsp/sony_s_dsp/hyaw_sample.hpp, shared by both builds, with an accessor that reads zero past the end (the last BRR block runs into it); anddsp/atari_pokey.hppgains a by-reference constructor so a heapless caller cannot land on itsnew Enginefallback.Deliberate departures
setFrequency(), which converts it again, leaving the filter about eight times too slow and quantised too coarsely to track V/Oct.Two things that look wrong were left alone, because changing them changes what the modules sound like — both written up in the README: Super VCA's loudness compensation rises with the filter mode while the filter weakens (so the mode labelled quietest is unfiltered and boosted 8×), and Super Sampler's built-in sample is packed into BRR nibbles without masking, so a negative sample's sign extension sets the neighbouring nibble.
Type of change
How Has This Been Tested?
make -C distingNT/test. The harness allocates exactly the memory each algorithm declares with guard regions around it, poisons it first so nothing can rely on zeroed memory, and renders 256 steps in three passes — defaults, every input saturated at 5V, and eight rounds of pseudo-random parameters. It checks the parameter tables against their pages, that nothing writes outside its allocation, that every sample is finite and not a runaway, and that an instrument-tagged algorithm makes a sound.git submodule update --init dep/distingNT_API && make -C distingNTpluginEntry, and each one's undefined-symbol set was checked witharm-none-eabi-nm -uagainst the set the API's own examples produce — nooperator new, nomalloc, no__cxa_*SuperSampler.cppwere compiled natively with-Wall -Wextraaway from Rack, cleanstatic_assertin each algorithm ties its parameter table to its parameter enum, so a mismatched page index fails the buildNot tested on hardware. The plug-ins have not been loaded on a disting NT, and no algorithm's sound has been compared against its Rack counterpart — the harness cannot check that.
Test Configuration
Checklist
Doxygen style