NullPerator supports three products: the ESP32-S3 hardware firmware, the browser WASM workbench, and the native iOS application. All three use the same application model and UI2 renderer.
cmake -S tests -B build-host -DCMAKE_BUILD_TYPE=Release
cmake --build build-host --parallel
ctest --test-dir build-host --output-on-failuretools/build-wasm.sh Release
cd web
pnpm install --frozen-lockfile
pnpm test --run
pnpm devSee the WASM build guide and test guide for the complete browser workflow.
Install and export ESP-IDF, then run:
idf.py --project-dir sources -B sources/build/node -DNode=true build
idf.py --project-dir sources -B sources/build/node -DNode=true flash monitorThe target is fixed to esp32s3. See the
hardware build guide for configuration and troubleshooting.
Install and package the shared Svelte presentation before opening the Xcode project:
cd web
pnpm install --frozen-lockfile
cd ..
ios/scripts/package-web.sh
open ios/NullPeratorIOS.xcodeprojSelect the NullPeratorIOS scheme and an Apple Developer Team. Xcode builds the
native C++ library for the selected device or simulator before linking the app.
See the iOS build guide for runtime details.
- UI state and animation stay in UI2; project data remains in the application model and services.
- Platform adapters implement explicit fixed-capacity interfaces.
- The audio callback must not allocate, lock, log, or touch UI state.
- NullPerator hardware, WASM, and iOS preserve the same project format and editing semantics.
- Add focused host tests for model, workflow, persistence, and input changes.
- Run the native layout Playwright suite for shared mobile UI changes.
The bank has 64 logical slots, not fixed per-type preset pools. NONE slots
share an empty instrument. Creating or replacing a preset allocates only the
chosen type; transactional replacement publishes it after validation succeeds.
Handle allocation failure without overwriting the existing slot.
Drum, Stack, and Chiptune each use bank-owned, per-track voice storage instead
of an eight-voice array inside every preset. The three GB types share a single
per-track pool allocated when the first GB preset is created and freed after
the last one is removed. These allocations happen outside the audio callback.
Respect TrackVoicePool ownership when rendering, applying FX, or stopping a
voice; a replaced preset must not affect the new owner on that track.
This removes preset quotas, not engine constraints: SID still shares one three-oscillator chip, OPAL remains monophonic per preset, MIDI has 16 protocol channels, and the song still has eight tracks. Test clone/import/load failures as well as creating many presets of the same type.