# Detecting K4/K5 with a script



## Big Bob (May 19, 2013)

From time to time I see scripters asking if there is any way that a script can detect whether it is running under K4 or K5? While the KSP provides no direct way (such as an environment variable that can be read), I can think of a general stategy that might be able to accomplish this.

If a bug first appeared with K4 and didn't get corrected until K5, this might be exploited to detect the environment. I know of at least one such bug that could be used but, there may be others.

When K4 was first introduced, there were a number of Call bugs that appeared. Most of these were corrected with later versions of K4 except for one. As of version 4.2.4.5316 (which I think is the last K4 release), one of the Call bugs is still present. And, at least as of V5.0.3.5812, the problem has been corrected. I know there is a later version of K5 but I just haven't gotten around to updating yet. However, the latest version of K5 will more than likely also work properly but I don't know about the earlier versions of K5.

Here is a small code snippet that can distinguish K4 from K5 when run on my two versions (V 4.2.4.5316 and V 5.0.3.5812). Those of you that have other versions of K5 can try this code and report success or failure.

*on init*
``message("")
``pgs_create_key(PINIT,1)
``pgs_set_key_val(PINIT,0,1)
*end* on

*function* dummy
*end* *function*

*on pgs_changed*
``message("This is K4")
``*call* dummy
``message("This is K5")
*end* on

The bug being exploited is that an 'empty' KN function still acts like an 'exit' command when invoked from a callback in K4. Therefore, any code lines after the Call are not executed by K4. However, since K5 seems to have corrected this problem, the lines of code after the Call *are* executed by K5.

You could easily adapt this code to set a 'Version' variable to either 0 or 1 for K4 or K5 respectively. The only hitch is that you can't Call a function from the ICB so you cannot read the Version until some other callback runs to set it. That's the reason I used the pgs stuff in the example. The pgs stuff is used to 'force' a callback immediately after the ICB exits (the standard post-initialization trick).

Rejoice,

Bob


----------



## Sasje (May 19, 2013)

Nice Bob! ...seems to work here on K5.1! I just knew there had to be _some_ way of doing this. 

Initially I was thinking about trying to load a Kontakt factory image/impulse from either K4 and K5 to see what message it would give me back and act on it.


----------



## Big Bob (May 19, 2013)

Glad to hear it works on the latest K5 as well.

As I see it, the only problem then with using the Call bug is that it can't be detected in the first ICB pass. This probably means that to set the pixel height differently when in K4 and K5 a double start would have to be required. 

For example, you could use code something like this:

*on init*
``message("")
``*declare* $Ver
``read_persistent_var($Ver)
``set_ui_height_px(350+($Ver*190))
``make_persistent($Ver)
``pgs_create_key(PINIT,1)
``pgs_set_key_val(PINIT,0,1)
*end* on

*function* dummy
*end* *function*

*on pgs_changed*
``*call* dummy
``$Ver := 1
*end* on

Then, ask the user to 'apply' the script twice. For example, if the script is separate from the instrument, after the user pastes it into the KSP Editor, have them hit the 'Apply' button twice. Or if the script is distributed as a .nkp file, have the user hit the Apply button once after loading the .nkp.

Since this is a bit clumsy, it would be nicer if we could find a K4 bug that can be detected in the ICB. I know of a few of these but unfortunately they haven't been corrected in K5 (at least not yet). But, perhaps someone else is aware of a KSP bug or two that have been fixed in K5?

Rejoice,

Bob


----------



## mk282 (May 20, 2013)

The problem with this method is if you use some K5 KSP specific commands, the script will not compile in K4 at all. So, it's definitely not a perfect solution.

It's best to have two versions of scripts, after all.


----------



## Big Bob (May 20, 2013)

Hi Mario,

Yes, a K4/K5 script can only use the K4 subset but I assume that was understood from the get go. Still there are many scripts that can be written without requiring the K5 superset, except for a few things like maybe the ui_height as in Sasje's original inquiry.

Besides, the challenge was to see if there was some way for the script to determine whether it was running in K4 or K5 regardless of its ultimate value in the real world. :lol: 

I think the larger problem with using the Call bug is not being able to detect the environment in the ICB thus forcing an extra operation on the user such as putting up a message to 're-apply'. So, it would be nice if we could find a K5-corrected bug that's still in K4 and can be detected in the ICB. Unfortunately, all such remaining bugs in K4 that fit this criteria, at least that I'm aware of, are also still with us in K5. I was just hoping that maybe someone knows of a few KSP bugs I'm not aware of. Do you? :roll: 

Rejoice,

Bob


----------



## polypx (May 20, 2013)

If you're not going to use the K5 features, you could use a newer parameter like this:


```
on init
message(get_engine_par( $ENGINE_PAR_OUTPUT_CHANNEL, -1, -1, 1024))
end on
```

Which will return zero in K4 but -1 in K5 if you haven't edited the bus system in the K5 version. 

Obviously an instrument made in K4 will open in K5 with the bus system set to default, so for many applications the above could perhaps work?

cheers
Dan


----------



## Big Bob (May 20, 2013)

Hey Dan,

That's a great idea. This ought to be just about perfect for what Sasje was trying to do. For example, she could then use something like this:

*on init*
``message("")
``*if* (get_engine_par($ENGINE_PAR_OUTPUT_CHANNEL,-1,-1,1024)=0)
````set_ui_height_px(350)
``*else*
````set_ui_height_px(540)
``*end* *if*
*end* on

I think I'll award you the Grand Prize for this one :lol: 

Rejoice,

Bob


----------



## polypx (May 20, 2013)

The danger might be if a user opened the instrument in K5, made some changes to the bus system, and saved their own version. Next time they open it, they might have the wrong interface.

Maybe a make_persistent($var) could step in and save that situation?

Thanks for the prize!! 

cheers
Dan


----------



## Big Bob (May 20, 2013)

Good point Dan but, I think you're right about using persistence to 'save the day'. For example, you could use something like this:

*on init*
``message("")
``*declare* $Ver
``read_persistent_var($Ver)
``*if* ($Ver=0)
````$Ver := get_engine_par($ENGINE_PAR_OUTPUT_CHANNEL,-1,-1,1024) .*or*. 1
``*end* *if*
``set_ui_height_px(445-(95*$Ver))
``make_persistent($Ver)
*end* on

The first time the script is run Ver will initially be zero but then changed to +1 or -1 by K4/K5 respectively. If the instrument is then saved, the next time its run, Ver will be +/- 1 and therefore the ep will not be read anymore.

I think this will work. :roll: Maybe someone could check it by loading it into K5 and setting the bus channel to zero and resaving?

Rejoice,

Bob


----------



## Sasje (May 20, 2013)

Looks great to me.  it's a pity that Kontakt is quite limited with scripting. KSP is nice, but it would have been way better if it was able to run Python code. In the Reaper DAW I can use pure python which is called ReaScript/JS, it's amazing :D


----------



## polypx (May 20, 2013)

Actually Bob, yours isn't working quite right.

But I do this, and it seems to work correctly:

```
on init
message("")
declare $ver := 0
make_persistent($ver)
if (get_engine_par($ENGINE_PAR_OUTPUT_CHANNEL,-1,-1,1024)=0)
$ver := 0
else
$ver := 1
end if
read_persistent_var($ver)
if($ver = 1)
set_ui_height_px(540)
else
set_ui_height_px(350)
end if
end on
```

Not sure what the difference is tho. And in fact, looking at mine, you'd think it would reset to ver 0 after I change the output bus, but it doesn't. Weird.


----------



## Big Bob (May 20, 2013)

Hi Dan,

Oh my! Nothing is ever easy is it :lol: 

When you say my code doesn't work after you change the bus channel in K5 do you mean after hitting 'apply' again or after saving and reloading or ???

Precisely what is your test sequence?

BTW I'm going to be quitting for the day in a few minutes but I'll check in again tomorrow morning.

Rejoice,

Bob


----------



## polypx (May 20, 2013)

Hi Bob,

With your example script, I get the shorter UI height in K5 as well. Even the first time I apply with default values.

With mine, I get the taller UI in K5, so long as the bus output is at default the FIRST time I apply the script. I can change it freely after that and it never seems to get short again.

cheers
Dan


----------



## mk282 (May 20, 2013)

Sasje @ 20.5.2013 said:


> Looks great to me.  it's a pity that Kontakt is quite limited with scripting. KSP is nice, but it would have been way better if it was able to run Python code. In the Reaper DAW I can use pure python which is called ReaScript/JS, it's amazing :D



KSP is super-duper optimized. Using Python would just add unnecessary CPU and RAM overhead.

I bet that's one of reasons for inefficiencies of PLAY, they use Python scripting in the back-end.


----------



## Sasje (May 21, 2013)

mk282 @ Mon May 20 said:


> KSP is super-duper optimized. Using Python would just add unnecessary CPU and RAM overhead.
> 
> I bet that's one of reasons for inefficiencies of PLAY, they use Python scripting in the back-end.



It probably is. But I rather have some overhead instead of doing all sorts of crazy tricks to do something that should be very simple. How hard could it be to implement some basic math/string functions into KSP to ease some of the work. We don't even have script access to the waveform source itself. That should be standard in any audio application, especially a sampler in the age we live in today. It's K5 already, and as far I know they only added a useless MIDI read functionality, a limited waveform display that can't even be styled, and some extra constants which no-one seems to want or need. Not very progressive... I wonder what K6 will bring and if it's worth another $99 upgrade... it's that everyone uses Kontakt otherwise I would have switched to MachFive yesterday, which just happens to support all basic math and string functions through the LUA virtual machine beneath MachFiveScripting.


----------



## mk282 (May 21, 2013)

MIDI functionality is not really useless, and those new constants are plenty useful - just because you don't use them doesn't mean they aren't valid.

Lua is all great and neat simple code, but it is several times more CPU intensive than KSP. I, for one, care about the additional overhead, especially with the scripts I write, and MF3 is definitely not yet optimized enough to be a true competitor to Kontakt's performance.


----------



## Big Bob (May 21, 2013)

polypx @ Mon May 20 said:


> Hi Bob,
> 
> With your example script, I get the shorter UI height in K5 as well. Even the first time I apply with default values.
> 
> ...



HI Dan,

I'd be willing to bet that you have not been clearing the persistence buffer before retesting. Nothing will cause greater confusion with persistent vars than neglecting to do that. Especially since your script also uses the same name $ver for the version number.

Try this. Load your test instrument without either my script or your script. Then, using load preset, load the Factory 'Empty' script to clear the persistence buffer. In addition, change the name of $ver in one of our scripts so they aren't using the same name for the version number flag.

Now paste my script for the first time. If you paste it into K5 with the bus output at default and then change your bus setting and then hit apply again, you should get the 540px height both times.

Then, to test your script, repeat the above. If you have changed your $ver name to something different than mine, you may not have to clear the persistence buffer but it never hurts. Especially when testing something new to avoid confusion. Whenever you want to test a new script for the first time, it's always a good idea to first load the 'empty' script to clear the buffer. Otherwise, some previously loaded script may have left a persistent value with the same name as some p var in your script.

I have never had occasion to change the bus channel in K5 so I'm not sure I would know how to do it. As I understand it, the problem that we expect to arise is that after setting the channel to zero, both K4 and K5 will then report 0 when the ep is read. Can you briefly describe the procedure to change my bus channel in K5 to zero and then how I can change it back to the default? If it's easy to do, I could then perform the full test here as well for comparing notes.

Rejoice,

Bob


----------



## polypx (May 21, 2013)

Sorry Bob, this is getting rather complicated. I probably did make a persistence mistake yesterday. 

Now, if I pasted your script DIRECTLY in a fresh K5 instrument, it sets the UI height correctly.

And if I make a fresh K4 instrument, it also sets the height correctly (for K4).

But if I save the K4 instrument and open it in K5, it doesn't open with a taller UI.

Can you verify that behaviour?

cheers, Dan

PS To change the bus settings of 1024 (which is bus 0), open the Instrument Buses section of the editor, and select Bus 1, the first in the top row. The default output is shown to be Output (Inserts) on the lower right... which is value -1. If you set it to output to St.1 then the value will be 0, the same as the result from a K4 instrument.


----------



## Big Bob (May 21, 2013)

Hi Dan,

Rosie just called me for breakfast but I'll check this out afterward and get back to you.

Rejoice,

Bob


----------



## Big Bob (May 21, 2013)

Hi Dan,

You are correct regarding the latest scenario you described where you save an instrument along with the script in K4. When such an instrument is loaded into K5, it won't open up the height. When I coded my proposed snippet, I was thinking of the following scenario. You add the script to a K5 instrument, change the channel setup from the default and then save the .nki along with the script. I was thinking that the concern was the next time you reload into K5.

Your scenario is of course more realistic and real life. To cover that situation I would modify my snippet as follows:

*on init*
``message("")
``*declare* $Ver
``read_persistent_var($Ver)
``*if* ($Ver#-1)
````$Ver := get_engine_par($ENGINE_PAR_OUTPUT_CHANNEL,-1,-1,1024)
``*end* *if*
``set_ui_height_px(350-190*Ver)
``make_persistent($Ver)
*end* on





The idea is to keep reading the ep channel until the first time it is done in K5. Until the script runs in K5, the value of Ver will remain 0. However, once the script runs in K5, the value of Ver will change to -1 and will never return to 0 for any subsequent runs in K5. Even if K5's channel is changed, since it will never again read the channel. And, of course if the nki is saved in K5, it can't be read into K4 anyway so there is no worry in that direction. However, the original nki & script that was made in K4 will still continue to have Ver = 0 when loaded into K4, so everything should be cool.

Now regarding the final part of the test, I have not yet been able to perform it here. I'm probably doing something wrong but unfortunately I haven't been able to change the value returned by K5 when reading the ep output channel. No matter what I change the output setting to (with the dropdown), a read of the ep still returns -1. I've tried St, and Bus 1..16 but nothing changes. I've never had any occasion to use output or bus options so I'm probably missing some very fundamental step in the process. :oops: 

Rejoice,

Bob


----------



## Big Bob (May 21, 2013)

Ahhh, dumb, dumb :oops: 

Hey Dan, Please forget the last part of my prior post. I was changing the channel for Group 1 instead of the Instrument. I got my head back on now so let me finish my testing here and I'll report back.

Rejoice,

Bob


----------



## Big Bob (May 21, 2013)

Hi Dan,

Everything seems to work OK here now. If you save an instrument (with my last version of the script) in K4, all subsequent loads of that nki into K4 set the height to 350. Whereas as soon as the nki is loaded into K5, the height is set to 540. Any K5 re-saves of this instrument (with or without changing the bus assignment), always load into K5 with h = 540.

So, your idea still wins the Grand prize for

The Big K4/K5 Detection Contest

Rejoice,

Bob


----------



## polypx (May 21, 2013)

Hi Bob,

That last version runs perfectly here as well, so I think we have a nice concise solution.

I think you should win the prize tho, since you have it down to 7 lines of code. 

cheers!
Dan


----------



## Big Bob (May 21, 2013)

OK my friend, I'll split the prize with you :lol: 

Now let me see, how much is zero divided by 2 anyway :roll:


----------



## Sasje (May 22, 2013)

mk282 @ Tue May 21 said:


> MIDI functionality is not really useless, and those new constants are plenty useful - just because you don't use them doesn't mean they aren't valid.
> 
> Lua is all great and neat simple code, but it is several times more CPU intensive than KSP. I, for one, care about the additional overhead, especially with the scripts I write, and MF3 is definitely not yet optimized enough to be a true competitor to Kontakt's performance.



First Python is bad, then C is bad? Oh please... I mean, LUA is actually written in C. There is no performance issue at all. If that was the case, Kontakt's KSP should suffer from it as well. Do some intense scripting in KSP and see what it does to the CPU cycles. I wrote some pretty simple routines and Kontakt just went crazy when I turned a simple knob. Talk about performance... Native C support should yield a greater performance. Stability wise it can be argued upon, that's the only drawback I see. If I had to choose I pick the math/string support over a MIDI player in a sampler. Or I am just nuts to have this preference? 

I don't like to argue, but it seems that you're just disagreeing to disagree. Am I right?  

It's all I have to say. Back to schedule. :D


----------



## mk282 (May 23, 2013)

The fact that Lua is written in C doesn't mean anything - it's still less efficient than C, by quite a margin. My tests with MF3 in comparison with the same thing being done in Kontakt clearly showed this. Lua is less efficient than KSP, period.

KSP is written assembler IIRC. Can't beat that, sorry.


----------



## andreasOL (May 23, 2013)

Sorry for hijacking the thread...

IMO KSP will stay more efficient than any other scripting language as long as it does not provide concepts like true functions with parameters, classes, overloading, etc.

If I can implement the factorial of a number with a recursive function it looks elegant but has the stack handling overhead between each multiplication. If one has to do it with a loop (as KSP would require it) it is faster.

If I can define objects and classes with virtual functions and stuff there's additional look-up code necessary.

KSP can be compiled (and I hope it is ) to a stream of simple basic operations in the integer realm and very efficient address arithmethics for array usage. Most complicated stuff data-wise is probably the handling of string variables because they can have variable length which needs some garbage collection stuff happening from time to time. Apart from that everything is static in KSP. Calling a function with the call keyword does not need a stack because recursion is forbidden so the return address to the caller can be stored in a static place. The ui functions are implemented and optimized natively so there the nature of the scripting language is irrelevant.

So in my opinion it's the simpleness of KSP that makes it so fast or better: that allows it to be as fast as it is.

Cheers,
Andreas


----------

