Anatomy of a toot

src/synth.zig is pure Zig stdlib: no libc, file I/O, or device access. It renders mono 44.1 kHz PCM; WAV output is 16-bit. The instrument converts that synthesis into float samples for its shared phrase-to-bar path.

One syllable combines a low buzzy oscillator with falling pitch, a noisy attack splat, and a fluttering decay. A small parser groups Swahili vowels, digraphs, and consonant onsets; it is not a general linguistic model.

Vowel pitch

Vowel Base frequency
a 92 Hz
e 110 Hz
i 138 Hz
o 86 Hz
u 74 Hz

cents multiplies these by 2^(cents/1200). The breath tail's 88 Hz carrier follows that shift. Shuzi has randomly selected pitch keyed by its seed.

Onset character

Class Typical consonants Attack Noise mix Wobble rate
Voiceless stop p t k ch 4 ms 0.40 32 Hz
Voiced stop b d g j 6 ms 0.28 30 Hz
Fricative s sh z f v th dh h gh 10 ms 0.50 29 Hz
Nasal m n ng ny 25 ms 0.12 26 Hz
Liquid/glide l r w y 14 ms 0.18 28 Hz
Bare vowel none 8 ms 0.25 28 Hz

Voice knobs scale those classes. Effort scales level/noise/stress; wobble controls depth rather than rate. See the user-facing controls.

Timing

Voiced syllables last 240 ms, except a word's voiced penultimate syllable, which is stressed and lasts 280 ms. Gaps last 40 ms within a word and 120 ms between words. A rare consonant-only tail uses a shorter 90 ms duration. Do not extrapolate the normal syllable formula to every tail case.

Determinism has a boundary

Phrase text seeds the synthesis noise; the instrument's --seed instead keys upload GUIDs and Ogg serials. The same build and inputs reproduce exact bytes. LLVM floating-point transformations can change synthesized bytes between Debug and ReleaseSafe or across platforms.

src/golden.zig therefore pins bit-stable windowed-energy fingerprints, plus syllable/sample/peak/zero-crossing measurements, rather than making a false universal WAV-hash promise. The live demo separately compares exact Ogg upload hashes from two equal-input runs in one configuration.

Phrase ends are already zero. The measured loop-crossfade experiment made the wrap worse; tests preserve that result instead of adding fashionable DSP.