Wire the modular input layer into the Console and reshape the browser engine so input axes are genuine independent dimensions. Inputs (manifold/src/inputs/): - gamepad-source: emit press+release edges with standard-mapping labels (enables hold-and-move); single/double-stick already present. - midi-input-source: single-device selection + batch "MIDI Learn" (every CC swept while armed becomes an axis); notes stay discrete. - input-layer: compose() forwards each axis 1:1 (no mean-blend); add onReducedInput so the manifold tracks gamepad/MIDI position. - types: InputAction.phase, InputMode. Console (manifold/src/console/): - ConsoleApp: bind gamepad buttons to verdicts (RB up / LB down / X randomise / Y nudge / B undo / A-hold reposition); mirror composed position onto the manifold. - Drawers: rebuilt Inputs drawer (source picker, gamepad legend, MIDI device picker + batch-learn flow, learned-control meters). Engine (nisps/wasm, manifold/src/engine): - DefaultMLP widened MLP<2,..> -> MLP<32,..> (32 = MAX_AXES); each active axis gets a dedicated slot, unused slots held at 0 (inert). Rebuilt nisps.wasm (playground + manifold). - spine/engine-api: setInputs writes the full N-D vector (was dropping arr[2+]); primary pair keeps the 2-D pipeline; process() re-ticks the whole vector via spine.reprocess(). Tests: - parity_check/parity_wasm: ParityMLP -> 32 inputs, widen example bufs. - CMakeLists: build parity binary with -ffp-contract=off so native matches FMA-free WASM (training amplified the gap past 1e-5). Inputs dock is still an exclusive picker; mixing toggles, reshape modal, and the >2-D slider view (inputs-spec.md) are groundwork-laid but not yet wired. See docs/redesign/midi-gamepad-inputs-worklog.md. |
||
|---|---|---|
| .. | ||
| bindings.cpp | ||
| README.md | ||
nisps/wasm
Emscripten target that exposes nisps/ml (MLP) and nisps/engines (audio
engines) to the SolidJS playground 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 playground/public/nisps.{wasm,js}.
Building
scripts/build-wasm.sh
Requires emcc (Emscripten). The script defaults to
/usr/lib/emscripten/emcc and respects an EMCC env var override.
Output:
playground/public/nisps.wasm— the compiled module.playground/public/nisps.js— Emscripten glue (factory functioncreateNispsModule, MODULARIZE=1).
Both files are committed (so the playground works from a fresh clone
without a C++ toolchain). Re-run build-wasm.sh after changes to
nisps/{core,ml,engines,wasm}.
Architecture limit (read this)
The MLP class template is parametrised on (input_size, hidden1, hidden2, hidden3, output_size). WASM cannot recompile templates at runtime, so
this build instantiates exactly ONE configuration:
nisps::ml::MLP<2, 10, 14, 18, 126>
That serves the playground use case (2-D joystick → up to 126 synth
parameters). nisps_ml_create() accepts caller-supplied dimensions for
forward compatibility but currently ignores them — see comment at the top
of bindings.cpp. The schemas in schemas/modes/*.json use up to
output_size=126; modes whose output_size is < 126 simply ignore the
trailing entries.
To support additional architectures, either:
- Compile multiple wasm modules (
nisps_small.wasm,nisps_default.wasm, …) and let the playground load the right one based on the active mode. - Add a runtime-shape MLP variant to
nisps/ml(heap allocation only atcreate(); no impact on hot paths).
Both options are deferred to a future stream.
C API surface
See bindings.cpp for the full list. Summary:
| Group | Functions |
|---|---|
| ML life | nisps_ml_create, nisps_ml_destroy, nisps_ml_reset |
| 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).