What's new

KSP: get sample length

Fredeke

Senior Member
I may be splitting hair but...

Something that could be useful is knowing the total length of the sample that is being played. The only function I found in the doc is get_sample_length(<zone-ID>), but in order to know the zone-ID, I must know the zone-name: find_zone(<zone-name>) - which I suppose is the .wav's name.

It would be much easier to know the zone(s) that are being played in a group, ideally in relation to a triggering event. Is there a way to know that, or any way to know the total length of a sample being played, from the note or event that triggered it?
 
Last edited:
Yes.
In this case, if your goal is getting the lenght, yes, you need to get the ID, then get the lenght.

I'd recommend getting all the IDs with the blip trick, save the resulting array, loading the array on init mode 2, then using that array in the NCB, like this:

target lenght = target note + (target group * number of keys)

To make this simpler, you should probably use 128 for number of keys (as that's the max per group and doesn't require you to complicate things with inactive zones and asymmetrical group configurations).

There's nothing stopping you from getting the values in realtime if the NCB is simple enough, otherwise, go with the arrays and gain some extra processing time for more important stuff.

As with the blip trick, also use wait(1) if you go realtime ID retrieval.

Cheers.
 
Yes.
In this case, if your goal is getting the lenght, yes, you need to get the ID, then get the lenght.

I'd recommend getting all the IDs with the blip trick, save the resulting array, loading the array on init mode 2, then using that array in the NCB, like this:

target lenght = target note + (target group * number of keys)

To make this simpler, you should probably use 128 for number of keys (as that's the max per group and doesn't require you to complicate things with inactive zones and asymmetrical group configurations).

There's nothing stopping you from getting the values in realtime if the NCB is simple enough, otherwise, go with the arrays and gain some extra processing time for more important stuff.

As with the blip trick, also use wait(1) if you go realtime ID retrieval.

Cheers.
This would seem simple enough, once I know what the blip trick is. Could you please educate me on this?

There's nothing stopping you from getting the values in realtime if the NCB is simple enough,
Ah! I wouldn't exactly call my NCB simple ;).
But just for my education's sake, I'd be curious to know how you do that.
 
Last edited:
It's just a temp note, normally inaudible in order to produce a certain result.
The idea is to provide Kontakt with an artificial trigger.

Here's something ready to go. I think it should work (i'm not near kontakt atm).
With this, zone id will get -1 if no zone is found, and sample lenght will get 0 (or -1, i don't remember).

You could set this in an adjacent slot and change the save mode so it goes directly into your data folder, preferably your resources data folder to keep things organized.
When you're done, load the array from your init with the according mode.

When you're done changing zones, groups, etc and you don't need it anymore, you can just delete it.

Alternatively, keep it in your main code and just comment it out.
You could also use this in the persistence changed callback, for example.

If you got issues with the code, adjust the wait time. I set it to 10000, but machine modes may require higher values (and an optional fade out), you'll test it and see how it goes. But yes, careful with machine modes - they're glitchy sometimes.

Notice that i didn't use the internal $NUM_GROUPS variable to define the array size precisely because it's a variable, thus it can't be used to define array sizes, which would make this process more automated... :/

Code:
on init
    declare $blip_id
    declare $group_i
    declare $note_i
     
    declare const $GROUPS := 50
    declare const $NUM_KEYS := 128
     
    declare %zone_ID[$GROUPS * $NUM_KEYS]
    declare %zone_length[$GROUPS * $NUM_KEYS]
     
    declare ui_button $Save_Zone_Lgt
end on
 
on ui_control($Save_Zone_Lgt)
   
    $group_i := 0
   
    while($group_i < $GROUPS)
        $note_i := 0
        while($note_i < $NUM_KEYS)
            $blip_id := play_note($note_i, 1, 0, 1)
            set_event_par_arr($ALL_EVENTS, $EVENT_PAR_ALLOW_GROUP, 0, $ALL_GROUPS)
            set_event_par_arr($blip_id, $EVENT_PAR_ALLOW_GROUP, 1, $group_i)
            wait(1)
            %zone_ID[$note_i + ($group_i * $NUM_KEYS)] := get_event_par($blip_id, $EVENT_PAR_ZONE_ID)
            %zone_length[$note_i + ($group_i * $NUM_KEYS)] := get_sample_length(get_event_par($blip_id, $EVENT_PAR_ZONE_ID))
            wait(1000)
            inc($note_i)
        end while
        inc($group_i)
    end while

    save_array(%zone_ID, 0)
    $Save_Zone_Lgt := 0
end on

Cheers
 
get_event_par($blip_id, $EVENT_PAR_ZONE_ID)
Thanks!
I think I understand what you're doing.
And from your code I get that $EVENT_PAR_ZONE_ID is the var I missed in the doc, which is the key to answering my original question.

However, how does get_event_par($blip_id, $EVENT_PAR_ZONE_ID) know which group we're talking about? Does the command "magically" know that the only allowed group is the one to consider? I get that in your example, only one group is playing at a time, but out of curiosity: What would the command return if several groups were allowed in a note?

(I get the exchange about velocity, but that's not an issue here)
 
Last edited:
I'm not sure i get the question.

In the note callback you'd just (taking in consideration my previous example):

$sample_length := %zone_length[$EVENT_NOTE+ ($active_group * $NUM_KEYS)]
or
$sample_length := %zone_length[get_event_par($EVENT_ID, $EVENT_PAR_NOTE) + ($ACTIVE_GROUP * $NUM_KEYS)]

So, when each note is triggered, it gets the apropriate lenght value. You only need to update your active group.

If you want to filter out groups, use get_event_par_arr($EVENT_ID, $EVENT_PAR_ALLOW_GROUP, $active_group).
 
Alright. If you really want to do this on the fly...

Code:
on note
    wait(1) 
    %sample_lenghts[$EVENT_NOTE + ($ACTIVE_GROUP * 128)] := get_sample_length(get_event_par($$EVENT_ID, $EVENT_PAR_ZONE_ID))
end on

or

Code:
on note
    wait(1)  
    $sample_lenght:= get_sample_length(get_event_par($$EVENT_ID, $EVENT_PAR_ZONE_ID))
end on

Edit: You'll still need to define your array size on init to reflect the number of groups, and you do need to use an array to store multiple lenghts at the same time.
If this is not enough (multi layer setups), use poly vars.

Cheers.
 
Last edited:
I'm not sure i get the question.

In the note callback you'd just (taking in consideration my previous example):

$sample_length := %zone_length[$EVENT_NOTE+ ($active_group * $NUM_KEYS)]
or
$sample_length := %zone_length[get_event_par($EVENT_ID, $EVENT_PAR_NOTE) + ($ACTIVE_GROUP * $NUM_KEYS)]

So, when each note is triggered, it gets the apropriate lenght value. You only need to update your active group.

If you want to filter out groups, use get_event_par_arr($EVENT_ID, $EVENT_PAR_ALLOW_GROUP, $active_group).
Oh, yes, I get that the array would work without problem... I'm just surprised at one aspect of its generation: I guess what puzzles me is that the command get_event_par($EVENT_ID, $EVENT_PAR_ZONE_ID) doesn't require a specified group, even though more than one group could theoretically be allowed (although that is not the case in your code).

Alright. If you really want to do this on the fly...

Code:
on note
    wait(1)
    %sample_lenghts[$EVENT_NOTE + ($NUM_GROUPS * 128)] := get_sample_length(get_event_par($$EVENT_ID, $EVENT_PAR_ZONE_ID))
end on

Edit: You'll still need to define your array size on init to reflect the number of groups, and you do need to use an array to get multiple lenghts at the same time.
If this is not enough (multi layer setups), use poly vars.

Cheers.
I have been caressing that idea, but I must admit it won't work, because I'm trying to get the maximum amount of offset appliable in play_note() - that is, before getting the EVENT_ID allowing to retrieve the info. So the pre-generated table seems like the way to go.
 
Last edited:
I guess what puzzles me is that the command get_event_par($EVENT_ID, $EVENT_PAR_ZONE_ID) doesn't require a specified group, given that more than one group could theoretically be allllowed (although that is not the case in your code).
That's why we can filter groups. For situations like this. And you can indeed use multiple sample lenghts from different groups at the same time.


I have been caressing that idea, but I must admit it won't work, because I'm trying to get the maximum amount of offset appliable in play_note() - that is, before getting an EVENT_ID.
This is why my initial suggestion was creating the arrays first.
And, you can simply ignore the EVENT_ID (or not allow it with set_event_par_arr) and use the EVENT_NOTE (or whatever variable you'd like) to fetch the correct lenght from the array.

But even on the fly, get the lenghts from the $EVENT_ID, ignore it, do your calculations with the sample lenght, then do play note with the $new_id.
 
Don't forget you can just get all zone IDs by using Creator Tools and put it all in a lookup array. No need for blip note trick then, or find_zone etc.
 
Don't forget you can just get all zone IDs by using Creator Tools and put it all in a lookup array. No need for blip note trick then, or find_zone etc.
What about the users who don't own K6 or don't like to create arrays manually? :D
 
But even on the fly, get the lenghts from the $EVENT_ID, ignore it, do your calculations with the sample lenght, then do play note with the $new_id.
Yes indeed. I didn't think about that - thanks. (Except my NCB may be long enough as it is)
 
Last edited:
Hi guys, it's been a while, but reading this thread again after having let it rest makes it look much clearer. I get how simple it is now. (For example: of course zones in different groups have different IDs, so no need to mention the group). I just needed more than a couple nights of sleep before tackling this again ;)
 
Last edited:
Don't forget you can just get all zone IDs by using Creator Tools and put it all in a lookup array. No need for blip note trick then, or find_zone etc.

Would you mind telling how to do that in Creator Tools? There's a lot of info about zones, but I wasn't able to find anything about zone IDs. Is this possible by using some custom LUA script? Thanks.
 
Yeah you'd use a Lua script, however getting zone IDs is broken in latest version of CT unfortunately.

Code:
-- Check for valid instrument
if not instrument then
    print("Creator Tools are not focused on a Kontakt instrument! " ..
        "To solve this, load an instrument in Kontakt and select it from the instrument dropdown menu on top.")
end

local root = 60
local vel = 96

print("Zone IDs:")
for i, g in pairs(instrument.groups) do
    for n, z in pairs(g.zones) do
        if z.keyRange.low <= root and z.keyRange.high >= root and z.velocityRange.low <= vel and z.velocityRange.high >= vel then
            print(z.uniqueID)
        end
    end
end

Above checks all groups at MIDI note 60, velocity 96 and picks up the zone IDs and prints them out.
 
Yeah you'd use a Lua script, however getting zone IDs is broken in latest version of CT unfortunately.

Code:
-- Check for valid instrument
if not instrument then
    print("Creator Tools are not focused on a Kontakt instrument! " ..
        "To solve this, load an instrument in Kontakt and select it from the instrument dropdown menu on top.")
end

local root = 60
local vel = 96

print("Zone IDs:")
for i, g in pairs(instrument.groups) do
    for n, z in pairs(g.zones) do
        if z.keyRange.low <= root and z.keyRange.high >= root and z.velocityRange.low <= vel and z.velocityRange.high >= vel then
            print(z.uniqueID)
        end
    end
end

Above checks all groups at MIDI note 60, velocity 96 and picks up the zone IDs and prints them out.

Thanks! Hopefully it'll work again soon.

I guess if I want to check all zone IDs in each group then I'll need another for statement with a correct range, right?
 
No you would just remove that if clause and then it would get you zone IDs for everything in that group.
Ah right, I'm new to Lua :). I've did that and console returned a lot of '-1'. I guess that's because it's currently broken?

Is there a way to somehow copy the output of the console? Or maybe save it as a file?

EDIT: Nevermind the second question, found my answer in the manual, it's ⌘/Ctrl-Alt-C
 
Top Bottom