L-System Granular Pitch — User Guide

Rule-based grain scheduling for rhythmic gating and cumulative pitch transposition while preserving the detected source F0 contour.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.6.1 (2026) License: MIT License Repo: https://github.com/ShaiCohen-ops/Praat-plugin_AudioTools
Contents:

What this does

L-System Granular Pitch converts an L-system string into a sequence of fixed-duration control windows. Each window receives a symbol, a cumulative semitone shift, and a play/skip gain. The pitch schedule is applied to the detected source F0 contour with Praat Manipulation resynthesis, then the gain schedule is applied directly to the resulting continuous Sound.

Signal flow: L-system → grain-indexed pitch/gain schedule → optional pitch resynthesis → continuous gating envelope → peak safety.

The term grain refers here to the time grid used for L-system control. The script does not extract, reorder, repeat, or overlap separate audio fragments. Pitch remains a continuous Praat resynthesis process, and gating is applied to the continuous output Sound.

The L-system itself is deterministic: the same source, rules, iterations, and processing settings produce the same control string and schedule. There is no random generator or seed.

Quick start

  1. Select exactly one Sound object in Praat.
  2. Run L-System_Granular_Pitch.praat.
  3. Choose one of the eight built-in presets or Custom.
  4. For Custom, define the axiom, the five production rules, the iteration count, and the maximum generated-string length.
  5. Set the control-window length with GrainDuration_ms.
  6. Use GrainOverlap to smooth gain changes at grain boundaries, or disable it for hard gain steps.
  7. Set the play/skip gains and cumulative pitch parameters.
  8. Choose whether to draw the visualization and play the result.

Symbol semantics

SymbolGain behaviorPitch behavior
GPlayed at RepeatGainNo pitch-step change
SUses BaseSkipGainNo pitch-step change
UPlayed at RepeatGainAdds PitchStep_semitones to this grain
DPlayed at RepeatGainSubtracts PitchStep_semitones from this grain
NPlayed at RepeatGainNo pitch-step change
Custom symbols: characters other than G/S/U/D/N are preserved by the rewriting engine unless a rule replaces them. In the audio schedule they behave like a neutral played event: no pitch-step change and RepeatGain.

L-system generation

The current string begins with Axiom. At each iteration every character is replaced in parallel by its matching production rule. Characters without one of the five defined rule names pass through unchanged.

Defined productions
G → Rule_G
S → Rule_S
U → Rule_U
D → Rule_D
N → Rule_N

Iterations and MaxStringLength are converted to integers. String growth is capped while each new generation is being built; the script does not first create an oversized temporary generation and truncate it afterward. If the axiom is already longer than the limit, it is truncated before rewriting begins.

If the generated L-system is shorter than the required number of control grains, the final string is reused cyclically across the Sound.

Grain schedule and gating

The control-window duration is GrainDuration_ms / 1000. The number of grains is calculated with ceiling(sound_duration / grain_duration), so the last grain may be shorter and reaches the exact end of the Sound.

Cumulative pitch schedule

The running shift starts at BasePitchShift_semitones, which is first clamped to ±MaxPitchShift_semitones. For every grain, a U or D symbol updates the running shift before that grain's shift is stored. The running value is then clamped again to the same limits.

U grain: shift ← min(MaxPitchShift, shift + PitchStep)
D grain: shift ← max(−MaxPitchShift, shift − PitchStep)
G / S / N: shift unchanged

Continuous gating

After pitch processing, each grain interval is multiplied by either RepeatGain or BaseSkipGain. A skip is therefore not necessarily silence: it is silence only when BaseSkipGain = 0.

GrainOverlap does not overlap audio grains. When enabled, each grain begins with a raised-cosine transition from the previous grain's gain to the current grain's gain. The transition lasts up to 12 ms, limited to at most half of the nominal grain duration and to the actual length of the final partial grain. The first grain ramps from gain 0. When GrainOverlap is disabled, gain changes are hard steps at grain boundaries.

Pitch processing

Pitch analysis uses a mono reference: multichannel input is converted to mono for analysis only. The analysis settings are fixed at a 10 ms time step, a 40 Hz floor, and a ceiling of min(1200 Hz, 0.45 × sample rate).

If usable pitch is detected, the script creates a target PitchTier on a fixed 10 ms / 100 Hz control grid. At each voiced control point it reads the detected source F0 and applies the semitone shift of the grain that contains that time:

targetF0(t) = sourceF0(t) × 2^(grainShift(t) / 12)

The target is limited to 20 Hz through 0.45 × sample rate. Only times with a defined source F0 become PitchTier points. The pitch stage therefore preserves the detected source contour and transposes it according to the L-system schedule; it does not replace the source with one fixed pitch per grain.

For multichannel input, the same source-derived target PitchTier is applied independently to every original channel, and the processed channels are combined again afterward. The original channel count is preserved.

No usable F0: if no median F0 or no usable voiced control points are found, the script skips Praat pitch resynthesis and copies the original Sound forward. L-system gating still runs normally.

Presets

The menu contains eight built-in presets plus Custom. Presets overwrite only the fields explicitly set below; all other form values remain as entered by the user. In particular, MaxStringLength, MaxPitchShift_semitones, Draw_visualization, and Play_result are never changed by a preset.

PresetL-systemAudio overrides
Rhythmic StutterA=GS; G→GSS; S→SG; U→U; D→D; N→N; iter=440 ms; overlap on; skip 0; repeat 1; base shift 0 st; step 1 st
Pitch Walk UpA=GU; G→GUN; S→N; U→UUN; D→N; N→G; iter=360 ms; base shift −6 st; step 1 st
Pitch Walk DownA=GD; G→GDN; S→N; U→N; D→DDN; N→G; iter=360 ms; base shift +6 st; step 1 st
Chaotic GlitchA=GSUD; G→GSUN; S→N; U→UD; D→DU; N→G; iter=350 ms; base shift 0 st; step 2 st
Melodic ArpeggioA=GUUUDDD; G→G; S→G; U→UN; D→DN; N→N; iter=280 ms; base shift −4 st; step 2 st
Sparse TextureA=S; G→GSSS; S→SSSG; U→U; D→D; N→S; iter=430 ms; skip 0.05; repeat 0.8; step 3 st
Dense GranularA=G; G→GGUNG; S→G; U→UNG; D→DNG; N→NG; iter=325 ms; skip 0.2; repeat 0.9; step 1 st
Fibonacci PatternA=GU; G→GU; S→G; U→SD; D→GU; N→N; iter=545 ms; base shift −6 st; step 1 st
CustomUses all form values unchanged.

Parameters

L-system

ParameterDefaultMeaning
PresetCustomEight built-in configurations or direct use of the form values.
AxiomGInitial string.
Rule_GGSUNReplacement for G.
Rule_SNReplacement for S.
Rule_UUDReplacement for U.
Rule_DDUReplacement for D.
Rule_NGReplacement for N.
Iterations3Number of parallel rewriting passes; floored to an integer and must be at least 1.
MaxStringLength10000Maximum generated-string length; floored to an integer and must be at least 1.

Grain-indexed gating

ParameterDefaultMeaning
GrainDuration_ms50 msDuration of each L-system control window.
GrainOverlapYesRaised-cosine gain smoothing at the start of each grain; it is not literal grain overlap.
BaseSkipGain0.0Linear gain applied to S grains; must be non-negative.
RepeatGain1.0Linear gain applied to G/U/D/N and other non-S symbols; must be non-negative.

Pitch

ParameterDefaultMeaning
BasePitchShift_semitones0 stInitial cumulative transposition; clamped to ±MaxPitchShift before the first grain.
PitchStep_semitones2 stAmount added by U or subtracted by D. The value itself may be positive, zero, or negative.
MaxPitchShift_semitones12 stPositive symmetric limit on the cumulative schedule.

Output

ParameterDefaultMeaning
Draw_visualizationYesDraw the current run in the Picture window.
Play_resultYesPlay the final Sound after processing.

Output behavior

Visualization

When Draw_visualization is enabled, the Picture window shows:

The visualization is limited to the first 200 scheduled grains even when the Sound contains more. The complete L-system length and processing summary are reported in the Info window.