granular

27 Mar 2026

Granular: Zero-Crossing Grain Synthesis Toolkit

A collection of Python tools for splitting audio recordings into grains at rising zero-crossing points and then playing them back through various musique concrete-inspired engines: diffusion clouds, Tonnetz harmonic grids, and cellular automata.

Core Idea

Instead of using fixed-length windows or onset detection, this toolkit splits audio at rising zero-crossings – the natural points where the waveform crosses from negative to non-negative. This produces grains that:

  • Start and end near zero amplitude, eliminating click artefacts without windowing
  • Preserve the harmonic structure of the original signal
  • Have durations that naturally correspond to the pitch content (shorter grains = higher frequencies)
  • Can be concatenated back to perfectly reconstruct the original signal (at diffusion=0)

Each grain’s duration maps to a MIDI note number via the relationship midi = 60 + 12 * log2(ref_period / duration), turning a recording into a pitched palette for resynthesis.

Project Structure

granular/
├── diffuse/      Splitter + diffusion-based playback engine
├── tonnetz/      Tonnetz harmonic grid visualisation + playback
├── cellular/     Conway's Game of Life driving grain triggers on Tonnetz grid
└── archive/      Earlier prototypes and experiments

diffuse/

The core splitting engine and a real-time playback system with a diffusion parameter (0.0-1.0) that morphs between exact reconstruction of the original recording and a fully randomised granular cloud. Features backbone/overlay architecture, Poisson-triggered voices, equal-power stereo panning, and soft limiting. Also includes an ESP32-targeted packed grain exporter and MIDI mapping utilities.

tonnetz/

Visualises grain playback on a 2D Tonnetz harmonic lattice where MIDI = 3*x + 4*y. Grains play back seamlessly while their corresponding pitch-class cells light up in colour on a Pygame grid. Supports grain ordering by length (ascending, descending, or original).

cellular/

Runs Conway’s Game of Life on the Tonnetz grid. Live cells trigger grain playback for their MIDI pitch; dead cells are silent. Supports scale filtering (e.g. pentatonic, modal), multiple grain selection modes (single-shot, looping, different-each-loop), and produces emergent polyphonic textures.

archive/

The original splitter and emitter prototypes that preceded the current tools.

Setup

python3 -m venv .venv
source .venv/bin/activate
pip install numpy scipy librosa soundfile sounddevice pygame

For .m4a input files, install ffmpeg: brew install ffmpeg

Quick Start

# Split and play back with exact reconstruction
python diffuse/01_granular_synthesis.py recording.m4a --diffusion 0.0

# Split and play with moderate diffusion
python diffuse/01_granular_synthesis.py recording.m4a --diffusion 0.5

# Visualise on Tonnetz grid
python tonnetz/02_play_grains_tonnetz_seamless.py recording_grains/

# Cellular automaton with C major pentatonic
python cellular/tonnetz_granulatoma.py recording_grains/ --scale "C 2 2 3 2 3"

See each subfolder’s README for detailed usage and parameters.

Recent Activity

  • dd06e64 added hann analysis for comparison, finalised paper and submitted (2026-03-27)
  • 6823af3 added fx and tidies up some recording bugs (2026-02-24)
  • 1f6df83 separate recording, session save/load, tuner display, MIDI output, and correct t (2026-02-24)
  • a00c268 separate grain and structure files - need searte record button (2026-02-23)
  • edda0d1 add interactive 88-key piano with click-to-play and one-shot grain triggering (2026-02-22)

Languages

  • Python: 56%
  • JavaScript: 34%
  • TeX: 7%
  • HTML: 2%
  • CSS: 2%