| KeyKit :: Language Reference Manual |
A primary goal of KeyKit has been to build a highly extensible system, therefore the built-in capabilities of the KeyKit language are intentionally minimal. The default user-defined function library contains KeyKit code for an extensive multi-window sequencer-like environment with sliders, buttons, and other tools for creating and editing MIDI music. A separate reference manual and tutorial describe this user interface. This document describes only those capabilities that are actually built into the KeyKit language.
If you're just getting started with KeyKit, this is not the document you want to read first.
variable assignment-operator expr
if ( condition ) statement [ else statement ]
while ( condition ) statement
for ( statement ; condition ; statement ) statement
for ( variable in array-name-or-phrase-expr ) statement
function { name | ? } [ ( arguments ) ] { statement(s) }
task expr ( arguments )
class name { method name (arguments ) {...} ... }
new name ( arguments )
return ( [ expr ] )
break
continue
#define name (args ) value
#include "filename"
#library "filename" function-name
eval string-expr
delete array-element-or-object
undefine variable
readonly variable
global variable
Any variable that is not global (either implicitly, because it starts with an upper-case character, or explicitly, because of a global statement or function) automatically becomes a local variable in the function in which it is encountered. Previous versions of KeyKit required that you "declare" local variables by including them as extra arguments in the parameter list of a function (as in awk). This is no longer required. So, local variables are created merely by using them.
a = [] a["foo"] = [0="hello",1="world"] print(a["foo"][1]) # Prints "world". b = [[0=0,1=1],[0=1,1=0]] # Creates 2-d array.
which may be followed in any order by these modifiers:a,b,c,d,e,f,g a normal note p# a normal note, where # is the MIDI pitch number r a rest
Some of the modifiers don't make sense (but are not disallowed) for some note expressions, for example the rest and pitch expressions will ignore the octave modifier. If any of these modifiers is omitted from a note expression, its value defaults to the value of that modifier for the previous note. For example, all the notes in the phrase 'ao2v90,b,f,d' would be in the 2nd octave and have a volume of 90. At the beginning of each constant phrase, the default values are: octave 3, volume 63, duration 96 (the number of clicks in a beat), channel 1.+ (sharp) or - (flat) o and an octave number (-2 to 8) v and a volume (0 to 127) d and a duration (in clicks) c and a channel (1 to 16) t and a starting time (in clicks relative to the beginning of phrase) ` and an attribute value (terminated with another grave quote)
The separator between notes in a phrase constant determines the default starting time of the next note. A comma separator (possibly surrounded by white space) sets the default starting time to the end of the previous previous note. Hence the phrase 'e,f,g' is equivalent to 'et0,ft96,gt192'. If there is no comma separator (ie. only white space) between notes, the default starting time will be the starting time of the previous note, so the phrase 'c e g' is a chord, equivalent to 'ct0,et0,gt0'. Naturally, an explicit time modifier on a note will override the default starting time implied by the separator.
As a convenience, the o preceding positive octave numbers can be omitted, e.g. b4 is b in the 4th octave. Negative octave numbers must be specified with the o, to avoid ambiguity with the - used for flats.
Normally, the length of a phrase constant is equal to the ending time of the last note. The length can be explicitly set by using an l (lower-case L) followed by the length in clicks. E.g. 'a,b,c,l96' would have a length of 96 clicks (even though some of the notes extend beyond that).
A normal note implies two MIDI messages, a note-on and a note-off. In some cases, you may want only the note-on or note-off. These can be specified with an initial + (for note-on) or - (for note-off). For example, '+a,-at96' is equivalent (in terms of MIDI output) to 'a'.
If two strings are combined with the + operator, the result is the concatenation of the strings. If two strings are compared with a relational operator (e.g. == != <= ), an ASCII string comparison is done. The ~~ relational operator can be thought of as a "contains" operator - the result is true if the first operand contains a substring that matches the second operand, a regular expression.&& || and, or | & ^ bit-wise or, and, xor == != < > <= >= ~~ equal to, not equal to, etc. << >> left shift, right shift + - addition, subtraction * / % multiplication, division, modulo - ! ~ unary minus, not, one's complement
- phrase + phrase
- The result is the concatenation of the 2 phrases in series, using the length (NOT the ending time of the last note) of the first phrase as the starting time of the second phrase.
- phrase | phrase
- The result is the merging of the 2 phrases in parallel, and the length is the maximum of the 2 lengths.
- phrase - phrase
- The result is a copy of the first phrase, after removing all notes that match notes in the second phrase.
- phrase & phrase
- The result contains all notes in the first phrase that exactly match notes in the second phrase.
- phrase % number
- The result is a single-note phrase containing the n-th note of the first operand, where n is the value of the second operand. For example, 'a,b,c'%2 would be equal to 'bt96'. Notice that the original time of the note is retained. This operator can also be used on the left-hand side of an assignment (e.g. ph%2='c' ) to replace (or delete, if the right-hand side is the null phrase, '' ) a single note of a phrase.
- phrase { condition }
- The result of this operation (referred to as a select), is a phrase containing all notes for which the given condition is true. The condition is repeatedly evaluated, with the special token ?? being replaced with each note in the original phrase. For example, 'c,d,e,f,g'{??.pitch>'e'} would be equal to 'ft288,g'.
- pitch
- MIDI pitch value (0-127).
- vol
- MIDI volume value (0-127).
- chan
- MIDI channel number (1-16).
- dur
- Note duration, in clicks.
- time
- The starting time of a note, in clicks, relative to the beginning of the phrase in which it resides.
- length
- The length of a phrase, in clicks. This attribute is independent of the duration and placement of notes within the phrase. It's primary use is in the semantics of the phrase+phrase operation; the starting time of the second phrase is the length of the first phrase.
- type
- This attribute of a note indicates what type it is (for example, whether it's a note or a sysex message). The possible values are pre-defined constant values, and a list is given below.
- number
- Within the conditional expression of a select operation, this attribute can be used to refer to the position (starting at 1) of a note within the selected phrase. For example, the expression 'a,b,c'{??.number>2} is equivalent to 'c'.
- attrib
- This string-valued attribute of a note can be used to store arbitrary user-defined information. To save memory, this feature may not be enabled on all versions of KeyKit.
- flags
- This integer-valued attribute of a note can be used to store arbitrary user-defined information. By convention, the lowermost bit of this integer is used to identify picked notes in the graphical interface of KeyKit.
The value of an attribute for a multi-note phrase is the average of the attribute values of the individual notes. When used on the left-hand side of an assignment, an attribute expression changes all notes in the phrase. For example, x='a,b,c' ; x.vol = 60 would set the volume of all 3 notes. Increment, decrement, and operator-assignment statements work on each note independently. For example, x='c,d,e'; x.pitch += 2; print(x) would produce 'd,e,f+'. However, the right-hand side is only evaluated once. For example, x='c,d,e'; x.pitch += rand(4); would add the same random value to the pitch of each note. An attribute of a single note within a phrase can be obtained and set by using the % operator. For example, x='c,ed12'; x%1.pitch=x%2.pitch; print(x) would produce 'e,ed12'.
- NOTE
- a normal note, implying a MIDI note-on and note-off
- NOTEON
- a note-on only, e.g. '+a'
- NOTEOFF
- a note-off only, e.g. '-a'
- CHANPRESSURE
- a channel pressure message
- CONTROLLER
- a controller message
- PROGRAM
- a program change message
- PRESSURE
- a pressure message
- PITCHBEND
- a pitch bend message
- SYSEX
- a system exclusive message
- SYSEXTEXT
- a system exclusive "text note" (see above)
- POSITION
- a song position pointer message
- SONG
- a song message
- CLOCK
- a clock message
- STARTSTOPCONT
- a start, stop, or continue message
- MIDIBYTES
- an unrecognized sequence of MIDI bytes
Explicit conversion to a particular type can be done with a built-in function whose name is the same as the type (similar in style to C++). For example, string(4+5) is equivalent to "9", integer(4.9) is equivalent to 4, float("9"+"."+"9") is equivalent to 9.9, and phrase( "'a" + ",b'" ) is equivalent to 'a,b'. Note that when converting a string to a phrase, the value of the string must contain the surrounding single quotes. And, a phrase converted to a string will contain surrounding single quotes. Strings converted to integers can be interpreted as hexidecimal if they include an initial "0x", for example integer("0x40") is equivalent to 64.
As in awk, the if(string-expression in array) construct can be used to test whether a particular array element exists, without having the side effect of creating the array element. A similar construct using phrase expressions, if(phrase-expression in phrase-expression), is true if each note in the first phrase is included anywhere in the second phrase. Only pitch is relevant in this test; time, volume, channel, and duration are ignored.
# These functions expect a single note as an argument,
# and return a chord based on it.
function major(k) { return(k|transpose(k,4)|transpose(k,7)) }
function minor(k) { return(k|transpose(k,3)|transpose(k,7)) }
# The return value of randchord() will be a function pointer.
function randchord() {
if ( rand(2) == 0 ) # True 500f the time.
return(major)
else
return(minor)
}
f = randchord()
f('c') # Plays either 'c' major or 'c' minor.
randchord()('c') # Ditto.
return( function major(k){return(k|transpose(k,4)|transpose(k,7))} )
An "in-line" function doesn't need a specific name - a ?
can be used instead, and a unique function name will be substituted for it.
So, another variation would be:
return( function ? (k) {return(k|transpose(k,4)|transpose(k,7))} )
function add(...) {
sum = 0
for ( n=0; n<nargs(); n++ )
sum += argv(n)
return(sum)
}
The special token ... can be used in an argument list to represent
a variable number of arguments, and can actually be "passed" in the argument
list of another function call:
function compute(sign,...) {
sum = add(...)
return(sum * sign)
}
Arguments can be packed into an array by giving
two parameters to argv(). For example, the array returned
by argv(3,10) would contain the values of argv(3) up to (but not
including) argv(10).
Such an array can then be "unpacked" to create an argument list, by using
varg(). This lets you store a list
of arguments in a single value (the array), to be used later:
function savecall(f,...) {
# save a function and argument list
Callfunc = f
Callargs = argv(1,nargs())
}
function docall() {
# call the function we saved, with the saved argument list
Callfunc(varg(Callargs))
}
for (;;)
print(get(Consolefifo))
The Consolefifo will return each character typed on the console as
a separate string. Another special fifo is the Midiinfifo:
for (;;)
print(get(Midiinfifo))
Each item read from Midiinfifo will be a single note-on,
note-off, or MIDI sysex message. Complete notes will not be
seen - if you want to process complete notes, you
should make use of the Recorded variable (described later)
that collects all MIDI input. In fact, most processing of MIDI input
should be done by using the Recorded variable, to avoid the
inefficiency of processing each note separately.
for (;;) {
m = get(Mousefifo)
print("Mouse button state = ", m["button"])
print("Mouse x,y position = ", m["x"], ",", m["y"])
}
As this example shows, the value received from the Mousefifo is
an array - the subscripts of its elements
are "button", "x", and "y".
Fifos are also the mechanism by which files are read:
f = open("/etc/passwd")
for ( n=1; (v=get(f)) != Eof; n++ )
print("line ",n," is ",v)
close(f)
f = open("/unix","r")
fifoctl(f,"type","b") # turn on "binary" mode for reading fifo f
for ( nc=0; get(f) != Eof; nc++ ) ;
close(f)
if ( nc > 500000 ) print("Too big.")
File fifos are opened for reading by default, but can also be
opened for writing, by using the "w" flag:
f = open("/tmp/debug","w")
put(f,"hello world\n");
close(f)
Fifos reading from pipes can (on those systems where pipes are supported)
be created by adding a third argument:
f = open("pwd","r","pipe")
pwd = get(f)
close(f)
print("The current directory is ",pwd)
Writing to a pipe can be done as follows:
f = open("lp","w","pipe")
put(f,"This should appear on the printer\n")
close(f)
# Play a chord whenever a note below a given pitch is seen.
# The 'chordfunc' parameter should be a function value,
# which is called to generate the chord.
function autochord(chordfunc,limit) {
while ( (n=get(Midiinfifo)) != Eof ) {
if ( n.pitch < limit )
realtime(chordfunc(n),0) # play the chord via MIDI output
}
}
function major(nt) {
return ( nt | transpose(nt,4) | transpose(nt,7) )
}
task autochord(major,64) # a C chord will be played whenever
# anything below pitch 64 is seen
print("Play away...")
After the autochord() function was invoked as a task,
it would continue on in the background,
and the "Play away..." message would be immediately printed. From then
on, any time a note below pitch 64 was seen on MIDI input, a major chord
corresponding to that note would be generated.
The realtime() function used in this example will play a phrase
via MIDI output - it will be described in more detail later.
Tasks that are blocked, either waiting for a message on a fifo or waiting for a specific time, impose no overhead. The task statement returns an integer value which is a task id - this value can be given to the kill() function when you want to terminate the task:
Communication and synchronization between tasks is typically done through fifos, since a get() on a fifo will block until there is something to read. The wait() function can be used to wait until a particular task is finished, and the sleeptill() function will wait until a particular (absolute) time is reached. These concepts are demonstrated by the example below, which creates an interactive mode in which pressing keys on either the console or MIDI keyboard generates chords.tid = task autochord(major,64) kill(tid)
# A utility function for continuously
# forwarding messages from one fifo to another.
function fifoforward(fromfifo,tofifo) {
for ( ;; )
put(tofifo,get(fromfifo))
}
# Generate chords in response to messages received on fifo 'f'
function chordfifo(f) {
for ( ;; ) {
m = get(f)
# The message can be a single note (from the MIDI fifo)
# or a single-character string (from the Consolefifo).
if ( typeof(m) == "phrase" )
realtime( major(m), 0 )
else if ( m>="a" && m<="g" )
realtime( major(phrase("'"+m+"'")) )
}
}
function taskdemo() {
fmerge = open()
tid1 = task fifoforward(Midiinfifo,fmerge)
tid2 = task fifoforward(Consolefifo,fmerge)
tid3 = task chordfifo(fmerge)
sleeptill( Now+32b )
kill(tid1)
kill(tid2)
kill(tid3)
}
The fifoforward() function shown above is a simple utility that
continuously reads messages from one fifo and forwards them to another fifo.
The taskdemo() function spawns two instances of this utility, to forward
messages from the Midiinfifo and Consolefifo fifos into a single fmerge fifo.
The fmerge fifo is then read by the chordfifo() function, generating
a chord in response to each message it receives. After spawning the 3 tasks
that will do all the work, taskdemo() uses sleeptill() to wait
until 32 beats have elapsed, and then kills the 3 tasks.
printf("num=0\n",num)
The output of the built-in printf function is always sent to "standard
output", which, in a graphics environment,
may result in a separate pop-up window.
Formatted output to other destinations can be done with sprintf:
f = open("tmpfile","w")
put(f,sprintf("The current tempo is 0\n",tempo()))
close(f)
Note that in the default user interface of KeyKit, the
printf function is immediately redefined so that it sends output to
the Console window.
The user-defined function library defines a print function that is useful for simple printing - it merely prints its arguments separate by spaces. For clarity, this function (print) is used in most of the examples in this document, rather than printf.
function writephr(ph,fname) {
f = open(fname,"w")
put(f,string(ph))
close(f)
}
writephr(ph,"phrasefile.k") # example usage
Phrases can be read from files with the readphr() function
(built-in, not user-defined):
ph = readphr("phrasefile.k")
The variable Now contains the current time, in clicks, and is continuously updated. The sleeptill() function can be used to pause until a specified absolute time:Clicks = 96 # 96 clicks per beat tempo(500000) # 500000 microseconds per beat, i.e. 120 bpm
function reminder(tm,msg) {
sleeptill(tm)
print(msg)
}
task reminder(Now+16b,"16 beats are up!")
This example would print the message "16 beats are up!" after 16 beats,
which, with the default tempo and Clicks values, would be 8 seconds.
would slowly speed up during its playback. These special text notes also get translated into the tempo messages of a Standard MIDI File.'"Tempo=500000",c,g,"Tempo=400000",c,g,"Tempo=300000",c,g'
realtime('c e g, f a c')
would play 2 chords (C and F major) via MIDI output, beginning immediately.
A second argument to realtime() can specify the absolute
time at which to begin playback:
tid = realtime('c e g, f a c', Now+4b )
This would begin playing the phrase after 4 beats. Because realtime()
spawns a new task, it will always return immediately - the playing of
the MIDI output is done in the background by the new task.
The return value of realtime() is the id of the new task -
you can use it to kill the task like any other, thereby terminating
the playback of the phrase.
ph = cut(Recorded,CUT_TIME,Now-4b,Now) ph = flip(ph) realtime(ph)
Since the value of Now might be incremented between the execution of these two function calls, we would not be guaranteed that the drums and melody would be in perfect sync. A slightly better method would be:realtime(drums,Now) # equivalent to realtime(drums) realtime(melody,Now)
This would synchronize the playback of the two phrases. However, the first note of the drums phrase might still get played before the first note of the melody (though they would be in perfect sync thereafter). This is usually not enough of a problem to worry about, but if you really want to schedule phrases independently and be assured of them starting playback at exactly the same time, you should guarantee that they are all scheduled sometime in the future:start = Now realtime(drums,start) realtime(melody,start)
Of course, for this example you could finesse the whole issue with:start = Now + 1b/4 realtime(drums,start) realtime(melody,start)
realtime( drums | melody )
A complete list of special variables can be found in the keyvar(5) manual page. There are many things that can be tweaked through those variables, so reading that manual page is important if you want to use KeyKit effectively.
- Clicks
- The number of clicks in a single beat. The default is 96.
- Current
- This phrase contains, at any point in time, all notes that are being held down (ie. note-ons without note-offs) at that time.
- Merge
- If non-zero, all MIDI input is echoed to MIDI output. This is used when your MIDI controller is separate from your MIDI synth.
- Now
- This is the current time, in clicks.
- Record
- If the value of this variable is zero, recording of MIDI input is disabled, otherwise recording is enabled. The default value is 1.
- Recorded
- This phrase records all MIDI input when Record is non-zero.
- Recsched
- If non-zero, the Recorded phrase also records any MIDI output generated by KeyKit.
The data elements of an object can take on arbitrary values, but these values can only be accessed from within a method of that object. So, the only way in which objects are manipulated is through invocation of their methods, and the data elements within an object are completely hidden.
Methods are used like functions. This example invokes the method named meth of an object named obj, passing it 3 arguments:
While executing a method of an object, the special symbol $ is an alias for that object. (See below for an explanation of what the special symbol $$ means.) So, the statement:obj.meth(1,2,3)
would set the value of the data element in the current object (the object on whose behalf the method is being executed). Since data elements of objects are only accessible within methods, the $ notation is actually the only way that object data can be referenced. The $ notation also becomes a useful visual flag that distinguishes object data from local variables.$.data = 99
Any expression in parenthesis following an object. will be treated as a string value that will be used as the method name. This lookup is (obviously) done at execution time, and in fact even explicitly-named methods are executed by doing a lookup at execution time.methname = "meth" obj.(methname)(1,2,3)
class point {
method init {
$.xvalue = 0
$.yvalue = 0
}
method x {
return($.xvalue)
}
method y {
return($.yvalue)
}
method set (x,y) {
$.xvalue = x
$.yvalue = y
}
}
An object of class point can then be created and manipulated as follows:
o = new point()
o.set(33,44)
print("x is ",o.x()," y is ",o.y())
Although it is conventional for objects to have a delete method, this method is not called automatically by the language. The default user-defined library has a deleteobject function that, if used, will call the delete method of an object, allowing it to clean up any tasks and graphics that it owns. The deleteobject function also automatically deletes any children objects.delete o
If you print the value of an object, you will see a result like this:
o = new point() print(o) $18448396
When you want to create an object of a given class, and you want to use an existing object id (as just described), the following syntax should be used:
The value in parenthesis after new is the object that will be initialized with the named class (in this case, point).o = new($123) point()
class polarpoint {
method init {
$.pt = new point()
$.inherit($.pt)
}
method setpolar (ang,r) {
x = r*cos(ang)
y = r*sin(ang)
$.pt.set(x,y)
}
}
Note that inheritance requires explicit creation of an object
from which methods are inherited.
In this example, the setpolar method explicitly calls
the set method of $.pt. Because of the inheritance
that has been established, this call could actually be written
as $.set(x,y). Use of the polarpoint() class is illustrated here:
o = new polarpoint()
o.setpolar(3.14,100)
print("x is ",o.x()," y is ",o.y())
Note that the x and y methods of the polarpoint
object will be inherited from the point object.
When executing a method that has been inherited, the special symbol $$ (rather than $) will refer to the higher-level object which has established the inheritance relationship, rather than the inherited object. This can be used with both method invocations and object variable references. This code illustrates:
class A {
method init {
$.value = "AVALUE";
}
method id() {
return("A")
}
method basefunc(numdollars) {
if ( numdollars == 1 ) {
print($.value)
print($.id())
} else {
print($$.value)
print($$.id())
}
}
}
class B {
method init {
someA = new A()
$.inherit(someA)
$.value = "BVALUE";
}
method id() {
return("B")
}
}
b = new B()
b.basefunc(1)
# will print "AVALUE" and "A"
b.basefunc(2)
# will print "BVALUE" and "B"
function xy(x0,y0,x1,y1) {
return( ["x0"=x0,"y0"=y0,"x1"=x1,"y1"=y1] )
}
In actuality, this function is a built-in function, since it is so
heavily used. And, the built-in function is also capable of dealing
with only 2 arguments, in which case it creates an array whose
subscripts are "x" and "y".
- style(type)
- This sets the drawn style of a window - a type of NOBORDER means no border at all, BORDER means a simple outline border, BUTTON means a 3-d button look, MENUBUTTON means a 3-d button with an extra underline under the text (to distinguish a drop-down menu button), and PRESSSEDBUTTON means a 3-d button that looks like it's pressed. If given no argument, this method returns the current border type.
- contains(xyarray)
- This method returns 1 (true) if the point specified by xyarray is contained within the window. If xyarray specifies an area, this method returns 1 if the area overlaps (by any amount) the window.
- ellipse(xyarray [,mode] )
- This draws the outline of an ellipse or circle within the rectangle specified by the coordinates in xyarray. The optional mode can be set to CLEAR, or STORE. The default mode is STORE.
- fillellipse(xyarray [,mode] )
- This draws and fills an ellipse or circle within the rectangle specified by the coordinates in xyarray. The optional mode can be set to CLEAR or STORE. The default mode is STORE.
- fillrectangle(xyarray [,mode] )
- This fills a rectangular region using the coordinates in xyarray. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- line(xyarray [,mode] )
- This draws a line using the coordinates in xyarray. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- mousedo(mouse-array)
- This processes the data from a mouse event (as received from the Mousefifo) and takes whatever action is appropriate for the current window object. For example, many of the behaviours of a menu object (scrolling, item highlighting) are done in response to handing it mouse events with this method. The return value of mousedo(), when used with a menu object, indicates which item the user has selected. Other valid return values for a menu object are MENU_DELETE (for the X-area in the upper-right corner of a menu), MENU_MOVE (the bar area in the upper-left corner of a menu), and MENU_NOCHOICE (no choice was selected).
- rectangle(xyarray [,mode] )
- This draws a rectangle using the coordinates in xyarray. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- redraw()
- This redraws the window. Note that this does not redraw anything inside the window.
- resize(xyarray)
- This changes the size of the window to the value specified in xyarray. If no argument is given to resize(), it returns the current size of the window (as an xyarray).
- restoreunder()
- Restores the latest bitmap saved with saveunder().
- saveunder()
- Saves the screen area covered by the window as a bitmap, which can be later restored with restoreunder(). Intended for use with pop-up menu windows.
- setconsole()
- Sets the window so that it is considered the "console" - all error messages and the output of print statements are seen in this window.
- size(xyarraygp)
- This is an alias for the resize method.
- textcenter(string,xyarray [,mode] )
- Draw the string centered within the area specified byxyarray. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- textheight()
- Returns the current height, in pixels, of text characters.
- textleft(string,xyarray [,mode] )
- Draw the string left-justified within the area specified byxyarray. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- textright(string,xyarray [,mode] )
- Draw the string left-justified within the area specified byxyarray. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- textwidth()
- Returns the current width, in pixels, of text characters.
- windtype()
- Returns the window type as a string - "generic", "phrase",
"menu", or "console".- xmax()
- Returns the x value at the right side of the window.
- xmin()
- Returns the x value at the left side of the window.
- ymax()
- Returns the y value at the bottom of the window.
- ymin()
- Returns the y value at the top of the window.
- closestnote(xyarray)
- Returns the note in the window that is closest to the specified point.
- drawphrase(phrase [,mode])
- Draws the specified phrase in the window. The optional mode can be set to XOR, CLEAR, or STORE. The default mode is STORE.
- scaletogrid(xyarray)
- Scales the coordinates in xyarray from raw window values (pixels) to click (time) and pitch coordinates. The scaled coordinates are relative to the window's current view (as set by the view() method).
- sweep(fifo,type,xyarray)
- Begins a sweep operation.
- trackname(string)
- Sets the name of the track displayed in the window.
- view(xyarray)
- This method controls what area of the phrase is seen within the window, i.e. it allows you to zoom and pan around the phrase, using the window as a viewport. The argument to this method is assumed to be an xyarray value that specifies the desired viewing area. The coordinates are specified in terms of click (time) and pitch values. For example, if the phrase in window w were 32 beats in length, this statement would cause it to be dislayed in its entirety: w.view(xy(0,0,32b,127))
- menuitem(label)
- Adds an item with the specified label to a menu object.
- menuitems()
- Returns an array containing the current list of menu items in the menu. The index values of the array are the menu item labels.
- acos ( x )
- Returns the arc-cosine of x.
- argv( arg-index-start [,arg-index-end] )
- Used within a user-defined function to give generalized access to the arguments passed to it. If given one argument, argv returns a single argument from those passed to the current user-defined function. For example, argv(0) will return the first argument. If given two arguments, argv returns an array containing the specified argument range (from the first value up to, but not including, the second value). The index values of the returned array start at 0. For example, argv(0,nargs()) returns an array containing all of a function's arguments.
- ascii( integer-or-string )
When given a string argument, this function returns the ascii value of its first character. When given an integer argument, this function returns a string containing a single character whose ascii value is that integer. - asin ( x )
Returns the arc-sine of x. - atan ( x )
Returns the arc-tangent of x. - chdir(dir)
Changes the current directory to dir. - close ( fifo )
Closes the specified fifo. - colorset ( colorindex )
Sets the current color index for drawing things. - colormix ( colorindex, red, green, blue )
Sets the color for a given color index. The values for red, green, and blue can range from 0 to 65535. Color index 0 is main background color, color index 1 is the main foreground color, color index 2 is the "pick" color (used for displaying highlighted notes in phrase windows), color index 3 is the background in buttons, and color index 4 is the shadow in buttons. Other color indicies can be used when drawing lines. - cos ( angle )
Returns the cosine of angle (a value in radians). - currtime()
Returns the current time, in seconds (typically since Jan 1, 1970). - cut( phrase, type, ... )
Returns a phrase containing notes cut from phrase. The type determines what the cut is based on. Possible values for type (as pre-defined macros) are CUT_TIME, CUT_CHANNEL, CUT_TYPE, CUT_NOTTYPE, and CUT_FLAGS. If type is CUT_TIME, the cut is based on time. The third and fourth arguments specify the starting and ending time. The fifth argument, if present, controls how this cut behaves at the boundaries - possible values are NORMAL (the default), TRUNCATE, and INCLUSIVE. The NORMAL type of time cut is an efficient equivalent to the expression: phrase{??.time>=time1 && ??.time<time2}. A TRUNCATE cut will chop off notes that cross the boundaries, while an INCLUSIVE cut will include those notes unchanged.
If type is CUT_CHANNEL, the cut is based on channel. The third argument is the channel number (as a value from 1 to 16) of the notes that will be in the cut
If type is CUT_TYPE, the cut is based on type. The third argument is the type - any notes that have this value as their .type will be in the cut.
If type is CUT_NOTTYPE, the cut is based on the inverse of a type. The third argument is a type - any notes with this .type value will not be in the cut phrase.
If type is CUT_FLAGS, the cut is based on the flags attribute of the notes. The third argument is a mask that is or'ed with the flags of each note - the cut contains any notes for which this results in a non-zero value.
- debug(type)
Used as a debugging hook, whose meaning varies from time to time. - defined(variable-or-function-name)
Returns non-zero if the named variable or function has been defined, and 0 if it is undefined. - error( message )
Generates an error, printing the specified message string and terminating the calling task. - exp ( x )
Returns the exponential function e**x. - exit()
Quits the entire KeyKit program, completely and abruptly. - fifoctl ( fifo, cmd, mode )
Sets the given fifo to a particluar mode. The cmd argument is intended as a hook to machine-dependent fifo commands. The only command universally accepted is "type". If mode is "l", then reads from the fifo are done a line at a time (this is the default mode of fifos). If mode is "b", then reads from the fifo are done a byte at a time rather than a line at a time. - fifosize ( fifo )
Returns the number of unread data values in the specified fifo. - filetime ( filename )
Returns the modification time of the named file, consistent with the values returned by currtime(). - finishoff()
Send note-off messages on MIDI output to terminate any currently-held notes. - float ( value )
Converts its argument (typically an integer or string) to a floating point value and returns it. - flush ( fifo )
Flush all unprocessed data values in the specified fifo. If the fifo is attached to a file or pipe, the data is flushed. For other types of fifos, any unprocessed values in the fifo are discarded. - funkey ( num, statement )
Assigns a KeyKit statement (specified as a string beginning with '{' ) to the num-th function key. Whenever that function key is pressed, the statement will be immediately executed. - get ( fifo )
Retrieves a value from the specified fifo. The task blocks if the fifo is empty. - gettid ( )
Returns the task id of the current task. - integer ( value )
Converts its argument (typically a string or float) to an integer value and returns it. - kill ( task-id )
Terminates the specified task, possibly invoking a cleanup function that the task has registered with onexit(). The return value of kill() is normally 0. Killing a non-existant task is okay - no error is produced, and the return value is 1. - log ( x )
Returns the natural logarithm of x. - log10 ( x )
Returns the logarithm of x to base 10. - lsdir ( directory )
Returns an array of the files and directories contained in the specified directory. The index values of the elements in the array are the actual file and directory names. The value of an element is 1 if it is a directory, and 0 if it is a file. - midibytes ( num-or-phrase, num-or-phrase, ... )
Returns a phrase containing a single MIDIBYTES note that is the concatenation of the bytes specified by all the arguments. Each argument can be either a number - specifying a single byte of the result; or a phrase - all of its MIDIBYTES notes are copied to the output phrase. - midifile(filename) or midifile(array,filename)
The first usage (with only a filename as an argument) reads a Standard MIDI File and returns an array containing its tracks, starting at array index 0. The global variable Mfformat is set to the format type (0, 1, or 2). The value of global variable Defrelease specifies the default release velocity. If the value of global variable Onoffmerge is 1 (its default value), noteons and noteoffs are merged.
Used as midifile(array,filename), the elements of the specified array are used as tracks to create a Standard MIDI File in the named file. The array subscripts should be numeric, since they will be sorted to determine the order of tracks in the file. If global variable Tempotrack is 1 (its default value), a tempo track is automatically created as the first track of the file. The value of Clicks is used as the 'divisions' value in the header.- milliclock ( )
Returns the (relative, not absolute) value of a millisecond-resolution clock. - objectinfo(object,info)
Returns an array containing information about the specified object. If the value of info is "methods", the array will contain the names of all of the object's methods. If the value of info is "data", the array will contain the names of all of the object's data - both variables and methods. The array index values will be the method/data names, and the array element values will be the type of each item. - objectlist()
Returns an array containing all objects. - nargs ( )
Returns the number of arguments passed to a user-defined function. - onchange(variable, func)
Arranges for func (a function pointer value) to be called whenever the value of the specified variable is changed. - onexit(func [,arg(s)] )
Arranges for func (a function pointer value) to be called when the current task is finished (either voluntarily or by being killed). If there are additional arguments, they are passed as arguments to func when it is called. - open( [file-or-pipe [,mode] ] )
Allocates a new fifo and returns its id. If given one argument, open interprets it as a filename to be opened for reading. A second argument can modify the interpretation: "w" will open the file for writing rather than reading; "|" will interpret the first argument as a shell command, opening a pipe that can be used to read its output; and "|w" will execute a command, opening a pipe that can be used to write to it. - phrase ( value )
Converts its argument (normally a string which includes the single quotes) to a phrase value and returns it. For example, a=phrase("'a,b,c'"). - pow ( x, y )
Returns x**y. - printf(format [,arguments])
Print formatted output. See the section on "Printing" above, and see the description of sprintf below for the type of formatting that can be done. - priority(task [,priority])
With one argument, priority() returns the current priority of the specified task. With two arguments, priority() sets the current priority of the task to the specified priority value. If the value of task-id is -1, priority() returns or sets the global priority limit, which specifies a lower limit for runnable tasks - only tasks with a priority greater than or equal to the current global priority are permitted to run. - put ( fifo, value )
Puts the value on the specified fifo. The return value is normally 0. If fifo does not exist, the return value is -1. - readphr(fname)
Reads the specified file, expecting it to contain a KeyKit phrase whose value is returned. The value of Musicpath is used to search for the file. - realtime(phr [,time])
Spawns a new task for playing the given phrase in realtime via MIDI output, and returns its task id. An optional second argument specifies the starting time; the default value is Now. - reboot()
Forces a reboot, terminating all tasks and calling Rebootfunc(), a function whose initially-null value is typically redefined in keyrc(). - rand ( n1 [,n2] )
Returns a random number between n1 and n2, inclusive. If only n1 is given, the random number is between 0 and (n1-1), inclusive. If only n1 is given, and it is negative, then it is used to seed the random number generator. - setmouse(type)
Set the cursor type for the mouse. Values for type are: ARROW, SWEEP, CROSS, LEFTRIGHT, UPDOWN, BUSY, and NOTHING. - sin ( angle )
Returns the sine of angle (a value in radians). - sizeof(arg)
Returns the number of notes in a phrase, or the length of a string, or the number of elements in an array. - sleeptill(time)
Causes the task to go to sleep until the specified time, expressed in absolute clicks. - sqrt ( val )
Returns the square root of val. - split(phrase-or-string)
When given a string as its first argument, this function breaks it into white-space-separated words and inserts them as separate elements into an array. The return value of this function is a pointer to this newly-created array. The subscript of the first array element is 0. When given a phrase, this function breaks it into a array of short phrases, using the starting and ending times of the notes in the original phrase to determine the split points. To visualize this operation, imagine drawing vertical lines through the starting and ending point of every note in the original phrase. The array elements would be the phrases contained between these vertical lines. For example, x = split('a,bt12')would result in x[0]='ad12' ; x[1]='ad84t12 b' ; x[2]='bd12t96'. This is useful for constructing monophonic phrases, and any other operation in which you want to reconsider what notes should be playing whenever any note starts or stops. - sprintf ( format, args )
Formatted printing, with the result returned as a string. The format may contain the following conversion specifications: 0 (decimal), 0 (hex), 0.000000 (float/double), (string), 0 (phrase), and % (literal percent character). Width and precision prefixes (e.g. 0 and 0.00) are recognized. - string ( value )
Converts its argument to a string and returns it. - subbytes(phrase,start,leng)
Works vaguely like substr, but operates on notes whose type is MIDIBYTES, allowing you to pull off individual bytes or ranges of bytes. For example, subbytes('xc005c106c207',3,2) would return 'xc106'. Note that the start value for the first byte is 1, not 0. - substr(string,start,leng)
Returns a substring of a string. Note that the start value for the first character of a string is 1, not 0. - system(string)
- The string is executed by the shell (or whatever program is the command interpreter for a given machine). This may not be supported on all machines.
- tan ( angle )
Returns the tangent of angle (a value in radians). - taskinfo("list") or taskinfo ( taskid, type )
If given a single argument (whose only valid value is "list"), taskinfo() returns an array with entries for each currently-running task - the array element indicies are the task ids, and the array element values are all zero. If given two arguments, taskinfo() expects the first to be a task id, and the second is a string that indicates what piece of information about the task should be returned by taskinfo(). The valid values of type are: "status" (returns a string describing the running status), "parent" (returns the id of the task's parent), "count" (returns the number of interpreted instructions that the task has executed), "schedtime" (returns the time at which the task is scheduled to awaken, if it is sleeping), "wait" (returns the id of the task whose termination is being awaited), "blocked" (returns the id of the fifo, if any, on which the task is blocked), "fulltrace" (returns a string with a complete function traceback, including parameter values), "trace" (returns a function traceback without parameter values), or "priority" (returns the priority value of the task). - tempo( [newtempo] )
When invoked with no arguments, tempo returns the current tempo. When given an argument, the current playback speed is set to newtempo, whose units are microseconds per beat. The return value is the old tempo. - typeof(arg)
Returns a string describing the type of its argument: "string", "integer", "float", "phrase", "array", "function", or "uninitialized". - undefine(variable-or-function-name)
Causes the definition of the named variable or function to be forgotten. This can be used to force the rereading of a user-defined function from the file that defined it, and is typically useful when a new function is being written and tested. - wait(task-id)
Causes the current task to go to sleep until the specifed task has finished. - xy(x0,y0,x1,y1)
Returns an xyarray (see descrption in the Windows section above) containing the specified values.