Dynamic Stochastic Grain Field — User Guide
An inhomogeneous-Poisson granular synthesizer whose event density evolves over time while grain frequencies follow an octave-domain trajectory. Each event becomes a Hann-windowed sine grain with random phase, optional pitch jitter, overlap-aware amplitude compensation, and optional grain-level stereo placement.
What this does
Dynamic Stochastic Grain Field generates a cloud of short sine grains from scratch. The important feature is that the probability of a new grain appearing is allowed to change continuously over the duration. A sparse beginning can therefore become statistically dense, or a dense texture can thin out, without placing events on a regular grid.
- A time-varying event rate says how many grains per second are expected locally.
- A Poisson process turns that rate into an irregular sequence of actual onset times.
- Each onset receives a duration, frequency, phase, amplitude, and pan position.
- The stored grains are rendered exactly into mono or stereo audio.
The density curve is a statistical target, not a deterministic command that guarantees an exact number of grains in each time interval. Two runs with the same settings can therefore have different local clusters and gaps. A positive Random seed makes that realization reproducible.
Why this is not Xenakis's GENDYN
The historical term dynamic stochastic synthesis is strongly associated with Iannis Xenakis. In Xenakis's stochastic-synthesis lineage, including GENDYN, the waveform itself is represented by breakpoints whose positions evolve stochastically in time and amplitude. This script does not implement that algorithm.
Here the stochastic process operates at the level of granular events: it determines when grains occur and randomizes grain-level properties such as duration, pitch offset, phase, and, in some spatial modes, pan. The individual waveform inside every grain is a sine wave under a Hann envelope. The name used by the current script — Dynamic Stochastic Grain Field — therefore describes the implementation more accurately.
Quick start
- Run
Dynamic_Stochastic_Synthesis.praat; no input Sound is required. - Choose a preset or leave Custom.
- Set Duration, Base frequency, Initial density, Final density, and Frequency evolution (octaves).
- Choose Mono or one of the three grain-level stereo modes.
- Enable Edit grain details when you want to change duration range, pitch jitter, random seed, or edge fade.
- Click OK. The final Sound remains selected and is named
dynamic_stochastic_grains_<preset>.
Event density: target versus realization
The two density controls define the instantaneous Poisson intensity lambda(t) in grains per second. The script linearly interpolates between them:
If the density rises from 20 to 200 grains/s, the process becomes increasingly likely to generate short inter-onset intervals near the end. It does not first generate a fixed number of uniformly distributed events and then relabel them with different densities.
How the onset times are generated
The cumulative intensity is
The script advances through cumulative-intensity space with exponential random increments and then analytically inverts Lambda(t) to obtain the next event time. The resulting onset list is already chronological.
Expected and actual grain counts
For a linear density trajectory, the expected number of events is
That number is an expectation only. The actual Poisson realization can contain more or fewer grains. The Info window and visualization report both values. The script refuses settings whose expected count exceeds 8000 and also aborts if an unusually large realization reaches 10,000 grains.
Pitch trajectory and grain model
Frequency evolution is measured in octaves
The center frequency follows an exponential trajectory in frequency but a straight line in octave space:
+1 therefore ends one octave above the starting center, +2 ends two octaves above it, -1 ends one octave below it, and 0 holds the center frequency constant.
Frequency jitter
Each grain receives an independent uniform offset in octave space:
This makes the jitter perceptually symmetric as a pitch ratio rather than as a fixed number of hertz. Frequencies below 20 Hz are raised to 20 Hz and counted in QC. The upper synthesis guard is 0.45 * sample rate; if the requested base frequency could place the trajectory above that guard, the base is reduced automatically.
One grain
Each event is a sine oscillator with a random starting phase and a Hann amplitude envelope:
Duration is chosen uniformly between the current minimum and maximum grain durations. A grain beginning close to the end of the requested sound is shortened so that it ends exactly at the output boundary.
Density is not secretly a loudness envelope
More simultaneous grains would normally increase RMS level. To reduce that confound, per-grain amplitude is divided by the square root of the expected local overlap:
A small random amplitude factor remains. The compensation is approximate — it uses the expected local overlap and mean duration, not the exact number of simultaneously active grains — but it makes density primarily a texture/occupancy control rather than simply a volume control.
Presets
Presets set the central stochastic/granular parameters and the spatial mode. They do not replace the chosen sample rate, normalization, visualization, playback, random seed, or edge fade. The duration is overridden only by the presets explicitly shown below as 8 or 10 seconds.
| Preset | Duration | Base Hz | Density /s | Evolution | Grain ms | Jitter | Spatial |
|---|---|---|---|---|---|---|---|
| Sparse-to-Dense Bloom | form value | 80 | 15 -> 60 | +0.5 oct | 30-100 | +/-0.18 oct | Mono |
| Steep Density Build | form value | 100 | 20 -> 200 | +1.2 oct | 10-50 | +/-0.30 oct | Stereo Evolution |
| Slow Two-Octave Drift | 10 s | 60 | 10 -> 80 | +2.0 oct | 50-150 | +/-0.20 oct | Rotating Cloud |
| Short-Grain Rising Cascade | form value | 180 | 40 -> 180 | +1.5 oct | 10-40 | +/-0.35 oct | Wide Field |
| Medium Density Growth | 8 s | 90 | 25 -> 100 | +0.8 oct | 25-90 | +/-0.22 oct | Stereo Evolution |
| Dense Pitch Cloud | form value | 110 | 35 -> 120 | +1.0 oct | 20-60 | +/-0.10 oct | Mono |
| High-Density Short Grains | form value | 200 | 50 -> 250 | +1.8 oct | 8-30 | +/-0.40 oct | Wide Field |
| Sparse Long-Grain Cloud | 10 s | 70 | 8 -> 40 | +0.3 oct | 40-120 | +/-0.15 oct | Rotating Cloud |
Parameters
Main form
| Parameter | Default | Meaning |
|---|---|---|
| Duration_s | 6.0 | Total synthesis duration; valid up to 120 s. |
| Sample_rate_Hz | 44100 | Direct rendering rate, 8000-192000 Hz. |
| Base_frequency_Hz | 120 | Center frequency at time 0, before pitch jitter. |
| Initial_density | 30 | Poisson event intensity at the beginning, in expected grains/s. |
| Final_density | 150 | Poisson event intensity at the end, in expected grains/s. |
| Frequency_evolution_octaves | +1.0 | Total center-frequency change from start to end; accepts -8 to +8 octaves. |
| Spatial_mode | Mono | Mono, Stereo Evolution, Rotating Cloud, or Wide Field. |
| Edit_grain_details | off | Opens the optional compact second page after preset values have been applied. |
| Normalize_output | yes | Optional final target peak normalization to 0.90. |
| Draw_visualization | yes | Draw target/realized statistics, grain field, measured spectrogram, waveform, and QC. |
| Play_result | yes | Play the final Sound. |
Grain-details page
| Parameter | Default | Meaning |
|---|---|---|
| Min grain duration | 20 ms | Lower endpoint of the uniform duration range. |
| Max grain duration | 80 ms | Upper endpoint; limited to 2000 ms. |
| Frequency jitter | 0.25 oct | Uniform +/- octave offset around the evolving center; 0-2 octaves. |
| Random seed | 0 | 0 uses the current/unpredictable RNG state; a positive integer produces a reproducible stochastic realization. After a fixed-seed schedule is generated, the script restores Praat's unpredictable RNG initialization. |
| Edge fade | 0.02 s | Short final protection fade at both ends, capped at 20% of total duration. |
Spatial modes
Stereo is created per grain. A grain receives one pan value from its onset time and keeps that pan for its whole duration. Left and right gains use equal-power panning:
| Mode | Pan behavior |
|---|---|
| Mono | One-channel render; no stereo gain pair is applied. |
| Stereo Evolution | Pan follows normalized onset time from left toward right, with independent +/-0.12 stochastic deviation, then is constrained to 0.02-0.98. |
| Rotating Cloud | Grain positions sample a sinusoidal pan trajectory whose rotation rate rises linearly from 0.08 to 0.28 cycles/s over the sound. The accumulated rotation phase is integrated analytically. |
| Wide Field | Each grain is randomly assigned to a near-left region (0.03-0.23) or near-right region (0.77-0.97). |
These modes do not create width by complementary EQ or by filtering a finished mono signal. The left/right balance is part of each grain's render.
Exact chunked rendering
The output is rendered in chronological chunks of at most 1 second. Chunking is only a way to keep Praat formula strings manageable; it is not supposed to alter the stochastic timeline.
Crossing grains are preserved
If a grain begins in one chunk and ends in the next, both chunks evaluate it using the same original onset, duration, frequency, random phase, and envelope age. The second chunk therefore continues the already-running Hann grain instead of restarting it. After rendering, the chunks are concatenated end-to-end.
The expected count is capped before scheduling, but long grains and high densities can still create many simultaneously relevant terms in a chunk. Reducing density or grain duration lowers that workload.
Output and level behavior
| Property | Behavior |
|---|---|
| Source | Generated entirely from sine grains; no selected Sound is required. |
| Sample rate | Rendered directly at Sample_rate_Hz; there is no later resampling stage. |
| Channels | Mono in Mono mode; two channels in all three spatial modes. |
| Edge protection | One combined linear fade-in/fade-out using the requested edge-fade value, capped at 20% of duration. |
| Normalization | If enabled, non-zero output is scaled to a target peak of 0.90. Pre-normalization peak and RMS are measured first and reported. |
| Object name | dynamic_stochastic_grains_<preset>. |
Visualization and QC
The current figure separates the stochastic control process from the measured audio:
| Panel | What it shows |
|---|---|
| A — Event Density | The linear target intensity as a line and the actual Poisson realization measured in time bins. Local bars are expected to fluctuate around the target rather than match it exactly. |
| B — Actual Grain Field | Each sampled line segment runs from a realized grain onset to its end at the realized grain frequency. Frequency is displayed logarithmically. In stereo modes, color indicates broad left/center/right pan regions. |
| C — Model -> Measurement | A measured spectrogram of the higher-RMS representative output channel, with a sampled subset of the actual grain frequencies drawn as guides. |
| D — Measured Output | The measured waveform of that representative channel. |
The QC strip reports expected and actual event counts, realized mean density, seed status, realized frequency range, mean grain duration, spatial mode, and pre/final level measurements. The Info window additionally reports the maximum number of terms used in any one-second chunk and the number of low-frequency corrections.