Lindenmayer function

Hey all, I'm trying to use the Lindenmayer function, which returns a string. To convert this string to a pattern, the documentation suggests using the step' function to translate the characters in the Lindenmayer string into sounds in a pattern. However, I want to directly turn the string into a numeric pattern and pass it to the note function. What would be the best way to achieve this?

1 Like

There's the listToPat function which can convert from a numeric output into a tidal pattern, if that's what your looking for?

what is a Lindenmayer function?

L-systems can be used for procedural generation. They are called Lindenmayer systems because of the person who developed them, Aristid Lindenmayer.
They consist of an axiom (your starting point, which is a string of symbols) and a set of rules to expand each symbol into a string of symbols.

This article says something about how L-systems can be used to generate melodies.

The first approach I personally had with them was with a Matlab implementation of the Sierpinski triangle.

3 Likes

how do you know all this shit? i feel like i am so woefully uninformed about just about everything that goes on here.

also, thanks for the links :wink:

2 Likes

Nah, some stuff here and there.
But I didn't know what woefully means! :upside_down_face:

1 Like

Are strings in haskell represented as lists? If so, this would work very well! And either way, this looks like a useful function. Thank you!

i love how the documentation references a function called step and then uses a variation called step' in the example. meanwhile, neither step nor step' can be found in any index of functions elsewhere on the site. :face_with_symbols_over_mouth:

do you suppose Autechre were referring to L-systems when titling their EP L-event? :thinking:

one of my favs: https://twitter.com/LSystemBot

Taken from https://twitter.com/LSystemBot/status/1265708107692310528:

{"start":"NNF","rules":{"F":"[]F[NN]-+-F","N":"[-]+F+"},"a":45,"iter":5}

image

5 Likes

pro tip on the lindenmayer: works brilliantly if you put it in a stack by itself. from there you can apply whatever transformations you want.

e.g. d1 $ stuffOverHere $ stack [slow 16 $ sound $ step' ["feel:0", "sn:1", "bd:0"] (take 512 $ lindenmayer 5 "0:1~~~,1:0~~~2~~~~~0~~~2~,2:2~1~,~:~~1~" "0")] # stuffOverHereToo

@sdsd19 FYI i placed my note values to the left of the stack which worked great.

8 Likes

I have absolutely no idea, but it might worth asking them directly!

2 Likes

can anyone caution a guess as to what is happening within the string?

"0:1~~~,1:0~~~2~~~~~0~~~2~,2:2~1~,~:~~1~"

i am assuming the number to the left of the colon indicates the "step" but as far as the recursion "rules" that follow to the right of the colon, i'm a little lost. it's not quite binary but it does appear to work like an "on/off" switch. what do you suppose the integers to the right side of the colon indicate?

Yes- a string in Haskell is a list of the type Char. Let me know if this function works for this!

@sdsd19 just looking into the documentation I found a function that can be helpful to you: lindenmayerI.
Basically, same as lindenmayer but with fromIntegral applied for free.

Think of it as current value: substitution.

The string should contain the rule set for the L-system, so the string is telling you:

  • every time I see 0 I substitute it with 1~~~
  • every time I see 1 I substitute it with 0~~~2~~~~~0~~~2~
  • every time I see 2I substitute it with 2~1~
  • every time I see ~I substitute it with ~~1~

and then the process starts from the simplest string: "0" - this is the last argument of the function.
Does it make sense?

3 Likes

yes, that's helping me get closer to understanding; thank you! but what are the integers themselves mapped to? in the case of step 2, we're looking at 0s and 2s...how are those two values operating on "sn:1"?

1 Like

The string is one argument of step', whereas the other argument is ["feel:0", "sn:1", "bd:0"].
What the function does is to select the string given the index coming from the string. The string then is wrapped into the Pattern context and is ready to be passed to sound to get played.

To sum up:
l-system -> value -(index of)> sample -> sound -> out

1 Like

yep, i get all that. what is unclear to me (and this is not on you, but frankly the lack of info in the docs -- thank you for all your help explaining this) is what the actual values in the string refer to...in my mind, either the sample plays or it doesn't. in the above string, we have a 0, a 1, a 2, and a ~. reading up on L-systems, the rules all seem relate to morphological positions (move forward, tilt by n degrees, etc.). so my question really is this: what rules are we giving to the samples?

1 Like

They refer to possible index values.

I think that you should not make this association because here there is no procedural drawing and therefore you don't need to make rules on how to move. You could rather think of an abstract set of rules that you can apply (at least here) to anything you want.

In this case, the values go from 0 to 2 because we happen to have 3 samples in the list of strings - and Haskell starts counting from 0.

One more example: say you want to build an L-system for melodies.
In this case, what I would do is to use scale and create a set of rules that defines substitutions for the first 7 numbers, i.e. 0 .. 6 (considering a scale made of 7 notes) because this is enough for me to apply the system using note (scale "minor" lindenmayerList).

5 Likes