# Logarithm calculation withiin KSP?



## polypx (Jun 25, 2007)

Hi guys

I'm trying to find a way to find the cents difference between two frequencies within KSP.

There are no logarithms in KSP, and I can't think how else to do it.

I have Hertz values.. basically I generate a frequency by my algorithm, find the nearest key, and then want to detune it by the remainder, but that remainder is a Hertz difference and I need to know a detune amount in cents.

ie. I generate a value 439, find key 69, and need the cents offset. 
(I'm assuming the keyboard is equal tempered at A440.)

Any ideas much appreciated.

cheers
Dan


----------



## kotori (Jun 25, 2007)

Hi Dan
Please see Big Bob's math library.

Maybe it would be easier to do the calculations in millicents from the start though.


----------



## polypx (Jun 25, 2007)

Hi Nils

Ok, I'm trying to use the math library and your editor both for the first time. In this simple example, the editor compiles successfully.. but it still leaves a "Log2" in the output script which KSP doesn't understand of course. 



> import "KSPMath_V105.txt"
> 
> on init
> declare $f_1 := 440
> ...


I'm probably missing something really basic here, but if I can solve this simple example, I think I can take it from there.

cheers
Dan


----------



## kotori (Jun 25, 2007)

Hi Dan,
My script compiler doesn't have support for return values so instead of writing "$result := Log2($x)" you have to write "Log2($x, $result)". Please keep in mind that KSP only handles integer so for example 500/440 equals 1 when rounded. To keep precision you have to scale up before dividing, eg. 1000 * 500/440 equals 1136. I hope this helps.

Cheers,
Nils


----------



## polypx (Jun 25, 2007)

Or maybe I can't sort this out.  

I can't just scale up the ratio and use the logarithm from that. Darn!

I should have paid more attention in math class ...


----------



## kotori (Jun 25, 2007)

polypx @ Mon Jun 25 said:


> I can't just scale up the ratio and use the logarithm from that. Darn!



Why not? Let's say that A is the factor and x is the original value. Then log(A*x) = log(A) + log(x). Since log(A) is just a constant you can calculate it by hand so you have log(x) = log(A*x) - log(A).


----------



## Big Bob (Jun 25, 2007)

Hi Dan,

Before I elaborate on the scaling issues, etc, I'd like you to try out this little script and then tell me if this is the sort of thing you are trying to do.

*import* "KSPMath_V105.txt"

*on init*
``*declare* ui_value_edit F (8,13300,1)
````move_control(F,4,1)
``F := 440
``*declare* ui_button Calculate
````move_control(Calculate,4,2)
``*declare* pitch
``*declare* midi_note
``*declare* tune
``*declare* result
``*declare* scaled_ratio
``*declare* ui_label Info (3,5)
````move_control(Info,1,1)
````set_text(Info,'')
``*declare* ui_button Clear
````move_control(Clear,1,6)
*end on*

*on ui_control* (Clear)
``Clear := 0
``set_text(Info,'')
*end on*

*on ui_control* (Calculate)
``scaled_ratio := 512*F/440
``Log2(scaled_ratio,result)
``pitch := 120*result - 3900000
``midi_note := pitch/100000
``tune := pitch mod 100000
``show_results
*end on*

*function* show_results
``add_text_line(Info,'MIDI Note# = ' & midi_note)
``add_text_line(Info,'Tune upward by ' & tune & ' mcts')
*end function*



If this isn't precisely what you wanted, perhaps you could elaborate a little more?
Once I'm sure I understand what you want, I'll explain it all to you if you like.

God Bless,

Bob


----------



## kotori (Jun 26, 2007)

polypx @ Tue Jun 26 said:


> (Btw Nils, a couple niggles in the Mac version of your editor... pasting text into it gives a Python error (unknown error 0), and it doesn't accept ten-key entry of numbers.)



That's strange. I will soon try to make a Universal Binary version for Tiger, maybe it will work better than when I can update the UI library I use. Do most mac users use Tiger, btw?


----------



## polypx (Jun 26, 2007)

I'd say most of us stay updated. I'm currently on OS 10.4.9. Although there's a big updated coming very soon... new cat, not sure what type.


----------



## Big Bob (Jun 26, 2007)

> Bob, your script does EXACTLY what I need to do, and much more concisely than my version, so that's brilliant. Thank you! It's always a wonder to me when I see an expert write something in so few lines of code.
> 
> I'm going to try and move this into my big script and see if I get meaningful results.. I'm still coming to grips with Nils editor as well, so I may be some time



Hey Dan,

Glad to hear my example script 'fit the bill'. Would you like me to post the math and scaling theory that I used or do you think 'you already have it cold'? :wink: 

Let me know if you'd like me to post my worksheet steps. (I didn't want to clutter up this thread in case I had the wrong picture of what you wanted).

God Bless,

Bob


----------



## polypx (Jun 26, 2007)

Hi Bob

I don't want you to go through any more trouble than necessary.. but if the worksheet steps are lying around somewhere, please post them. 

I have a feeling that converting frequencies to midi + cent offset will be something I'll use again in future, so it will help me to understand exactly what the steps are.

All the best,
Dan


----------



## Big Bob (Jun 26, 2007)

Hi Dan,

All I have to do is type the equations from my scribbled notes and add a few comments so, it's no trouble at all to provide this (at least not while it's still fresh in my mind). Memory is my biggest problem these days :? 

The basic equation relating pitch to frequency is:

(1) p - p0 = 1200000 * lg(F/F0)

where p = pitch (corresponding to frequency F) in mcts
and p0 = pitch at the reference frequency F0

NOTE:' lg' is somewhat standard math notation for logarithm to the base 2

If we use F0 = 440Hz as our frequency reference, the corresponding reference pitch, p0 is 6900000 mcts above MIDI Note 0 (ie A3 = MIDI note 69 expressed in mcts above note 0).

Thus we can re-write equation (1) as shown next in equation (2):

(2) p = 6900000 + 1200000*lg(F/440)

where p = pitch in mcts (above MIDI Note 0) and F is the corresponding frequency in Hz.

Thus, equation (2) is the one we want to implement, but using the KSP's integer arithmetic package (with some help from the KSPMath module). The math library provides the 'lg' function in the form: Log2(x,lgx) where 'x' is an input integer argument in the range from 0 < x < 16384 and the result 'lgx' is equal to lg(x) scaled up by a factor of 10000.

Thus, to maintain a reasonable amount of precsion, we want to scale F/440 to produce an integer value no larger than 16383. For the MIDI note range (0..127) the corresponding frequency range is about 8Hz to 12600Hz. So if we scale F by K = 512, the value of K*F/440 will be about 14662 for Note 127. This is pretty close to the log2 math library limit of 16383 and should suffice. We could scale it just a tad more but it was 'convenient' (though certainly not necessary) to scale by an integer power of 2 to make it a little easier to understand.

Now, rewrite (2) with the scale factor included as shown in equation (3):

(3) p = 6900000 +1200000*lg(K*F/440) - 1200000*lg(K)

which if we choose K = 512 = 2^9, reduces to equation (4)

(4) p = 1200000*lg(512*F/440) - 3900000

Now, we replace the 'lg' math operator by the library function' log2' (which remember provides its result scaled by 10000), and we obtain equation (5)

(5) p = 120*log2(512*F/440) - 3900000

Equation (5) is the desired 'magic' equation that gives us p = pitch in mcts (above note 0) for any frequency F in Hz.

I hope you find this useful.

God Bless,

Bob


----------



## polypx (Jun 26, 2007)

Hi Bob,

Very very useful! Thank you... I know this isn't really the 'math revision forum', but that's very kind of you. 

I like the fact that the reference pitch (440) stays in the equation... I guess if necessary this could be a variable and be adjusted if a script was to be used at something other than concert pitch.

Thanks again, I've archived this into my 'lessons' folder.

All the best, 
Dan


----------

