2026-03-27 23:36:46 +01:00
|
|
|
#include "plugin.hpp"
|
|
|
|
|
#include <nisps/nisps.hpp>
|
|
|
|
|
|
2026-03-27 23:38:58 +01:00
|
|
|
static constexpr int NUM_ML_INPUTS = 2;
|
|
|
|
|
static constexpr int NUM_ML_OUTPUTS = 12;
|
|
|
|
|
|
2026-03-27 23:36:46 +01:00
|
|
|
struct MEMLNaut : Module {
|
|
|
|
|
enum ParamId {
|
2026-03-27 23:38:58 +01:00
|
|
|
PARAM_SPREAD,
|
|
|
|
|
PARAM_RAND,
|
2026-03-27 23:36:46 +01:00
|
|
|
PARAMS_LEN
|
|
|
|
|
};
|
|
|
|
|
enum InputId {
|
|
|
|
|
INPUT_X,
|
|
|
|
|
INPUT_Y,
|
|
|
|
|
INPUTS_LEN
|
|
|
|
|
};
|
|
|
|
|
enum OutputId {
|
|
|
|
|
OUTPUT_1, OUTPUT_2, OUTPUT_3, OUTPUT_4,
|
|
|
|
|
OUTPUT_5, OUTPUT_6, OUTPUT_7, OUTPUT_8,
|
|
|
|
|
OUTPUT_9, OUTPUT_10, OUTPUT_11, OUTPUT_12,
|
|
|
|
|
OUTPUTS_LEN
|
|
|
|
|
};
|
|
|
|
|
enum LightId {
|
|
|
|
|
LIGHTS_LEN
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-27 23:38:58 +01:00
|
|
|
nisps::IML<float> iml{NUM_ML_INPUTS, NUM_ML_OUTPUTS, {16, 24, 16}};
|
|
|
|
|
dsp::BooleanTrigger randTrigger;
|
|
|
|
|
|
2026-03-27 23:36:46 +01:00
|
|
|
MEMLNaut() {
|
|
|
|
|
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
|
2026-03-27 23:38:58 +01:00
|
|
|
configParam(PARAM_SPREAD, 0.f, 1.f, 0.6f, "Spread", "%", 0.f, 100.f);
|
|
|
|
|
configButton(PARAM_RAND, "Randomize weights");
|
2026-03-27 23:36:46 +01:00
|
|
|
configInput(INPUT_X, "X");
|
|
|
|
|
configInput(INPUT_Y, "Y");
|
2026-03-27 23:38:58 +01:00
|
|
|
for (int i = 0; i < NUM_ML_OUTPUTS; i++) {
|
2026-03-27 23:36:46 +01:00
|
|
|
configOutput(OUTPUT_1 + i, string::f("Out %d", i + 1));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 23:38:58 +01:00
|
|
|
// Initial randomization with default spread
|
|
|
|
|
iml.set_mode(nisps::IML<float>::Mode::Training);
|
|
|
|
|
iml.randomise_weights(0.6f);
|
|
|
|
|
iml.set_mode(nisps::IML<float>::Mode::Inference);
|
2026-03-27 23:36:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void process(const ProcessArgs& args) override {
|
2026-03-27 23:38:58 +01:00
|
|
|
// Handle RAND button
|
|
|
|
|
if (randTrigger.process(params[PARAM_RAND].getValue() > 0.f)) {
|
|
|
|
|
float spread = params[PARAM_SPREAD].getValue();
|
|
|
|
|
iml.set_mode(nisps::IML<float>::Mode::Training);
|
|
|
|
|
iml.randomise_weights(spread);
|
|
|
|
|
iml.set_mode(nisps::IML<float>::Mode::Inference);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read inputs, normalize 0-10V → [0,1], clamp
|
|
|
|
|
float x = clamp(inputs[INPUT_X].getVoltage() / 10.f, 0.f, 1.f);
|
|
|
|
|
float y = clamp(inputs[INPUT_Y].getVoltage() / 10.f, 0.f, 1.f);
|
|
|
|
|
|
|
|
|
|
iml.set_input(0, x);
|
|
|
|
|
iml.set_input(1, y);
|
|
|
|
|
iml.process();
|
|
|
|
|
|
|
|
|
|
// Write outputs: sigmoid [0,1] → 0-10V
|
|
|
|
|
const float* outs = iml.get_outputs();
|
|
|
|
|
for (int i = 0; i < NUM_ML_OUTPUTS; i++) {
|
|
|
|
|
outputs[OUTPUT_1 + i].setVoltage(outs[i] * 10.f);
|
|
|
|
|
}
|
2026-03-27 23:36:46 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct MEMLNautWidget : ModuleWidget {
|
|
|
|
|
MEMLNautWidget(MEMLNaut* module) {
|
|
|
|
|
setModule(module);
|
|
|
|
|
setPanel(createPanel(asset::plugin(pluginInstance, "res/MEMLNaut.svg")));
|
|
|
|
|
|
2026-03-27 23:38:58 +01:00
|
|
|
// Knobs
|
|
|
|
|
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(12.0, 20.0)), module, MEMLNaut::PARAM_SPREAD));
|
|
|
|
|
addParam(createParamCentered<VCVButton>(mm2px(Vec(28.0, 20.0)), module, MEMLNaut::PARAM_RAND));
|
|
|
|
|
|
2026-03-27 23:36:46 +01:00
|
|
|
// Inputs (left side)
|
2026-03-27 23:38:58 +01:00
|
|
|
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8.0, 38.0)), module, MEMLNaut::INPUT_X));
|
|
|
|
|
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(8.0, 50.0)), module, MEMLNaut::INPUT_Y));
|
2026-03-27 23:36:46 +01:00
|
|
|
|
2026-03-27 23:38:58 +01:00
|
|
|
// Outputs (2 columns of 6, below inputs)
|
2026-03-27 23:36:46 +01:00
|
|
|
for (int i = 0; i < 6; i++) {
|
2026-03-27 23:38:58 +01:00
|
|
|
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(12.0, 62.0 + i * 10.0)), module, MEMLNaut::OUTPUT_1 + i));
|
|
|
|
|
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(28.0, 62.0 + i * 10.0)), module, MEMLNaut::OUTPUT_1 + 6 + i));
|
2026-03-27 23:36:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Model* modelMEMLNaut = createModel<MEMLNaut, MEMLNautWidget>("MEMLNaut");
|