• SONAR
  • CAL Script: trigonometric operators?
2018/07/21 20:02:50
rogeriodec
I am building a CAL script that should emulate a sine wave for modwheel, but for this, I need to know if CAL has functions like SIN, COS, SQRT, etc?
2018/07/21 21:11:13
ZincTrumpet
I couldn't see any trig functions looking at the CAL script manual on this thread...

http://forum.cakewalk.com...tilities-m3392713.aspx

I guess you could use some kind of lookup tables with pre-calculated trig values or maybe there's a better way.
2018/07/21 21:18:34
msmcleod
There's two ways I can think of doing this:
 
1. Write an external DLL that exposes these functions for you that you can call from CAL
2. Implement your own SIN / COS routines in CAL. If you search for how old 8 bit computers did this before maths co-processors came along, you should find some examples of how to do this with simple math operators. 
 
 
 
2018/07/21 22:25:18
promidi
Have a look in your CAL folder for the cal script SINUS.CAL.  I think that will do what you need.
2018/07/21 23:07:11
rogeriodec
promidi
Have a look in your CAL folder for the cal script SINUS.CAL.  I think that will do what you need.


I don't have it, could you send me?
2018/07/22 17:38:14
msmcleod
I found this on the VGuitarForum: http://www.vguitarforums.com/smf/index.php?topic=11665.msg84641
 

;
; FOR EACH NOTE SELECTED...
; Write a series of controllers in a sine wave pattern
; for the duration of the note
;
; Parameters:
; Controller = CC#
; min = min value for CC
; max = min value for CC
; xtop & xbottom define the frequency
; The ratio of xtop to xbottom allows for fractions,
; e.g., 1 (xtop) / 2 (xbottom) means 1/2 cycle per note, & 4/1 = 4 cycles per note
; Offset = allows you to start waveform at different positions
; e.g., 90 starts at max, 270 starts at min, 0 & 180 start at midpt between max & min
;
;
; The SIN curve is created using Bhaskara I's sine approximation formula:
; SIN(x) = 4x(180-x)/(40500-x(180-x))
;
; The Bhaskara formula only works great for about the first 180 degrees,
; so I basically only really use the first 180 degrees & transform it
; for any other input value.
;
; sjrb, 7/1/14
;
;
; Prologue - Executed once at start
;
(do
; Init some Variables

; prompted user values - defaults
(int evController 12) ; selected controller
(long min 10) ; min value of waveform
(long max 120) ; max value of waveform
(long xtop 1) ; sin frequency - top (numerator)
(long xbottom 1) ; sin frequency - bottom (denominator), freq is in top/bottom (allows for fractions)
(long offset 0) ; offset in degrees - allows you to start at different places in waveform
; User Prompts (if desired... otherwise comment 'em out...)
(getInt evController "Input CC#" 0 127)
(getInt min "Input CC minimum value" 0 127)
(getInt max "Input CC maximum value" 0 127)
(getInt xtop "Input cycles/note numerator" 1 120)
(getInt xbottom "Input cycles/note denominator" 1 120)
(getInt offset "Input offset in degrees" 0 359)
; config stuff - mod these to change behavior
(long timeinc 120) ; distance between controller events in ticks
; event details
(long evChan 0)
(long evVal 0)
(long evTime 0)
; work variables
(long currTime 0) ; time being operated on
(long xval 0) ; input for sin calc (in degrees)
(long xresult 0) ; output of sin calc
(long xmod180 0) ; temp used during calc
(long xd180m2 0) ; temp used during calc
(long xf180x 0) ; temp used during calc
(long divisor 0) ; temp used during calc
(long ranged2 0) ; temp used during calc
(long temp 0) ; temp used during calc
; doesn't work too well if min > max....
(if (< max min) (do
(= temp min)
(= min max)
(= max temp)
))
; 1/2 range (max-min) is used in a couple places...
(= ranged2 (/ (- max min) 2))
)
;
; Body - Executed once per selected event
;
(do
(if (== Event.Kind NOTE) (do
(= currTime 0)
(= evChan Event.Chan)
(while (<= currTime Note.Dur) (do
; how far are you thru the note * freq = (time/dur) * (top/bottom)
(= xval (+ offset (/ (* (* currTime 360) xtop) (* Note.Dur xbottom))))
; Start of Bhaskara algorithm
; If you want to reuse this logic,
; load up xval with your input angle prior to getting here
; These mods & divs help me mirror 0-180 degrees for 180-360
(= xmod180 (% xval 180))
(= xd180m2 (% (/ xval 180) 2))
; x(180-x) is used a couple times in calc, so do it once here
(= xf180x (* xmod180 (- 180 xmod180)))
; Build the divisor used in the algorithm
(= divisor (- 40500 xf180x))
; This is where you reverse it if is 180-360
; Note formula modified by ranged2 here to scale it to min/max
(if (== xd180m2 0)
(= xresult (* 4 ranged2))
;else
(= xresult (* -4 ranged2)))
(*= xresult xf180x)
; This wraps up the Bhaskara algorithm, result now in xresult
(/= xresult divisor)
; Offset from min value...
(+= xresult min)
; Offset by 1/2 of range to keep everything +
(+= xresult ranged2)

; debug...
;(pause "input: " xval " output: " xresult)
;(pause "input: " xval " xmod180: " xmod180)
;(pause "input: " xval " xd180m2: " xd180m2)
;(pause "input: " xval " xf180x: " xf180x)
;(pause "input: " xval " divisor: " divisor)
; Do some safety edits, then pass result to evVal
(if (< xresult min) (= xresult min))
(if (> xresult max) (= xresult max))
(= evVal xresult)
; insert controller event
(= evTime (+ currTime Event.Time))
(insert evTime evChan CONTROL evController evVal)

; increment time...
(+= currTime timeinc)
)) ; End of While
)) ; End of IF NOTE
) ; End of Body

;
; Epilogue - Executed once at end
;
(do
(pause "Complete!")
)

2018/07/23 02:44:30
rogeriodec
msmcleod
I found this on the VGuitarForum: http://www.vguitarforums.com/smf/index.php?topic=11665.msg84641

 
Perfect. The magic of mathematics!
Thank you very much!
2018/08/04 23:59:05
rogeriodec
msmcleod
1. Write an external DLL that exposes these functions for you that you can call from CAL
 

 
Based in the CAL "DLL" syntax:
 
(DLL <”filename”> <procedurename> <argument1> .. <argumentN>)

 
 How can I get the RESULT of a DLL function?
 
Also, do you know some DLL for triconometric operations?
2018/08/05 01:01:21
msmcleod
rogeriodec
msmcleod
1. Write an external DLL that exposes these functions for you that you can call from CAL
 

 
Based in the CAL "DLL" syntax:
 
(DLL <”filename”> <procedurename> <argument1> .. <argumentN>)

 
 How can I get the RESULT of a DLL function?

 
That, I'm not sure of. The documentation on CAL in this area is pretty sparse.
 
At one point, I'm sure I came across some examples, but I've been unable to find them again - so many of these old CAL sites are no longer there, and internet archives such as the wayback machine only store so much.
 
If the DLL can't return a value, one (horrible hacky) way of doing it would be to get the DLL to write out the values to it's own CAL script, assigning the values to variables, and save this as a known filename to disk. The next line of your CAL program could include that file and use those variables.
 
rogeriodec
Also, do you know some DLL for triconometric operations?

 
I don't, but even if there was one it's unlikely it would help. All the documentation I've read on CAL DLL calls goes on about how fussy CAL is with regard to the "signature" of the DLL function - i.e. the parameter types have to be exactly as CAL expects/supports, else it'll crash CbB/SONAR.
 
By far the easiest approach would be to write a bunch of CAL "sub programs" that do the trig calculations, and use them as includes, within your scripts. This could be in the form of lookup tables (be careful of the 32K limit of CAL programs though), or as I said in an earlier post, you could look at other ways of approximating the functions (e.g. Chebsyshev polynomials, Bhaskara I)
 
I was lucky to find that CAL example in my previous post that shows how to do a SIN wave using Bhaskara's approximation, but my earlier post regarding 8-bit computers doing math without a math co-processor is still valid. 
 
For example, the Sinclair ZX81 (a 1K z80 machine released in UK in 1981) used Chebyshev:
 
see: https://www.tablix.org/~avian/spectrum/rom/zx81.htm  and search for "TRIGONOMETRIC" and also "SERIES GENERATOR"
 
 
© 2025 APG vNext Commercial Version 5.1

Use My Existing Forum Account

Use My Social Media Account