The Function module enables you to write your own script to control what the module does. The scripting "language" is familiar calculator script, so you can start using it right away without needing to invest time learning a programming language.
Here is an example of a script that averages 3 inputs and sends the result to the output:
Out sends a value to an output:
Out(Num, Value) - sends Value to output number Num.
In1, In2, and In3 return the values from inputs 1 to 3.
So, inputs 1, 2, and 3 are being added, then divided by 3 to get the average, and then sent to Output 1.
Creating a Function module
To create the above Function module, right click on the Workspace to get the pop up module menu, and select Function . Click on the module's upper right Property button to open the Property dialog. In the General tab, you can give the module a name, such as "Average3," as well as a custom tool tip which will show 1-line module doc in the status bar when you mouse over the saved function in the popup module creation menu. If you put a comment in the larger text box it will show as a multline balloon type tool tip instead of the single tool tip line whenever you mouse over the module in the workspace.
You can also change the icon color. Icon colors in Function modules have no effect on the module, they exist only to provide visual grouping - you can set them to whatever color you like, or ignore them.
The default Function module has one input and one output; we want 3 inputs, so click on the Input tab and click More twice for a total of 3 inputs. As with other modules with a flexible number of inputs and outputs, you can enter custom labels and tool tips. The module already has 1 Output, so there is no need to change that.
Select the Function tab to enter the function script. When first created Function modules simply pass the input to the output of the module, so you will see the default function:
This text area is a simplified text editor, similar to Notepad. Highlight the existing function and hit backspace to delete it, then type in the averaging function (or you can simply copy it from this page and paste it in):
Click on the Test button to make sure there are no syntax errors - if nothing happens, the function is good; if you get a error message, correct the error ant Test again. Finally, click on OK to update the Function module and exit the Property dialog. Your new Function module will now average its 3 inputs and send the result to the output.
Function, Fn Reset, Fn Load
There are three Function script tabs. They are identical except for when the function runs.
A script in the Function tab runs much like other standard modules. You can select whether it should run always, or just upon a strobe or change at input 1, with the option menu at the bottom center of the Property dialog.
A script in the Fn Reset module runs only on the System Reset Flag - which occurs whenever the internal clocks are reset, same as when the Clock modules reset, etc.; and a script in Fn Load runs only on the Load Flag - which occurs when a Patch, Macro or Function file is loaded. You can also manually trigger Load and Reset with the toolbar buttons.
The purpose of the three different scripts is to provide setup functions when needed. the Fn Load script always runs first, then the Fn Reset, followed by the Function script. So you can initialize arrays or variables before they are used for the first time, and be assured they will be run prior to the Function scrip running.
Function Execution Options
The Function module executes its script on every clock tick by default, however this can be changedt to run only when a strobe is received in input 1, or only when input 1 is changed by selecting the option button on the bottom section of the module properties pop up:
Run Always - default action, executes on every clock tick.
Run on In1 Strobe - when selected, executes only when input 1 receives a strobe or clock-On.
Run on In1 Change - when selected, executes only when input 1 changes.
Additionally, the Reset and Load pages can be disconnected from the system Reset and Load flags, and forced to run ahead of the Function page when a strobe is received in input 2 (Reset page) or Input 3 (Load page). This is useful for conditional execution, for example when you want to reset the default values of a function that normally runs in the Function page:
FnReset when In2 Strobe - check to enable execution of Reset page script
when input 2 receives a strobe.
FnLoad when In3 Strobe - check to enable execution of Load page script when input 3 receives a strobe.
These options are grayed out if the Function module does not have an input 2 or 3. Add the inputs and activate the options with the Inputs tab "More" button.
The execution order is: Load Page, Reset Page, Function Page. The Reset and Load pages only run on an input 2 or 3 strobe, but if either or both runs, the Function page will always follow, with input 2 or 3 acting like an input 1 strobe. In no event will pages run more than once per clock tick. So if inputs 1, 2, and 3 receive simultaneous strobes, each page will execute once on that clock tick: the Load page, then the Reset page, then the Function page.
The Fn Prototypes tab provides a quick reference to all built in functions. It serves both as a quick reference for functions, and as an aid to help prevent syntax errors
To see how the prototypes work, use it to find the reference for the Out function, used above. Start by placing the cursor in the Function tab edit window (or the Fn Reset or Fn Load edit windows). Then click on the Fn Prototypes tab, and click on the "+" icon of "Variables and Constants." The section opens and you will see the line:
Out(N, X) ~ Send X to module Out #N
Move the cursor to the line and click on it. You are returned to the editor window and the function text "Out(N, X)" is inserted at the cursor. Replace "N" and "X" with values or other functions that return values, and you have a working function.
Loading and saving functions
Function modules may be saved and loaded just as Macro modules. To save a Function module, click on the Save button in its properties.
To load a Function module right click on the module Workspace background, and select it from the popup menu. When you load the function module it will show up at the Workspace position where you right clicked.
The scripting language is a slightly expanded version of standard calculator script, that you use with hand held calculators. In general, you write functions as you would with a calculator, using parentheses to control grouping and precedence: as with calculators, calculation proceeds from inner parentheses to outer.
The comment character is a semicolon";" - everything after a semicolon on a line is ignored. Comments do not take space in the function compiler memory and they take no processing time, so you can and should use comments liberally. Here is an example of a commented line:
Out(1, In1) ; the default function sends input 1 to output 1
Functions are separated by spaces or lines. Generally it is a good idea to place each function in a script on a separate line, with a comment. You may have up to 128 separate functions per script, but you should avoid having more than a few lines of script per function module in order to maintain readability. The computation overhead in breaking a large function into several function modules is negligible, and it makes your script much easier to understand when you need to make changes to it later.
All functions and sub functions return a value when they are evaluated (run). Some functions are not run for the value they produce, but for the "side effect," and usually these functions will simply return 0 after doing whatever they do. Some functions return a different value if an error is encountered. The particular error behavior of a function will be listed in the function documentation.
Items separated by a comma are evaluated left to right, and the expression result is the last item evaluated. Within a comma field, items will be given the following operator precedence from highest to lowest:
Anything inside parenthesis is performed first () Factorial, percentage !, % Exponentiation ^ Negation (unary) - Multiplication, division *, / Integer division \ Other operators Modulo (remainder) MOD Addition, subtraction +, - Relational operators <, >, >=, <=, =, <> AND operator OR, XOR (exclusive or) EQV (equivalence) IMP (implication)
When consecutive operators have the same priority, they are evaluated from left to right. This means that an expression such as "a-b-c" is evaluated as "(a-b)-c". Generally, it is a good idea to make liberal use of parentheses to be sure your expression is being evaluated the way you want.
The compiler supports notations for binary, octal, and hexadecimal numbers. These numbers must be preceded by the character # followed by b, o, or h for binary, octal, or hexadecimal. The prefixes are part of the number following, so no space is allowed. With #h legal numerals are 0-9 and A-F; with #o, only 0-7 are allowed; and with #b only 0 and 1 are allowed.
Note that the numeric base format for function script is slightly different than for module inputs. The decimal value 127 can be entered into a module input as hexadecimal "&H7F" but the same value in calculator script would be "#H7F."
The default number type for the function compiler is double precision floating point, the same as ArtWonk values. Unless otherwise noted, you may assume functions, variables, etc. will be in that format and they will automatically be converted to and from other numeric types as needed.
Double precision floating point numbers have an enormous range: -1.79769313486232E308 to -4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values.
Values for True and False
Logical values in calculator script are the same as generally used by ArtWonk modules. False is always 0 and True is anything else. Relational operators (>, <, <=, >=, =, <>) return a 1 for True.
Each Function module created has a set of private variables for use by any of the 3 function scripts (Function, Fn Reset, Fn Load) within it but not visible by other Function modules. These are the letter variables A to H, and J-Z, with I reserved as the Loop index. Note that letter variables H and J-Z are shared with the private array elements 100-127. For this reason, you should avoid either using private array elements 100-127, or avoid using the letter variables H and J-Z in any one particular Function module.
Since letter variables are private to the Function module, you can use the same letter names in other Function modules, and they will refer to only to the variables within that module.
To fetch the contents of a letter variable, simply use it:
Out(1, A) ; sends value stored in A to output 1
To store a value into a letter variable attach .(), as A.(3) to store 3 into A.
To access Function modules outputs, use Out(num, value), where num is the 1 based (starts with 1, not 0) output number and value is the value to send to it. To access Function module inputs, use In(num) with num as the 1-based input number. Properly speaking these are arrays, not variables. But they are so oftern used with letter variables, so we group them here.
Inputs 1-20 can also be accessed by using their variable-like aliases, In1 to In20.
Prototypes for Variables and ConstantsA ~ Return value of variable A-H and J-Z
The text functions give the ability to input text strings, to store them in local text variables, and to combine, or concatenate, the text strings. Other text manipulation functions, such as extracting a string from within a string, are available through the Text modules, by passing the text between the Text and Function modules.
The functions that return a text string (i.e. TxA and TxIn) may be used anywhere within a function where quoted text is called for. For example you could use an input to display a status message with:
One caution, when using the functions that return a string (TxA, TxIn, and directory names, but not the assignment functions) only use them within a function that calls for a string argument. Using string-returning functions outside of a function that requires a string will result in unpredictible behaviour and possibly even a crash.
Prototypes for Text functionsTxA ~ Return the text of string variable A-D
The File/Link functions act both as regular file read/write functions that give great flexibility to the data format, and also they can be used to make direct communication links with multiple instances of ArtWonk, or with ArtWonk and other programs that support link files, such as the Analog Box2 soft synth. Links may be made with multiple applications on the same computer, or with different computers connected in a Local Area Network.
File/Links look like random read/write files, and in fact you can open any file as a link file, or you can ignore the link capability and just use the File/Link functions to access data files of your own choosing. To open a network connection, simply open the link file as a networked file.
To make a file link between two (or more) applications, open the same file with each application you want to link, then treat the data locations (records) as input and output channels. When sending data, simply write to the location, which effectively makes it an output channel relative to the application doing the writing. When reading data generated by another application, read from the location the external application is writing to. For example, one program might treat file location 1 as the outpt channel, writing data to that location; and it would treat file location 2 as the input channel, reading data from that location. Then a second program would treat the two locations the reverse: location 1 would be the input channel, and location 2 would be the output channel.
OpenFile(type="Double", fname="", handle=0) ~ Opens a file for linked read or write. Returns 0 if file is successfully opened, 1 on error. If the file does not exist, one will be created. Any opened files are closed automatically when ArtWonk exits, when a new patch is loaded, or when a handle is reused. All parameters are optional.
"Type" is a string literal or string variable that defines the data type of the file. Valid type names are:
- Byte - 1 byte per record, 8-bit unsigned integers 0-255, or text characters. Byte is the default type.
- Word - 2 bytes per record, 16-bit signed integers -32,768 to 32,767.
- Long - 4 bytes per record, 32-bit signed long integers -2,147,483,648 to 2,147,483,647.
- Single - 4 bytes per record, 32-bit signed single floating point- 3.402823E38 to -1.401298E-45 for negative values; 1.401298E-45 to 3.402823E38 for positive values.
- Double - 8 bytes per record, 64 bit signed double floating point -1.79769313486232E308 to -4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values.
- (string) - set to type string by giving the length of the longest string you plan to use.
fname is the name of the link file to be opened. File names may be literal (in quotes) or a string variable. You can give a full name+path ("c:\directory\name.ext"), or a network name ("\\computer\alias\directory\name.ext"). You can also just give a name+ext and the link file will be placed in the same directory as the current patch. Finally, you can simply omit the name, and the file will be created with the name, "Link00.@@@" in the ArtWonk array directory (the number after "Link" is actually the handle you give it, which will default to 0 if you do not give a handle)..
handle is a value from 0 to 99 that defines the opened link file to be used with ReadFromFile() and WriteToFile() below. Defaults to 0. Use handle if you are going to use more than 1 link file at a time, up to 100 simultaneously opened files. It does not matter what number you assign the handle, as long as you use the same number for subsequent reads and writes. If you open a file with a handle that is currently in use, the open file is first closed before the handle is reused.
Prototypes for File/Link
FileExists("filename") ~ returns 1 if filename exists, 0 if not found
GetLinkFileName(handle=0) ~ Returns handle's filename string as set by OpenFile()
CleanupLinkFiles(flag=1) ~ Delete link files on exit/load (0=none, 1=default only, 2=all)
OpenFile(type="Double", fname="", handle=0) ~ Opens/creates for read or write
WriteToFile(value, position=1, handle=0) ~ Write to file opened with OpenFile()
TxWriteToFile("string", position=1, handle=0) ~ Write text to file opened with OpenFile()
ReadFromFile(position=1, handle=0) ~ Read from file opened with OpenFile()
TxReadFromFile(position=1, handle=0) ~ Read text from file opened with OpenFile()
Functions modules have both private and global arrays.
A Private array, like a private variable, is available only to the scripts within a Function module, and not available to other Function modules. The size of the local array is 100 elements, 0-99. In addition to being private, the local array is persistent - whatever values you place into it, remain until changed; and the array is stored with the module when you save it.
Global arrays are available to any Function module, and in fact are the same arrays used by the Array sequencer modules, so they are accessible to these modules as well. These arrays are assigned a handle, which may be from 100 to 999, for a total of 900 possible arrays. You should never give arbitrary array numbers; instead always use an Ary# handle as returned by the NewArray() function, or by any modules that returns Ary# handles.
The first 100 arrays, numbered 0-99 are not used by the array manager and should not be used by modules or functions. They are available for compatibility with earlier versions of the software, but may be removed in a future version.
Global arrays are not saved with the module or function, but they may be saved and loaded with the SaveNameArray and LoadNameArray functions. You can give just a file name to place the array into the ArtWonk Array folder; or you can give a full path + name to place the array file wherever you choose. Do not give the file extension, as ArtWonk arrays always have the extension "awa," which will be supplied by the function.
Note that while ArtWonk does not place constraints on the size of arrays, they will be constrained by the amount of memory available to the computer, and the amount of CPU time required to process array functions. As always, there are tradeoffs to be made, and and computer resources should be managed carefully.
Caution: some array functions such as creating new arrays and resizing them should not be run every clock tick; instead they should only be placed in the Load or Restart edit box, or in the Function box only if Run on Strobe or Run on Change is checked.
Prototypes for Private Arrays
Fetch(Index) ~ Return value at Index (0-99) of private array
Store(Index, Val) ~ Assign val to private array at Index (0-99)
Prototypes for Global ArraysGet(Ary, Index) ~ Return global Ary value at Index (0 based)
Prototypes for Math#h ~ Base prefix for hexadecimal: #h7F = 127
A full set of double precision floating point math functions are available.
Prototypes for PowersSqr(N) ~ Square root
Relational operators work on the parameters as a whole and except for IIF, they return True (1) or False (0)
IIF is a special function that is defined as: IIF(condition, ifTrue, ifFalse). If the value of condition is True, then the value of the ifTrue parameter is returned, else the value of the ifFalse parameter is returned. Both ifTrue and ifFalse parameters are evaluated, so this function can not be used as a switch.
Prototypes for Comparison= ~ Returns True if equal: A = B
These are bitwise operators that return results on a bit by bit basis. Numeric values are automatically converted to 32 bit integers for the operations, then converted back to double precision floating point to return the results.
Prototypes for LogicalNot(N) ~ Bitwise NOT: Not(12) = ~13
A full set of double precision trig functions are available, including Arc (Inverse) and Hyperbolic functions. The default mode for trig functions is Radian; but you can change that by entering Radian or Degree or Grad (Gradient) for the mode you want. These functions return a number indicating the new mode: 1 for Radian, 2 for Degree, and 3 for Grad. If you want to query the current mode, use the special variable TrigMode (no parenthesis), which returns the current mode as above but does not change it.
Prototypes for Trig
Radian ~ Set mode to Radian (default)
Degree ~ Set mode to Degree
Grad ~ Set mode to Grad
TrigMode ~ returns mode 1, 2, or 3
Sin(N) ~ Sine
Cos(N) ~ Cosine
Tan(N) ~ Tangent
Asin(N) ~ Arc sine
Acos(N) ~ Arc cosine
Atan(N) ~ Arc tangent
Sec(N) ~ Secant
Cot(N) ~ Cotangent
Prototypes for Hyperbolic TrigSineh(N) ~ Hyperbolic sine
These functions do not fit in any neatly defined catagory, so they are grouped toghther here.
You can loop functions, however the entire function as defined in the script page is looped; you cannot loop a single statment within a function. Since ArtWonk is modular, this is not a problem: to loop a particular statment, simply break it out into a separate Function module.
The Loop(number) function causes the script page it is on to loop number of times. It does not matter where in the script you place the function as the entire page of script is looped; however it is good practice to place it as the first statment, for readibility. When a script is looping, you can access the 0-based iteration number with the loop variable I.
MasterClock(clocknumber) reads the System AutoClock for the given clocknumber (2-192). These are countdown clocks, when they are 0 the clock fires. So you can read them as logical values, with False (0) to indicate the trigger point, or you can read the value to indicate the duration within the clock cycle.
StatusMessage(messagetext) prints the text string messagetext on the ArtWonk status message at the bottom of the screen. Since messagetext is a string, it must be in quotes, such as:
StatusMessage("Notification of process completed")
Prototypes for SpecialLoop(N) ~ Cause function to immediately repeat N times
ArtWonk is Copyright © 2003-2014 by John Dunn and Algorithmic Arts. All Rights Reserved