# Coarse & Fine Tuning



## armageddonbeatz (Jan 7, 2012)

Hi there,

I'm really new to KSP programing and currently diggin' into it. The basics so far I have understood and creating and coding GUIs is no problem. So I want to dig now "deeper" into this topic.

I'm currently working on a test library where I have the idea to have two "tune" knobs. The first one manages the semitones in total called $coarse (-36s/+36s), the second one works as "fine tune" with a semitone (-50c/+50c) called $fine. So that's the idea.

Here's the code i have:


```
{ *** begin script *** }
on init
	{ *** general settings *** }
	message ("")
	make_perfview
	declare $count
	
	{ * declare an amount of knobs * } 
	declare const $standard_knob_uid := 2
	
	{ * declare knobs  * }
	declare ui_slider $coarse (0,1000000)
	declare ui_slider $fine (486050,513950)
		
	{ * standard knobs array *}
	declare %standard_knob_id[$standard_knob_uid]
	%standard_knob_id[0] := get_ui_id($coarse)
	%standard_knob_id[1] := get_ui_id($fine)
	
	{ * set grafix *}
	$count := 0
		while ($count < $standard_knob_uid)
			set_control_par_str (%standard_knob_id[$count],$CONTROL_PAR_PICTURE,"myknob")
			set_control_par(%standard_knob_id[$count], $CONTROL_PAR_MOUSE_BEHAVIOUR, -500)
			inc ($count)
		end while

	{ *** set default values *** }
	$coarse := 500000
	$fine := 500000
	
	set_control_par(%standard_knob_id[0],$CONTROL_PAR_DEFAULT_VALUE,500000)
	set_control_par(%standard_knob_id[1],$CONTROL_PAR_DEFAULT_VALUE,500000)
end on

{ *** coarse *** }
on ui_control($coarse) 
	set_engine_par($ENGINE_PAR_TUNE,$coarse, 0, -1, -1)
end on

{ *** fine *** }
on ui_control($fine) 
			set_engine_par($ENGINE_PAR_TUNE,$fine, 0, -1, -1)
end on
{ *** end script *** }
```

So as you may see the problem is at the moment - that *$fine* overwrites *$coarse* and vice versa. So my question is how can I manage this in the code that I first set a certain tuning with $coarse and then finetune with $tune?

Any help, hint or tip is really appreciated!

Thanks,
Bob


----------



## Mike Greene (Jan 7, 2012)

I would use _"get_engine_par (x,x,x,x)"_ first in the ui_control callback, so that I know what the tuning was before the knob was touched. That way you can extract the course or fine parts of the existing tuning that you'd want to keep (keep the course part if the fine knob is touched, etc.) Then do whatever math is necessary, and *then* use the _"set_engine_par (x,x,x,x,x)"_ command to plug in the new tuning.


----------



## paoling (Jan 7, 2012)

I'd prefer to use two variables ad use


set_engine_par($ENGINE_PAR_TUNE,$coarse+$fine, 0, -1, -1) 

for both.


Generally you have different methods when you want multiple parameters to affect the same property.

The first is the above, the second is to have a variable that keeps track of the sum of those values. In this way you can save some calculations in callbacks like the NCB (note callback). The sum is not a problem, but you could have a very complex equation to evalutate each time.
The third method is the Mike Green's one that is good, but it could a bit complex since you need to calculate the exact interval every little step that the knob can do (and I don't know if you can loose some values). Doing maths while you move a control is something that you need to control very well, since it could slowdown your script due to the CPU calculations. 

In short: try to avoid RELATIVE calculations like: 
tune:= tune-offset
or the relative KSP functions like change_tune($event_id, $tune, 1)

Apart from exotic effects like fade_outs, glissandos, and so.

Paolo


----------



## Mike Greene (Jan 7, 2012)

If there aren't any other complicating factors, Paolo's way is the way to go. I didn't even think of that. :roll:


----------



## paoling (Jan 7, 2012)

There are some differences between programming and the human thinking, and this thing doesn't end to amaze me. 

Your solution was more "human". If you want to add some water to a glass you just add that water to the glass. But CPUs tends prefer to trow that water away and redo the calculation (this is not always the case, animation is often an example of the contrary).

I'd like to read something about this theme, since my approach in programming tends to be a lot like a direct translation of my thoughts, but sometimes the most intuitive solution is not the best one. It's like thinking Italian and then translate to English... Uhm I've just realized that I've 2 problems now.


----------



## armageddonbeatz (Jan 8, 2012)

Thanks Mike and paoling for your replies!



paoling @ Sat Jan 07 said:


> In short: try to avoid RELATIVE calculations like:
> tune:= tune-offset
> or the relative KSP functions like change_tune($event_id, $tune, 1)



You are completely right! To be honest such a similar solution came first into my mind but I have learned really fast that this is a huge complex thing. So this is what I want to prevent from begining on - relative calculations.

This is what lead me to think about if there is possibly another solution which I am because of my fresh and small knowledge of KSP not aware of at the moment.



paoling @ Sat Jan 07 said:


> set_engine_par($ENGINE_PAR_TUNE,$coarse+$fine, 0, -1, -1)



Hm this seems a cool thing but in the end at least if I implement this in the code I will get the problem that TUNE will always calculate $coarse+$fine and this will not solve my problem? Do I need to do some math thing here?

In the end I want is: I want to tune a sample with $coarse in semitones. After that I want to do some fine tuning on base of $coarse in a +/- 50cents range.

Example: Tune with $caorse to -12 semitones. And after that finetune the sample with $fine to -12.34. 

So $fine only influences the digits after the point. $coarse only before.

I don't have any idea yet how to get this coded :cry:


----------



## paoling (Jan 8, 2012)

I'm not sure that I understand correctly.

If I'd were you I'd use not the group tune setting, since you have to calculate a relation between knob values (0-1000000) and semitones (this is not difficult, but why make your life complex?)

The usual way is the change_tune($EVENT_ID, $TUNE, 0) function.
With this function you aren't limited by the group tune range, and you just can avoid strange mathematical calculations.

if the Fine tune knob range is -100000 to 100000 and the coarse tune knob is -12 to, for example, 12 you can just use the function in the note on part. 
So
on init
declare ui_knob $fine (-100000,100000, 1000)
declare ui_knob $coarse (-12,12, 1)
end on

on note
change_tune($EVENT_ID, $coarse*100000 + $fine, 0)
end on

Paolo

EDIT: 
Keep in mind that EVERY knob inside Kontakt have a range of 0 to 1000000. This is for everything you can change with set_engine_par. In short you can't change the Tune knob thinking in terms of semitones, you should make a proportional calculation, that could work for that setting in particular, but for other engine parameters the equation could be different (logaritmic or custom calculations by NI)


----------



## mk282 (Jan 8, 2012)

Here's how I do it if I utilize $ENGINE_PAR_TUNE to change, for example, the tuning for group 1:


```
on init
	declare ui_knob $Coarse (-35,35,1)
	declare ui_knob $Fine (-100,100,100)

	set_knob_defval($Coarse,0)
	set_knob_defval($Fine,0)

	$Coarse := 0
	$Fine := 0

	make_persistent($Coarse)
	make_persistent($Fine)

	message("")
end on

on ui_control ($Coarse)
	set_engine_par($ENGINE_PAR_TUNE,500000 + ($Coarse * 13888) + ($Fine * 139),0,-1,-1)
end on

on ui_control ($Fine)
	set_engine_par($ENGINE_PAR_TUNE,500000 + ($Coarse * 13888) + ($Fine * 139),0,-1,-1)
end on
```


I would avoid using change_tune() if absolutely not necessary, because you can adjust $ENGINE_PAR_TUNE in realtime, but change_tune() is only evident on new key press, not in realtime.


----------



## Big Bob (Jan 8, 2012)

Hmmm



> I would avoid using change_tune() if absolutely not necessary, because you can adjust $ENGINE_PAR_TUNE in realtime, but change_tune() is only evident on new key press, not in realtime.



I don't think this is true. Again, it may be faulty memory on my part but I think even a sustaining note will respond to pitch changes, at least this is true if you use the set_event_par form of change_tune because I use it all the time.

I also have to disagree with Paolo regarding avoiding relative tuning, etc. The fact that we now have access to all of the key event parameters (via set/get_event_par) means we can finally write scripts that can be chained with other scripts and still work properly. Ffor example, even when both scripts twiddle with the the tuning, by using both relative tuning and passing on 'inherited' tuning in each script we can make them work together.

Someday when I get enough time I intend to post a set of guidelines that can be followed for script compatibility, utilizing some of the new K4 features added to the KSP.

Rejoice,

Bob


----------



## paoling (Jan 8, 2012)

Yes, set_event_par (don't know change_tune) works even in realtime, but it is a bit tricky to get it work properly for all the events that are playing. But set_mark function can help indeed. 
About relative functions, this was something I realized slowly working on my last script: how can you overcome rounding errors if you add and subtract values according to various parameters, ensuring that there possibly be a 0 point when the values are at their default?

And another question: how do you solve the problem of incremental calculations when moving the knob? (I can't explain better in english, this is when you move the knob and the system is recalculating the values according to the difference between the last knob value and the current one and then adding that value to the current knob state, after the processing to render it compatibile))


----------



## paoling (Jan 8, 2012)

I'm asking this since I have several things (knob, equations, realtime values) in my script that affects the same properties, like tuning, note volume and so, so I'd like to understand if there's a better way to update those properties than:
function update_vol
change_vol($NOTE_ID, (insert the very complex equation here), 0)
end function
recalculating this everytime a parameter of the equation changes.


----------



## Big Bob (Jan 8, 2012)

Hi Paolo,

Unfortunately right now, I don't have enough time to discuss this thoroughly but I can say that you are sighting some problems that really have very little to do with whether one is doing relative tuning or absolute tuning. Furthermore, I think we might be viewing this from quite different angles.

Let me use a simple example of the sort of thing I'm thinking of.

Script B wants to retune the input note by 1875 mcts so it uses:

```
set_event_par(id,EVENT_PAR_TUNE,1875)
```
This is all well and good but, supposing that a prior Script A has TKT'd the note by 100000 mcts (This would arise for example if the TKT script lowered the MIDI note# by 1, let's say c3 has been changed to b3, and compensated by retuning it up by 100000 mcts). What's coming out of Script A is a note that sounds like c3. Now, Script B wants to sharpen the c3 by 1875 mcts but, if the above code is used, the result will be B3 sharpened by 1875 mcts.

The way to avoid this rather easily is to use the following:

```
set_event_par(id,EVENT_PAR_TUNE,get_event_par(id,EVENT_PAR_TUNE)+1875)
```

This is the kind of thing I'm talking about when I say 'relative tuning'. Unfortunately, as I indicated above, I don't have enough time to talk about arithmetic rounding issues with this post but maybe we can discuss this at some future point.

Rejoice,

Bob


----------



## paoling (Jan 8, 2012)

Ok, but looking through mk282 point of view of changing the value in realtime; for example with change_tune($EVENT_ID, $tune_interval, 1) {relative}

The knob behaviour is not so unimportant, IMHO, since you don't change the tune only in the NCB but even in the Controller Callback (CCB?), while you're moving the knob. (if you don't want to change it during an endless loop in the NCB).


----------



## Big Bob (Jan 8, 2012)

Yes, I understood the complications you were alluding to but, done properly, there need be no more complications with relative tuning than there are with absolute tuning. Unfortunately my time is too oversubscribed at the moment to go into all the gory details. Sorry, but like I said, maybe we can discuss this at some point in the future when things calm down a bit here.

I probably shouldn't have responded with something that may be perceived as controversial when I'm so short of time. Sorry :( 

Rejoice,

Bob


----------



## paoling (Jan 8, 2012)

Oh, don't worry Bob! 
Take your time, this is just a conversation, but I can't hide that I'm interested about your personal KSP teqniques; in the meantime I hope that armageddonbeatz has found a solution for his issues


----------



## mk282 (Jan 8, 2012)

This conversation is starting to get interesting!


I was always quite angry that factory microtuning script does not work with factory unisono/portamento script... The unisono/portamento script is well at 1800+ lines with very complex NCB, that even I can't quite unravel what the heck is going on around in there. And that script does not track polyphonic portamento well at all...


I just wonder why NI didn't program those scripts to be interoperable for K4, when they obviously enabled stuff like that with get/set_event_par commands, as per Big Bob's findings...


----------



## paoling (Jan 8, 2012)

I'm still quite puzzled why NI doesn't offer a native legato solution. Writing a good legato is still a nice and fun project to do, but with a factory standard system with lots of options about legato techniques, sampled/emulated, and so, it could be very very useful!


----------



## mk282 (Jan 8, 2012)

Yes, I sometimes wonder the same.


----------



## Mike Greene (Jan 8, 2012)

I can see why it might be a good idea . . . but I'm kinda thankful they don't. :mrgreen:


----------

