Five independent modules with no interdependencies: - event-bus.js: namespaced pub/sub (seq.*/ml.*/ui.*) with wildcard subscriptions and automatic AudioContext/performance.now timestamps - prng.js: seedable mulberry32 PRNG with pure-functional API, fork() for independent per-primitive streams, serializable state for freeze - pattern.js: symbolic pattern description data structure with create/clone/merge/validate, additive and multiplicative merge modes - param-map.js: maps fixed 16-output MLP to variable-count primitive params via linear interpolation, with optional per-param min/max scaling - seq-iml.js: factory for second WasmIML instance (2 inputs, 16 outputs, [16,16,16] hidden layers) following existing imlJoy/imlHand pattern All modules are ES modules with no build step. PRNG, pattern, and param-map are port-ready (explicit state, typed arrays, no closures).
76 lines
2.8 KiB
JavaScript
76 lines
2.8 KiB
JavaScript
// ShapeSeq — Sequence NISPS Instance
|
|
//
|
|
// Factory for creating a second WasmIML instance dedicated to sequence control.
|
|
// The MLP has a fixed 16-element output which a downstream param mapping layer
|
|
// (not in this module) fans out to however many primitive params the current
|
|
// chain requires.
|
|
//
|
|
// Input routing is configurable and wired externally (default: hand tracking
|
|
// features 0+1). This module only creates the IML instance — it does not
|
|
// subscribe to any input source. The integration layer (see meml-9tf) is
|
|
// responsible for calling setInputs() with routed values each frame.
|
|
//
|
|
// Usage:
|
|
// import { createSequenceIML } from './shapeseq/seq-iml.js';
|
|
// const seqIML = await createSequenceIML();
|
|
// // Per frame:
|
|
// seqIML.setInputs([x, y]);
|
|
// seqIML.process();
|
|
// const params16 = seqIML.getOutputs();
|
|
|
|
import { WasmIML } from '../nisps/nisps-wasm.js';
|
|
|
|
// Fixed architecture for the sequence MLP.
|
|
// 2 inputs (routed externally), 16 outputs (fixed — param mapping fans out).
|
|
// Smaller network than the synth MLP ([3,32,48,64,126]):
|
|
// three hidden layers of 16 neurons keeps inference cheap while providing
|
|
// enough capacity for 16 continuous outputs.
|
|
const SEQ_N_INPUTS = 2;
|
|
const SEQ_N_OUTPUTS = 16;
|
|
const SEQ_HIDDEN_LAYERS = [16, 16, 16];
|
|
|
|
// Training hyperparameters — same defaults as the synth IML
|
|
const SEQ_MAX_ITERATIONS = 1000;
|
|
const SEQ_LEARNING_RATE = 1.0;
|
|
const SEQ_CONVERGENCE_THRESHOLD = 0.00001;
|
|
|
|
/**
|
|
* Create a WasmIML instance configured for sequence control.
|
|
*
|
|
* Follows the same creation pattern as imlJoy / imlHand in a-app.js:
|
|
* const iml = await WasmIML.create(nInputs, nOutputs, hiddenLayers, ...);
|
|
*
|
|
* The returned object is a standard WasmIML instance with the full interface:
|
|
* setInput / setInputs, getOutputs, process,
|
|
* addExample, clearDataset, train, trainAsync,
|
|
* randomiseWeights (drawWeights), moveWeights,
|
|
* exampleCount, destroy, etc.
|
|
*
|
|
* Additionally exposes SEQ_N_INPUTS, SEQ_N_OUTPUTS, SEQ_HIDDEN_LAYERS as
|
|
* properties on the returned object for introspection by downstream code.
|
|
*
|
|
* @returns {Promise<WasmIML>} — the sequence IML instance (augmented with
|
|
* .SEQ_N_INPUTS, .SEQ_N_OUTPUTS, .SEQ_HIDDEN_LAYERS)
|
|
*/
|
|
export async function createSequenceIML() {
|
|
const seqIML = await WasmIML.create(
|
|
SEQ_N_INPUTS,
|
|
SEQ_N_OUTPUTS,
|
|
SEQ_HIDDEN_LAYERS,
|
|
SEQ_MAX_ITERATIONS,
|
|
SEQ_LEARNING_RATE,
|
|
SEQ_CONVERGENCE_THRESHOLD
|
|
);
|
|
|
|
seqIML.setLogger(msg => console.log('[NISPS:seq]', msg));
|
|
|
|
// Attach architecture metadata for introspection
|
|
seqIML.SEQ_N_INPUTS = SEQ_N_INPUTS;
|
|
seqIML.SEQ_N_OUTPUTS = SEQ_N_OUTPUTS;
|
|
seqIML.SEQ_HIDDEN_LAYERS = SEQ_HIDDEN_LAYERS;
|
|
|
|
return seqIML;
|
|
}
|
|
|
|
// Re-export constants for use by other modules (e.g., param mapping layer)
|
|
export { SEQ_N_INPUTS, SEQ_N_OUTPUTS, SEQ_HIDDEN_LAYERS };
|