#include
directive,
nGen will copy the file directly into the current file
before parsing the current file. For example:
#include |macros.txt|
will copy the file "macros.txt" (in the current directory or folder) and will insert it starting at the # sign. Include files may also contain their own include directives (recursion). When recursive includes are used, there is a limit of 12 files on the depth of the recursion. The file- or path-name must be enclosed in |s.
On the Macintosh this will look something like this:#include |C:/ngen/includes/macros.txt|
#include |Macintosh HD:ngen stuff:includes:macros.txt|
On all platforms except the Macintosh GUI, the "/" character is used to separate directories (folders). On these systems the forward slash (/)should be used but under DOS/Windows the backslash (\) may also be used. If a path name does not precede the file name, it will attempt to look for it in the current working directory.
Spaces are allowed in file names, which can be up to 255 characters (spaces must match the actual path and/or file name exactly as it is on your system). For extremely long file names you may put a carriage return in the file name but it must be an extra character (in addition to any spaces).
#if(n) (N.B. must be on its own line) ... (any code to be conditionally included) #endif (N.B. must be on its own line)
Similar to the C programming language, you can now use "#if" and "#endif" statements to omit or include chunks of code in the ngen input file (done after include file processing and before all macro preprocessing. If the value within ()s, and immediately after the "#if", which has to be an integer or floating-point value, is non-zero then the code within the statements will be included, otherwise it will be ignored. The value with ()s can also be a text-based or numerical macro (including an equation ~[...]) that evaluates to a zero-/non-zero value (macros within ()s in #if statements are processed with the #if statement and not during the regular macro preprocessing pass).
#if/#endif statement pairs may be nested and will not be written to the macro expansion file (-x command-line switch).
IMPORTANT: #if and #endif statements MUST be exclusive to the line they are on -- they may be preceded by whitespace but can be the only thing on that line (and they must EACH be on separate lines).
Example 1
One of the most useful things is to use #if/#endif as a simple switch
to turn things on/off with. In this example it would be particularly
useful if I had an input file of many i-blocks that were used as
a big texture.
Example 2
#const ON 1
#const OFF 0
#const Inst1 ON
#const Inst2 OFF
#if(~Inst1)
i1 = 5 0 22.1 {
...
}
#endif
#if(~Inst2)
i2 = 5 1.75 9.5 {
...
}
#endif
#if(~Inst1)
i1 = 5 10.25 -5 {
...
}
#endif
#if(~Inst2)
i2 = 5 14.25 -100 {
...
}
#endif
#if(~Inst2)
i2 = 5 0 -1 {
...
}
#endif
The following advanced example shows how #if/#endif can be useful to
create multiple "variables" for different renderings of one i-block.
I have created two groups of macros, one of which will be initialized
to create data for the i-block at the bottom of the input file --
this will depend on what I want to render. I have set-up the
if statements to work as a typical #if/#else/#endif (as can be found
in the C programming language). I set a constant called "FIRST";
if "FIRST" is 1 (TRUE) the first chunk will be used, otherwise,
the second one will initialize. Note that I've done this by checking
for even and odd numbers (in this particular case the first chunk
would initialize whenever "FIRST" is even -- x mod 2 = 0 if even).
nGen File:
/****/
#const FIRST 1 ;If "FIRST" = 0 use first #if, else use second #if
; This is a way to use #if/#endif like #if/#else/#endif
#if(~[FIRST % 2]) ;If "FIRST" is non-zero do this:
#const AMPFAC .5
#const TIME 15.5
#define TEMPO #te(0, ~TIME, 56, 106, e)#
#define WINSIZE #bn4#
#define WINFUNC(dur) #se($dur 1. *[10 11 12 13 14 15])#
#endif
#if(~[FIRST + 1 % 2]) ;Otherwise, do this:
#const AMPFAC .97
#const TIME 30
#define TEMPO #te(0, ~TIME, 100, 60, V.25)#
#define WINSIZE #bn5#
#define WINFUNC(dur) #se($dur 1. [12 13 14 15])#
#endif
$TEMPO
i1 = 6 0 ~TIME
{
p2 ra(T 1. [L .01 .1]) ;granular w/ emphasis on quicker grains
p3 dv(.1) 10 ;grain duration 10x start interval w/ 10% dev.
p4 pf(~AMPFAC) 1. ;grain amplitude
p5($WINSIZE) no mo(T 1. E c2 b9) ;move across bins, low to high expon.
p6(in) $WINFUNC(T*.5) se(T 1. [10 11]) ;grain window function
}
nGen Console Output:
Expanding const "equation" ( 1.00) into line 5...
Expanding const "equation" ( -0.00) into line 12...
Expanding macro "TEMPO" into line 21...
Expanding const "TIME" ( 15.50) into line 21...
Expanding const "TIME" ( 15.50) into line 22...
Line 24: T evaluated at = 15.50
Expanding const "AMPFAC" ( 0.50) into line 26...
Expanding macro "WINSIZE" into line 27...
Line 27: T evaluated at = 15.50
Expanding macro "dur" into line 28...
Expanding macro "WINFUNC" into line 28...
Line 28: T evaluated at = 7.75
Line 28: T evaluated at = 15.50
671 events generated in block #1 (i1).
Total i-block duration: 13.53 (secs), 15.48 (beats)
Cumulative i-block duration: 13.53 (secs)
Global cumulative duration of all i-blocks = 13.53 (secs)
You can define a macro using the #define
directive.
Macros may be deleted from memory using
the #undef
directive (you only
need to do this if you would like to use the macro name again but with
new contents).
#define V1 #0# #define V2 #100# #define Range1 #[g $V1 $V2]# #define Range2 #[b $V1 $V2]# #define mo(percent'low'high) #mo(T*$percent 1. $low $high)#
Now to call the "mo" macro:
$mo(.5'$Range1'$Range2) /* can also be called like this:$mo(.5#$Range1#$Range2) */
Expands to:
mo(T*.5 1. [g 0 100] [b 0 100])
Now, to remove the macro from memory (you need only do this when redefining the contents of a predefined macro name):
#undef mo
Notes on Macro Syntax:
Numeric macros (or more aptly, numeric constants) are preprocessor macros that are recognized as numbers for the purpose of altering them or plugging them into expressions for special circumstances during the pre- or post- processing of an input file. They are parsed as preprocessor directives (like macros) *after* regular (textual) macros (i.e., a textual macro can include a numeric macro (variable)).
TO DEFINE A NUMERICAL MACRO
#const LABEL VALUE (e.g., #const END 22.45)
where LABEL can be any text string that begins with a letter and can
contain any alphanumeric character including the '_' after the first
character. This is just like textual macros.
CALLING NUMERICAL MACROS
There are two ways to call macros (the ~ (tilde) flags them):
EQUATIONS
In the equation syntax, A-D represent "terms". A term can be an integer or a
floating point number, a previously declared variable name, or a
special token (see below). Equations must be on the same line.
OPERATIONS
These are identical to the "EX" DDF. The available operations
are +, -, *, /, and %. IMPORTANT: the order of operation is from
*left to right*. For example:
((((A o B) o C) o D) o E). So, 7 + 2 * 3 = 27 and 2 * 7 + 3 = 17.
SPECIAL TOKENS
There are three special tokens, "@1", "@2", and "?":
N.B. At the moment numerical macros will always evaluate to a floating- point number with a decimal-point precision of 3. This will make for some problems if you have to use them as integers. In some cases, since the variable evaluation is preprocessed you can get around this by using the "IN" input mode. You can't, however, use a variable in the i-block header for the number of events. :(
As stated above, numeric macros and equations are processed after textual macros. In this way, numeric macros and equations can be part of a textual macro argument and/or definition (since they won't be expanded until after all of the textual macros are expanded). For example, in:
$NEXT (a text-based macro) can be placed anywhere but will not be expanded in the textual macro definition (but rather in the final macro-expanded file). In this example, $NEXT is serving as the start time for each i-block. "@2" will be changing its value at the end of each i-block in the input file -- it will be accruing time with each new i-block.#const Interval 10 ; time between blocks #define NEXT #~[@2 + Interval]# ...later... i7=4 $NEXT -10 {