Advanced Poisson Synthesis System — User Guide

Ultra-fast granular synthesis using Poisson process timing: generates complex textures from mathematical stochastic processes with optimized batch formula generation for high-performance synthesis.

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

What this does

This script implements Poisson-based granular synthesis — generating complex sonic textures using stochastic timing (Poisson processes) and granular synthesis techniques. Process: (1) Creates multiple layers (1-8) of sound grains, (2) Each layer uses Poisson process timing (random with average rate), (3) Each grain is a sine wave with Hanning envelope, (4) Parameters (frequency, duration, amplitude) vary per grain based on synthesis mode, (5) Layers are combined with optional stereo spatialization, (6) Output is a complex, evolving texture with natural-sounding randomness and density control.

Key Features:

What is Poisson synthesis? Traditional granular synthesis: grains at regular intervals or triggered manually. Poisson synthesis: grain timing follows Poisson process (random events with average rate λ). This creates natural-sounding textures with: (1) Clustering: Random timing means grains sometimes cluster together. (2) Gaps: Sometimes longer silences occur. (3) Natural density: Sounds like rain, fire, crowds — natural phenomena follow Poisson statistics. Each grain: sine wave × Hanning envelope (smooth fade in/out). Multiple layers: different rates, frequencies create complexity. Stochastic but controlled: average rate determined, exact timing random. Result: textures that sound organic, evolving, non-repetitive.

Technical Implementation: (1) Layer generation: For each layer (1 to number_of_layers): Create Poisson PointProcess with rate layer_rate. Get random event times from process. For each event: generate grain parameters (frequency, duration, amplitude) based on synthesis_mode. (2) Formula optimization: Instead of adding grains one by one (slow in Praat), build complete formula string with all grains for layer. Single Create Sound from formula with complex conditional statement. (3) Layer combination: Add layer sounds together into final output. (4) Spatial processing: Apply stereo effects: Mono (direct), Stereo Wide (filtered L/R differences), Rotating (panning automation). (5) Final processing: Apply fade in/out, normalize peak amplitude. Key innovation: batch formula generation allows thousands of grains without performance degradation.

Quick start

  1. In Praat, ensure no objects selected (generates from scratch).
  2. Run script…advanced_poisson_synthesis.praat.
  3. Choose preset (Standard Three Layer recommended for first try).
  4. Or select Custom and adjust parameters manually.
  5. Set Duration (sec) for output length.
  6. Choose Synthesis_mode for grain character.
  7. Choose Spatial_mode for stereo image.
  8. Click OK — synthesis process runs with progress updates.
  9. Output named "poisson_presetname" appears in Objects window.
  10. Output automatically played when complete.
Quick tip: Start with Standard Three Layer preset for balanced texture. Try Dense Cloud for thick, complex sound. Use Sparse Atmosphere for ambient backgrounds. Duration affects generation time — start with 5-10 seconds. Base_frequency sets tonal center — 100Hz for bassy textures, 400Hz for mid-range. Frequency_range adds variation — larger = more harmonic spread. Low_rate/High_rate control density — higher = more grains per second. Number_of_layers adds complexity — 3-5 layers typical. Enable Randomize_parameters for natural variation. Use Stereo Wide spatial mode for immersive textures.
Important: COMPUTATIONALLY INTENSIVE — high grain counts (high rates × many layers × long duration) can be slow. FORMULA SIZE LIMITS — very dense textures may exceed Praat's formula length limits. MEMORY USAGE — each layer creates large formula strings. GRAIN COUNT displayed during generation — monitor for performance. VERY LONG DURATIONS (60+ seconds) with high density may crash or timeout. RANDOMIZATION means each run produces different results. NO UNDO — generated sound is new object, but parameters not saved. EXPERIMENT WITH CAUTION — extreme settings can lock up Praat temporarily.

Poisson Synthesis Theory

Poisson Process Fundamentals

What is a Poisson Process?

Mathematical definition:

Poisson process: stochastic process counting random events over time Properties: 1. Events occur independently 2. Average rate λ (events per second) constant 3. Time between events follows exponential distribution 4. Number of events in interval follows Poisson distribution Exponential inter-arrival times: P(time between events = t) = λ·e^(-λ·t) Poisson distribution for count in interval T: P(k events in T) = (λT)^k · e^(-λT) / k! Praat implementation: Create Poisson process Generates random event times satisfying Poisson statistics Used as grain triggers in this script

Why Poisson for Synthesis?

Natural sound analogy:

🎵 Natural Sounds Following Poisson Statistics

Rain: Drops hit surface at random times

Fire: Crackles and pops occur randomly

Crowd murmur: Individual voices at random intervals

Geiger counter: Radioactive decay events

Popcorn popping: Random timing between pops

Natural texture: No regular rhythm, but average density

Psychological effect: Sounds "alive", not mechanical

Granular Synthesis Basics

What is a Grain?

Grain structure in this script:

🔊 Grain Components

Carrier: Sine wave at frequency f

Envelope: Hanning window (raised cosine)

Duration: Typically 0.03-0.5 seconds

Amplitude: Scaled by layer and synthesis mode

Timing: Start time from Poisson process

Hanning Envelope Mathematics

Formula for smooth grain:

Hanning window (raised cosine): w(t) = 0.5·(1 - cos(2π·t/T)) for 0 ≤ t ≤ T where T = grain duration In script formula: "(1 - cos(2*pi*(x - start_time)/grain_duration))/2" Combined with sine carrier: grain(t) = A·sin(2π·f·(t-t₀))·0.5·(1 - cos(2π·(t-t₀)/T)) Properties: Smooth fade in from silence Smooth fade out to silence No clicks at boundaries Good frequency localization

📐 Grain Visualization

Time domain:

┌─────────────────────────────────────┐

│ ___ │

│ __/ \__ │

│ ___/ \___ │

│/ \ │

└─────────────────────────────────────┘

Hanning envelope × sine oscillations

Frequency domain:

Peak at grain frequency, spread depends on duration

Shorter grain = wider frequency spread

Batch Formula Optimization

The Performance Problem

Why naive grain insertion is slow:

NAIVE APPROACH (slow):
Create empty sound
For each grain (thousands):
Create grain sound
Add to main sound (Formula or addition)
Remove grain sound

PROBLEMS:
1. Object creation/deletion overhead
2. Memory fragmentation
3. Formula reevaluation each addition
4. O(n²) complexity for n grains

EXAMPLE: 1000 grains → 1000 object creations
Each with memory allocation, Formula application
Extremely slow in Praat

Batch Formula Solution

How this script optimizes:

BATCH FORMULA GENERATION: 1. For each layer, build single formula string: Start: "0" (silence) 2. For each grain in layer, add term: " + if x >= start and x < end then A·sin(2π·f·(x-start))·Hanning((x-start)/dur) else 0 fi" 3. Result: One long formula with all grains Example (3 grains): "0 + if x>=0.1 and x<0.2 then ... fi + if x>=0.3 and x<0.4 then ... fi + if x>=0.5 and x<0.6 then ... fi" 4. Create Sound from formula once with complete formula ADVANTAGES: - Single object creation per layer - Single Formula evaluation - No intermediate objects - Much faster (10-100× speedup) LIMITATION: Formula length has practical limits Too many grains → formula too long → Praat error

Mathematical Implementation

Complete Grain Formula

Script implementation details:

Single grain term in formula: Variables: start = grain start time (from Poisson process) dur = grain duration (0.005-0.5 seconds) end = start + dur A = amplitude (scaled by layer) f = frequency (Hz) Term: " + if x >= " + start$ + " and x < " + end$ + " then " + A$ + " * sin(2*pi*" + f$ + "*(x - " + start$ + ")) * (1 - cos(2*pi*(x - " + start$ + ")/" + dur$ + "))/2 else 0 fi" Where start$, end$, A$, f$, dur$ are string representations Complete layer formula: Starts as "0" (silence) For each grain: concatenate grain term Result: "0 + grain1 + grain2 + ... + grainN" Example with 2 grains: "0 + if x>=0.1 and x<0.2 then 0.5*sin(2*pi*440*(x-0.1))*(1-cos(2*pi*(x-0.1)/0.1))/2 else 0 fi + if x>=0.3 and x<0.4 then 0.5*sin(2*pi*550*(x-0.3))*(1-cos(2*pi*(x-0.3)/0.1))/2 else 0 fi"

Layer Combination Mathematics

Adding layers together:

Output sound construction: Let: L₁(x), L₂(x), ..., Lₙ(x) be layer sounds Output: S(x) = Σ Lᵢ(x) for i = 1 to n In script: 1. Create output sound initialized to 0 2. For each layer i: Generate layer sound Lᵢ with formula Update output: S(x) = S(x) + Lᵢ(x) Implementation using object reference: Formula: "self + object(layer_id, x)" Where layer_id is Praat object ID Praat's object() function retrieves value from another sound Amplitude scaling: Each layer's grains have amplitude Aᵢ Typically: Aᵢ = scaling_factor / n So sum doesn't clip (approximately) Final normalization adjusts overall level

Preset Configurations

Preset Overview

1 Custom

User-defined parameters

Use: Full manual control

2 Standard Three Layer

3 layers, balanced rates

Character: Natural texture

3 Dense Cloud

4 layers, high density

Character: Thick, complex

4 Sparse Atmosphere

3 layers, low density

Character: Ambient, spacey

5 Rhythmic Pattern

4 layers, no randomization

Character: Pulsed, structured

6 Chaotic Texture

5 layers, high variation

Character: Wild, unpredictable

Preset Details

🎵 Standard Three Layer (Preset 2)

Character: Balanced, natural-sounding texture

Parameters:

  • Duration: 12 seconds
  • Base frequency: 100 Hz
  • Frequency range: 300 Hz
  • Low rate: 3 events/sec
  • High rate: 15 events/sec
  • Layers: 3
  • Randomization: Yes
  • Synthesis mode: Three Layer Standard
  • Spatial mode: Mono

Grain characteristics: Medium duration (0.1-0.3s), balanced amplitudes

Best for: General texture, background pads, natural sounds

🎵 Dense Cloud (Preset 3)

Character: Thick, complex granular cloud

Parameters:

  • Duration: 10 seconds
  • Base frequency: 150 Hz
  • Frequency range: 400 Hz
  • Low rate: 10 events/sec
  • High rate: 25 events/sec
  • Layers: 4
  • Randomization: Yes
  • Synthesis mode: Dense Granular
  • Spatial mode: Stereo Wide

Grain characteristics: Short grains (0.03-0.11s), high density

Best for: Dense textures, noise-like sounds, complex backgrounds

🎵 Sparse Atmosphere (Preset 4)

Character: Open, ambient, spacious texture

Parameters:

  • Duration: 20 seconds
  • Base frequency: 80 Hz
  • Frequency range: 500 Hz
  • Low rate: 1 events/sec
  • High rate: 5 events/sec
  • Layers: 3
  • Randomization: Yes
  • Synthesis mode: Sparse Atmospheric
  • Spatial mode: Rotating

Grain characteristics: Long grains (0.3-0.8s), sparse timing

Best for: Ambient music, background atmospheres, spacey textures

🎵 Rhythmic Pattern (Preset 5)

Character: Structured, pulsed, less random

Parameters:

  • Duration: 15 seconds
  • Base frequency: 120 Hz
  • Frequency range: 200 Hz
  • Low rate: 5 events/sec
  • High rate: 12 events/sec
  • Layers: 4
  • Randomization: No
  • Synthesis mode: Rhythmic Pulses
  • Spatial mode: Mono

Grain characteristics: Short-medium grains (0.08-0.2s), consistent

Best for: Rhythmic textures, pulsed backgrounds, structured sounds

🎵 Chaotic Texture (Preset 6)

Character: Wild, unpredictable, high variation

Parameters:

  • Duration: 12 seconds
  • Base frequency: 100 Hz
  • Frequency range: 600 Hz
  • Low rate: 2 events/sec
  • High rate: 20 events/sec
  • Layers: 5
  • Randomization: Yes
  • Synthesis mode: Chaotic Scatter
  • Spatial mode: Stereo Wide

Grain characteristics: Variable grains (0.05-0.35s), extreme variation

Best for: Experimental sounds, chaotic textures, sound effects

Synthesis & Spatial Modes

Synthesis Modes

ModeGrain FrequencyGrain DurationGrain AmplitudeCharacter
Three Layer Standardbase + random×range0.1-0.3s1.5/layersNatural, balanced
Dense Granularbase×(0.5+layer×0.3) + random×range0.03-0.11s1.2/layersDense, cloud-like
Sparse Atmosphericbase×(0.3+layer×0.4) + random×range×0.50.3-0.8s2.0/layersOpen, ambient
Rhythmic Pulsesbase×layer + random×range×0.30.08-0.2s1.8/layersPulsed, structured
Chaotic Scatterbase×(0.5+2×random) + random×range0.05-0.35s1.5/layersWild, unpredictable

Spatial Modes

🔊 Mono (Mode 1)

Processing: No spatial processing

Output: Single channel mono sound

Characteristics: Centered, focused

Best for: Further processing, mono compatibility, simple textures

Implementation: Direct output with no modification

🎧 Stereo Wide (Mode 2)

Processing: Different filtering for L/R channels

  • Left: 0.8× amplitude, band-pass 0-4000Hz
  • Right: 0.8× amplitude, band-pass 200-8000Hz

Output: Stereo with spectral differences

Characteristics: Wide, immersive, frequency-separated

Best for: Headphone listening, ambient music, immersive textures

Psychoacoustic effect: Different frequency content per ear creates width

🔄 Rotating (Mode 3)

Processing: Amplitude modulation for panning

  • Left: 0.6 + cos(2π·0.25·x)×0.4
  • Right: 0.6 + sin(2π·0.25·x)×0.4

Output: Stereo with automated panning

Characteristics: Moving, swirling, dynamic

Best for: Motion effects, evolving textures, psychedelic sounds

Panning rate: 0.25 Hz (complete cycle every 4 seconds)

Implementation: 90° phase difference between L/R modulation

Layer Rate Calculation by Mode

Three Layer Standard (mode 1): With randomization: layer_rate = low + (high-low)×(layer-1)/(n-1)×(0.8+0.4×random()) Without: layer_rate = low + (high-low)×(layer-1)/(n-1) Dense Granular (mode 2): With randomization: layer_rate = high×1.5×(0.7+0.6×random()) Without: layer_rate = high×1.5 Sparse Atmospheric (mode 3): With randomization: layer_rate = low×0.5×(0.6+0.8×random()) Without: layer_rate = low×0.5 Rhythmic Pulses (mode 4): With randomization: layer_rate = (low+high)/2×(0.9+0.2×random()) Without: layer_rate = (low+high)/2 Chaotic Scatter (mode 5): With randomization: layer_rate = (low + (high-low)×random())×(0.5+random()) Without: layer_rate = low + (high-low)×random() Where: random() = randomUniform(0,1) low = Low_rate parameter high = High_rate parameter layer = current layer number (1 to n) n = number_of_layers

Parameters & Effects

Core Synthesis Parameters

ParameterTypeDefaultRangeDescription
Duration (sec)positive121-60Output sound length in seconds
Base frequency (Hz)positive10020-2000Center frequency for grains
Frequency range (Hz)positive3000-2000Maximum variation from base frequency
Low rate (events/sec)positive30.1-50Minimum Poisson process rate
High rate (events/sec)positive151-100Maximum Poisson process rate
Number of layersinteger31-8Independent synthesis layers to combine
Randomize parametersboolean1 (yes)0/1Add random variation to layer rates
Fade time (sec)positive20-10Fade in/out duration at boundaries

Mode Selection Parameters

ParameterTypeOptionsDescription
Synthesis modeoptionmenuThree Layer Standard, Dense Granular, Sparse Atmospheric, Rhythmic Pulses, Chaotic ScatterDetermines grain characteristics and layer rates
Spatial modeoptionmenuMono, Stereo Wide, RotatingStereo processing and spatialization
Normalize outputboolean0/1Scale peak amplitude to 0.9 (prevents clipping)

Parameter Interaction Guide

Duration considerations:
  • Short (1-5s): Quick generation, good for testing
  • Medium (5-20s): Typical for textures, reasonable generation time
  • Long (20-60s): For ambient tracks, slower generation
  • Very long (>60s): Risk of formula limits, very slow

Generation time ∝ Duration × Total grain count

Frequency range effects:
  • 0 Hz: All grains same frequency (chorus effect)
  • 50-200 Hz: Subtle variation, cohesive texture
  • 200-500 Hz: Moderate variation, rich texture
  • 500-1000 Hz: Wide variation, complex harmonic content
  • 1000+ Hz: Very wide, potentially dissonant

Range adds around base: frequency = base ± random(0,range)

Rate density calculation:
  • Total grains ≈ Duration × Average rate × Layers
  • Example: 10s × 10 grains/s × 3 layers = 300 grains
  • Dense: > 20 grains/s total
  • Medium: 5-20 grains/s total
  • Sparse: < 5 grains/s total
  • Performance: Keep total grains < 5000 for reasonable speed

Performance Optimization

Batch Formula Technique

The Optimization Breakthrough

Traditional vs optimized approach:

TRADITIONAL (Individual Grains):
For each grain (1 to N):
Create Sound: grain formula
Select output
Formula: "self + object(grain_id, x)"
Remove grain
Complexity: O(N) object operations
Praat overhead: high

OPTIMIZED (Batch Formula):
Build formula string:
formula$ = "0"
For each grain (1 to N):
formula$ = formula$ + grain_term
Create Sound: formula$
Complexity: O(1) object creation
Praat overhead: low

SPEED IMPROVEMENT:
1000 grains: 100× faster
10000 grains: 1000× faster
Limited by formula string length

Formula Length Limits

Practical formula length limits:
Praat limitation: Formula strings have maximum length
Estimate: ~1,000,000 characters practical limit
Per grain: ~200-400 characters per grain term
Maximum grains: ~2500-5000 grains per layer
Total grains: layers × grains_per_layer
Error symptom: "Formula too long" or crash
Solution: Reduce duration, rates, or layers
Workaround: Generate multiple sounds and combine manually

Performance Guidelines

ScenarioSettingsApprox. GrainsGeneration TimeRecommendation
Quick TestDuration: 3s, Layers: 2, Rates: 5-10~50-100< 5 secondsFor parameter testing
Standard TextureDuration: 10s, Layers: 3, Rates: 3-15~200-40010-30 secondsTypical use case
Dense CloudDuration: 15s, Layers: 4, Rates: 10-25~1000-200030-90 secondsComplex textures
Ambient LongDuration: 30s, Layers: 3, Rates: 1-5~200-30020-40 secondsLong sparse textures
ExtremeDuration: 30s, Layers: 5, Rates: 20-40~3000-60002-5 minutesRisk of formula limits

Memory and CPU Considerations

System resource usage:
  • CPU: Single-threaded during generation (Praat limitation)
  • Memory: Formula strings in memory, plus sound buffers
  • Disk: No disk I/O during generation
  • Praat objects: Creates 2×layers + 3 objects temporarily
  • Sound buffer: duration × samplerate × 8 bytes (double)

Example: 30s @44.1kHz = 1,323,000 samples × 8 bytes = ~10.6 MB per sound

Troubleshooting Performance Issues

Problem: Generation very slow
Causes: High grain count, long duration, many layers
Solutions: Reduce duration, lower rates, fewer layers
Problem: Praat crashes or hangs
Causes: Formula too long, memory exhaustion
Solutions: Use more conservative settings, restart Praat
Problem: "Formula too long" error
Causes: Exceeded Praat's formula length limit
Solutions: Significantly reduce grain count, generate in chunks
Problem: Output contains clicks or gaps
Causes: Grains too short (< 0.005s), formula precision issues
Solutions: Use synthesis modes with longer grains, avoid extreme settings

Applications

Ambient Music Production

Use case: Generate evolving pads and atmospheric backgrounds

Technique: Use Sparse Atmosphere preset with Rotating spatial mode

Example: 30-second ambient bed for film/tv

Sound Design & Effects

Use case: Create unique textures for film/games

Technique: Experiment with Chaotic Texture and Dense Cloud modes

Workflow:

Algorithmic Composition

Use case: Stochastic music generation

Technique: Use as sound source for further manipulation

Application: Generative music systems, aleatoric composition

Psychoacoustic Research

Use case: Study perception of stochastic textures

Technique: Precise control over statistical properties

Advantages: Reproducible, parameterized, mathematically defined

Therapeutic Soundscapes

Use case: Create calming/ focusing audio environments

Technique: Low base frequencies (80-120Hz), sparse rates

Example: Meditation background, focus enhancement

Educational Tool

Use case: Teach stochastic processes, granular synthesis

Advantages:

Practical Workflow Examples

🎬 Film: Underwater Atmosphere

Goal: Create deep underwater rumble with occasional bubbles

Settings:

  • Base frequency: 60 Hz
  • Frequency range: 100 Hz
  • Low rate: 1 events/sec
  • High rate: 8 events/sec
  • Layers: 4
  • Synthesis mode: Sparse Atmospheric
  • Spatial mode: Stereo Wide
  • Duration: 45 seconds

Post-processing: Add low-pass filter, slight reverb

Result: Deep, evolving underwater environment

🎵 Music: Granular Pad Layer

Goal: Add textured pad to electronic track

Settings:

  • Base frequency: 220 Hz (A3)
  • Frequency range: 150 Hz
  • Low rate: 5 events/sec
  • High rate: 15 events/sec
  • Layers: 3
  • Synthesis mode: Standard Three Layer
  • Spatial mode: Rotating
  • Duration: 16 bars at 120 BPM (32 seconds)

Integration: Side-chain compress to kick, add delay

Result: Evolving pad that moves in stereo field

🎮 Game: Magic Spell Effect

Goal: Create sparkling magical energy texture

Settings:

  • Base frequency: 800 Hz
  • Frequency range: 1200 Hz
  • Low rate: 8 events/sec
  • High rate: 25 events/sec
  • Layers: 4
  • Synthesis mode: Dense Granular
  • Spatial mode: Stereo Wide
  • Duration: 5 seconds

Post-processing: High-pass filter, bright reverb, volume envelope

Result: Sparkling magical energy burst

Advanced Techniques

Parameter automation (manual):
  • Generate multiple versions: Different settings for different sections
  • Crossfade: Blend between different parameter sets
  • Dynamic evolution: Change parameters over time by generating sections
  • Stochastic automation: Use random walks for parameter changes

Praat doesn't support real-time parameter changes, but can generate sections manually

External control possibilities:
  • MIDI mapping: Map parameters to MIDI controls (external software)
  • OSC control: Use Open Sound Control for parameter changes
  • Script automation: Write Praat script to generate evolving textures
  • Parameter sequences: Pre-calculate parameter progressions

Advanced users can extend script for dynamic control

Hybrid synthesis approaches:
  • Layer with recorded sounds: Mix Poisson textures with field recordings
  • Filter banks: Process different frequency ranges separately
  • Spectral processing: Apply FFT-based effects to generated texture
  • Multi-modal synthesis: Combine with other synthesis techniques

Poisson synthesis as one element in complex sound design

Creative Parameter Explorations

ExplorationParameter SettingsExpected ResultCreative Use
Micro-soundscapeDuration: 60s, Rates: 0.2-2, Layers: 5Very sparse, isolated eventsMinimalist composition
White noise textureBase: 1000, Range: 10000, Grains: 0.01sNoise-like but structuredTextured noise bed
Harmonic cloudBase: 100, Range: 0, Layers: 8All grains at 100Hz, chorus effectTuned texture
Frequency sweep textureBase automation via sectionsEvolving pitch textureRising/falling effects
Rhythmic structureRandomize: 0, Layers: 1, Specific ratesRegular but Poisson-timedStochastic rhythm

Technical Implementation Details

Poisson Process Generation

Praat's Create Poisson Process

Script command: Create Poisson process: name, start, end, rate Parameters: name = "poisson_layer" (descriptive) start = 0 (beginning of duration) end = duration (from parameter) rate = layer_rate (calculated per layer) Returns: PointProcess object Contains list of event times Times follow exponential distribution between events Average time between events = 1/rate Example: rate = 10 events/sec Average time between events = 0.1 seconds Actual times: random with exponential distribution Some gaps shorter, some longer Statistical properties ensured by Praat: - Events independent - Stationary (statistics don't change over time) - Exponential inter-arrival times - Poisson count distribution

Grain Formula Construction

String Building Algorithm

PSEUDOCODE:
formula$ = "0"
for each grain in grains:
start$ = string(grain.start, precision=6)
end$ = string(grain.start + grain.duration, precision=6)
amp$ = string(grain.amplitude, precision=6)
freq$ = string(grain.frequency, precision=2)
dur$ = string(grain.duration, precision=6)

term$ = " + if x >= " + start$ + " and x < " + end$ +
" then " + amp$ + " * sin(2*pi*" + freq$ + "*(x - " + start$ +
")) * (1 - cos(2*pi*(x - " + start$ + ")/" + dur$ + "))/2 else 0 fi"

formula$ = formula$ + term$
endfor

PRECISION NOTES:
- Times: 6 decimal places (microsecond precision)
- Frequencies: 2 decimal places (0.01 Hz precision)
- Amplitudes: 6 decimal places
- Ensures numerical accuracy
- Avoids rounding errors in grain boundaries

Spatial Processing Implementation

Stereo Wide Filtering

Left channel processing: 1. Copy mono sound → "poisson_left" 2. Apply amplitude: Formula: "self * 0.8" 3. Apply filter: Filter (pass Hann band): 0, 4000, 100 - Pass band: 0-4000 Hz - Smoothing: 100 Hz Right channel processing: 1. Copy mono sound → "poisson_right" 2. Apply amplitude: Formula: "self * 0.8" 3. Apply filter: Filter (pass Hann band): 200, 8000, 100 - Pass band: 200-8000 Hz - Smoothing: 100 Hz Rationale: - Different frequency content per ear - Creates psychoacoustic width - Left: more low-mid frequencies - Right: more high frequencies - 0.8 scaling prevents clipping when summed Combine: Combine to stereo (left, right)

Rotating Panning Mathematics

Left channel amplitude modulation: A_L(x) = 0.6 + cos(2π·0.25·x)·0.4 Right channel amplitude modulation: A_R(x) = 0.6 + sin(2π·0.25·x)·0.4 Where: x = time in seconds 0.25 Hz = panning rate (cycle every 4 seconds) 0.6 = center level 0.4 = modulation depth Phase relationship: sin(θ) = cos(θ - π/2) So A_R lags A_L by 90° (π/2 radians) Result: When A_L is maximum (1.0), A_R is 0.6 (center) When A_R is maximum (1.0), A_L is 0.6 (center) Creates smooth circular panning motion Implementation: Formula: "self * (0.6 + cos(2*pi*0.25*x) * 0.4)" Formula: "self * (0.6 + sin(2*pi*0.25*x) * 0.4)"