memlnaut-nisps/nisps-core
w1n5t0n 74c52fadc7 feat(nisps-core,vcv): complete Phases 6 + 7 — persistence, derived outputs
Phase 6 — State persistence:
- Full state serialization: version, weights (3D), examples (features+labels),
  mlpConfig, noiseLevel, slewMs, output/input ranges
- Validation on load: version check, graceful missing field handling
- .nisps preset save/load via right-click menu (osdialog file dialogs)
- Param values included in preset files

Phase 7 — Derived outputs:
- Mean, STD, delta computed on audio thread (trivial cost)
- Novelty/confidence: nearest_example_distance() computed on background
  thread after each training/perturbation job, cached for audio thread
- Defaults with 0 examples: novelty=10V, confidence=0V

nisps-core IML additions:
- get_weights() / set_weights() for MLP weight serialization
- get_example_features/labels() / load_examples() for dataset serialization
- nearest_example_distance() for novelty/confidence metric
- get_example_count() / get_max_examples() for UI display
2026-03-28 01:27:19 +02:00
..
examples fix: audit and fix nisps-core extraction issues 2026-02-08 18:01:48 +01:00
include/nisps feat(nisps-core,vcv): complete Phases 6 + 7 — persistence, derived outputs 2026-03-28 01:27:19 +02:00
test feat(nisps-core,vcv): complete Phase 0 + Phase 1 2026-03-28 00:36:46 +02:00
CHANGELOG.md fix: audit and fix nisps-core extraction issues 2026-02-08 18:01:48 +01:00
CMakeLists.txt feat: extract nisps-core platform-agnostic ML library 2026-02-08 17:47:23 +01:00
README.md fix: audit and fix nisps-core extraction issues 2026-02-08 18:01:48 +01:00

NISPS Core

Neural Interactive Shaping of Parameter Spaces - Core Library

A platform-agnostic C++20 header-only library for interactive machine learning. Train neural networks to map input parameters to output parameters through interactive demonstration.

What Is This?

NISPS core is a parameter mapping engine, not a synthesizer. It takes N input parameters (joystick position, sensor data, audio features) and maps them to M output parameters through an interactively-trained neural network.

Use it to control: synthesizers, effects, lights, robots, game parameters, or anything that responds to control data.

Features

  • Header-only: No compilation needed, just include and use
  • Platform-agnostic: Pure C++20 with standard library only
  • Interactive learning: Train by demonstration, not by code
  • Programmatic training: add_example() API for non-interactive use
  • Lightweight: ~3,500 lines of optimized neural network code
  • Flexible: Map 1-100 inputs to 1-100 outputs

Quick Start

Installation

Copy the include/nisps/ directory to your project, or add it to your include path:

# Option 1: Copy headers
cp -r nisps-core/include/nisps /path/to/your/project/include/

# Option 2: Add to CMakeLists.txt
target_include_directories(your_target PRIVATE /path/to/nisps-core/include)

Basic Usage

#include <nisps/nisps.hpp>

// Create IML with 2 inputs, 4 outputs
nisps::IML<float> iml(2, 4);

// Runtime: set inputs and get outputs
void update(float x, float y) {
    iml.set_input(0, x);
    iml.set_input(1, y);
    iml.process();

    const float* outputs = iml.get_outputs();
    my_synth.set_filter_cutoff(outputs[0] * 10000.f);
    my_synth.set_resonance(outputs[1]);
    my_synth.set_envelope_attack(outputs[2] * 5.0f);
    my_synth.set_envelope_release(outputs[3] * 10.0f);
}

Programmatic Training

// 1. Enter training mode
iml.set_mode(nisps::IML<float>::Mode::Training);

// 2. Add examples directly
float in1[] = {0.1f, 0.1f}; float out1[] = {0.9f, 0.1f, 0.5f, 0.8f};
float in2[] = {0.9f, 0.9f}; float out2[] = {0.1f, 0.9f, 0.2f, 0.3f};
iml.add_example(in1, 2, out1, 4);
iml.add_example(in2, 2, out2, 4);

// 3. Exit training mode (automatically trains the network)
iml.set_mode(nisps::IML<float>::Mode::Inference);

Interactive Training (hardware/UI)

// For interactive systems with physical controls:
iml.set_mode(nisps::IML<float>::Mode::Training);

iml.set_input(0, 0.3f);
iml.set_input(1, 0.7f);
iml.save_example();      // Stops inference
// ... user adjusts output controls ...
iml.set_output(0, 0.8f); // Or read from hardware
iml.save_example();       // Stores the input->output mapping

iml.set_mode(nisps::IML<float>::Mode::Inference);

API Reference

IML Constructor

nisps::IML<Float>(
    size_t n_inputs,                           // Number of input parameters
    size_t n_outputs,                          // Number of output parameters
    std::vector<size_t> hidden_layers = {10, 10, 14},  // Hidden layer sizes
    size_t max_iterations = 1000,              // Training iterations
    Float learning_rate = 1.0f,                // Learning rate
    Float convergence_threshold = 0.00001f     // Stop training threshold
);

Input/Output

void set_input(size_t index, Float value);     // Set single input (0-1 range)
void set_inputs(const Float* values, size_t count);  // Set multiple inputs
void set_output(size_t index, Float value);    // Set single output (for training)
void set_outputs(const Float* values, size_t count); // Set multiple outputs
const Float* get_outputs() const;              // Get output array
void process();                                // Run inference

Training

enum class Mode { Inference, Training };
void set_mode(Mode mode);                      // Switch modes
void add_example(const Float* in, size_t n_in, // Add training pair directly
                 const Float* out, size_t n_out);
void save_example();                           // Interactive: store input->output pair
void clear_dataset();                          // Clear training data
void randomise_weights();                      // Randomize for exploration

Logging

void set_logger(LogFn fn);                     // Set callback for messages
// LogFn = void(*)(const char*)

Building the Tests

cd nisps-core
mkdir build && cd build
cmake ..
make
ctest --output-on-failure

Requirements

  • C++20 compiler (GCC 10+, Clang 10+, MSVC 2019+)
  • CMake 3.14+ (for building tests only)

Architecture

Core Components

  • IML: High-level interactive ML interface
  • MLP: Multi-layer perceptron (feedforward neural network)
  • Dataset: Training data management
  • Layer/Node: Neural network building blocks
  • Loss: MSE and categorical cross-entropy functions
  • Utils: Activation functions (sigmoid, ReLU, tanh, etc.)

Design Decisions

  1. Header-only: Simplifies integration, allows template specialization
  2. C++20: Enables std::span for efficient array views
  3. No SIMD: Portable code, relies on compiler auto-vectorization
  4. RMSProp optimizer: Fast convergence for interactive training
  5. Gradient clipping: Prevents numerical instability

Examples

See examples/simple_mapping.cpp for a complete working example that demonstrates:

  • Untrained inference
  • Programmatic training with add_example()
  • Interactive training workflow with save_example() + set_output()

See test/main.cpp for tests including convergence verification.

Origin

Extracted from MEMLNaut-NISPS - an embedded ML platform for audio synthesis on Raspberry Pi Pico.

Key changes from MEMLNaut-NISPS:

  • Removed Arduino/RP2040 dependencies
  • Removed audio synthesis code (use this to control your synth)
  • Added proper namespacing
  • Converted to header-only library
  • Updated to modern C++20

License

Mozilla Public License Version 2.0

Original MLP code derived from David Alberto Nogueira's MLP project.

Contributing

This library is extracted from an active research project. Contributions welcome:

  • Bug fixes
  • Performance optimizations
  • Example code
  • Documentation improvements

Please keep the library dependency-free and platform-agnostic.

Citation

If you use this in research, please cite:

MEMLNaut-NISPS: Neural Interactive Shaping of Parameter Spaces
https://musicallyembodiedml.github.io/memlnaut/approaches/nisps

Support