Skip to content

granular

Granular — Granular synthesis engine. Slices a sample buffer into tiny grains and re-synthesises them with controllable position, density, scatter, and pitch.

Quick Start

granular({ url: './sample.wav', grainSize: 0.08, density: 12 })

Parameters

Name Type Default Range/Options Description
url string 音声ファイル URL (CORS 必須)
grainSize number 0.08 0.01–0.5 s グレインの長さ
density number 12 0.5–100 grains/s 1秒あたりのグレイン数
scatter number 0.3 0–1 タイミングの散布量 0–1
position number 0.5 0–1 バッファ内の再生位置 0–1
positionVar number 0.1 0–1 再生位置の揺らぎ 0–1
pitch number 0 -24–24 semitone ピッチシフト 半音単位
gain number 0.7 0–1 出力ゲイン

How it works

On each play() call, granular schedules multiple BufferSourceNode triggers over the note duration. Each grain:

  • starts at a position in the buffer determined by position ± positionVar
  • has a duration of grainSize seconds
  • is windowed with a Hann-style amplitude envelope to avoid clicks
  • is spaced 1 / density seconds apart, with optional scatter jitter

Examples

Ambient cloud texture

function* song(ctx) {
const key = scales(8, 'E3:dorian')
const g = granular({
url: './pad.wav',
grainSize: 0.18,
density: 20,
scatter: 0.8,
position: 0.4,
positionVar: 0.3,
gain: 0.6,
})
chain(g, reverb({ size: 1.2, mix: 0.6 }))
yield cast(g, key, seq(8, '\{0,4\},~,~,~,~,~,~,~'), ctx)
}

Slow position sweep over time

function* song(ctx) {
const pos = (ctx.cycle % 32) / 32 // scan 0→1 over 32 cycles
const g = granular({ url: './drone.wav', grainSize: 0.12, density: 16, position: pos, gain: 0.5 })
yield cast(g, scales(4, 'C3:minor'), seq(4, '0,~,~,~'), ctx)
}

Combined with stutter

const g = chain(
granular({ url: './loop.wav', density: 8, scatter: 0.5 }),
stutter({ rate: 16, duty: 0.4, mix: 0.6 }),
reverb({ mix: 0.4 }),
)