Storing / Loading States :D

Im not entirely sure how best to approach this. Like a few other users I'm delving into the ability to save and load "presets". I'd like an input widget that gives the preset its name and then of course save and load buttons.

It would be nice to have a widget that populates based on the amount of presets but that could prove difficult. I saw this example:

My assumption is that a custom module is the only way to save and load files to disk. I've read through quite a lot of posts already but cant quite figure out how to do it myself.

I created a little repository with a session file and a custom module that demonstrate how this could be done, I'll add some comments later in the custom module.

Edit: @BillTribble might be interested in this too

2 Likes

Im running into a persistent issue where loading a state from disk that isnt the C drive seems to trigger a loop. The image attached shows a debug block that constantly runs until i force stop the server.

This is what im using to load the states after they've been saved:

  • send('IP', '/STATE/OPEN', '@{StateName}.state')
  • send('IP', '/STATE/SET', '@{StateName.state}', false)

For what it's worth, ip addresses beginning with 192.* have no meaning outside of you local network, no need to obfuscate them.

  • send('IP', '/STATE/OPEN', '@{StateName}.state')
  • send('IP', '/STATE/SET', '@{StateName.state}', false)

Where are you writing this ? It looks wrong because

  • you should not "send" this message to the outside, it should be transmitted to the clients from the custom module using receive()
  • advanced syntaxes must be avoided in scripts @{}
  • it's not clear what you're actually sending as value but given the error message I it looks like it's simply not a valid state object.

Besides, this doesn't follow the idea that's demonstrated in the example above, have you tried using it / understanding it ?

Im writing those two lines inside a button widget to my ip: OSC port. Simply because thats what allowed me to finally store a state.

I've used the example from the prior thread but have not looked at the new repository with comments yet.

And thankyou btw for always replying to these forums. Always happy to see such passion behind this software!

I've updated the repository with comments in the custom module, please try loading it with the associated session, I believe it's a good starting point.

1 Like

Looking through the custom module im able to understand and expand upon it. Thankyou for taking the time to comment it out and making the repository. I was able to make buttons that step through the states, like next and previous, in the custom module with some help from ChatGPT :rofl:.

Which this is what Chat came up with for future context.

// state Next button
// 1st argument: slot name
else if (address === '/state/next') {
    const currentStateName = args[0].value;

    const slotNames = Object.keys(states);
    const currentIndex = slotNames.indexOf(currentStateName);

    if (currentIndex !== -1) {
        // Check if the current state is not the last one
        if (currentIndex < slotNames.length - 1) {
            // Get the name of the next state
            const nextStateName = slotNames[currentIndex + 1];
            const nextState = states[nextStateName];

            // Load and send the next state
            loadState(nextStateName);

            receive('/NOTIFY', `Loaded state: ${nextStateName}`);
        } else {
            receive('/NOTIFY', 'No more states available');
        }
    } else {
        receive('/NOTIFY', 'State name doesn\'t exist!');
    }

    // empty return to bypass the original message
    return;
}

Hehe ChatGPT took the long way it seems, a momentary button with this onValue script would do the trick

// get switch's values
var slots = getProp('slot_switch', 'values')

// compute index of switch's current value
var index = slots.indexOf(get('slot_switch'))

// increment index
// replace '+ 1' with "- 1 + slots.length"  to decrement
// "% slots.length" makes it loop when reaching the end
var new_index =  (index + 1) % slots.length

// set switch value
set('slot_switch', slots[new_index])

True, but the GPT method loaded the state as well as going to the next one, but I just added the load onValue script to the end of the button so that slot is redefined and loaded :rofl:.

One thing that i'm trying to figure out still is if I can select a random slot and load it with just the switch, rather than having to select an item on the switch then manually press load. Seems thats where my initial problems of infinite loops persist because im using the onValue script of the Switch.

And forgive my ignorance of JS, I can easily read and understand the syntax but writing it is a struggle for me currently.

This seems to work

// switch's onValue
var slot = value
if (slot) {
  // get state of all widgets in panel
  var state = stateGet('panel_1')
  // send state to custom module
  send('custom:module', '/state/load', value)
}

// or, if the load button is still around, just trigger it
set('load', 1)

I tried similar methods actually, even triggering the load button. But the problem for me crops up when you go to press a 2nd, 3rd, 4th option in the switch. Its odd to me but from what i gather the switch is an array of values, and that array isnt properly being addressed. At least for this case, the first time you select an option it works fine, but then whatever data isnt cleared when you go to press the next option, creating an infinite loop.

And im using the debug log on the server to see what i believe to be an "infinite loop" for reference.

I'm not sure to understand the issue, I've implemented the above script in the repository and it works fine regardless of how many times I select a slot and how many slots there are.

Wait, I think I figured it out. I noticed initially at the start of all this that panel_1 is what's being saved. At some point I moved all the options into a separate panel and forgot to move that panel outside of panel_1. So it was still a child.

I had suspicions it could be the problem but it works too in the example when saving the root's state instead of the panel's. Anyway I think it's better to keep the state management widgets outside of what's saved.