Phase 1 group 4 (S33, S34, L54).
- S33: removed 12 dead entries across the full 5-layer registration chain
(bindings.cpp KEEPALIVE -> EXPORTED_FUNCTIONS -> the NispsModule declaration
table -> the WasmIML wrapper -> the EngineApi facade): nisps_ml_reset,
example_count, move_weights, feedback_learning_paused, feedback_drag,
jolt_lr_scale, jolt_tick_lr_ramp, pipeline_state_size/save_state/load_state,
feedback_placing and feedback_state. Each was grepped against manifold/src,
manifold/tests, the e2e specs, manifold/tests/wasm-load.ts and
tests/cpp/parity_wasm.mjs — the parity gate builds its own API via cwrap and
is a real consumer, so it counts.
KEPT deliberately: EXPORTED_RUNTIME's heap views + ccall/cwrap (the parity
harness and wasm-load.ts depend on them), and nisps_ml_feedback_static_output,
whose C export IS called directly by parity_wasm.mjs even though no TS
wrapper reaches it. Also dropped parity_wasm.mjs's moveWeights cwrap, which
was declared but never invoked.
- S34: deleted the publishWeights_ channel — EngineSink.setWeights,
Spine.setWeights/weights()/liveWeights and every call site. It ran a C->heap
copy plus a fresh Float32Array allocation at up to 200 Hz into a field
nothing read. getWeights survives for persistence and the debug probe.
- L54: worklet loader — deleted the unused imports object, the 'c' branch,
exMap and the duplicate second loop, and replaced the silent `() => 0` stub
with one that throws, so a missing import fails loudly instead of returning
plausible zeros into the audio path.
manifold/public/nisps.{js,wasm} rebuilt with the trimmed export list (emcc
3.1.69, the CI-pinned version) and committed — the freshness gate added in
Phase 0 requires it, and the webhook ships this artifact to production.
Gates: run-all-tests.sh ALL GREEN, parity 1273 floats within 1e-5.
|
||
|---|---|---|
| .. | ||
| bindings.cpp | ||
| README.md | ||
nisps/wasm
Emscripten target that exposes nisps/ml (MLP) and nisps/engines (audio
engines) to the browser apps via a flat C ABI.
This directory is a leaf — it does not export headers for inclusion by
other C++ code. The only artifact is bindings.cpp plus the build script
that turns it into manifold/public/nisps.{wasm,js} (with a transitional
copy to playground/public/ until P1 of
docs/specs/plans/one-core-engine-refactor.md retires the playground).
Building
scripts/build-wasm.sh
Requires emcc (Emscripten). The script defaults to
/usr/lib/emscripten/emcc and respects an EMCC env var override.
Output:
manifold/public/nisps.wasm— the compiled module.manifold/public/nisps.js— Emscripten glue (factory functioncreateNispsModule, MODULARIZE=1).
Both files are committed (so the browser apps work from a fresh clone
without a C++ toolchain). Re-run build-wasm.sh after changes to
nisps/{core,ml,engines,wasm}.
Architecture (runtime-shaped since one-core-engine P2)
The browser MLP is MLPCore<DynamicStorage> (nisps/ml/dynamic_storage.hpp):
nisps_ml_create(input, output, hidden[3], n, seed) HONOURS its dimensions.
The 4-layer topology (ReLU×3 + Sigmoid) is fixed; only the dimensions are
runtime, capped at 4096 per dim. Non-positive/null arguments fall back to the
historical defaults:
32 inputs → [10, 14, 18] hidden → 126 outputs
nisps_ml_reshape(ml, in, out, hidden, n, spread) constructs a new net at
the requested shape, warm-starts it by copying the overlapping weight region
(nisps/ml/warm_start.hpp), and swaps it in. The C-side dataset and the
feedback controller state RESET on reshape (front-end shows a confirm modal).
Heap is used only at create/reshape time, never per-call; the firmware target
never compiles the dynamic storage at all (#error under
NISPS_TARGET_EMBEDDED).
C API surface
See bindings.cpp for the full list. Summary:
| Group | Functions |
|---|---|
| ML life | nisps_ml_create, nisps_ml_destroy, nisps_ml_reshape |
| ML I/O | nisps_ml_set_input, nisps_ml_process, nisps_ml_outputs, nisps_ml_infer_batch |
| Training | nisps_ml_add_example, nisps_ml_train, nisps_ml_eval_loss, nisps_ml_clear_examples |
| Weights | nisps_ml_weight_count, nisps_ml_get_weights, nisps_ml_set_weights, nisps_ml_draw_weights |
| Diag | nisps_ml_get_layer_stats, nisps_ml_describe |
| Engines | nisps_engine_create, nisps_engine_destroy, nisps_engine_set_params, nisps_engine_process_block |
Engine-id strings follow the C++ engine_id() constexpr accessors:
thru, paf_synth, channel_strip, xiasri, verb_fx, memlcelium,
breakor, elysiamorf, analysis. Unknown ids fall back to thru
(silent passthrough).