ENGINE=graincloud · src/engine/graincloud/ · class GraincloudEngine

A polyphonic grain cloud (engine #11 in docs/engine-ideas.md) - the granular the looper isn't: dozens of grains with independent pitch / pan / position scattered over the recorded buffer. It is built as a self-contained variant of the granular engine: src/engine/graincloud/ is a copy of the granular tree (so it keeps granular's recording, SD save/load, dual-deck, crossfade, FX and UI verbatim) with only the grain-generation core replaced - Generator::process sums a GrainflowLib cloud (gf_cloud.{h,cpp}) reading the recorded Buffer instead of driving the granular Vox. It is its own engine (SPK_ENGINE_GRAINCLOUD); plain granular is untouched.

Implementation, the GrainflowLib port, the per-block/per-sample bridge, and the file map live in docs/dev/graincloud-impl.md.

How to use it

Exactly like the granular engine - same record, save/load, pad and transport gestures. If you know granular, you know graincloud. The only difference is the sound: instead of granular's tape-loop scanning, the recorded buffer is granulated into a continuous cloud (it plays whenever a deck has audio; there is no separate "play").

Controls

Per deck:

Controlcloud meaning
POScloud centre / playhead scrub position
SIZEgrain size (duration, ~8 ms – 1.5 s)
PITCHgrain transpose (independent of playhead speed)
ENVposition spray of grain starts
MODFREQgrain density (overlap)
MOD_AMTper-grain pitch + pan spread
SOSdry/wet
Mode switch (L/C/R)grain direction: top = reverse, centre = forward, down = random
Alt + PITCHplayhead speed (down = freeze, noon = 1x, up = 4x)
Alt + POSvibrato depth
Alt + SOSglisson (per-grain pitch glide)

The cloud knobs are tapped from the raw knob values directly (bypassing granular's mode-dependent routing), so they always control the cloud. The GrainflowLib character controls (direction / playhead speed / vibrato / glisson) sit on the otherwise-idle Mode switch and the three routable Alt layers (Alt+PITCH/POS/SOS). Pong is implemented but unmapped (only three Alt knob-layers route on this platform).

Grain count is 8 per deck (a conservative, CPU-safe default; raise after a METER run). The cloud guarantees >=2 overlapping grains for a smooth (non-tremolo) envelope.

Build / flash

make -j8 ENGINE=graincloud        # compiles src/engine/graincloud/ + vendored GrainflowLib, at -Os
make ENGINE=graincloud program-dfu
make engine-graincloud            # one-shot: clean + build + flash

Builds at -Os (the granular code + the GrainflowLib templates overflow the 186 KB execution SRAM at -O2); fits at ~97%. The grain scratch lives in fast RAM (static per-deck), only the recorded buffer is SDRAM. The vendored, de-STL'd GrainflowLib is under src/engine/graincloud/thirdparty/grainflow/.

On-device cost of the scattered grain reads is unconfirmed; if a high-density patch glitches, lower the grain count in gf_cloud.h (kMaxGrains) and/or run METER=1 to find the ceiling.