LMUSe (Java version)
01/01/01
david sharp davidsharp@rcn.com
Note: This documentation is not complete. In the meantime you can direct questions to davidsharp@rcn.com
contents
You will need to have a Java Runtime Environment (JRE) installed which is compatible with version 1.3 of the Java API. A free (and large, approx 5MB for the Windows version) package is available from java.sun.com for most systems. LMUSe may run (untested) with version 1.2.2 of JRE if you also have installed the Sound extensions (also available for free from java.sun.com)
The basic sequence of operations to make music from a set of transformation rules is:
1. Load a Rule file (or type an axiom into the 'axiom box' , and type some transformation rules into the 'rules box')
2. Make a production string from the axiom and rules.
![]()
3. Interpret the production string as MIDI events
4. Play the resulting music.
The buttons on the side are to 'find' a particular frame (for example, if one is hidden behind others). The 'P' button brings the Production frame to the front. 'I' is to get the Interpretation frame. The 'flowery tree' is the Drawing frame, and the quarter note is to find the MIDI playback.
L-systems were invented by Aristid Lindenmayer and others to model the development of living organisms by recursively applying a set of transformation rules to a simple initial string of symbols and interpreting the resulting (usually more complex) string of symbols as structure elements of the organsism. L-systems also provide a concise grammar for generating classic fractals like von Koch snowflakes, dragon curves, etc, as well as for modeling organic growth.
An L-system starts in generation 0 with a simple string of symbols called the 'axiom', and for each subsequent generation, symbols are replaced by new symbols or strings of symbols according to a set of rules. Say the axiom is just a single symbol (the axiom must contain at least one symbol):
A
and say the two rules are:
Rule 1: A=B
Rule 2: B=BA
The replacement rules tell how each symbol in the current generation should be replaced to make the next generation.
The axiom is the starting generation (generation 0). According to Rule 1, every 'A' in the current generation should be replaced by a 'B'. Rule 2 says that each 'B' in the current generation will be replaced with 'BA' in the next generation. If we follow the evolution of our axiom for a few generations
we get:
generation # production notes 0 A the axiom 1 B the A was replaced with B (rule 1) 2 BA the B of generation 1 was replaced with BA (rule 2) 3 BAB the B of gen 2 replaced with BA (rule2) and the A replaced with B (rule1) 4 BABBA The number of generations is the recursion level.
With more complex rules, the production can get very long after a few generations. When the produced symbols are read from left to right and interpreted as drawing commands, the resulting pictures can get very complex. Because of the recursive way the production string is made, L-systems are a concise way to generate the 'self-similar' nature of fractals.
In most L-system implementations a particular symbol ('F' in LMUSe) is interpreted as a command to "draw a line". Other symbols have other interpretations. '+', for example, could mean 'turn right'. The purpose of LMUSe is to interpret the resulting symbol strings as musical directions. For example, 'F' is interpreted as "play the note" (See 'Symbols' for the complete list of interpretations). Which note, and with what duration and volume, is determined by how you have chosen to map the system's geometry (the turtle's state) to notes.
Normally, LMUSe starts with a 'rule file' which contains an axiom string, a set of replacement rules, a default recursion level, the default turning 'angle' (a number of the specially interpreted symbols have to do with changing direction and orientation of lines) and a default line thickness.
#=== Sample Rules file ==== 5 #recursion level 30 #angle 10 # thickness AB #axiom A=+FB # first rule B=AF # second rule #===========================In LMUSe, everything on a line after a '#' is ignored to allow you to put comments to the right of #'s.
The rules are applied to the axiom (the '0' generation) to make a 'production string' (the first generation). The rules are then applied to the production string in turn, making a new production string (the second generation), which is run through the rules, the process repeated "recursion level" number of times. The result at the end is just called the "production string".
By itself, the production string is just a string of symbols. The production string is then 'interpreted'. That is, the symbols are mapped to drawing and/or music playing commands.
Context Sensitive and Stochastic Rules
Rules like A=AB, and X=FB^&F, are called 'context-free' because the symbol to be replaced (on the left of the '=') is replaced by the right side of the '=' no matter what other symbols happen to surround the symbol to be replaced. LMUSe also allows for 'Context-sensitive' rules. These are rules whose application does depend on the surrounding symbols. In LMUSe, context-sensitivity of a rule is denoted with '>' and/or '<'. The Java version of LMUSe reads in context-sensitive rules differently than the DOS version. In the Java version, a context sensitive rule looks like
X<B>Y=CDE
which tells LMUSe that 'B' should be replaced with 'CDE' if 'X' is to the left of the 'B' and 'Y' is to the 'B's right. This rule will only be applied if 'B' is between 'X' and 'Y'. If this was the only rule, then the string LMNOXBYPQBS would transform like:
current gen.
LMNOXBYPQBSnext gen
LMNOXCDEYPQBSContext sensitivity can be 'one-sided':
For examples:
A>B=HIJ
# "if there is a B is to the immediate right of A replace the A with HIJ". Whatever happens to be to the left of the A does not matter to this rule.F<A=XYZ
# "if there is an F is to the left of A, replace the A with XYZ"<A=WXYZ # "if there is no symbol to A's left (A is at the start of the production string), replace it with WXYZ"
B<A>=QP'(1.2)
# "if there is a B to A's left, and A is at the end of the production string, replace the A with QP'(1.2)If two rules happen to apply to a symbol in the production string, generally the most restrictive rule is applied. (A two-sided rule overrules a one-sided rule) If the two rules are equally restrictive, then there is no rule to decide which will be applied (One of them will be applied, but you should not count on which one).
A problem with the above syntax is how to write rules which replace '>'s and/or '<'s as context. For example, what is the rule
<>=L
supposed to do? Perhaps the '>' is the symbol to be replaced and its required left context is an empty left side. Or maybe the '<' is the symbol to be replaced and the rule says "replace '<' with L if there is an empty right side". Currently there is no good way in LMUSe to write rules for replacing '<' or '>' that have a required context.
LMUSe also implements 'stochastic rules'. Note that the Java version of LMUSe reads in stochastic rules differently than the DOS version.
A=BBA
simply replaces every occurrence of A by BBA. But
A(.5)=BBA
will replace A with BBA only 50% of the time. Just which particular A's will be replaced by BBA is randomly determined by LMUSe. The pair of rules:
A(.5)=BBA
A(.5)=ABA
will replace A with BBA 50% of the time, but otherwise (the other 50% of the time) A is replaced with AAB.
To have three stochastic rules each with a probability of (approximately) 1/3, you could write:
A(1/3)=BBA
A(1/3)=ABA
A(1/3)=BABB
or, slightly simpler
A(1/3)=BBA
A(1/3)=ABA
A=BABB
since a rule without a stochastic condition (the third one) will act as a default (that is, it will be applied if neither of the other two are).
There are two ways to combine a stochastic condition with a context-sensitive condition:
F<A>B(.5)=IJK
(.5)F<A>B=FF
The first rule will be applied 50% of the times that FAB is encountered. The second rule says that 50% of the times that A is encountered, the context will be tested to see if the rule should be applied.
Stochastically applied rules only have their random effect as the production string is being built. Once the production string is done you would have to do another 'Make' to see any difference due to the randomness. (LMUSe transformation rules can contain another type of randomness. The '~' (tilde) changes the current turtle state's direction randomly. The '~' does its 'work' at the time of interpretation and will give (probably) different results every time the production string is interpreted.)
In interpreting the production string, the string is treated as sequence of commands to a 'turtle'. The turtle's function is to look at each symbol in the production string and if the symbol is a reserved command symbol, then the turtle does what the command "says". The commands alter the turtle's state and/or cause the turtle to draw or make MIDI events.
In LMUSe, the turtle's state consists of
- the turtle's position
- a forward vector telling it what direction it is facing,
- an up vector which tells what direction the top of its head is pointing,
- a left vector telling what direction is to the turtle's left.
- the current line length and draw length
- line thickness
- color (instrument timbre),
- the size of the default turning angle
- which map the turtle is currently using to convert its current state into pitches, durations, and volumes.
- the current 'play time' (when the notes it is currently making are to be played)
- how far to transpose pitches.
Each of these components of the turtle's state can change and develop as the production string is interpreted.
There is only one turtle, so in order for it to make branching structures, or polyphonic musical lines, it needs some sort of memory of where it has been so that it can go back to certain points in its development to pick up where it left off. The turtle's state stack acts like the turtle's memory. The command which tells the turtle to put its state onto the stack is called 'push', and a command which tells the turtle to retrieve its old state from the stack is called a 'pop'. When a state is 'pushed' it is always placed on 'top' of the stack, and when the turtle does a 'pop' it always gets its new state off the top of the stack ('last in, first out').
The symbol '{' (curly bracket) is used to push the turtle's state and time and the accompanying pop state and time symbol is '}'.
For example:
F{FF}ZZ
On musical interpretation, this sequence of symbols would store the MIDI events for playing a note (F), then the '{' would push the current state and playing time. Then it makes another note (the third F), makes another note, and then pop ('}')the time and state that were pushed by '{'. The following note (Z) would start playing at the same time as the two notes inside the '{ }', since the time that was popped is the time that was pushed.
To push the state of the turtle, but not time (that is, so that a 'pop' will send the turtle back to where it was geometrically, but not back in time), you use '[', and the accompanying pop symbol is ']'.
It is often convenient to just push and pop the time (to allow the turtle to continue developing, but parallel in time to its previous development). The LMUSe symbols for pushing and popping just the time are '\' (push) and '/' (pop).
These are the symbols which have meaning during the interpretation.
Some of these are not used by Lparser or have a different interpretation. This can cause unexpected behavior if you use an Lparser file which contains them in LMUSe. For example, since m is not a special symbol in Lparser, it is often used in Lparser files as an 'intermediate' symbol. But in LMUSe, m ( or m(x)) changes the interpretation map. If you don't want this to happen, you can usually just change the m's in the file to M's or to something else.
Symbols which are 'command' symbols in LMUSe, but not in Lparser:
d, v, *, m, \, /.
Also, while '{' is interpreted by Lparser, in LMUSe, '{x' not only pushes the turtle state and time onto the stack, but begins writing to MIDI channel x.
Commands specific to music
t(x) transpose up (+x ) or down (-x ) by x semitones t transpose 0 d(x) multiply note durations by x d multiply note durations by 1.0 (cancels d(x)) v(x) multiply velocities (volume) by x v multiply velocities by 1.0 (cancels v(x)) *(x) write to MIDI channel x (modulo 16) * increment MIDI channel (modulo 16) m(x) interpret using map number x m increment map number Direction commands
+ turn left around up vector +(x) turn x degrees left around up vector - turn right around up vector -(x) turn x degrees right around up vector & pitch down around left vector &(x) pitch x degrees down around left vector ^ pitch up around left vector ^(x) pitch x degrees up around left vector < roll counter clockwise around forward vector <(x) roll x degrees left around forward vector > roll clockwise around forward vector >(x) roll x degrees clockwise around forward vector | turn 180 degrees around up vector % roll 180 degrees around forward vector $ roll until horizontal ~ turn/pitch/roll in a random direction ~(x) turn/pitch/roll in random direction to a maximum of x degrees Movement / Play commands
F draw full length forward play
F(x) draw x length forward play
Z draw half length forward play
Z(x) draw x length forward play
f move forward full length, draw within {} play within {}, otherwise rest
f(x) move forward x, draw within {} play within {}, otherwise rest
z move forward half length, draw if within {} play within {}, otherwise rest
z(x) move forward x, draw if within {} play within {}, otherwise rest
g move forward full length rest
g(x) move forward x rest
. don't move Stack commands
[ push current state but not event time ] pop current state but not event time { push current state and time {x push current state and time, writing to MIDI channel x } pop current state and time \ push just the time \x push just time, writing to MIDI channel x / pop just the time. only use '/' to pop a time that was 'pushed' with '\' Increment/Decrement commands
" increment length (times 1.1) ' decrement length (times 1/1.1) "(x)
'(x)multiply length with x ; increment angle (times 1.1) : decrement angle (times 1/1.1) :(x)
;(x)multiply angle with x ? increment thickness (times 1.4) ! decrement thickness (times 1/1.4) ?(x)
!(x)multiply thickness with x Color / timbre-instrument commands
c increment color index increments instrument program number
c(x) set color index to x sets current MIDI instrument program to x. Set to negative value (x<0) to silence.
@ end of rules, start maps (optional, but recommended, in rules file)
The format for rule files follows the format set by Lparser. Each rule file must be organized in this order, line by line:
- File can start with a list of declared constants, one to a line (optional) (Note that these are not supported in the DOS version of LMUSe or LParser. Such lines must be removed from (Java) LMUSe files before trying to use them in LParser or in DOS LMUSe).
- a recursion level
- angle (in degrees)
- thickness (optional in LMUSe, required by Lparser)
- axiom
- transformation rule 1 (optional)
- transformation rule 2 (optional)
- more rules, one to a line (optional)
- @ (end of rules marker) (optional in LMUSe, required by Lparser)
In addition, the file can contain comments. Anything after "#" on a line is ignored by LMUSe.
An example rule file :
transp=-12 # a declared constant # this whole line is ignored 4 # default recursion level 25 # basic angle of 25 degrees 50 # thickness is 50% of length A # the axiom A=+B^FA # rule 1 B=BBt(transp)F # rule 2 @ # end
Making the production string can often take longer than you expected. You interrupt a 'Make' by clicking the 'Interrupt' button.
The Axiom is loaded from the rule file. You can change the axiom by typing changes into the 'Axiom box'.
Production String
When the production string is complete (or its 'make' has been interrupted), the it appears in the box labeled 'Production String'. This is the string that will be interpreted. You can make adjustments to this string by typing into this box. For example, if you wanted to just turn the picture/interpretation by 90 degrees, instead of having to re-make the string, you could just type
-(90)
at the start of the string, then interpret. The string in the Production String box is the literal string that is interpreted from the Interpretation Frame.
It is often convenient to be able to 'declare' names for certain numerical constants which may appear several times in the transformation rules. To declare a name for a number, type your name for the number followed by '=', then the number. For example typing:
i1=12
in the 'declare box', then hitting Enter, 'declares' that the name (i1) in the rules or axiom will stand for the number 12.0 on interpretation (all numbers are converted to floating point format). However, the 'i1' in the rules or axiom will only interpreted as 12.0 if the name 'i1' is within parentheses.
c(i1)
in a rule would be interpreted as "change the instrument (color) number to 12". But
ci1
would be interpreted as three successive production symbols ('c','i','1').
A declared constant name is not converted to its number value until interpretation time. This means, for example, that if you are using i1 as an instrument name in your rules, c(i1), you do not need to remake the production string in order to change instruments, you only need to change the value of the declared constant in the declare box and re-interpret.
You can change the value of a declared name by changing the left side of the '='. A declared name can be 'undeclared' by removing the left side of '=' and hitting Enter. For example, typing:
pi=3.1415926535 <Enter>
i1=cos(pi/4)would change the value of 'i1' to .707.... .,
Typing
i1=
by itself will remove i1 from the list of defined constants.
If the production string contains a 'reassignment' in parantheses, e.g.:
gF+MA(i=i+4)
then the reassignment will take place at the time those characters are interpreted. (In this example, i is incremented by 4). You can even declare new constants within the rules or the production string, however if the definition or reassignment depends on the value of the constant (for example, the above i=i+4 depends on i having already been defined), that constant must actually have been previously defined or the code has no effect at all. Care should be taken in using reassignments this way since the assignment itself evaluates to 0, meaning a statement like
gF+Mc(i=i+4)
will also change the color/instrument to color/instrument #0. The point being that since it is often hard to predict just what symbols will precede such an assignment statement at interpretation time, it is probably a good idea to precede such assignments with a 'dummy symbol' for which you have no replacement rule. The dummy symbol will buffer the assignment from being 'misunderstood' as a parameter for some other L-symbol. For example, you could replace the above line with:
gF+McA(i=i+4)
Expressions can contain the elementary operations and functions :
+ - * / ^ (binary operations placed between numbers) ( ) [ ] { } (various parentheses) sin(x) cos(x) tan(x) Trig functions's argument x is in degrees asin(x) acos(x) atan(x) Inverse trig functions return degrees abs(x) sqrt(x) root(x) (various other unary functions) log10(x) log(x) alog10(x) exp(x) alog(x) int(x) nint(x) int(x) returns integer part of x. nint(x) rounds x to nearest integer rand(x) seed(x) rand(x) returns random number. 0<=rand(x)<x. Seed(x) can be used to get reproducible results from the random number generator. and previously declared names for constants. This capability is due to Tom Yarker's great TYParse class (see Credits).
Note:
Evaluating a bad expression, an undefined constant, or infinite expression generally returns 0.
Context-sensitive rules are applied if the symbols to the left and/or right of a symbol match the rule's declared context. Numerical expressions (numbers, or names of declared constants within parentheses) do not count as 'context'. For example, the rule
c<F=ZF
would match the string
c(foo)F
because the only thing between F and the c to F's left is a number. Other symbols that you want to be ignored as 'context' can be typed into the Ignore Context box and those symbols will not 'count' as context.
Makes a random change/mutation to the currently loaded rules. These mutations include things like appending one replacement string to another, changing directions in a rule, etc. Hitting 'Mutate' once may have no effect or it may have a devastating effect. It is, after all, random. The Undo button should revert the rules to the set of rules from before the last successful mutation (sometimes Mutate is unsuccessful, that is it doesn't actually change anything). Note that "Mutate" just mutates the rules; it doesn't make a new production string.
Load Rule File
Opens a "file dialog" to find a rule file to load. You can load a 'Rule w/ Map file' from here also, but the map part of the file will not be read.
Save Rule File
Saves current transformation rules, the rules in LMUSe's memory, to disk. The recursion level and basic angle included will be the ones current in LMUSe. If the rules were originally loaded from disk, be aware that 'Save Rule File' does not keep comments that may be in the original file. In other words, those nice comments you put in to let you know what the rules are about will not be in the saved file. Declared constants are saved as literal numbers. (For example, the original file may say "xx=sqrt(2)", but when written with Save Rule File, this will become something like "xx=1.4142135623730951". To keep the contents of your original file, save the rules with a modified name so the original file isn't overwritten.
If no file name extension is given, the file will be saved with extension .L
Load Map File
Gets parameters (maps, scale, etc) from a previously saved map (ususally *.map, or *.ini) file.
Save Map File
Save parameters (maps, scales, etc) to a map file. The default file name extension is .map
Load Rule w/ Map File
Gets rules and map parameters from a 'rule and map' file. A 'rule and map' file is simply a file which contains a rule file followed by a map.
Save Rule w/ Map File
Saves rules and map parameters in a single file. If no file name extension is given the file will be saved as *.rwm
Save MIDI
Saves your music as a (SMF format 1, multitrack) MIDI file. MIDI files are widely supported by sequencing programs, sound cards, and web browsers on nearly every type of computer. There are utilities available for converting MIDI files into CSound scores and other formats. In order to save different instruments (MIDI programs) to different tracks, select "Save Instruments on Separate Tracks" under the Options menu before saving. (Be aware, however, that if your creation has many instruments on many channels, you will get many many tracks). Other MIDI file options that were offered in the DOS version of LMUSe (SMF 0, etc) are not (yet) available in the Java version.
The map(s) determine how the L-system production string (the list of symbols resulting from the recursive rewriting of the axiom) is interpreted as notes to be played. By using the m(x) symbol, the production string can give directions as to which map should be used (see Symbols).
Currently you can use 5 different maps within a single interpretation. Edit a particular map by clicking on its tab (one of the numbers from 0 to 4). The interpretation will change maps when it encounters m or m(x) in the production string. Each map contains a Pitch box, a Duration box, and a Volume box for choosing which turtle state parameter should be used to pick pitches, durations and volumes of the notes produced. The pitch 'spread' slider bar is used to amplify or dampen the influence of the actual 'pitch parameter' values. Similarly, the duration slider and the volume slider are for amplifying the effect of the duration parameter and the volume parameter.
Each map also has its own Scale, Duration Multiplier, and Transpose amount.
The Interpretation dialog frame has two fields at the top, the Angle and Thickness, which are shared by all the maps. These are the starting default angle and default thickness.
In the Interpretation dialog frame, each field is part of the map and will be saved as part of the map file.
Click on the 'Pitch' box with the mouse to choose the parameter you want to dictate the pitches to be played. Similarly for 'Durations' and 'Volume'. The list of State Variables presented include the x, y, and z coordinates of an interpreted production, three directions: forward (where the line is headed), up, and left (each is a unit vectors with x, y, and z components), and a 'length' and 'drawlength'.
The difference between 'length' and 'draw length' is that the 'length' only changes with the length scale incrementing and decrementing commands (see Symbols). The 'draw length' comes from the actual length being drawn (or not drawn) on the screen. The draw length is affected by the difference between F and F(5) for example, or the difference between F and Z. (see Symbols).
Use the three "spread" sliders to amplify the interpreted range of the parameters. For example, by making the "pitch spread" greater than 1.00, the mapped pitches will be spread out further from middle c. A pitch spread between 0 and 1.00 causes the mapped pitches to be squeezed closer to middle c. Basically, increasing the "spread" makes changes in pitch, duration, or volume more dramatic. A negative value for the spread `inverts' the map. For example, when the duration spread is positive and duration is mapped to `draw length', longer lines make for longer note durations, but if a negative value is chosen for the duration spread, longer lines will yield shorter notes.
New State Variables
You can define new state variables in terms of x, y, z, forwardx, forwardy, forwardz, leftx, lefty, leftz, upx, upy, upz, length, drawlength, and/or thickness. The expression used to define a new state variable needs to reference the 'old' state variables as they are written here. That is, without spaces. An expression for a new variable is typed into the "New State Variable" box. The expression must begin with an equals sign to be accepted.
=expression
For example:
=sqrt(x*x+y*y+z*z)
will give the distance of the turtle from 0,0,0 (its starting point at the beginning of the interpretation). Or
=drawlength*forwardy
will give a new state variable which, if we consider the lines drawn by the turtle as 3d vectors, would be the component of the turtle's drawn line in the y-direction.
Once the expression for the new variable has been typed in, press the Return key. If accepted, the expression will then be added to the three lists (in the pitch box, duration box, and velocity box lists), ready to be chosen. Currently, about the only thing that keeps a new state variable from being accepted is if it doesn't start with '='. That is, no checking is done to see if your variable makes sense in terms of the default variables. If it doesn't (for example, if you misspelled 'forwardy' above as say 'fowady'), that new variable will always return a value of 0.
There is a check box labelled '"Normed". If checked, all new state variables will be scaled on interpretation. For example, 'forwardy' by itself (unscaled) is always between -1 and 1, but if 'normed', that -1 to 1 range is expanded so that a full range of MIDI pitches are possible on interpretation (or a range of durations or velocities). This is the default for 'old state variables', but the "Normed" box must checked for new state variables to be normed. A similar scaling can be done 'manually' by using the "spread" sliders, at least within the limited range of the sliders.
To remove one of the new state variables from the lists, select the one you want to delete in the "New State Variables" box, erase all but the equals sign "=", then hit Return. That variable will then be erased from all the lists.
Scale Box
The "Scale" box is for choosing, or defining, a musical scale into which the generated notes are "forced".
Duration Multiplier
The Duration multiplier slider is for stretching or compressing musical event times. Multiplying by a number greater than 1.0 stretches out the notes, while multiplying durations by a number less than 1.0 compresses all the notes. Similar to changing tempo, but only applies to notes mapped under this map.
You can load a previously saved map with 'Read Map File' under the File menu. (See 'Map Files' below). "Load Map File" in the File menu loads a previously save map file.
There are two files that are important for defining an LMUSe 'piece'. The first is, of course, the rule file. The other is the map file. A 'map' file is a text file that contains the map parameters (basically, the parameters you choose in the map dialog) which tell LMUSe how to interpret the turtle's state as note pitches, note durations, and note volumes. The format of these files is a list of "parameter=value" statements. The hash ('#') is used as a comment starter (everything on a line after a hash symbol is ignored). Here is an example map file, with comments
# Everything to the right of '#' on a line is ignored. # Each map line is of the form 'parameter=value'. # Including any of these parameter fields is optional. # Letter cases in map files are ignored. # 'new' state variables statevariable=upx+sqrt(x*y) # Declared constants violin=40 pi=3.14159 # tempo in beats per minute tempo=120 # scale new state variables? normed=false # mapnumber tells which map (0 thru 4) the following assignments # (up to the next mapnumber statement) apply to # when the file is loaded. mapnumber statements are # necessary to include several maps in a single map file mapnumber=0 # pitch, duration, and volume of notes are each determined by # any one of the following L-system variables, or expressions in # in terms of these: # x - the x coordinate of the turtle's position # y - the y coordinate of the turtle's position # z - the z coordinate of the turtle's position # forwardx - the x component of the turtle's forward direction # forwardy - the y component of the turtle's forward direction # forwardz - the z component of the turtle's forward direction # leftx - the x component of the turtle's 'left' orientation # lefty - the y component of the turtle's 'left' orientation # leftz - the z component of the turtle's 'left' orientation # upx - the x component of the turtle's 'up' orientation # upy - the y component of the turtle's 'up' orientation # upz - the z component of the turtle's 'up' orientation # length - (or 'statelength') the state length of the L-system # drawlength - the 'draw length' (affected by temporary length modifiers) # thickness - the Lparser line thickness pitch=x # This line says that map 0 will get pitches from # the x-coordinate of the turtle's position duration=drawlength # This map will get note durations from the length # of drawn lines. volume=forwardx-upy # Note volume comes from the difference between the # the x component of the turtle's forward direction # and the y component of the turtles up direction # pspread, dspread, and vspread are magnifiers for the influence # of the pitch, duration and volume parameters on the notes generated. # Recommended to stay in interval -4.0 to 4.0 pspread=1.000000 dspread=1.000000 vspread=1.000000 # 'scale=scalename' tells LMUSe what scale to use. # The predefined scale choices are 'Major', 'minor', 'Blue1','Penta1', # 'diminished', 'Twelvetone', or 'whole'. # Alternatively, you can give a list of number halfsteps from # starting with the number '0'. For example, a major scale # could be given by: scale=0,2,4,5,7,9,11 scale=Major # transpose amount transpose=0 # scale mode (which scale step is the tonic) mode=0 # duration multiplier dmultiplier=1.000000 # Here we start the parameters for map 1 (the second map) mapnumber=1 pitch=x duration=drawlength volume=forwardx pspread=1.000000 dspread=1.000000 vspread=1.000000 scale=Major scalefn=slideto transpose=0 dmultiplier=1.000000 # maps 2 thru 4 could go here. (order is not important) # Here, we just go straight to map 4 mapnumber=4 pitch=x duration=drawlength volume=forwardx pspread=1.000000 dspread=1.000000 vspread=1.000000 scale=Major scalefn=slideto transpose=0 dmultiplier=1.000000You can save the current rules together with the currently defined map in a single file (a 'rule and map' file). The easiest way to create a map file is to use the 'Save Map File' function under the File menu, but one typed in a text editor should work fine. Note that all of the above parameters do not have to be defined in a map file. You can create one that just sets certain map parameters by only including those parameters in the file.
An additional "parameter=value" is "file=filename" which will recursively read in another map file from this map file.
# Read in some other file file=test.mapValues in this new file can either override or be overridden by the parameters read in by the original file, depending on the placement of the 'file=filename' statement occurs in the original file. (If the new file is read in before the "parameter=value" statements in the original file, the new files values will be over-ridden when the original file values are read)
You can choose or create a musical scale that will be used while the 'current' map is in effect from the Map 'Scale box'. The scales are described below.
Any scale not in the drop-down list can just be typed into the box. The scale you type in should start with '0' (lowest note of the scale) and thereafter each following number denotes the next higher note in the scale, in 'half tones'. Put spaces or commas between different scale notes. For example:
0 2 4 5 7 9 11
would make a major scale.
Note: In the DOS version of LMUSe, scale definitions started with '1', not '0'.
The scales in the list are defined, either by convention or by me, as:
Twelvetone 0 1 2 3 4 5 6 7 8 9 19 11 c c# d d# e f f# g g# a a# b Major 0 2 4 5 7 9 11 c d e f g a b Penta 0 0 3 5 7 10 c d# f g a# Penta 1 0 4 7 9 10 c e g a a# Penta 2 0 2 4 7 9 c d e g a Minor 0 2 3 5 7 8 11 c d d# f g g# b Blues 1 0 2 3 4 7 8 9 10 c d d# e g g# a a# Whole tone 0 2 4 6 8 10 c d e f# g# a# Diminished 0 1 3 4 6 7 9 10 c c# d# e f# g a a# Hijaz 0 1 4 5 7 8 10 c c# e f g g# a#
The drawing frame should be considered mainly as an interpretation step progress indicator; in general it is often not an accurate representation of the Lparser object. (see) The buttons along the bottom are for changing the 'viewing plane'.
Note that the interpretation step is speeded up noticeably when the drawing frame is 'iconified' so that the drawing frame isn't actually painted (click the little square in the upper right hand corner of the drawing frame).
The MIDI view frame should automatically come to the front when
the interpretation of the production string is finished. The graphic is supposed to show all of the created notes, arranged from bottom (low pitch) to top (high pitch) and left (beginning) to right (end). The color of a little bar is the same as the color of its corresponding 'graphical element'. That is, it is, modulo 17, the Lparser color of the MIDI instrument number playing the note.
While you can change the tempo of the playback (using the Tempo slider), this does not change the sequence itself. (For example, restarting the sequence will reset the tempo). In order to change the sequence's tempo, you need to set the tempo with the slider, then reInterpret the production string.
The 'q' button is to quantize the note times in the current sequence. That is, it aligns all notes to the chosen beat fraction. Quantizing to '1/8', for example, will align the timing of all notes to eighth note time divisions. Remember that quantizing loses timing resolution so use with discretion. Quantizing the sequence is the only 'sequence editing' function available in LMUSe. Any other changes are accomplished by re-Interpreting with new parameters to get a new sequence. Also, there is no 'undo' button. To undo a quantization, re-Interpret the production string.
The Play/Stop button starts/stops playing the MIDI sequence.
The slider directly below the Play/Stop button is for finding a particular time in the sequence. Sadly, it is not very well synchronized with the graphic representation. (Eventually, this will be improved). And resetting the tempo without re-Interpreting the production string completely screws up the synchronization.
Rules Files Compatibility
Lparser *.LS files should all work in LMUSe (meaning only that they will be accepted and interpreted by LMUSe). Be aware, though, that files that work in LMUSe won't necessarily work with Lparser. The LMUSe parser was designed to interpret the large number of LParser files available but LParser won't accept some of the LMUSe rules (context sensitive or stochastic rules). Also, rules files saved from the Java version of LMUSe can contain 'declared constants' before the rules. These must be removed before trying to load such files into LParser or the DOS version of LMUSe. On the other hand, while LParser can make beautiful graphics, LMUSE can't. The drawing that LMUSe does while interpreting is intended mainly as a 'progress indicator'.
I have tried to keep the file extensions of the examples consistent. A file with just an 'L' extension is an LMUSe rules file which does not contain a 'thickness' (the third non-comment in Lparser files is the starting thickness of lines as a percent of their length and must be present for the file to work properly with LParser), or if it contains stochastic rules (like A(.5)=ABB) or context sensitive rules (e.g. A<F=BF), or if for some other reason it may not be compatible with Lparser.. If I believe a file is compatible with Lparser (for example, contains a thickness and no context sensitieve or stochastic rules), it should have the 'ls' extension. A file that has been mutated by LMUSe (saved after 'mutating') is given the 'lm' extension. 'lm' files which were originally 'ls' files before mutation should still be compatible with Lparser, but I haven't checked all of them.
Certain of the symbols are interpreted differently in the two programs. For example 't(-12)' in LMUSE transposes the following notes down by 12 semitones. In LParser, t is interpreted as a 'tropism' or gravity influence. This interpretation of 't' is completely ignored by LMUSE. In LMUSE, '{' and '}' are mostly for creating parallel in time (polyphonic) musical lines. Their use in LParser is for making polygons like leaves, flower petals, etc). LMUSE does not know 'polygons' at all and so the generated graphics often look different from what you might expect from seeing the same file interpreted by LParser.
Please email dsharp@rcn.com for any problems not listed here.
The drawing does not resemble the LParser rendering: There are a number of LParser's drawing symbols which are interpreted differently (or not at all) by LMUSe. LParser polygons are not supported by LMUSE. (Running the various treeXX.ls LParser files illustrates the problem. The leaves are bigger than the rest of the tree!). In a minimal attempt at compatiblility, LMUSE takes a stab at drawing the polygons by treating them as normal (non-polygon) drawing commands, but you will notice that this is a poor compromise. Also, while LMUSe does keep track of line 'thickness' (you can map note parameters to it), line thickness is completely ignored in the drawing. The drawing is mainly meant to be a progress indicator while LMUSe is turning the production string into music.
The MIDI position slider is not synchronized with the note graphic, when the tempo is changed: Hopefully this will be fixed in some future version.
Special Thanks to
Laurens Lapre, ljlapre@xs4all.nl, for LParser. Home page : http://www.xs4all.nl/~ljlapre/
Tom Yarker, tyarker@netexpress.net for the TYParse class which makes the 'declared constants' possible in LMUSe.
Lindenmayer, A. Mathematical models for cellular interaction in development, Parts I and II. J. Theor. Biol., 18:(1968),280-315.
Prusinkiewicz, P., and Hanan, J.Lindenmayer. Developmental Models of Herbaceous Plants for Computer Imagery Purposes. SIGGRAPH '88 ,Volume 22, Number 4, August. Springer-Verlag, New York (1988).
Prusinkiewicz, P., and Hanan, J. Lindenmayer systems, fractals, and plants. InD. Saupe (Ed.): Fractals: Introduction, basics and applications. [Course notes] SIGGRAPH '88, Volume 79 of Lecture notes in biomathematics. Springer-Verlag, New York (1989).
Prusinkiewicz, P. and Lindenmayer, A. The Algorithmic Beauty of Plants. Springer-Verlag, New York (1990).
Prusinkiewicz, P. Modeling and visualization of biological structures. In Proceedings of Graphics Interface '93, pages 128-137, May 1993. Held in Toronto, Ontario, 19-21 May 1993.
Rozenberg, G. and Salomaa, A.The mathematical theory of L systems. Academic Press, New York(1980).
Rozenberg, G. and Salomaa, A. Lindenmayer systems: impacts on theoretical computer science, computer graphics, and developmental biology. Springer-Verlag, New York (1992).
Most references grabbed from Christina Swindells & Jelle Ouwerkerk
Dr. Przemyslaw Prusinkiewicz's page
http://www.math.okstate.edu/mathdept/dynamics/lecnotes/node12.html
http://life.csu.edu.au/complex/tutotials/tutorial2.html
C van der Mark's excellent tutorial for LParser.
CALResCo: The Complexity & Artificial Life Research Concept for Self-Organizing Systems has an astounding collection of complexity, artificial life, and fractal type resources.
A list of L-systems software for various OS's
The Spanky Fractal Database has loads of fractal related materials, including many 2-d L-system rules for Fractint (Also see Converting Fractint L-systems for use in LMUSe
Guenter Nagler's MIDI utilities.
End of File