How do I save and recall module's variables?

I imagine json_real_value() does the same kind of check? The default values are 0.0 so when 0 is returned it wouldn’t do any harm.

Yes, all json_*_value() and json_*_get() gracefully handle NULL.

I’ve been tinkering on (re)storing settings via json for a few days now, and I’m getting there. But as I understand from these few posts the PARAM values are stored in a patch by default, which I have been able to verify. This raises 2 questions:
1: how can I access them?
2: why is there a mechanism involving json if the params are stored by default anyway?

params[MY_PARAM].value

Some modules have internal state that is not determined by knob positions.

So the params are automatically saved, but I must restore any variable related to them myself (e.g. a boolean keeping track that a button was pressed)?

A bool as an int is implicit, the two can be connected.

bool isZero = true;
if (isZero == jsonValue) // true/false

As long as the json value is 0 or 1 you’re conditions would be executed or not.

Param values are saved AND LOADED automatically for you. But not all “widgets” set their state from a param. Knobs always do, but not all switches do. The slide switches in VCV mostly do, but many pushbuttons do not. You can write your own if you want. in some cases you can associate a widget with a parameter yourself, although it can get tricky. While you are learning, probably best to just stick with widgets that do what you want. Most modules do not do their own JSON serialization.

If you’re emulating analog modules, no internal state needs to be saved into the patch because the state of the module is entirely defined by the panel. But imagine Mutable Instruments Plaits, where the internal state is the mode shown by the LEDs. Since no knob determines the mode, you’d need to save to EEPROM so it’s loaded after being powered on.

Could someone be kind enough to give me a quick sanity check on the following please? Am I doing it right, is there a better way to dump just two buffers?

        float bufferA[10000] = {};
        float bufferB[10000] = {};

        json_t* dataToJson() override {
        json_t* rootJ = json_object();

        json_t* samplesAJ = json_array();
        json_t* samplesBJ = json_array();

        for(int i = 0; i < 10000; i++) {
            json_array_append_new(samplesAJ, json_real(bufferA[i]));
            json_array_append_new(samplesBJ, json_real(bufferB[i]));
        }

        json_object_set_new(rootJ, "samplesA", samplesAJ);
        json_object_set_new(rootJ, "samplesB", samplesBJ);

        return rootJ;
    }

    void dataFromJson(json_t* rootJ) override {
        json_t* samplesAJ = json_object_get(rootJ, "samplesA");
        json_t* samplesBJ = json_object_get(rootJ, "samplesB");

        if(samplesAJ) {
            for(int i = 0; i < 10000; i++) {
                bufferA[i] = json_real_value(json_array_get(samplesAJ, i));
                bufferB[i] = json_real_value(json_array_get(samplesBJ, i));
            }
        }
    }

Do you really need to save all 10000 values? I‘d add some logic to store only used array cells. Keep in mind that Rack does an autosave every 15 seconds.

1 Like

Hmmm. I upped the buffer size from 1k as I figured if someone records fast knob movements over an extended time, then decides to just loop a portion of the buffer slowly, you’d potentially hear stepping between samples but now I think about it that could be smoothed out with a slew limiter. I’ll drop it back to 1k I think. Thanks Ben.

If you need 1000 or 10000 x 2 values, you may want to convert the arrays into one long base64 string. A further optimization would be to use integers instead of floats, and limit the integer range to the precision you require. Not only can integers pack better, it avoids portability problems with different endian representations on different machines.

1 Like

I had the same question some time ago and decided it’s not worth the effort to implement some fancy stuff.

1 Like

Surely json numbers are portable? That’s the whole point of json!

1 Like

At a glance, that looks like it’ll work, but remember to use json_number_value() instead of json_real_value(), so that integers like “42” will be converted to 42.0 instead of 0.0.

1 Like

My apologies for being unclear. JSON numbers are portable. Floats stored as binary representations in base 64 are not portable. I’m guessing that the original poster’s description of the data as fast knob movements means that float values are overkill if the data is a recording of parameter values.

Using base 64: two JSON characters could encode an integer with a range of 0 - 4095; as opposed to 6 characters encoding one float.

I ran into JSON becoming a CPU hog saving large data sets, but that may not be the case here.

1 Like

I believe it. I think we all agree that auto saving 100k variables is not a good idea, no matter what the format?

2 Likes

Is there any way to disable the automatic params update when loading a preset / duplicating a module? I’m only interested in what I saved via dataToJson and don’t want any parameters to change until I explicitly set them.

Sure, good idea. Added virtual methods paramsToJson() and paramsFromJson() to Module in Rack v2.

2 Likes

Tried your method today and got it working :slight_smile:

Very simple, but effective :wink:

Thanks a lot!