Repeated note polyphonic limit with change_vol() applied specifically.

realdealpeel
realdealpeel Member Posts: 20 Member

For a series of same-note voices, I would like a script that does these things:


on 1st note:

do nothing.


on 2nd note:

change_vol of 1st to half of whichever is quieter of the 1st or 2nd.


on 3rd note:

change_vol of 2nd to half of whichever is quieter of the 2nd or 3rd.

change_vol of the 1st to be half of whichever is quietest of the three.


on 4th note:

change_vol of 3rd to half of whichever is quieter of the 3rd or 4th.

change_vol of 2nd to half of whichever is quieter of the 2nd, 3rd, or 4th.

kill the 1st.


Repeated this process, updating the queue. Hopefully this makes sense.


I found this script:

{limit polyphony per key}
on init
	message(" ")
	declare const $POLYPHONY := 3
	declare const $FADEOUT_TIME := 5000
	
	declare %event_id_map[$POLYPHONY * 128]
	declare $count
	declare $head

	$count := 0
	$head := $POLYPHONY * 128
	while ($count < $head)
		%event_id_map[$count] := 2147483647
		inc($count)
	end while
end on

on note
	$head := $EVENT_NOTE * $POLYPHONY
	$count := $POLYPHONY -1
	fade_out(%event_id_map[$head + $count],$FADEOUT_TIME,1) {kill the oldest note}
	while ($count >0) {move queue}
		%event_id_map[$head + $count] := %event_id_map[$head + $count -1]
		dec($count)
	end while
	%event_id_map[$head] := $EVENT_ID {save note id}
end on

...but it only limits the same-note polyphony. It doesn't do the change_vol().

And there are things I don't understand like:

while ($count < $head)
    %event_id_map[$count] := 2147483647
    inc($count)
end while

What the hell is 2147483647?

and

$head := $EVENT_NOTE * $POLYPHONY

Wouldn't multiplying the event note number by 3 just produce an irrelevant number?

and

while ($count >0) {move queue}
    %event_id_map[$head + $count] := %event_id_map[$head + $count -1]
    dec($count)
end while

I don't fully understand any function of the script tbh. And the KSP manual is not helpful with its examples. I feel like I've missed a decade of schooling required to understand the manual.

Any help is appreciated and as always, I'm happy to send cash to anyone with a solution.

Comments

  • stephen24
    stephen24 Member Posts: 257 Advisor

    Reverse engineering a script like that would be difficult even if experienced.

    2147483647 is 2^31 -1, the largest (32-bit signed) integer in KSP arithmetic.

    %event_id_map is an array, with 3 elements for each note. X3 finds a note's data in the array.

    Best I can do.

  • realdealpeel
    realdealpeel Member Posts: 20 Member

    Thank you, sir.

    I've done some back and forth with chatGPT all night and it seems the 2147483647 is used sort of as a placeholder for when no note events are present in a cell of the array. So initializing all cells with 2147483647 is the same as giving the array a blank slate to work with.

    Don't know why it has to be such a huge number when note numbers only go up to 127. 127 * 3 is only 381. Don't know why it can't be 0 either, as no one ever composes with C-2.

  • realdealpeel
    realdealpeel Member Posts: 20 Member

    Just to be clear, I still need a solution. If anyone can nudge me in the right direction, that would of course be awesome 😊

  • stephen24
    stephen24 Member Posts: 257 Advisor
    edited December 2023

    Don't know why it has to be such a huge number when note numbers only go up to 127. 127 * 3 is only 381. Don't know why it can't be 0 either, as no one ever composes with C-2.

    It's a sort of generic initialiser. Guarantees that any new number it's compared with will be smaller.

    If I wanted to do this (unlikely) I would start afresh. You would need 4 variables which would hold the last 4 note EVENT_IDs (which are just numbers), and shuffle them down the line with each new note, after you have performed the operations you want on them, changing volume or releasing. get_event_par would find the volume of any of these events, so you could do your calculations.

    (Can't see what polyphony has to do with it.)

    Good luck. If you can pull this off you'll have become a pretty skilled programmer.

  • realdealpeel
    realdealpeel Member Posts: 20 Member
    edited December 2023

    Thanks again, Stephen. Polyphony of same-notes is what I'm aiming to isolate and control. If I perform the script on all notes played, then for example, C4 will kill D4, which isn't realistic.

    Just think about when you play a repeated note on piano with the pedal pressed, the resonance might build up a little but after 3 notes or so, it equalizes out because the hammer action causes a brief dampening effect to the resonances of all the previous hits of that same note. You want that mixing of consecutive same-notes because it gives each repeated note a unique timbre, but you don't want it to build up forever in a computer because its not realistic and eats up headroom and muddies the mix.

    I've continued to attack this all morning and here is an update which mostly now does what I need!! I just need to add all the logic to determine the change_vol()s as well as that get_event_par() function you suggested, which I did find a few hours ago.

    I wouldn't call myself a skilled programmer, but I've learned that if you keep trying different, random things, eventually the thing will do what you want.

    on init
        set_script_title("Limit same-note poly, reduce same-note vol")
        declare const $p := 4 {same-note polyphonic limit}
        declare const $f := 5000 {fadeout time of killed note}
        declare %map[$p * 128] {no idea what this really means}
        declare $c := 0 {$c := count} {or this}
        declare $h := $p * 128 {$h := head} {or this}
        while ($c < $h) {or this}
            %map[$c] := 2147483647
            inc($c)
        end while
    end on
    
    on note
        $h := $EVENT_NOTE * $p {or this}
        $c := $p - 1 {or this}
        change_vol(%map[$h],-3000,1) {reduce 2nd note}
        change_vol(%map[$h + 1],-3000,1) {reduce 3rd note}
        change_vol(%map[$h + 2],-3000,1) {reduce 4th note}
        fade_out(%map[$h + $c],$f,1) {kill oldest note}
        while ($c > 0) {or this}
            %map[$h + $c] := %map[$h + $c - 1] {this is a logical contradiction!}
            dec($c){move queue}
        end while
        %map[$h] := $EVENT_ID {save note id}
    end on
    

    In this case, I've added a 4th sounding voice in cue and reduced each one by 3db. The rest of the logic will make the script longer and more complex, but more realistic. Although this is 10x better than nothing. I'll come back with the finished script later!

Back To Top