Hello,
I made a simple mute module, and I wanted to let the user choose to save module state in the patch, with a context menu entry.
So I used dataToJson and dataFromJson.
It works correctly with small patches, but with with more complex patches, the state is saved (I looked at patch.json), but when VCV is reloaded the module state isn’t reverted.
What I’m doing wrong?
Code follows.
‘stateRestore’ is the context menu variable and it works good with all patches.
‘mute’ variable isn’t reverted with complex patches
Thanks
#include "plugin.hpp"
struct TestModule : Module {
enum ParamId {
PARAMS_LEN
};
enum InputId {
TRIG_INPUT,
IN_INPUT,
INPUTS_LEN
};
enum OutputId {
OUT_OUTPUT,
OUTPUTS_LEN
};
enum LightId {
OFF_LIGHT,
ON_LIGHT,
LIGHTS_LEN
};
bool stateRestore = true;
bool mute = false;
bool changes = true;
bool trigConnection = false;
bool prevTrigConnection = true;
float trigValue = 0;
float prevTrigValue = 0;
TestModule() {
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
configInput(TRIG_INPUT, "Trig/Gate");
configInput(IN_INPUT, "IN");
configOutput(OUT_OUTPUT, "OUT");
}
void onReset() override {
stateRestore = true;
mute = false;
changes = true;
}
json_t* dataToJson() override {
json_t* rootJ = json_object();
json_object_set_new(rootJ, "StateRestore", json_boolean(stateRestore));
json_object_set_new(rootJ, "Mute", json_boolean(mute));
return rootJ;
}
void dataFromJson(json_t* rootJ) override {
json_t* stateRestoreJ = json_object_get(rootJ, "StateRestore");
if (stateRestoreJ)
stateRestore = json_boolean_value(stateRestoreJ);
if (stateRestore) {
json_t* muteJ = json_object_get(rootJ, "Mute");
if (muteJ)
mute = json_boolean_value(muteJ);
}
}
void process(const ProcessArgs& args) override {
trigConnection = inputs[TRIG_INPUT].isConnected();
if (trigConnection != prevTrigConnection) {
changes = true;
if (trigConnection)
mute = false;
prevTrigConnection = trigConnection;
}
if (trigConnection) {
trigValue = inputs[TRIG_INPUT].getVoltage();
if (trigValue >= 1 && prevTrigValue < 1){
mute = !mute;
changes = true;
}
prevTrigValue = trigValue;
if (changes) {
if (mute) {
lights[OFF_LIGHT].setBrightness(1.f);
lights[ON_LIGHT].setBrightness(0.f);
} else {
lights[OFF_LIGHT].setBrightness(0.f);
lights[ON_LIGHT].setBrightness(1.f);
}
}
} else {
if (changes) {
lights[OFF_LIGHT].setBrightness(0.f);
lights[ON_LIGHT].setBrightness(0.f);
mute = true;
}
}
if (mute) {
if (changes)
outputs[OUT_OUTPUT].setVoltage(0);
} else {
outputs[OUT_OUTPUT].setVoltage(inputs[IN_INPUT].getVoltage());
}
if (changes)
changes = false;
}
};
struct TestModuleWidget : ModuleWidget {
TestModuleWidget(TestModule* module) {
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/TestModule.svg")));
addChild(createWidget<ScrewBlack>(Vec(0, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.62, 26)), module, TestModule::TRIG_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.62, 55.5)), module, TestModule::IN_INPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.62, 109)), module, TestModule::OUT_OUTPUT));
addChild(createLightCentered<SmallLight<GreenLight>>(mm2px(Vec(12, 105.5)), module, TestModule::ON_LIGHT));
addChild(createLightCentered<SmallLight<RedLight>>(mm2px(Vec(12, 114.5)), module, TestModule::OFF_LIGHT));
}
void appendContextMenu(Menu* menu) override {
TestModule* module = dynamic_cast<TestModule*>(this->module);
menu->addChild(new MenuSeparator());
menu->addChild(createBoolPtrMenuItem("Restore State on Load", "", &module->stateRestore));
}
};
Model* modelTestModule = createModel<TestModule, TestModuleWidget>("TestModule");