flora
project name: flora
project url: https://github.com/jaseknighter/flora
author: jaseknighter
description: l-systems sequencer and bandpass-filtered sawtooth engine
discussion url: https://llllllll.co/t/40261
documentation url: https://norns.community/authors/jaseknighter/flora
tags: generative synth sequencer midi crow jf w

Flora

An L-systems sequencer and bandpass-filtered sawtooth engine for monome norns

Demonstration video: https://vimeo.com/496481575
Follow the discussion on lines: https://llllllll.co/t/40261

Documentation

Overview

L-systems and their sequencing

L-system basics

An L-system is a parallel rewriting mechanism originally conceived by Aristid Lindenmayer in 1968 as a mathematical model of plant development.

The basic building blocks of most L-systems include:

Take the following:

The above axiom and rulesets will result in the following sentences when run six times, starting with the axiom b as Generation 0. Ruleset 1 states that each time the character b is encountered, it is replaced with a. Ruleset 2 states that each time the character a is encountered, it replaced with ab.

Sequencing the L-system

The Flora alphabet
Character Turtle Behavior Sound Behavior
F Move the turtle forward and draw a line and a circle Play current note
G Move the turtle forward and draw a line Resting note (silence)
[ Save the current position Save the current note
] Restore the last saved position Restore the last saved note
+ Rotate the turtle counterclockwise by the current angle Increase the active note’s pitch (see Changes in pitch below)
- Rotate the turtle clockwise by the current angle Decrease the active note’s pitch (see Changes in pitch below)
| Rotate the turtle 180 degrees No sound behavior
r Randomly increase or decrease the angle each frame Randomly increase or decrease the active note’s pitch (see Changes in pitch below)
! Randomly set an angle Randomly increase or decrease the active note’s pitch (see Changes in pitch below)
other Other characters are ignored by the turtle No sound behavior
Changes in pitch

Flora leverages L-systems to algorithmically generate music, in particular, by taking the angles written into the L-system sentences as indicators of an increase or decrease in pitch. The amount of change in pitch is set by the angle measured in radians multiplied by the current pitch. The changes in pitch are quantized, so if an angle multiplied by the current pitch is not greater than a whole number, the pitch stays the same.

If a change in angle results in a pitch that is greater than the number of notes in the active scale, the active note becomes the root (lowest) note of the active scale. Conversely, if a change in angle results in a pitch that is less than the root note of the active scale, the active note becomes the last (highest) note in the active scale.

Bandsaw

If the output parameter is set in norns to include audio, notes will be played using the Bandsaw engine, built around a bandpass filtered sawtooth wave generator. This engine is based on the marimba instrument demonstrated by Eli Fieldsteel in video, SuperCollider Tutorial #15: Composing a Piece, Part I.

Unlike a ‘typical’ oscillator, where the frequency of the oscillator is perceived as the note being played, the notes typically heard when the Bandsaw engine is played are determined by the center frequency of its bandpass filter, not the frequency of its sawtooth oscillator.

The parameters of this instrument may be set in the PARAMETERS->EDIT menu or on the water page of the Flora program (see water below for more details)

SAFETY NOTES

Safety Note #1
The SuperCollider documentation for its BandPassFilter (BPF) contains the following warning:

WARNING: due to the nature of its implementation frequency values close to 0 may cause glitches and/or extremely loud audio artifacts!

For safety purposes, the minimum note frequency value is set to 0.2 to prevent loud noises. This safety measure is implemented in both the Bandsaw engine and the Lua code for norns.

Safety Note #2
The Bandsaw engine becomes loudly percussive as the values for rqmin and rqmax increase. Please take care not to hurt your ears, especially when using headphones.

norns UI

Flora’s interface consists of five screens (or “pages”). Navigation between screens occurs using Encoder 1 (E1). While the controls for each screen vary, basic instructions for each screen can always be accessed using the key combination: Key 1 (K1) + Key 2 (K2). The instructions may also be found in the lib/instructions.lua file.

For many parameters, fine-grained adjustments can be made by pressing K1 along with the encoder (see below for details.)

Screens

The first three screens of the Flora program (Plant, Modify, and Observe) display two L-system rulesets, used by the program to sequence notes. The fourth screen (Plow) displays two envelopes. The fifth screen (Water) displays controls for the Bandsaw engine and other outputs (i.e. Midi, Just Friends, and crow).

Plant

e1: next page  
k1 + e1: select active plant  
k1 + e2: replace active plant  
e3: increase/decrease angle  
k2/k3: previous/next generation  
k1 + k3: reset plants to original forms and restart their sequences

Modify

e1: next/previous page  
k1 + e1: select active plant  
e2: go to next/previous letter  
e3: change letter  
k2/k3: delete/add letter  
k1 + k3: reset plants to original forms and restart their sequences

Observe

e1: next/previous page  
k1 + e1: select active plant  
e2: move up/down  
e3: move left/right  
k2/k3: zoom out/in  
k1 + k3: reset plants to original forms and restart their sequences

Plow

e1: next/previous page 
k1 + e1: select active plant  
e2: select envelope control  
e3: change envelope control value  
k2/k3: delete/add envelope control point  

The Plow screen provides controls for two envelopes, one for each L-system ruleset sequence. An extension of Mark Eats’ envgraph class, the envelopes controlled on this screen are applied to the Bandsaw engine when the envelopes’ respective L-system ruleset sequence triggers a note to play.

Unlike typical envelopes (AR, AD, ADSR, etc.), the envelope class developed for this program allows for a variable number of control points or ‘nodes.’ The program allows for anywhere from 3-20 nodes per envelope.

There are 5 types of controls for each of the two envelopes:

env level: the maximum amplitude of the envelope
env length: the length of the envelope
node time: when the node is processed by the envelope
node level: the amplitude of the envelope at the node time
node angle: the shape of the ramp from the prior node time to the current node time

With a few exceptions, the last of the three control types (node time, node level, and node angle) are adjustable for each of envelopes nodes.

Fine grain controls: All of the envelope controls allow for fine grain control using K1+E3.

Plow modulation
e1: next/previous page 
k1+k3: show/hide plow modulation menu
k1+e1: select active plant  
k2: select control
k3: change control value

As of version 0.2.0-beta, pressing K1+K3 on the plow screen brings up the plow modulators menu, which can be navigated using E2 and E3. There are eight parameters for each of the two plants related to modulating envelopes that may be set:

mod prob: The probability that one of the other modulation parameters will be evaluated. If it is set to 0%, no envelope modulation will occur for the selected plant.
time prob: The probability that the time value for each of the envelope’s nodes will be modulated.
time mod amt: The amount of modulation that will be applied to the time value of each of the envelope’s nodes.
level prob: The probability that the level value for each of the envelope’s nodes will be modulated.
level mod amt: The amount of modulation that will be applied to the level value of each of the envelope’s nodes.
curve prob: The probability that the curve value for each of the envelope’s nodes will be modulated.
curve mod amt: The amount of modulation that will be applied to the curve value of each of the envelope’s nodes.
env mod nav: Selects which of the above seven parameters are selected on when plow modulation is visible (by pressing K1+K3) on the plow screen. This parameter is useful for controlling the plow ui via midi.

In addition, the show env mod params parameter makes the parameter modulation navigation visible (again, useful for controlling the ui via midi).

Water

e1: next/previous page  
e2: select control  
e3: change control value  

The water interface provides control for the output parameters:

Fine grain controls: All of the controls in the above list with the characters ‘(fg)’ attached to the control names allow for fine grain control using K1+E3.

Note: Tempo scalar offset is a parameter that provides macro control over all active note frequencies. It is not yet available from the Water UI screen but can be adjusted from PARAMETERS->EDIT. The Tempo Scalar Offset’s default value of 1.5 can also be changed by updating the variable tempo_scalar_offset_default in the lib/globals.lua file.

Tinta and Tinta Envelope

e1: previous page  
enter commands with external keyboard

As of flora v2.0, the tinta interface provides control for the melody accompanying the plant melodies via external keyboard or the Maiden REPL and was inspired by Aarvo Pärt’s method of Tintinnabuli).

Tinta makes extensive use of sequins.

Options have been added to the PARAMETERS menu controls to output tinta notes to midi, crow, jf, and w/.

as of flora v2.1, three options have been added to set the envelope used by tinta, using the new tinta env type parameter in the tinta section of flora’s parameters menu:

for the morphing envelope type, the duration and number of steps, and “shape” of the morph may be set with two new tinta commands: edu and est.

there are three “styles” of envelope morphing, set with the new tinta env morph style parameter:

Keyboard commands (using an external keyboard)

Command Description
tin set the melody
format: tin=s{1,3,5,s{4,2}}
oct shift the octave
recommended range: +/- 2
format: oct=s{0,1}
vel set the velocity of each note
recommended range: 0 - 10
format: vel=s{0,5}
rhy set the rhythm of each note
recommended range: 0.1 - 2
format: rhy=s{1,0.25}
stop stop the melody
format: stop
play play the melody
format: play
offdance don’t adjust melody relative to plant melody
format: offdance
ondance adjust melody relative to plant melody
format: ondance
estart start envelope morphing
format: estart
estop stop envelope morphing
format: estop
edu set the recommendation morphing duration (in beats)
recommended range: 0.125 - 50
format: edu=s{1,10}
est set the number of steps to complete the morph (each step generates an envelope)
recommended range: 1 - 50
format: est=s{3,20}

Important note: when setting the rhythm (rhy), nested sequins will throw an error (e.g. rhy=s{1,s{0.5,0.25}}).

REPL commands (using the Maiden REPL)

Using the maiden REPL to control the tinta interface, more complex sequins functionality can be utilized such as flow-modifiers.

Tinta Command Description
tin set the melody
format: tt.tin=s{1,3,5,s{4,2}}
oct shift the octave
recommended range: +/- 2
format: tt.oct=s{0,1}
vel set the velocity of each note
recommended range: 0 - 10
format: tt.vel=s{0,5}
rhy set the rhythm of each note
recommended range: 0.1 - 2
format: tt.set_rhythm({1,0.25}). (note that when setting the rhythm with the maiden repl, a table is passed to the method tt.set_rhythm instead of setting the rhythm directly with sequins.)
edu set the envelope morphing duration (in beats)
recommended range: 0.25 - 50
format: tt.edu=s{1,10}
est set the number of steps to complete the morph (each step generates an envelope)
recommended range: 1 - 25
format: tt.est=s{3,20}

Tinta params menu | Paramter | Description | | ———————- | —————————————————————– |
| tinta enabled | turns the tinta melody generator on and off | | dancing notes | if set to on the tinta melody is set relative to the notes played by the plant forms | | tinta target | sets which plant to determine the tinta melody when the dancing notes parameter is set to “on” | | tinta method | sets how the tinta note is selected: cycle, closest, and furthest | | tinta env type | selects the type of envelope used by tinta: ad,plant,morph | | tinta env morph | starts and stops morphing when the tinta env type parameter is set to morph| | tinta env morph style | determins how morphing occurs: shuttle, loop,1-shot |

PSET Sequencer

As of version v0.2.0-beta, a PSET sequencer has been built into Flora. This feature allows PSETS saved in the PARAMETERS->PSET menu to be sequenced. The sequencer’s parameters (accessed from the PARAMETERS->EDIT menu) include:

Parameters that are part of an enabled exclusion set will be excluded when a PSET is saved. Accordingly, parameters in an enabled exclusion set won’t be overwritten when the sequencer loads a PSET. Please note that for this feature to work, exclusion sets need to be enabled (in the PARAMETERS menu) before saving the PSETS. Enabling a PSET exclusion set while the PSET sequencer is playing will have no immediate effect.

Custom exclusion sets can be created by adding, deleting, and modifying the tables defined in the init function of the flora.lua file.

Generating new L-system axioms and rulesets

L-system instructions are found in the files lib/gardens/garden_default.lua and lib/gardens/garden_community.lua. There are eight required variables/tables for each L-system instruction set:

Variable Description
start_from the starting x/y screen coordinate (format: vector:new(<x>,<y>)
ruleset[] the l-system ruleset(s) (format: rule:new('<character>',"<character(s)")
axiom the starting sentence (format: "<character(s)>"
max_generations the maximum number of generations
length the starting length (in pixels) of the segments drawn by the turtle
angle the default turtle rotation angle (in degrees)
initial_turtle_rotation initial turtle rotation angle (in degrees) applied to the turtle prior to evaluating the ruleset
starting_generation the initial generation to display

Example instruction set :

instruction.start_from = vector:new(screen_size.x/2-10, screen_size.y - 10)
instruction.ruleset = {}
instruction.ruleset[1] = rule:new('F',"F++F++F|F-F++F")
instruction.axiom = "F++F++F++F++F++F"
instruction.max_generations = 2
instruction.length = screen_size.y/8
instruction.angle = 36
instruction.initial_turtle_rotation = 0
instruction.starting_generation = 1

Advanced sequencing

Multiple rulesets Multiple rulesets can easily be added to the instruction.ruleset table.

Example instruction set with multiple rulesets:

instruction.start_from = vector:new(screen_size.x/2, screen_size.y )
instruction.ruleset = {}
instruction.ruleset[1] = rule:new('F',"G[+F]G[-F]+F")
instruction.ruleset[2] = rule:new('G',"GG");
instruction.axiom = "F"
instruction.max_generations = 3
instruction.length = 7
instruction.angle = 30
instruction.starting_generation = 2
instruction.initial_turtle_rotation = 90

source: http://algorithmicbotany.org/papers/abop/abop-ch1.pdf (Figure 1.24(d))

Community gardening

As of Flora v0.4.0, a new community gardening feature has been enabled, which leverages norns.online to allow custom plant shapes (i.e. sequences) to be shared through the norns’ UI.

To take advantage of the new community gardening feature, install Flora v0.4.0 or later as well as the norns.online script.

Once Flora v0.4.0 and norns.online have been installed, the community gardening features may be accessed from the Gardening section at the bottom of the PARAMATERS>EDIT menu as follows:

Steps to share a plant shape with the community

  1. Save plant to nursery: locally saves the active plant shape to the norns’ filesystem (in data/flora/nursery/)
  2. Enter the Community gardening submenu
  3. Select refresh directory
  4. Select upload from nursery and choose a plant
  5. Choose the plant you saved to your nursery in step 1 above

Steps to obtain a plant shape from the community garden

  1. Enter the Community gardening submenu
  2. Select refresh directory
  3. Select download to nursery and choose a plant
  4. Exit the Community gardening submenu
  5. Select Add plant to garden and choose the plant you downloaded from the community gardens

** Note, selecting a plant to be added to your local ‘garden’ will append it to the end of the list of selectable plants found on the plant screen. On this screen, use K1+E2 to select the plant. By default there are 11 plants, so the first plant added to the garden will be shown as plant i12, the second plant will be shown as plant i13, and so on.

Additional gardening features

W Integration

Overview

As of v0.4.0, Flora provides i2c integration with Whimsical Raps’ W/2 eurorack module via crow. All three modes, W/Tape, W/Syn, and W/Del, are supported. See the W/2 documentation on the lines forum about how each mode functions.

Flora’s integration with W/2 is accessed via the PARAMETERS>EDIT menu. Prior to accessing the parameters for a particular mode, W/2 must first be put into the proper mode.

W Syn sequencing

W/Syn can be sequenced with Flora via i2c by setting the wsyn output parameter in the parameters>edit>w/syn menu.

Karplus-Strong sequencing

W/Del supports Karplus-Strong style string synthesis, which can be sequenced with Flora via i2c by setting the Karplus-Strong parameter in the parameters>edit>w/del menu.

Integration with other norns scripts

Flora’s code to integrate with W/2 may be relatively easily dropped into another norns script:

  1. Install Flora v0.4.0 or later
  2. At the start of the norns script add the following two lines of code:
    cs = require 'controlspec'
    w_slash = include("flora/lib/w_slash")
    
  3. At the end of the script’s init function add the following six lines of code:
      params:add_group("w/del",15)
      w_slash.wdel_add_params()
      params:add_group("w/syn",14)
      w_slash.wsyn_add_params()
      params:add_group("w/tape",17)
      w_slash.wtape_add_params()
    

Note, enabling sequencing with w/Syn and W/Del in another script requires additional code (see Flora’s plant_sounds_externals.lua file for details).

Requirements

Preliminary Roadmap

Credits

References