Stochastic Source
Tier: Core | ComponentType: 25 | Params: 16
Eight stochastic process types for random modulation with configurable rate, amplitude, and process-specific parameters.
Overview
StochasticSource is a modulation generator that implements eight distinct stochastic processes, each producing a different character of randomness. It has no audio input — it generates a modulation signal in the range [-1, 1] that can be used to control parameters or modulate audio amplitude in the signal chain.
The eight process types span a range from smooth, continuous random walks to discrete event-based triggers:
- Brownian motion — Gaussian random walk with reflection at boundaries
- Ornstein-Uhlenbeck — Mean-reverting random walk that orbits a configurable center
- Perlin noise — Smooth, organic noise with multi-octave layering
- Levy flight — Heavy-tailed jumps for intermittent, burst-like modulation
- Poisson — Random pulse triggers with configurable duration
- Shot noise — Pool of decaying impulses triggered by Poisson process
- Markov chain — 8-state discrete chain with configurable transition matrix and 4 presets
- Sample and Hold — Random value held until next trigger (clock or Poisson)
A 64-sample history ring buffer (decimated every 64 samples) provides a scrolling trace for visualization. The xorshift32 PRNG can be seeded for deterministic reproducibility via the Seed parameter.
In chain mode, StochasticSource modulates the input amplitude: output = input * (0.5 + 0.5 * value).
File Locations
| Path | |
|---|---|
| Header | Sources/FolioDSP/include/FolioDSP/Core/StochasticSource.h |
| Implementation | Sources/FolioDSP/src/Core/StochasticSource.cpp |
| Tests | Tests/FolioDSPTests/StochasticSourceTests.swift |
| Bridge | Sources/FolioDSPBridge/src/FolioDSPBridge.mm (StochasticSourceBridge) |
Parameters
| Index | Name | Description | Min | Max | Default Min | Default Max | Default | Unit |
|---|---|---|---|---|---|---|---|---|
| 0 | Process | Stochastic process type (0-7) | 0.0 | 7.0 | 0.0 | 7.0 | 0.0 | |
| 1 | Rate | Update/modulation rate | 0.01 | 100.0 | 0.1 | 20.0 | 1.0 | Hz |
| 2 | Amplitude | Output amplitude scaling | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | |
| 3 | Seed | PRNG seed (0=default, nonzero=deterministic) | 0.0 | 65535.0 | 0.0 | 65535.0 | 0.0 | |
| 4 | Step Size | Random walk step size (Brownian/OU) | 0.0 | 1.0 | 0.01 | 0.5 | 0.1 | |
| 5 | Gravity | Mean-reversion strength (OU) | 0.0 | 10.0 | 0.1 | 5.0 | 1.0 | |
| 6 | Center | Mean-reversion target (OU) | -1.0 | 1.0 | -1.0 | 1.0 | 0.0 | |
| 7 | Octaves | Perlin noise octave count | 1.0 | 8.0 | 1.0 | 8.0 | 4.0 | |
| 8 | Persistence | Perlin amplitude decay per octave | 0.0 | 1.0 | 0.1 | 0.9 | 0.5 | |
| 9 | Lacunarity | Perlin frequency multiplier per octave | 1.5 | 4.0 | 1.5 | 4.0 | 2.0 | |
| 10 | Alpha | Levy stability parameter | 0.5 | 2.0 | 0.5 | 2.0 | 1.5 | |
| 11 | Duration | Poisson pulse duration | 1.0 | 1000.0 | 1.0 | 200.0 | 10.0 | samples |
| 12 | Decay | Shot noise impulse decay time | 1.0 | 500.0 | 5.0 | 200.0 | 50.0 | ms |
| 13 | Glide | Markov state transition smoothing | 0.0 | 100.0 | 0.0 | 100.0 | 20.0 | % |
| 14 | Clock Mode | S&H trigger mode (0=Poisson, 1=Clock) | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | |
| 15 | Slew | S&H output smoothing | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 |
Processing Algorithm
The process() function executes once per sample, dispatching to the selected process type.
0. Seed Management
When the Seed parameter changes to a nonzero value, the PRNG is reseeded via Knuth multiplicative hash:
A seed of 0 uses the default (non-deterministic) PRNG state.
1. Brownian Motion
A Gaussian random walk with boundary reflection:
where \(\sigma\) is the step size. Reflection at \(\pm 1\) keeps the output bounded without hard clamping artifacts.
2. Ornstein-Uhlenbeck
A mean-reverting stochastic differential equation:
where \(\gamma\) is gravity (mean-reversion strength), \(c\) is the center target, and \(\sigma\) is step size. The pull term \(-\gamma(v - c)\) creates an elastic restoring force toward the center.
3. Perlin Noise
Multi-octave 1D Perlin noise with smoothstep interpolation:
where \(\lambda\) is lacunarity (frequency multiplier) and \(p\) is persistence (amplitude decay). The 1D Perlin function uses a 256-entry permutation table with gradient noise and smoothstep interpolation:
4. Levy Flight
The Chambers-Mallows-Stuck algorithm generates alpha-stable random variables:
When \(\alpha = 2\), this reduces to Gaussian. When \(\alpha = 1\), it produces Cauchy-distributed jumps (\(L = \tan(V)\)). Lower \(\alpha\) values produce heavier tails with more extreme jumps.
5. Poisson
Random pulse triggers with a per-sample probability:
When triggered, the output holds at 1.0 for the specified duration (in samples), then returns to 0.0.
6. Shot Noise
A pool of 32 decaying impulses, triggered by Poisson process:
Each impulse has a random amplitude \(a \sim \text{Uniform}(-1, 1)\) and decays exponentially:
Active impulses are summed and soft-clipped:
Impulses are deactivated when their envelope falls below 0.001.
7. Markov Chain
An 8-state discrete Markov chain with configurable transition matrix:
State transitions use cumulative probability sampling against a uniform random value. Each state maps to a configurable value via stateValues[]. Output is optionally smoothed by glide:
Four presets configure the transition matrix:
- Drift: 70% self-transition, 12.5% to adjacent states (slow meandering)
- Cycle: 80% to next state, 10% self (deterministic-ish rotation)
- Random: uniform distribution across all states (maximum entropy)
- Absorbing: states 0-1 are sticky (90% self), states 2-3 are uniform (gravitates toward low states)
8. Sample and Hold
Holds a random value until the next trigger:
Clock mode (\(\text{clockMode} = 1\)):
Poisson mode (\(\text{clockMode} = 0\)):
On trigger: \(h \sim \text{Uniform}(-1, 1)\). Slew smoothing:
9. Output Scaling
The raw process output is scaled by the amplitude parameter:
Core Equations
Where \(r_s = f_{\text{rate}} / f_s\).
Snapshot Fields
| Field | Type | Range | Unit | Description |
|---|---|---|---|---|
| Process Type | Uint8 | 0–7 | Active stochastic process index | |
| Value | Float | -1–1 | Current output value (after amplitude scaling) | |
| Rate | Float | 0.01–100 | Hz | Current modulation rate |
| Amplitude | Float | 0–1 | Current amplitude scaling | |
| History | Float[64] | -1–1 | Decimated output history ring buffer | |
| History Index | Float | 0–63 | Current write position in history buffer | |
| Trigger | Float | 0–1 | Trigger indicator (Poisson/ShotNoise/S&H) | |
| Markov State | Uint8 | 0–7 | Current Markov chain state index | |
| Dist From Center | Float | 0–2 | Distance from OU center parameter |
Implementation Notes
- xorshift32 PRNG provides all randomness. Box-Muller transform generates Gaussian variates from uniform pairs. Exponential variates via \(-\ln(u)\).
- Seed parameter uses Knuth multiplicative hash (\(\times 2654435761\)) for good bit distribution. Changing the seed also re-shuffles the Perlin permutation table.
- ParamSmoother is applied to Rate, Amplitude, Step Size, Gravity, Center, Decay, and Slew parameters. The smoother uses
prepare(sampleRate)for coefficient calculation. - Shot noise pool is fixed at 32 impulses (no heap allocation). When all slots are active, new triggers are silently dropped.
- Perlin permutation table is a 256-entry Fisher-Yates shuffled array. The gradient function returns either \(+x\) or \(-x\) based on the least significant bit of the hash.
- Levy flight clamps individual steps to \([-10, 10]\) before accumulation to prevent numerical overflow, then applies
tanhsoft clamping to the accumulated value. - History decimation writes every 64 samples to avoid overwhelming the snapshot with per-sample data. The 64-sample ring buffer provides approximately 1.5 seconds of history at 44.1 kHz.
- Markov transition matrix is an \(8 \times 8\) array of floats. Rows should sum to 1.0 for valid probability distributions. The
setMarkovTransitionmethod sets individual rows;setMarkovPresetconfigures the entire matrix. - All parameters use
std::atomic<float>(orstd::atomic<int>) for lock-free thread safety. - Snapshot emission is decimated to ~60 fps (every 735 samples at 44.1 kHz).
Equation Summary
y = Brownian|OU|Perlin|Levy|Poisson|S&H