toxi_openframeworks · SoundReactiveField
Sound-Reactive Particle Field (Synthetic Audio)
Particles advected by a force field whose horizontal component is driven by a synthetic audio signal: a chain of N sinusoids at different frequencies/amplitudes (the 'audio'), with the audio's instantaneous value plus its time derivative ('beat onset') driving the field. The vertical component is a slow baseline oscillator. Particles leave low-alpha strokes on a fading canvas, producing the iconic oF audio-reactive aesthetic (Nick Hardeman's audio visualizer, Anthony Scavarelli's interactive visualizer).
Original: https://openframeworks.cc/ofBook/chapters/sound.html
▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.
Math essence
audio(t) = Σ amp_i * sin(2π freq_i t + phase_i). Field_x = field_strength * audio + beat_gain * d(audio)/dt, Field_y = slow baseline oscillator. Velocity update with max_speed clamp. Canvas *= trail_decay, then add ink * 0.10 at each particle position. Hue rotates by hue_shift per step.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 400 | 200–1000 | Square canvas side length in pixels. |
num_particles | int | 1200 | 200–4000 | Particle count. |
num_bands | int | 5 | 1–8 | Number of sinusoid bands in the synthetic audio chain. |
band_freqs | tuple | 0.42,0.97,1.7,2.5,3.3 | — | Per-band frequencies (Hz) of the synthetic audio. |
band_amps | tuple | 0.6,0.45,0.35,0.25,0.2 | — | Per-band amplitudes. |
field_strength | float | 2.4 | 0.1–8 | Gain applied to the audio-driven field component. |
beat_gain | float | 4 | 0–12 | Gain applied to the audio derivative (transient / beat onset) component. |
max_speed | float | 4.5 | 0.5–12 | Speed clamp (px/frame). |
trail_decay | float | 0.965 | 0.7–0.999 | Per-frame multiplicative fade of the canvas. |
hue_shift | float | 0.012 | 0–0.1 | Hue rotation per step (turns). |
bg_color | tuple | 8,10,18 | — | Background colour. |
seed | int | null | 0–999999 | RNG seed. |
Reference
First 60 lines of reference.py. Full source:
library_external/toxi_openframeworks/SoundReactiveField/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
class SoundReactiveField:
"""Sound-reactive particle field driven by a synthetic audio chain.
A bank of N sinusoids acts as the "audio signal":
audio(t) = Σ_i amp_i * sin(2π freq_i t + phase_i)
The instantaneous magnitude of this sum (and its derivative,
treated as a beat-onset detector) drives a horizontal force field
across the canvas. Particles feel this field, drift in the
direction of the force, and leave a low-alpha trail on a fading
canvas — the iconic look of openFrameworks audio-reactive
visuals (Nick Hardeman, Anthony Scavarelli, and the `oF` chapter
in the ofBook's *Sound* section all use this same skeleton).
"""
family: ClassVar[str] = "toxi_openframeworks"
sketch: ClassVar[str] = "soundreactivefield"
def __init__(
self,
dim: int = 400,
num_particles: int = 1200,
num_bands: int = 5,
band_freqs: tuple[float, ...] = (0.42, 0.97, 1.7, 2.5, 3.3),
band_amps: tuple[float, ...] = (0.6, 0.45, 0.35, 0.25, 0.2),
field_strength: float = 2.4,
beat_gain: float = 4.0,
max_speed: float = 4.5,
trail_decay: float = 0.965,
hue_shift: float = 0.012,
bg_color: tuple[int, int, int] = (8, 10, 18),
seed: int | None = None,
) -> None:
self.dim = dim
self.num_particles = num_particles
self.num_bands = num_bands
self.band_freqs = np.array(band_freqs, dtype=np.float32)
self.band_amps = np.array(band_amps, dtype=np.float32)
self.field_strength = field_strength
self.beat_gain = beat_gain
self.max_speed = max_speed
self.trail_decay = trail_decay
self.hue_shift = hue_shift
self.bg_color = np.array(bg_color, dtype=np.float32)
self._seed = seed
self._t = 0.0
self._last_audio = 0.0
self._hue = self.rng.integers(0, 360) if False else 0
self.reset()
def reset(self, seed: int | None = None) -> None:
if seed is not None: Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/toxi_openframeworks/SoundReactiveField/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from toxi · openFrameworks
Generative Type Letterforms
toxi_openframeworks · GenerativeTypeLetterforms
Letterforms assembled from a 9×9 stroke grid alphabet (A–Z subset), then modulated by a parametric function (bar widths and stroke positions follow `a * sin(b*x + c)` style curves) and optionally recursively subdivided into smaller marks.
Gray-Scott Reaction-Diffusion
toxi_openframeworks · ReactionDiffusionGS
The canonical two-species Gray-Scott reaction-diffusion model on a periodic square grid: dU/dt = Du*lap(U) - U*V^2 + F*(1-U), dV/dt = Dv*lap(V) + U*V^2 - (F+k)*V.
Median-Cut Color Quantizer
toxi_openframeworks · ColorQuantizer
Heckbert's 1982 median-cut color quantization applied to an evolving procedural gradient + low-resolution noise wash.
Pixel Sort (Glitch Art)
toxi_openframeworks · PixelSort
Per-row pixel sorting à la Kim Asendorf's `ASDFPixelSort` and Karsten Schmidt's own glitch-art Processing sketches.
Verlet Particle-Spring Network
toxi_openframeworks · ParticleSpring2D
A Verlet-integrated particle network connected to its k-nearest neighbours by Hooke's-law springs.
Voronoi Tessellation with Lloyd Relaxation
toxi_openframeworks · VoronoiRelaxation
Lloyd's algorithm applied to a jittered point cloud: each seed is replaced with the centroid of its Voronoi cell, repeatedly, producing ever-more-uniform polygonal cells.