# KEY_DOWN_OCT pitch shifting problem



## zzprod (Jul 30, 2012)

hi
Just starting playing with scripts after reading nils scripting tutorial.
What I'm trying to do is to have Kontakt lower the tune of a selected note in all octaves. I'm almost there, but after lowering the note, sometimes it affects also the adjacent note (if I play legato).
How can I solve this problem?
here it is:

on init
make_perfview
declare ui_button $C
declare ui_button $Db
declare ui_button $D
declare ui_button $Eb
declare ui_button $E
declare ui_button $F
declare ui_button $Gb
declare ui_button $G
declare ui_button $Ab
declare ui_button $A
declare ui_button $Bb
declare ui_button $B
end on

on note
if ($C=1 and (%KEY_DOWN_OCT[0]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($Db=1 and (%KEY_DOWN_OCT[1]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($D=1 and (%KEY_DOWN_OCT[2]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($Eb=1 and (%KEY_DOWN_OCT[3]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($E=1 and (%KEY_DOWN_OCT[4]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($F=1 and (%KEY_DOWN_OCT[5]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($Gb=1 and (%KEY_DOWN_OCT[6]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($G=1 and (%KEY_DOWN_OCT[7]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($Ab=1 and (%KEY_DOWN_OCT[8]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($A=1 and (%KEY_DOWN_OCT[9]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($Bb=1 and (%KEY_DOWN_OCT[10]=1))
change_tune($EVENT_ID,-50000,0)
end if
if ($B=1 and (%KEY_DOWN_OCT[11]=1))
change_tune($EVENT_ID,-50000,0)
end if

message("%KEY_DOWN_OCT state: " & %KEY_DOWN_OCT[0] & " " & %KEY_DOWN_OCT[1] & " " & %KEY_DOWN_OCT[2] & " " & %KEY_DOWN_OCT[3] & " " & %KEY_DOWN_OCT[4] & " " & %KEY_DOWN_OCT[5] & " " & %KEY_DOWN_OCT[6] & " " & %KEY_DOWN_OCT[7] & " " & %KEY_DOWN_OCT[8] & " " & %KEY_DOWN_OCT[9] & " " & %KEY_DOWN_OCT[10] & " " & %KEY_DOWN_OCT[11])
end on


----------



## ScoringFilm (Jul 30, 2012)

@zzprod,

You mention playing legato; is there any other script at work here, either before or after this one? The reason I ask is because many scripts are simply incompatible/contradictory and will cause unpredictable results.

Regards,

Justin


----------



## zzprod (Jul 30, 2012)

No, there isn't any other script, and it happen just when I play legato.


----------



## ScoringFilm (Jul 30, 2012)

OK,

You may need an array to store each note's properties. At the moment the script just reacts to the $EVENT_ID which may be the problem.

I'm not at my desktop at the moment so can't help. I'll have a look if I get chance tomorrow.

Regards,

Justin


----------



## Raptor4 (Jul 30, 2012)

Hi,
It seems you have posted this topic in a few KSP forums by now. I tried to reply you in the NI forum a few days ago (where my nick is Tangra) - did you read that reply ?


----------



## zzprod (Jul 30, 2012)

ScoringFilm said:


> OK,
> 
> You may need an array to store each note's properties. At the moment the script just reacts to the $EVENT_ID which may be the problem.
> 
> ...



great. thanks



Raptor4 said:


> Hi,
> It seems you have posted this topic in a few KSP forums by now. I tried to reply you in the NI forum a few days ago (where my nick is Tangra) - did you read that reply ?


thank you for the reply. I don't believe it's KEY_DOWN_OCT fault, which only signals which key is pressed. makes more sense it's $EVENT_ID which is common to all notes. I know the factory preset you mentioned but I'm trying to do it in a different way and to use the ui_button like in arabic keyboards.


----------



## mk282 (Jul 31, 2012)

$EVENT_ID has an unique value for each note that is played. It's not "common" for all notes.


----------



## Raptor4 (Jul 31, 2012)

> I don't believe it's KEY_DOWN_OCT fault, which only signals which key is pressed.


Definitely,
When you play legato sometimes you have not released the previous key so that's the issue. I tried to add a "Monophonic" feature (get it below and try), but it did not fix your problem. The monophonic feature kills the previous played note via $EVENT_ID, but physically the key is still down. So KEY_DOWN_OCT must be replaced with some other alternative, that's why I gave you an example with the factory script. Have a look at its main engine and try to redesign it using UI buttons to emulate the Arabic keyboards.

```
on init 
  declare ui_button $mono 
  declare $last_id 
  make_persistent($mono) 
end on 

on note 
  if ($mono = 1) 
    note_off($last_id) 
  end if 
  $last_id := $EVENT_ID
end on
```
Regards,

R4


----------



## zzprod (Jul 31, 2012)

mk282 @ Tue Jul 31 said:


> $EVENT_ID has an unique value for each note that is played. It's not "common" for all notes.


yeah bad choise of words. It's just that I have a feeling that EVENT_ID is more likely to be the reason for that. KEY_DOWN_OCT just turns 1 in one cell at a time.


----------



## Lindon (Jul 31, 2012)

Your not checking that you've processed a note, so lets look at your code...

on note 
if ($C=1 and (%KEY_DOWN_OCT[0]=1)) 
change_tune($EVENT_ID,-50000,0) 
end if 
....


first time thru you press a C...

$C1 = 1 and the octave is correct(say) so the script changes the tuning for the event it has received...

Now (whilst still holding down the C) you press a D

$C1 is still = 1 and the octave is still correct (say) so it changes the tuning on the note to hand..(in this case the D)...basically the bit of code above is going to process all notes in the relevant octave no mater what, and I think you are just trying to process the C...


Try this instead:

```
if $C1= 1 and (%KEY_DOWN_OCT[0]=1))
  if ($EVENT_NOTE mod 12) = 0   {its a C thats been pressed..}
     change_tune($EVENT_ID,-50000,0) 
   end if
end if
```


----------



## mk282 (Jul 31, 2012)

I think this can be done with a lot less code in the note callback (and with added flexibility of ui_table for per-note detune offsets):


```
on init
    make_perfview
	set_ui_height_px(110)

    declare ui_switch $C
    declare ui_switch $Db
    declare ui_switch $D
    declare ui_switch $Eb
    declare ui_switch $E
    declare ui_switch $F
    declare ui_switch $Gb
    declare ui_switch $G
    declare ui_switch $Ab
    declare ui_switch $A
    declare ui_switch $Bb
    declare ui_switch $B

    declare ui_table %detune[12] (6,4,-100)

	declare $i

	$i := 0
	while ($i < 12)
		set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_X,67 + (45 * $i))
		set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_Y,86)
		set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_WIDTH,46)
		set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_TEXT_ALIGNMENT,1)
		inc($i)
	end while

	set_control_par(get_ui_id(%detune),$CONTROL_PAR_WIDTH,545)
	set_control_par(get_ui_id(%detune),$CONTROL_PAR_HEIGHT,81)
	move_control_px(%detune,66,2)

    make_persistent($C)
    make_persistent($Db)
    make_persistent($D)
    make_persistent($Eb)
    make_persistent($E)
    make_persistent($F)
    make_persistent($Gb)
    make_persistent($G)
    make_persistent($Ab)
    make_persistent($A)
    make_persistent($Bb)
    make_persistent($B)
    make_persistent(%detune)

	message("")
end on

on note
    if (get_control_par(get_ui_id($C) + $EVENT_NOTE mod 12,$CONTROL_PAR_VALUE) = 1)
        change_tune($EVENT_ID,%detune[$EVENT_NOTE mod 12] * 1000,0)
    end if
end on
```


Done. 




zzprod @ 31.7.2012 said:


> mk282 @ Tue Jul 31 said:
> 
> 
> > $EVENT_ID has an unique value for each note that is played. It's not "common" for all notes.
> ...



But it isn't the reason for that. Lindon explained it well - since you've made an "if" branch for each key, when you play legato, KEY_DOWN_OCT[0] will remain at 1 while you hold C when legatoing to D, which will of course detune both keys.


Try my code, it works and it's simpler. Why did I use ui_switch? Because they are automatable/MIDI learnable, ui_buttons are not! Also, having persistent buttons is always a nice thing 


I wonder why didn't you use the factory microtuning script, though...


----------



## Lindon (Jul 31, 2012)

Wow Mario...


```
if (get_control_par(get_ui_id($C) + $EVENT_NOTE mod 12,$CONTROL_PAR_VALUE) = 1)
```

..using the declare sequence as a kind of array....and indexing it with the mod-ed $EVENT_NOTE....

very, very elegant.

L


----------



## zzprod (Jul 31, 2012)

thank you all for the help.
The reason I don't use the factory preset is because I don't want this detune table, only on/off (-50 cents/0 cents) buttons. I'm using a touch screen and trying to hit the -50 cents point is kind of hard.
mk282's script is much better for me because of the buttons, I just wish it had all the culumns constant at -50 and then I can even hide the table and just use the buttons.
anyway, that was my first script and I don't know half the functions use used...
thanks again
ZZ


----------



## mk282 (Jul 31, 2012)

zzprod @ 31.7.2012 said:


> thank you all for the help.
> The reason I don't use the factory preset is because I don't want this detune table, only on/off (-50 cents/0 cents) buttons. I'm using a touch screen and trying to hit the -50 cents point is kind of hard.
> mk282's script is much better for me because of the buttons, I just wish it had all the culumns constant at -50 and then I can even hide the table and just use the buttons.
> anyway, that was my first script and I don't know half the functions use used...
> ...




Why don't you say it's a touchscreen involved here! Then just use this:



```
on init
	make_perfview
	set_ui_height(2)

	declare const $DETUNE := -50000

	declare $i
	declare %black[5] := (1,3,6,8,10)

	declare ui_switch $C
	declare ui_switch $Db
	declare ui_switch $D
	declare ui_switch $Eb
	declare ui_switch $E
	declare ui_switch $F
	declare ui_switch $Gb
	declare ui_switch $G
	declare ui_switch $Ab
	declare ui_switch $A
	declare ui_switch $Bb
	declare ui_switch $B

	$i := 0
	while ($i < 12)
		if (search(%black,$i mod 12) # -1)
			if ($i > 5)
				set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_X,80 + (42 * $i))
			else
				set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_X,40 + (42 * $i))
			end if
			set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_Y,10)
		else
			if ($i > 4)
				set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_X,80 + (42 * $i))
			else
				set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_X,40 + (42 * $i))
			end if
			set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_POS_Y,54)
		end if
		set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_WIDTH,76)
		set_control_par(get_ui_id($C) + $i,$CONTROL_PAR_TEXT_ALIGNMENT,1)
		inc($i)
	end while

	make_persistent($C)
	make_persistent($Db)
	make_persistent($D)
	make_persistent($Eb)
	make_persistent($E)
	make_persistent($F)
	make_persistent($Gb)
	make_persistent($G)
	make_persistent($Ab)
	make_persistent($A)
	make_persistent($Bb)
	make_persistent($B)

   message("")
end on

on note
	if (get_control_par(get_ui_id($C) + $EVENT_NOTE mod 12,$CONTROL_PAR_VALUE) = 1)
		change_tune($EVENT_ID,$DETUNE,0)
	end if
end on
```


----------



## zzprod (Jul 31, 2012)

in one word: Perfect!
in two words: mk282 rules

How do one learns advanced scripting for kontakt?
I read Nils Liberg tutorial which is great but it's only the basic commands.


----------



## matthiasA (Aug 1, 2012)

Practice


----------



## ScoringFilm (Aug 1, 2012)

matthiasA @ 1/8/2012 said:


> Practice



+1

So much of KSP is undocumented and it really is a matter of trail and error sometimes. Of course this forum helps enormously!


----------



## mk282 (Aug 1, 2012)

zzprod @ 1.8.2012 said:


> in one word: Perfect!
> in two words: mk282 rules



Thanks 



zzprod @ 1.8.2012 said:


> How do one learns advanced scripting for kontakt?
> I read Nils Liberg tutorial which is great but it's only the basic commands.



A lot of practice. Previous programming experience is really valuable. KSP Reference contains the descriptions of almost all KSP commands (some are not yet in there, for unexplicable reasons - but those would be rarely used anyways, all the most important ones are in the reference).

I've been doing this for 3 years now. My first scripts weren't much better than your initial attempt. :D


----------

