memlnaut-nisps/nisps/wasm
monkey-w1n5t0n 1672fe3474 feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/
- nisps/pipeline/input_chain.hpp: faithful f32 port of the manifold input
  pipeline (invert→deadzone→circular clamp→momentum-modulated zoom→centred
  power→EMA→momentum update). Caller-supplied dt, internal accumulated
  clock (no wall clock — deterministic; matches the P1 fixtures' clock
  contract). Fixed-capacity velocity ring; serialisable state.
- nisps/pipeline/output_chain.hpp: curve→EMA→slew→freeze(+per-output mask)
  chain, capacity-templated (browser cap 4096; firmware would use NOut).
- nisps/core/math.hpp: + centered_power(x, exponent) (both chains use it).
- bindings: nisps_pipeline_create/destroy, nisps_input_set_config(15-float
  wire layout)/process/reset, nisps_output_set_config/set_freeze_mask/
  process/reset, pipeline state save/load, nisps_curve_apply(+batch)
  (ids 0-6 = Curve enum, 7 = centred power).
- parity v5 Stage 7: rational (transcendental-free) traces through both
  chains (2 configs each) + full curve catalog — 1273 floats PASS, the
  pipeline floats bit-identical native↔WASM.
- ctest test_pipeline.cpp: deadzone remap, circular clamp, zoom+freeze,
  sticky anchor, frame-rate-independent EMA, momentum zoom-out/recovery,
  state round-trip, slew, freeze gate/mask, reseed-on-length-change,
  centred-power endpoints.

Part of one-core-engine-refactor P4; the manifold TS switch follows.
2026-07-18 11:52:53 +02:00
..
bindings.cpp feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/ 2026-07-18 11:52:53 +02:00
README.md docs: P2 complete — burn down plan, close ALIGNMENT defect #3 (fixed WASM arity) 2026-07-14 03:56:04 +02:00

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 function createNispsModule, 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_reset, 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, nisps_ml_example_count
Weights nisps_ml_weight_count, nisps_ml_get_weights, nisps_ml_set_weights, nisps_ml_draw_weights, nisps_ml_move_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).