How do I save and recall module's variables?

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?


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.


Tried your method today and got it working :slight_smile:

Very simple, but effective :wink:

Thanks a lot!