Variables, Constants And Data Types
There are five data types in CAL and each is of somewhat different use. The main
difference between the types is the size of number it can hold (aside from the
"string" type, which is for text). Each can be assigned to a variable of your
own making, but which is best for what kind of variable depends on the use to which it
will be put. Here's a rundown of the five types listed by the abbreviation you will use
when referencing them in a CAL program. Note that they must be spelled exactly as you see
them here in order for CAL to recognize them.
- This stands for INTEGER and is the most common data type. It can hold a value from
positive 32676 to negative 32767. You will use the "int" data type for most of
your flags, loop counters, temporary buffers, and just about anything that doesn't involve
large values. There is an important exception. If you are going to scale values, that is,
take a number and multiply it by some factor and then divide it back down to a smaller
number again, don't forget to take into account that the variable must be big enough to
hold the temporary results of such scaling even if the final result would be well within
the limits of an integer type.
- A word is the same number of bits as an integer (16 bits) but goes from 0 to 65536. In
other words, it is a positive only value. Note durations are stored as "word"
values. Again, if you are going to be playing around with a duration value, you might want
to declare a variable larger than this one just in case you send the value over the top at
some point before you have a chance to correct it.
- Now we have a 32-bit value that can range from roughly positive to negative 2 billion.
Here's some room! This is a good variable to declare if you think you will be over-ranging
an integer's value during calculations. Also a good variable type for working with note
durations that might exceed the limits of a "word" during calculations.
- This is the big daddy of variable types. A "double word" is an unsigned 32-bit
value that can range from 0 to over 4 billion. Event times are stored as double words.
There is no variable type bigger, but none is likely to be needed in that 4 billion ticks
at 120 ticks per quarter note would run almost 9 million measures. Even Wagner would have
had a hard time writing a score that long!
- A string is a series of ASCII characters, or to put it simply, it is text. You can
declare strings, build strings and send strings to some functions that use text, but
unfortunately, you cannot input a string during the running of a CAL program.
Variables and Constants
There are several built-in variables and constants that CAL provides for our use. The
most important for everyday use are the constants that correspond to the types of events
in a sequence and the various parameters or data variables that belong to each one. The
following list should be memorized if you plan on doing a lot of work in CAL. Again I must
stress that you must use exactly the same spelling, capitalization and punctuation format
as you see here in order to use them. Note that many CAL internal variables have a period
between words, use capital letters in the middle of names and other odd things. As a
useful convention, CAL constants are named with all capital letters so they are easy to
to keep in mind; if you are writing code that will be using event constants that are only
recognized by later versions of CAL, and you want the code to be backwards compatible with
earlier versions, don't reference these constants by name but by the number they equal. If
you use the name, the versions of CAL that don't support them will give you an error
message and refuse to run. On the other hand, if you use the number, then CAL will simply
use this number and dismiss the result without issuing an error. For example, suppose you
wish to hunt for RPN events in a program that otherwise is just as useful in Cakewalk
versions other than 6 or above. If you use a function like:
(if (== Event.Kind RPN)
CAL versions below 6 will go belly-up. On the other hand, if you write it like this:
(if (== Event.Kind 9)
Cal versions 6and above will still respond true if they find an RPN event and other
versions of CAL will simply return results during the comparison that reflect they were
either unsuccessful in finding an event that doesn't exist in any sequence that could be
loaded into that version of Cakewalk, or they found something they don't know by name but
never the less spotted by value.
- CAL manages this variable and you should not attempt to assign it a new value. CAL gives
it a value based on the specific event in the sequence currently being accessed during a
"forEachEvent" loop. The specific number this variable holds is of little
importance in that is usually isn't necessary to view or calculate with it. Just for the
record, the number it holds will be 144 if the event is a note, 176 if the event is a
controller, 224 if the event is a pitch wheel and so on. The reason you don't need to know
this (except for compatibility issues as noted above) is that there are constants in CAL
(see below) that equal those numbers and all we need to do is see if
"Event.Kind" is equal to one or more of them. Note that the two words
"Event" and "Kind" have a period and no spaces between them. This will
be the case with allot of these CAL variables, so pay attention to this detail.
- All events have this parameter. CAL fills it with the "raw" time of whatever
event is being evaluated by the "forEachEvent" loop. It can also be assigned a
value to change the time of an event or when inserting events. It is of type
"dword" and so can be from 0 to over 4 billion.
- All events also have a MIDI channel number as part of their data pattern. CAL puts that
channel number in this variable when an event is being scanned by the
"forEachEvent" loop. There are two things to remember about event channel
assignments. First, this channel number will have no baring on what channel the event will
be sent over if the track in which it resides has a channel assignment. The track channel will
always override the event channel. If the track has no assigned channel, then the event
channel determines the final channel it will be sent over. Second, even though we number
the MIDI channels from 1 through 16, CAL numbers them one digit lower from 0 to 15.
Therefore, if an event or track lists on the screen with a channel assignment of, say, 5,
CAL will call it channel 4. This can be confusing, so keep alert to this quirk. As a side
note, the same is true for track number assignments. We see tracks 1 through 256 and CAL
sees them as 0 through 255. It's a binary thing.
- This is one of the constants that allow us to test "Event.Kind" and also to
assign the event within an "insert"
function. Simply put, "NOTE" always equals the number 144, which is the CAL
value for a note event.
- This variable is one of the parameters of a "NOTE" event. It contains the
pitch number of the note. It is of type "int" or integer and can range in value
from 0 to 127. CAL fills in this variable with the pitch value whenever
"Event.Kind" equals "NOTE", and you are free to work with, calculate
with or even change this value if you want to alter the pitch of the note event.
- Here is another parameter of a "NOTE" event. It is of type "int" and
contains the velocity of the note. It can range in value from 0 to 127. Like Note.Key, CAL
fills in the value for us whenever the current event is a NOTE and we are free to use and
change it as we see fit in order to effect the note's velocity.
- The duration of the note event is available to us through this variable. It is of type
"word", can range from 0 to 65535 and is provided by CAL when the
"Event.Kind" equals "NOTE". Changing this value moves the MIDI
"note-off" message for that note back and forth in time relative to the
- This is the constant that holds the value 176 for a controller event. Like
"NOTE", we use this constant to, among other things, test "Event.Kind"
to see if the current event is a controller.
- CAL sets this variable with the controller number value for events that are of the
"CONTROL" kind. For example, a value of 7 corresponds to a volume controller
event and 10 to a pan controller event. Changing this value changes the type of controller
we are working with. This variable is of the "int" type and can range from 0 to
- The value or strength of a controller event is placed in this variable. It is an
"int" and ranges from 0 to 127. Changing this value changes the amount of
controller action for this event.
- This constant identifies a pitch wheel event. It equals 224.
- Here we have a variable that can be positive or negative. It is of type "int"
and ranges from 8191 to -8192. When we have a "WHEEL" event, CAL fills in this
variable with the pitch bend amount. We are free to change it as we see fit, but remember,
be prepared to deal with either a positive or negative value.
- This constant equals 192 and denotes a patch change event.
- As you might guess, this is the patch number associated with the "PATCH"
event. It is an "int" from 0 to 127.
- The instrument bank can be found or changed in a PATCH event as well, and this variable
contains the bank number. It can range from -1 to 16384 with -1 meaning
- The key aftertouch event is denoted by this constant of 160. Some synthesizers do not
recognize this event, and still others will receive it but not send it.
- CAL fills in this variable with the pitch number when it sees a "KEYAFT"
event. Like "Note.Key", it is an "int" from 0 to 127 and denotes the
pitch or in this case, the physical key number associated with the event.
- CAL gives us this value when the "Event.Kind" is a "KEYAFT". Like
the "Note.Vel" variable, it is of type "int" and denotes the strength
of the aftertouch in values from 0 to 127.
- This "Event.Kind" constant is equal to 208 and is the channel aftertouch
event. Again, not all synthesizers use it.
- The one variable associated with a Channel Aftertouch event holds the strength of the
aftertouch. It is an "int" and can be from 0 to 127.
The following constants allow an "Event.Kind" test to locate these events in
a sequence, and yet there are no provisions for viewing, accessing or changing the values
associated with them. This makes their use rather limited to merely hunting for this type
of event but not being able to do anything with it once it has been found except deleting
them! Never the less, I list them here mostly because, for many of them, their existence
as they relate to CAL is undocumented. These constants are only available in the versions
of Cakewalk that support these data types as part of their feature package.
- This constant equals 0 and is for a System Exclusive Bank message. Its existence is
documented as a CAL constant even though it is impossible to access the data associated
with the event. Such manipulations may be possible in versions 6 or above through the
StudioWare feature depending on what you intend to do.
- These events have the actual bytes to be sent as part of the event data. Again, none of
this data is accessible. The constant value is 8.
- Text events equal 1. They are sort of like notes you write to yourself and place in the
sequence to serve as documentation or reminders. In some cases, you may want to enter
lyrics this way instead of using a LYRIC event.
- This constant equals 2. The data associated with this event is a single syllable or word
that is to be sung at that instant in the song. These lyrics can be displayed during
- An MCI command tells Windows to do something with one of its multimedia devices at
that instant in the song. See the user manual or the Windows Multimedia Programmers'
Reference for more details. Its constant value is 4.
- This value of 3 corresponds to the "Audio" events that can be added to a
- Expression events equal 5, and can be inserted into a sequence in the "STAFF"
view. They guide a musician in the performance of a piece.
- These events correspond to the Diminuendo and Crescendo marks available in the
"STAFF" view. Their constant equals 6.
- Chord names can be added to a sequence to assist guitar players following along with the
music. These events are entered in the "STAFF" View. The constant equals 7.
- RPN and NRPN
- The RPN or Registered Parameter Number, which equals 9, and NRPN or Non-Registered
Parameter Number, which is 10, are events used by Cakewalk versions 6 and above as sort of
controller event shorthand. Cakewalk gathers certain CONTROL events and merges them into
RPN and NRPN events to save space among other reasons. Each RPN or NRPN event contains two
numbers, a parameter value and a data value, each being a number between 0 and 16383. The
fact that the values associated with these events are not available to CAL is a major
pain. It is now impossible for a CAL program to, for example, interrogate or alter the pitch
bend depth instructions in a sequence because the CONTROL events that effect this
parameter are converted into a single RPN event and thus placed out of reach! If access to
such controller events is important to you, such as the example of accessing pitch bend
depth, then see the section called Tips, Techniques And
Work-Arounds under the sub-heading Preventing CAL
From Gathering Controller Events for a way around this problem.
- If you want to keep the RPN event function and still want a convenient way of changing
pitch bend depth from the Event List view, the following chart should prove valuable. To
change the bend depth for most General MIDI compatible synthesizers, you would issue 3
controller events. The first would be controller number 100 with a value of 0. The second
would be controller number 101 also with a value of 0, and the last would be controller
number 6 with a value corresponding to the number of semi tones you want the bend range to
have. Some instruments also require a forth controller event to terminate the string. It
is controller 38 with a value of 0. The RPN event that does the same thing will have two
digits associated with it. The first will be a parameter value of 0 and the second will be
a data value number equal to the number of semi tones of bend depth multiplied by 128. For
example, if you wanted to set the bend depth to plus or minus an octave, or 12 semi tones,
the controller sequence would be:
- Controller 100, value of 0
- Controller 101, value of 0
- Controller 6, value of 12
- Controller 38, value of 0 (not always needed)
The same job would be done by the single RPN event having a parameter value of 0 and a
data value of 1536. The following chart outlines all RPN data values for bend depth ranges
from +/- 1 to +/- 24 semi tones. In all cases, the RPN parameter value is 0.
(+/- semi tones)
RPN Data Value
(Depth X 128)
These next constants have to do with timekeeping and CAL version detection.
- This constant is the number of ticks per quarter note the user has selected for keeping
time in Cakewalk. The default value Cakewalk provides when it is installed is 120 ticks
per quarter note, but can be changed by the user. Because CAL sees time as the number of
ticks from the start of the sequence (referred to as "raw" time) and humans see
it as the number of measures, beats and ticks in the composition (referred to as M:B:T
time), this value is an important factor in equations that must take both time keeping
systems into account.
- This variable corresponds to the position of the bar cursor in the sequence and holds
the value visible in the "NOW" time window on the screen. It's the place where
playback would start if the "PLAY" button were clicked on the front panel. It has
little use in CAL. There are some strange limitations to the size of numbers this marker
variable can hold. Even though it is 32 bits wide, assigning it a number close to that
limit can crash some Cakewalk versions earlier than 7. See the section called Tips, Techniques And Work-Arounds under the sub-heading Hidden Traps In The CAL Editor for more information.
- This variable is the same as the "From" marker in the Cakewalk front panel. It
is the starting point for the "selected" part of a sequence. This value can be
changed during the running of a CAL program any place OTHER THAN within a
"forEachEvent" loop. This makes sense in that the "forEachEvent" loop
operates on events starting at the time stored in "From" and so cannot alter its
own starting point. "From" is of type "dword" and so can range from 0
to over 4 billion. If, during a CAL program, you change the value stored in
"From" before a "forEachEvent" loop, the loop will start at this new
location in the sequence. Thus, you can make the assigning of this variable, and so the
starting point of the loop, subject to conditions or calculation results within the
program itself. This can be very handy! Keep in mind, however, that just as Cakewalk will
not allow you to assign "From" a number larger than the value stored in
"Thru", neither will CAL. The offending value will be automatically reassigned
to correct the condition.
- "Thru" is the same as "From" except, of course, being the end marker
of the selected part of a sequence. Everything said above about "From" applies
- The final marker variable is really a "read-only" variable. It holds the
location of the end of the sequence and thus cannot be changed from within a CAL program.
- This constant contains the version of CAL currently running on the user's computer. It's
undocumented, but useful as an error checker. A test should be made at the start of every CAL
program to make sure the user has the proper version of CAL to run the program. This is
most conveniently done using the "include" function to run a small CAL program
called NEED20.CAL from within any larger program to check this "VERSION" value
and abort if it shows that an incompatible version of CAL is running. If you are creating
CAL programs that can only run on higher versions of CAL, you can edit this
"NEED20.CAL" program to test for, say, CAL version 3, 4 or so on instead of 2.
After the edit, save the new program under a name like "NEED60.CAL" or whatever.
- This is a constant that holds a value of 1. This constant is used in functions that
require a Boolean value of yes or no in order to signify the selecting or de-selecting of
some parameter. For example, if you are setting up an "EditCopy" function, there
are arguments that correspond to the check boxes used to set up the EDIT menu COPY
command. In order to translate to CAL the act of checking or unchecking these boxes, the
corresponding variables will be given a value of 1 for checked or 0 for unchecked. It is
allowable to substitute the constants TRUE and FALSE for 1 and 0 in these arguments.
- This constant is the other side of the TRUE/FALSE coin. It holds a value of 0. See the
definition for TRUE above for details.