Home Page

Functions And Keywords Page

Alphabetical Index

Next Topic

Previous Topic

Sample Programs

Updates And Corrections

Assignment Functions

Without the ability to alter the values in variables, a program wouldn't be of much use. It is with this in mind that we now introduce the various ways that we can manipulate the variables listed in the previous section. Remember, all of the "operations" you will be looking at in this section are bonafide functions. That means that the way the elements of the operation are ordered will follow the rules of function syntax and as such probably look a bit weird to you at first. Just keep in mind that as with all functions, the function keyword (or in most of these cases, key symbol) comes first followed IN PROPER ORDER by the arguments that will be operated on.

Declaration Statements

(int name value)
This declares an integer that you can name whatever you want. In this example it is called "name". You should use names that help remind you of the variable purpose such as "highnote" or "counter". It's a good idea to conserve memory by keeping the name simple and short. After the name comes the value it will be initialized to. If nothing else, initialize it to zero. You can also initialize a variable to the value of another variable so long as the latter has been declared and initialized. Suppose you declare a variable like (int range 12) and you want to declare another variable later that equals "range". Also suppose that in the meantime, "range" has been subjected to other functions and so it's value is unknown. You could do it like this:

(int lowpoint range)

and now "lowpoint" will be initialized to whatever value currently resides in "range". You could also have declared "lowpoint" and initialized it to zero at the same time you declare "range" and then when the time comes just set "lowpoint" equal to "range" like

(= lowpoint range)

which is the usual course of action. If you are one of those efficiency freaks that must use the absolute minimum number of statements to perform a task, you can save yourself the extra "equal" function by declaring at the time of assigning the value instead. Another way to save a few bytes is to chain the declaration of like variables. This means that you can list several variable names on the line after the "int" keyword, each separated ("delineated" in geek speak) by a space, and then at the end given an initial value. All of them will be initialized to that same value. Such a statement might look like this:

(int first second last loop lownote highnote maxvel minvel temp 0)

In this statement, all of the variables listed from "first" through "temp" would be declared as integers and initialized to zero. I don't like to do this because as luck would have it, at some point I might need to change the initial value of a variable as I'm shaking down my program and would have to edit this statement to remove the offending variable and then write a new one just for it. I like to keep my variables separate so all I have to do to change them is alter one statement. It also makes them easier to read and keep track of. Remember that an "int" has a range of 32676 to negative 32767 so be sure all of your integer variables will stay in that range throughout the running of your program.
(word name value)
This statement declares a word variable named "name" with an initial value of "value". Everything mentioned above applies here. Its range is limited to positive numbers and can go from 0 to 65536.
(long name value)
This declares a long variable. It is able to swing plus or minus 2.14 billion. Again, the rules are the same as noted above.
(dword name value)
This declares a double word called "name" initialized to a value of "value". These variables are positive only and can range from 0 to 4,294,967,295. Everything said about "int" applies here as well.
(string name "This is a bunch of text")
And now for something completely different! Here we have a variable declared as a string called "name" and initialized to the text enclosed in quotes. Strings can be very useful when we want our CAL program to generate track names or some such. Like it's kin above, you can chain declare multiple string variables and initialize them all to the text in quotes, but I see little use for such an occurrence. There's a limit to the size of a string variable, 126 characters. Rarely would a string of more that a two dozen characters be needed, so that issue will probably never come up in general use.
(undef name)
This function "undefines" or erases from memory the pocket occupied by a variable and deletes its name from the list of declared variables. It works on any variable you have declared using any of the above data types. This is a way of freeing up memory for new variables after a current one has outlived its usefulness. It can come in handy for erasing large variables like double words to make room for more integers for example. From time to time I have run into the limits of CAL's ability to keep up with too many variables. The use I tend to put this function to the most is undefining variables that an included program declares but doesn't need to pass back to the parent program. See the section describing the "include" function.

Input Functions

Once we declare a variable, it's fair game! However, there will be many times when the operation of a CAL program will depend on the ability of the user to set some of the parameters. Thus, we come to the "get" statements. There is a "get" statement for the integer and word and a special way of entering a double word as we will see shortly. There is no input statement for the string. Shame, this, as it would be nice to input strings from time to time. But, alas, we have not the luxury. As far as the numerical variables go, we are free to query the user for input at any time using the following statements:
(getInt name "Prompt the user with this text" minimum maximum)
(getWord name "Prompt the user Etc..." minimum maximum)
As should be obvious, each statement is meant for a specific data type. Note how the "get" part is in lower case and then without any space comes the name of the data type with it's first letter capitalized. Next comes the name of the variable we are giving the user the opportunity to change. After that comes some text in quotes that will serve as the prompt for the user. It can be anything you wish to convey, just limit it to less that a screen's width because the resulting dialog box will spill off the screen. Last come the restrictions you can place on the user's response in the form of two values. This is optional but recommended. The first is the smallest, or in the case of an "int", the most negative value you will allow. The second is the largest value allowed. As I mentioned earlier in this document, I like to leave a space or two at the end of the prompt before closing the quotes. The reason is that the dialog box displays a small window after the prompt containing the current value of the variable and a blinking cursor. The spaces allow a bit of esthetic room between the text and that little window. The user can just hit ENTER or click OK and accept the current value or can enter a new value and then hit ENTER or click OK. If they attempt to enter a value outside the limits you have set with "minimum" and "maximum", an error box appears displaying those limits and allows the user to try again until an acceptable value is entered. Your choice of "minimum" and "maximum" will depend on the nature of the variable. If you are requesting a MIDI channel number, the limits should be 1 and 16. If you are requesting they input a pitch, you would use 0 and 127 as your limits and so on.
(getTime name "prompt text requesting a time in M:B:T format")
This is a bit different in that the user is to enter a time value in measures, beats and ticks which CAL will convert into raw time and assign to the double word variable "name". This variable MUST be of type "dword" and have already been declared. Keep in mind that you can have a "tick" value of zero, but "beat" and "measure" must be a value of at least 1. Also, if you enter a beat that doesn't exist, such as 6 in 4/4 time, or a value of "tick" greater than the value set in "TIMEBASE", CAL will convert the values anyway by multiplying the number of "beats" by "TIMEBASE" and adding to the result the value in "ticks". If you reconstruct the raw time back into M:B:T time (see "makeTime" in the Musical Time Functions page), all of the values will be corrected to display a proper time given the "meter" and "TIMEBASE" values in use during that Cakewalk session. The other difference is that CAL will not allow the use of "minimum" and "maximum" limits for "getTime". Attempting to use limits results in a "wrong number of arguments" error at run time.
IMPORTANT NOTE: This feature has a bug in it for versiosn 7 and 8. The (getTime) dialog, which is supposed to request user input in M:B:T time, instead will only accept raw time. While this new ability to input double words is a great addition to the instruction set, it comes at the cost of an already well established feature. As a result, all CAL programs that depend on the user entering time in M:B:T format are totaly hosed for versions 7 and 8.


Assignment Functions

The following are mathematical assignment functions. They start with the most basic, the "equals" function, but then slide into a gray area between assignment and math. I will list them here before the mathematical functions they emulate because they do possess assignment characteristics.
(= variableA variableB)
This "equal" function assigns the value of "variableB" to "variableA". Take a close look at the sentence you just read! It is "variableA" that will be assigned and "variableB" that holds the master value that will be passed on by the "=" function, not the other way around. In English it would read "Make variableA equal to variableB". Don't get confused on the direction of flow in this and all following math functions, as it is easy to do given the odd syntax of CAL. Not surprisingly, you can replace "variableB" with a constant like "From", or even another function. For example, you could have something like

(= lowrange (- Note.Key base))

Here, the variable "lowrange" is set equal to the result of subtracting "base" from "Note.Key". Notice the brackets. The function "-" with its two arguments must be enclosed by its own set of brackets, but this does not lessen the necessity of enclosing the "=" function with a complete set of brackets as well.
(+= variableA variableB)
This is an assignment function that acts as a form of shorthand for making a variable equal to itself as modified by some other variable. In English, this would read "Make variableA equal to the result of adding variableB to it". As with any equation, variableB can also be a constant or another function. In CAL longhand, it would read

(= variableA (+ variableA variableB))

By the way, the double use of "variableA" in this longhand example is legal. You can use the same variable as both destination and source because CAL first does the calculations and then passes the result to the destination variable. This way, the contents of variableA are safely preserved until after it is used in the calculation, and only then it is changed to its new value. The "+=" function is simply a bit more efficient.
(-= variableA variableB)
(*= variableA variableB)
(/= variableA variableB)
These are just like the first example except they represent subtraction, multiplication and division respectively.
(%= variableA variableB)
This fellow may take some explaining. The percent sign means find the modulo value. A modulo value is the remainder left over after dividing the first variable by the second. CAL does not see fractions, fractional amounts or decimal values. It deals strictly in whole numbers. Therefore, if you divide 9 by 8, you will get an answer of 1. You will get the same result for dividing 9 by 7, 9 by 6, or 9 by 5. The result of dividing 9 by 4 would be 2. The remainder left over by any of these divisions is only available by obtaining the modulo value. The modulo value from dividing 9 by 8 is 1, as that is the remainder from dividing them. For 9 by 7 the modulo value would be 2, for 9 by 6 it would be 3 and so on. We can use this value after performing a "divide" function for various purposes such as rounding. Using the modulo assignment function is a bit more obscure than the rest of our math assignments described above. We are more likely to use a modulo value in the conventional math functions.
(++ variable)
Here is a special case of a combo math / assignment function. This simply adds 1 to the value of "variable". This is referred to as "incrementing" a variable and often happens in association with counting the occurrence of some kind of condition. Such things as counting the number of times a "while" loop has executed or tallying the number of notes encountered are handled by the "increment" function.
(-- variable)
This is the same thing as incrementing except it subtracts 1 from a variable. This is known as "decrementing" and has a lot of the same uses including countdown timers and so on. Keep in mind that it's a bad idea to let a variable decrement below zero unless the variable can handle negative numbers.


Next Topic Top Of Page