granular
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
dd06e64added hann analysis for comparison, finalised paper and submitted (2026-03-27)6823af3added fx and tidies up some recording bugs (2026-02-24)1f6df83separate recording, session save/load, tuner display, MIDI output, and correct t (2026-02-24)a00c268separate grain and structure files - need searte record button (2026-02-23)edda0d1add 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%