1. IMPORTANT:
    We launched a new online community and this space is now closed. This community will be available as a read-only resources until further notice.
    JOIN US HERE

Syntax for exponentiation? (KSP Math Library)

Discussion in 'Scripting Workshop' started by Jeremy Z, Apr 22, 2015.

  1. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hi Jeremy,

    Your numerical examples confirm that I must not understand just what this sync point is o_O. I originally thought that it represented the time it would take to get to some particular point in the sample when playing the sample with the lowest key (the zero wait condition).

    Obviously that is incorrect because if it were true, your 2nd example (root=60, lowest note=36, and current note=48) would result in something like a 12+ second wait. If you play a sample with key 36 and it takes 24+ seconds to reach the sync point, then, when you play that sample with key 48 it will take only 12+ seconds to reach that same point, so a wait of more than 12 seconds would be required for them both to reach the magic target at the same time.

    Please clarify for me just what this magic sync point is to help preserve my sanity:).

    Meanwhile, assuming that what you are trying to calculate is really what you want, let me take a look now at the scaling situation.

    Rejoice,

    Bob
     
    • Like Like x 1
  2. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Wow! Am I on Candid Camera or something?:)

    This get's weirder by the minute. Doesn't your 2nd example evaluate to 2*sync whereas you say it evalutates to 0.01028*sync?

    Maybe I've been smokin' something I shouldn't have ;)
     
    • Like Like x 1
  3. Big Bob

    Big Bob Forum Member

    Messages:
    606
    OK, I see what your scaling problem is but I'll wait until you check in and respond to the previous posts before I go through it with you.

    Rejoice,

    Bob
     
    • Like Like x 1
  4. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Hi, Bob! So $EVENT_NOTE-$lowestNote was an older issue. I think it was corrected by post #17.

    The sync point is used to align all instances of the sample at different playback rates to the same point in the original sample. So if the sync point is at 12 seconds when the sample is played back at it's normal rate (rate = 1), it would be at 24 seconds when the sample is playback half speed (rate = 0.5). BUT (here is the point of the code) I have to delay the sample playing back at it's normal rate (rate = 1) so that it's sync point at 12 seconds happens simultaneously with the half speed sample (the sync point is at 24 seconds).

    Real world, unexciting example: The sample is a cymbal swell with a ring out. Let's say at 5" the swell reaches its peak and then rings out after that. This is where I can put a sync point. I want all instances of the sample (played back at different rates) to meet at that sync point to create a larger than life cymbal swell. The instances with lower playback rates start first, as the sound progresses the higher rates enter until the highest enters last. They all peak together at the sync point.

    Hope that helps!

    Thanks very much for your help!
    -j
     
  5. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Ah! So, the sync point time is relative to the sample played with the root key and not the time to the event when played with the lowest note key. I agree then that the formula appears to be correct, however, what about your wait time calculation for the 2nd example? You indicated a result of 0.25 secs and I think it should be 48.654 seconds.

    In any case, I'll just assume that was an error and move on to helping you with the scaling problem. I'll need a little time to write down and post it but I'll try to fit this in before I quit for the day. One quick fix you can try would be to simply multiply the wait_time you are calculating by an additional factor of 10

    I'll explain this in my next post along with suggesting a better way to code this.

    Rejoice,

    Bob
     
    • Like Like x 1
  6. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Ug! Yes, the second example should have been 48.654. Sorry for the confusion.

    Correct about the sync point being relative to the sample played at the root key. Apologies for not explaining that from the start!

    Re the quick fix, wouldn't $waitTime*10 produce very long delays? Or am I misunderstanding (very possible).

    Many thanks, Bob.
    -j
     
  7. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hi Jeremy,

    For convenience, let's use the following symbolism shorthand:

    R0 = minFr = 2^((lowest_note - root_note)/12)
    Rx = currentFr = 2^(( current_note - root_note)/12)
    S = sync_time in msec
    W = wait_time = K*S

    K = 1/R0 - 1/Rx

    Your existing code first computes R0 and Rx scaled by 10^4. Then, you compute 1/R0 and 1/Rx using 10^6/R0 and 10^6/Rx. This makes your values for 1/R0 and 1/Rx scaled by 100 (10^6 / 10^4). Your S value is in msec and we require W to be in microseconds. So we need K to be scaled by 1000 instead of 100 as it is currently.

    Rather than just multiplying your wait_time expression by 10 you will get better precision if you compute your reciprocals with 10000000/R0 and 10000000/Rx.

    However, there is a better way to do this. Since all you need to calculate W are reciprocals of the frequency ratios, just compute these reciprocals directly by simply reversing the sign of the note differences.

    Since it is true that 1/2^X = 2^(-X) you can compute the reciprocals as follows:

    1/R0 = 1/minFr = 2^((root_note - lowest_note)/12)
    1/Rx = 1/currentFr = 2^(( root_note - current_note)/12)

    Because SExp2's output is currently scaled by 10^4, the reciprocals are then scaled by 10^4. So, now when you calculate K it will be scaled by 10^4 instead of 100 like it is now. Since we only want it to be scaled by 1000, we need to divide the W = K*S product by 10 to get it in us.

    Here is a little demo script that should clarify the foregoing.

    import "KSPMathV700.ksp"

    on init
    ``message('')
    ``SetMathMode(0, DG)
    ``declare lowest_note := 36
    ``declare root_note := 60
    ``declare sf``{ sync_tiime factor }
    ``declare current_note
    ``declare wait_time
    ``declare sync_time := 24327``{ msec }
    end on

    on note
    ``sf := K(lowest_note - root_note,EVENT_NOTE - root_note)
    ``wait_time := (sf*sync_time + 5)/10 { remove excess scale }
    ``message('wait_time = ' & wait_time & ' us')````{ delay in micro-seconds }
    end on

    function K(min_diff,current_diff)->result
    ``declare rfr1``{ reciprical frequency ratios }
    ``declare rfr2
    ``rfr1 := SExp2(-min_diff*250000/3)```````{ reciprical of minFr }
    ``rfr2 := SExp2(-current_diff*250000/3)```{ reciprical of currentFr }
    ``result := rfr1 - rfr2```{ K is scaled by 10000 }
    end function

    function SExp2(X) -> result``{ 10000*2^(X/1000000) }
    ``result := Exp2(X + 13287712)
    end function


    Hopefully the above will also answer your last posted question?

    Rejoice,

    Bob

    BTW if you post any more KSP code, please use the code tags so you don't lose all the formatting.
     
    Last edited: Apr 26, 2015
    • Like Like x 1
  8. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    What an awesome explanation. Thank you for this! I probably won't have a chance to try this until tomorrow night or Monday but I didn't want to wait that long to acknowledge your post. Thank you very much for your generosity.

    Cheers!
    JZ
     
  9. Big Bob

    Big Bob Forum Member

    Messages:
    606
    You're very welcome Jeremy, always glad to help when I can.

    Rejoice,

    Bob
     
    • Like Like x 1
  10. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Hi, Bob. This is so weird. Using your code, I still run into the same issue. Everything aligns fine down to a lowest_note of 38. 37 and lower and it no longer aligns to the sync point. However the equation seems fine. When I print 'wait_time' I see the expected result. Maybe there's a problem with the built-in 'wait' function?

    Here's my code:
    Code:
    import "KSPMathV700.ksp"
    
    on init
        message('')
        SetMathMode(0, DG)
        declare lowest_note := 36
        declare root_note := 60
        declare sf { sync_tiime factor }
        declare current_note
        declare wait_time
        declare sync_time := 24495  { msec }
    end on
    
    on note
        sf := K(lowest_note - root_note,EVENT_NOTE - root_note)
        wait_time := (sf*sync_time + 5)/10 { remove excess scale }
        message('wait_time = ' & wait_time & ' us')  { delay in micro-seconds }
        ignore_event($EVENT_ID)
        wait(wait_time)
        play_note($EVENT_NOTE,$EVENT_VELOCITY,0,-1)
    end on
    
    function K(min_diff,current_diff)->result
        declare rfr1  { reciprical frequency ratios }
        declare rfr2
        rfr1 := SExp2(-min_diff*250000/3)       { reciprical of minFr }
        rfr2 := SExp2(-current_diff*250000/3)   { reciprical of currentFr }
        result := rfr1 - rfr2```{ K is scaled by 10000 }
    end function
    
    function SExp2(X) -> result  { 10000*2^(X/1000000) }
        result := Exp2(X + 13287712)
    end function
    
    Many thanks!
    -j
     
  11. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Actually, the issue isn't tied to the lowest note exactly. It consistently arises when wait_time>approx 45 seconds!!
     
    Last edited: Apr 27, 2015
  12. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hi Jeremy,

    I wondered if you might have a problem associated with using the wait command. First off, it is not generally a very accurate or repeatable delay time because of the non pre-emptive multi-tasking system used for the KSP.

    I'm not aware of any special problems at specific wait times but they could well exist. Why don't you just run a separate test with values around 45 secs and a stopwatch?

    You might be able to work around the issues by breaking the long delay times down and issuing a series of shorter waits.

    If you are running in Sample mode, you might also consider reversing your logic and instead of delaying the faster playbacks you could offset the longer playbacks (using sample-start offset). Of course in DFD mode this might require such long S.Mod settings that it would use nearly as much RAM space as Sampler mode.

    Please let me know what you discover regarding this.

    Rejoice,

    Bob
     
    • Like Like x 1
  13. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Thanks, Bob. I think I can confirm that wait isn't working properly. I ran this simple script against a stopwatch and "TIME" came up around 41 seconds. :/ Here's the code:
    Code:
    on note
        message("")
        wait(1000000*50 )
        message("TIME")
    end on
    
    I tried dividing the wait times into several shorter delay times. Strangely it worked once. Running the same code, I couldn't get it to work again.

    Re your sample start offset idea, are you suggesting I start all but the highest instance after the beginning of the file? Because that would defeat the idea... :/ As far as I can tell, one can't add negative time to the start of the file, right?

    Many thanks!
    JZ
     
  14. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Well again Jeremy, maybe I still don't have the right picture here but, suppose for example that the sync point occurs in T seconds when you play the sample an octave above the root key.

    Then if you play the sample at the root key, the sync point will take 2*T seconds to hit, if you play the sample an octave below the root key, the sync point will occur in 4*T seconds. So, if you use a start offset of T seconds for the root key and a start offset of 3*T seconds an octave below the root key, the sync points should hit at the same time, no?

    You just sort of reverse the logic so that the highest key would use a zero offset.

    Like I said, maybe I just don't get it yet:)

    Rejoice,

    Bob

    BTW I'm thinking that I will probably add scaled versions of the Exp functions for the next library update. I think I'll provide a second argument to allow specifying the power of ten scaling, so something like SExp2(X,4) would produce what you are currently using to obtain 10000*Exp2(X).
     
    • Like Like x 1
  15. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hey Jeremy, if you decide to try the sample-start offset thing, before you go through the trouble of converting the math formula and such, you had better test Kontakt's accuracy and stability when using such long sample-start offsets. Since offsets are simply calculated as T/fs (instead of being measured) they should be accurate and stable but I would still check it out first.

    Bob
     
    Last edited: Apr 27, 2015
    • Like Like x 1
  16. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Thanks, Bob. I'm not sure I'm understanding your suggestion currently. My apologies!

    Sample offsets can only index after the start of the sample, yes (as opposed to adding silences to the start)? So a sample with a sample-start offset != 0 would start after the beginning?

    Best!
    -j
     
  17. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hi Jeremy,

    Yes, sample-start offset is some positive number of seconds into the sample playback. So, if you play a 5 second sample with an offset of 2 secs, only the last 3 seconds of the sample will play (ie starting from the 2 second point and through to the end of the sample). You sort of throw away the first 2 secs of the sample.

    Of course, to use the offset method, you will have to use a new formula where the former role of the lowest note will become the role of the highest note.

    The fact that you can't have negative offsets is no more of a detriment than the fact that you can't have negative delays with the other method. Your current method requires you to pair the wait=0 condition with the lowest playback key, the offset method requires that you pair the offset=0 condition with the highest playback key. I see no other differences between the two methods. If it works one way, it should be doable the other way also.

    If this is still not clear to you, let me know and I'll work out the revised formula for you and put together a demo script. But, before I do that you need to verify that long offsets are reliable and stable. Play the sample without offset and time it with a stopwatch to some sync point. Call this time Ts. Then play the same sample with (with the same key) using an offset of say Ts - 4 seconds. It should take about 4 seconds then to reach the sync point.

    But, again, remember that this scheme will require more RAM to hold the sample than it ordinarily would in DFD mode. The easiest way to test this though would be to simply switch to Sampler mode (at least until we're sure this works out for you).

    Clear as mud? :)

    Rejoice,

    Bob
     
    Last edited: Apr 28, 2015
    • Like Like x 1
  18. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hi Jeremy,

    I did a lot of testing with K4/5 and I'm just full of information and new algorithms for you:). However, I don't have time right now to write it all up and post it. But, the bottom line is very good news which you will soon see.

    I guess you've been rather busy also since you haven't checked in for a while but, please continue to keep your eye on this thread. I sure hope you haven't abandoned this topic because I have some really cool stuff to pass on to you.

    Probably in another day or two I should be able to post everything to date in some reasonably organized fashion and we can take it from there..

    Rejoice,

    Bob
     
    Last edited: Apr 29, 2015
    • Like Like x 1
  19. Jeremy Z

    Jeremy Z Member

    Messages:
    38
    Hi, Bob. sorry I've been out of the loop. I took a couple days off from the studio.

    That's very exciting news! I can't wait to see how you're approaching this! Just to be clear, I use the entire file at all different playback rates, not just the entire highest (ie shortest) file. So the lowest file starts first, second lowest next, all the way up to the highest file starting last. Not sure if that was clear.

    Many thanks!!!
     
  20. Big Bob

    Big Bob Forum Member

    Messages:
    606
    Hi Jeremy,

    Welcome back.

    I may not be clear on your latest statement. I kind of thought you were more or less playing one file at several different transpositions across the keyboard (polyphonically) and wanting each playback to reach the sync point at the same time regardless of what pitch transposition ie playback speed Kontakt is using. All this of course being achieved by delaying the faster playbacks (relative to the slowest playback ie lowest-note triggered).

    Your last post now sounds a little like maybe you also have multiple sample files involved? Hopefully, when you say something like the 'highest file' you just mean the common sample file played back with the highest key?

    Rejoice,

    Bob
     
    Last edited: Apr 29, 2015