# Read_persistent_var on the first initialization?



## olmerk (Oct 9, 2017)

From time to time I’m experiencing a discard of all ui controls when loading an instrument, though all of them have make_persistent/read_persistent_var assigned. I suspect it happens because when working on my script I accidentally flush down the script window and Kontakt "forgets" the stored values.


So my question is the following. What should be done to prevent the situation of “all-controls-down” on the first initialization? Is it necessary to assign at least some “workable configuration” on init? Will it be overridden with on_ persistence_changed block in case of next initializations, when user has touched some controls, thus creating a new configuration different from the default one set in on_init block?


----------



## P.N. (Oct 9, 2017)

Hi, olmerk.

The issue with variables getting flushed shouldn't happen, unless you want them too.
The variables are stored with the nki, so a blank instrument should have default variables assigned, in which case, you set a default value command so they always behave the way you want on a new instrument.

Also, the read_persistent command (when required) should always come before the make_persistent command.

The on_persistence_changed callback nullifies the need for read_persistent commands (in most cases).

Cheers.


----------



## olmerk (Oct 9, 2017)

P.N. said:


> The variables are stored with the nki, so a blank instrument should have default variables assigned, in which case, you set a default value command so they always behave the way you want on a new instrument.



I have $CONTROL_PAR_DEFAULT_VALUE assigned to GUI controls. Anyway, it still sometimes happens when I See them all discarded to zero values. What causes that?

Can this be a reason? ->


P.N. said:


> Also, the read_persistent command (when required) should always come before the make_persistent command.



I put make_persistent in the first place and then read_persistent_var right after it.


----------



## Tod (Oct 9, 2017)

P.N. said:


> Also, the read_persistent command (when required) should always come before the make_persistent command.



Hi P.N., I must say I'm as confused about this an anybody. I used to have all my make_persistent commands after the read_persistent commands, and as far as I know it always seemed to work. But then I've seen threads saying the make_persistent commands should come first, or have indicated that by the way they are using it. So lately I've been putting all the make_persistent commands first, and it also seems to work.

Consequently to me, regardless of where the make_persistent commands are, the most important thing is to have a read_persistent command come after where the variables are assigned a value and before where the variables are initialized in the ICB.

I'm sure Mario will step in here and explain it all to us.


----------



## P.N. (Oct 9, 2017)

Hi, guys.

I guess i tried to oversimplify some things based on how i personally organize my scripts.

Having the read_persistent_var (when needed) before the make_persistent, is a more organized way to keep the script, in my opinion, but the variables are always read in the end of the ICB anyway.
So, if you make a variable persistent, its value will be loaded no matter what.

The question is, do you need to load that variable's value before the ICB is finished? Are there any commands, if statements, while loops, etc, that depend on that variable's value that are kept on your ICB?
If so, use the read_persistent_var command so that you can retrieve the value on a precise point on your ICB.

Or, keep commands/statements that make use of that variable on the OPC callback. At this point, the variable is already loaded so any command that needs it, will retrieve its updated value.

To summarize:

When you define make_persistent, you're telling Kontakt that when the instrument is saved, or re-initialized, the persistent variable's value will be saved and Kontakt will recall it on the end of your ICB.

When you define read_persistent_var, you're telling Kontakt when exactly he should remember your variable's value, because the script will recall the value at that precise instant, not at the end of the ICB.

You don't actually need the read_persistent_var command for most operations. You only needed it (or persistent callback) to properly execute dependencies associated with that variable.


----------



## P.N. (Oct 9, 2017)

olmerk said:


> I have $CONTROL_PAR_DEFAULT_VALUE assigned to GUI controls. Anyway, it still sometimes happens when I See them all discarded to zero values. What causes that?
> 
> Can this be a reason? ->
> 
> ...



If you could show me a small example, i may be able to help sort this out.


----------



## Tod (Oct 9, 2017)

P.N. said:


> If you could show me a small example, i may be able to help sort this out.



This is a very simplified version of what I'm suggesting. Notice that the "make_persistent" comes just after "Volume" has been declared and set up with a value. Whether that's important or not, I'm not sure.

However, I do know that the "read_persistent_var" should come after where the value is initially set, ($Volume:=dflt) and where it is actually applied (set_engine_par), at least that's how it works for me. 


```
on init
  declare const dflt:=500000
  declare $Vol_ID[16]
  declare ui_knob $Volume  (1,1000000,1)
    $Vol_ID[idx] := get_ui_id($Volume)
    set_knob_unit ($Volume,%Knb_Unit[Unt])
    $Vol_ID[idx]->value := dflt
    $Vol_ID[idx]->default_value:=dflt
    $Volume:=dflt
    make_persistent($Volume)
    $Vol_ID[idx]->text:=!Cap_Txt[idx]
    $Vol_ID[idx]->pos_x:=x
    $Vol_ID[idx]->pos_y:=y
  
    read_persistent_var($Volume)
  
    set_engine_par($ENGINE_PAR_VOLUME,$Volume,-1,-1,-1)
    set_knob_label ($Volume,_get_engine_par_disp($ENGINE_PAR_VOLUME,-1,-1,-1))
end on
```


----------



## olmerk (Oct 10, 2017)

P.N. said:


> If you could show me a small example, i may be able to help sort this out.



For example:



```
declare $src_1_volume_slider_min:=99022
declare $src_1_volume_slider_max:=792174
declare ui_slider $src_1_volume_slider($src_1_volume_slider_min, $src_1_volume_slider_max)
set_control_par($src_1_volume_slider,$CONTROL_PAR_VALUE,499039)
set_control_par($src_1_volume_slider,$CONTROL_PAR_DEFAULT_VALUE,499039)
move_control_px($src_1_volume_slider,1_volume_slider_x,volume_pan_sliders_y)
make_persistent($src_1_volume_slider)
read_persistent_var($src_1_volume_slider)
```

The slider controls a group volume through $ENGINE_PAR_VOLUME. Nothing fancy, but from time to time I find this slider being all the way down, so I have to ctrl + double-click it to reset the $CONTROL_PAR_DEFAULT_VALUE.


----------



## P.N. (Oct 10, 2017)

Tod said:


> This is a very simplified version of what I'm suggesting. Notice that the "make_persistent" comes just after "Volume" has been declared and set up with a value. Whether that's important or not, I'm not sure.
> 
> However, I do know that the "read_persistent_var" should come after where the value is initially set, ($Volume:=dflt) and where it is actually applied (set_engine_par), at least that's how it works for me.
> 
> ...



Hi, again.
I've simplified your first example so we can focus on the issues.


```
on init
    declare const $dflt:=500000 {Default value.}
    declare ui_knob $Volume  (1,1000000,1)
    $Volume:=$dflt {Telling Kontakt to use the constant's value (for now) - if the instrument was not previously saved and no other state was found (or the persistent value is not read on ICB or adressed on OPC). If nothing is defined, the control will default to 0.}
    set_engine_par($ENGINE_PAR_VOLUME, $Volume,-1,-1,-1)
    set_knob_label ($Volume,get_engine_par_disp($ENGINE_PAR_VOLUME,-1,-1,-1))
    read_persistent_var($Volume) {Loads the variable state and replaces the value that was defined above by the constant; if no state was found (either first initialization or the control that updates the variable wasn't touched), the constant defined above will be used instead.}
    set_engine_par($ENGINE_PAR_VOLUME,$Volume,-1,-1,-1)
    set_knob_label ($Volume,get_engine_par_disp($ENGINE_PAR_VOLUME,-1,-1,-1))
    make_persistent($Volume) {The placement of this command is not important, but, personally i prefer to place then at the end of my script. This command ensures the variable state should be saved with the nki and/or recalled when the script is re-initialized.}
end on
```

I know your example was just an example, but, you're doing "$ENGINE_PAR_VOLUME,-1,-1,-1" which is setting up volume for the whole instrument, which is what the Kontakt volume slider does. I'm sure you have a good reason for this, but without seeing the script, it seems maybe a little redundant?
Again, this is just an example, but you have ui_knob $Volume (1,1000000,1).
A minimum of 1 for the volume knob, threw me off a little, without seeing the whole picture.

But this is not related to the issue we were discussing, so i hope the example i posted is helpful.

Cheers.


----------



## Tod (Oct 10, 2017)

Humm, your using the slider name with the "set_control_par", I think you need to use a "get_ui_id" with it instead. For example, something you might add:

```
declare $Slider_ID
$Slider_ID:=get_ui_id($src_1_volume_slide)
set_control_par($Slider_ID,$CONTROL_PAR_VALUE,499039)
set_control_par($Slider_ID,$CONTROL_PAR_DEFAULT_VALUE,499039)
```

EDIT: Heh heh, you beat me P.N., while I was typing.


----------



## Tod (Oct 10, 2017)

P.N. said:


> I know your example was just an example, but, you're doing "$ENGINE_PAR_VOLUME,-1,-1,-1" which is setting up volume for the whole instrument, which is what the Kontakt volume slider does. I'm sure you have a good reason for this, but without seeing the script, it seems maybe a little redundant?



Oh yeah, I was just showing an example of the order, I didn't pay any attention to exactly what I used. I had the KSP editor open so I just grabbed something I had there.


----------



## P.N. (Oct 10, 2017)

olmerk said:


> For example:
> 
> 
> 
> ...



Oh, you're using $CONTROL_PAR_DEFAULT_VALUE. I missed that on your previous post. Sorry.
That's exactly what $CONTROL_PAR_DEFAULT_VALUE does. When you ctrl-click, it will set the default value you define. It doesn't work like setting up a constant or $CONTROL_PAR_VALUE.

You can definitly still make use of it. Using your code as reference you could:


```
on init
    declare $src_1_volume_slider_min:=99022
    declare $src_1_volume_slider_max:=792174
    declare ui_slider $src_1_volume_slider($src_1_volume_slider_min, $src_1_volume_slider_max)
    set_control_par(get_ui_id($src_1_volume_slider),$CONTROL_PAR_VALUE,499039) {Sets the initial value. It will only be used if no variable state exists for this particular control.}
    set_control_par(get_ui_id($src_1_volume_slider),$CONTROL_PAR_DEFAULT_VALUE,499039){Sets the default value, accessable via ctrl-click.}
    read_persistent_var($src_1_volume_slider){Loads the persistent variable state. If no state is found, either first init, or the control wasn't touched, it will use the initial value defined above. If neither are found, it will revert to 0.}
    set_control_par(get_ui_id($src_1_volume_slider),$CONTROL_PAR_VALUE,$src_1_volume_slider){Sets the control value according to the control variable state. It will either be the initial value you defined above or the persistent value.}
    make_persistent($src_1_volume_slider) {Ensures the variable will be saved with the instrument and recalled after the ICB is complete.}
end on
```

Hope it helps.

Cheers.


----------



## P.N. (Oct 10, 2017)

Tod said:


> Oh yeah, I was just showing an example of the order, I didn't pay any attention to exactly what I used. I had the KSP editor open so I just grabbed something I had there.



Got it. It didnt' even compile so i assumed it was a very quick example indeed.


----------



## EvilDragon (Oct 10, 2017)

P.N. said:


> Also, the read_persistent command (when required) should always come before the make_persistent command



This is not correct. read_persistent_var() should only be used in the case you need to use the value stored in a persistent variable in init callback, there is no requirement if you should put it before or after make_persistent, but usually good sense would be to put it after, actually. If that's not the case, it doesn't have to be in ICB at all. And yes, persistence_changed removes the need for using this, provided you do all things related to values from persistent variables in it!


----------



## P.N. (Oct 10, 2017)

EvilDragon said:


> This is not correct. read_persistent_var() should only be used in the case you need to use the value stored in a persistent variable in init callback, there is no requirement if you should put it before or after make_persistent...



Hi, Evil Dragon. It wasn't my intention to induce anyone in error.
I was too focused on the way i personally do things but i corrected that statement in my following script notes.
I hope that clears it up for other users.



EvilDragon said:


> ...but usually good sense would be to put it after, actually.


Any particular reason for putting it after?

Cheers.


----------



## P.N. (Oct 10, 2017)

EvilDragon said:


> And yes, persistence_changed removes the need for using this, provided you do all things related to values from persistent variables in it!



That's how i usually proceed. I don't remember the last time i used "read_persistent_var". But i guess it will depend on the script complexity. Do you still use "read_persistent_var" on your scripts?


----------



## EvilDragon (Oct 10, 2017)

P.N. said:


> Any particular reason for putting it after?



Usually you first make a control persistent, THEN you want to read its value out?



P.N. said:


> Do you still use "read_persistent_var" on your scripts?



Nope. It's mostly all function calls in persistence_changed now - plus usually stuff that I needed read_persistent_var for were related to UI changes, and this ties well with NKS and usage of persistence_changed (which is only ran when snapshots change - so ICB is ran only one time, when you actually load the main NKI).


----------



## P.N. (Oct 10, 2017)

EvilDragon said:


> Usually you first make a control persistent, THEN you want to read its value out?


No, the other way around. Yeah, i know. It sounds a little awkward.

Well, my reasoning when i used the read_persistent_var, and why i put make_persistent at the end of my ICB (and after the read_persistent_var) was "script chronological" order. I know that's not how Kontakt actually works, but it was my way to organize stuff around.
The persistent variables were read at the end of the ICB anyway, so i assumed to "tag" the variables for persistence there too - at the end of the ICB - (even if it didn't matter) for coherency.

But i see what you're saying. Reading a persistent variable without making it persistent first, can sound counter intuitive, but since Kontakt doesn't care for the order as long as the variable is "tagged"...


----------



## Tod (Oct 10, 2017)

EvilDragon said:


> Nope. It's mostly all function calls in persistence_changed now - plus usually stuff that I needed read_persistent_var for were related to UI changes, and this ties well with NKS and usage of persistence_changed (which is only ran when snapshots change - so ICB is ran only one time, when you actually load the main NKI).



Thanks Mario, you've mentioned the persistence_changed before and I was always going to check it out, but I didn't get around to it. Checking just now, I think I'm getting the picture. Up till now I've been setting persistent values in the ICB, and even though I had functions to perform the same task, I couldn't use them in the ICB. 

So the persistence_changed is performed right after the ICB and these functions can be used there, right?

Heh heh, if that's the case, and you hear a rather loud thumping, it's me kickin' my self in the head.


----------



## P.N. (Oct 11, 2017)

Hey, Tod.
One more simple example, (this time without read_persistent_var but still using your example as reference), the way this could be done using OPC/functions and assuming snapshots type are set to 0 or default (no snapshot_type defined):

```
on init
    declare const $dflt:=500000 {Default value.}
    declare ui_knob $Volume  (1,1000000,1)
    $Volume:=$dflt {Telling Kontakt to use the constant's value (for now) - if the instrument was not previously saved and no other state was found (or the persistent value is not present on ICB or adressed on OPC). If nothing was defined, on first init (even with persistent variables), the control will default to 0.}
    make_persistent($Volume) {The placement of this command is not important, but, personally i prefer to place them at the end of my script. This command ensures the variable state should be saved with the nki and/or recalled when the script is re-initialized.}
end on

function update_volume
    set_engine_par($ENGINE_PAR_VOLUME,$Volume,-1,-1,-1)
    set_knob_label ($Volume,get_engine_par_disp($ENGINE_PAR_VOLUME,-1,-1,-1))
end function

on persistence_changed
    call update_volume {After the ICB, the persistent variables are automatically loaded so we can call a function where those variables are implemented. On first init, it will use the constant we defined on the ICB.}
end on
```

Cheers,
Paulo


----------



## EvilDragon (Oct 11, 2017)

That example would work with snapshot mode 1 as well. In fact, it is preferred to use mode 1, really, because it will make loading snapshots faster, since ICB doesn't need to be executed on loading each and every snap.

Also, placement of make_persistent() is of course important - you cannot place it before you actually define the control that is supposed to be persistent


----------



## P.N. (Oct 11, 2017)

EvilDragon said:


> That example would work with snapshot mode 1 as well. In fact, it is preferred to use mode 1, really, because it will make loading snapshots faster, since ICB doesn't need to be executed on loading each and every snap.


I was trying to keep it simple... but maybe i should have not mentioned snapshots at all...



EvilDragon said:


> Also, placement of make_persistent() is of course important - you cannot place it before you actually define the control that is supposed to be persistent



Come on! Now you're just messing with me... you know what i meant... 

Again i was just trying to help, with the limited knowledge i possess, and i encourage all users to follow Evil Dragon's advices over whatever (convulated advice) i post.


----------



## EvilDragon (Oct 11, 2017)

Wasn't intending to mess with you, but just make things absolutely clear


----------



## Lindon (Oct 12, 2017)

Yeah like Mario, for persistent vars - declare them and then set them as persistent in the ICB but read and act on them in the OPC - which gives you the ability to create function calls for activities.


----------



## Tod (Oct 12, 2017)

Okay, since we're on it here, I've got another question about "snapshots". I understand "set_snapshot_type" and the difference between 0 and 1, what I don't understand, and can't find in the manual is how to manipulate snapshots. I can't find any way to perform a snapshot.

I suppose that's a silly question...


----------



## EvilDragon (Oct 13, 2017)

You cannot "perform" them. What do you mean by "performing them"?

They're like mini-NKIs that don't contain mapping and MIDI CC/host automation information, so stuff that is stored in them are persistent variable values, internal layout of effects and modulators, and stuff like that. They were introduced in order to reduce the loading time of "presets" that use exactly the same NKI layout (as far as sample mapping goes), since samples are only loaded the first time (when you load the NKI), instead of every time.


----------



## Tod (Oct 13, 2017)

Okay thanks again Mario, so where does NI have the info concerning snapshots? I'm assuming this has to do with the "Snapshot" thingy in the instrument header, or not? I noticed that a long time ago but never really paid any attention to it.

So if I use "set_snapshot_type" in a script, that just tells how I want the snapshots to be read, is that right? 

I also looked in the manual and addendum, but couldn't find anything.


----------



## EvilDragon (Oct 13, 2017)

set_snapshot_type() is explained in KSP reference (no, you're not right in your assumption)  And snapshots are explained in the manual - you should have the latest version of it (5.7, 09/2017), there's a whole chapter called "Using Snapshots".


----------



## polypx (Oct 13, 2017)

You create and load Snapshots using the "Snapshot thingy" in the header.

Snapshot type just decides how that NKI responds to Snapshot loading.... basically it will either read the init when you load a Snapshot or not. Using Mode 1 you can exclude some parameters from being changed by Snapshot loading.


----------



## Tod (Oct 13, 2017)

Okay, thanks Mario, I haven't looked in the 5.7 manual, I just assumed it would be in the 5.5 manual since 5.5 has snapshots. However, I do have the 5.7 upgrade, I'm just not using it yet.



polypx said:


> You create and load Snapshots using the "Snapshot thingy" in the header.
> 
> Snapshot type just decides how that NKI responds to Snapshot loading.... basically it will either read the init when you load a Snapshot or not. Using Mode 1 you can exclude some parameters from being changed by Snapshot loading.



Thanks polypx, that's what I was getting at in my post above, I kind of got the gist of that in the KSP manual, so thanks for clearing that up.


----------

