From fe998e2375c50962552342867be504bdc888d4c7 Mon Sep 17 00:00:00 2001 From: Markus Graf Date: Thu, 26 Mar 2026 12:00:15 +0100 Subject: [PATCH] docs(02-01): complete synth foundation plan - Add 02-01-SUMMARY.md documenting config, oscillator, layer implementation --- .../02-01-SUMMARY.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 .planning/phases/02-audio-synthesis-engine/02-01-SUMMARY.md diff --git a/.planning/phases/02-audio-synthesis-engine/02-01-SUMMARY.md b/.planning/phases/02-audio-synthesis-engine/02-01-SUMMARY.md new file mode 100644 index 0000000..92231b9 --- /dev/null +++ b/.planning/phases/02-audio-synthesis-engine/02-01-SUMMARY.md @@ -0,0 +1,87 @@ +--- +phase: 02-audio-synthesis-engine +plan: "01" +subsystem: synth +tags: [synthesis, oscillator, EMA, harmonics, audio, go-lame, CGo] +dependency_graph: + requires: [classify/types.go] + provides: [synth/config.go, synth/oscillator.go, synth/layer.go] + affects: [synth/mixer.go (Plan 02-02)] +tech_stack: + added: [github.com/sjzar/go-lame@v0.0.9, gcc, ffprobe] + patterns: [phase-accumulator oscillator, EMA amplitude smoothing, additive synthesis, whisper floor] +key_files: + created: + - synth/config.go + - synth/oscillator.go + - synth/layer.go + - synth/config_test.go + - synth/oscillator_test.go + - synth/layer_test.go + modified: + - go.mod + - go.sum +decisions: + - "go-lame v0.0.9 added as indirect dependency (no direct usage yet); will be promoted to direct in Plan 02-02 when encoder is wired" + - "go-audio/wav intentionally excluded — writing interleaved int16 PCM bytes directly to LameWriter is simpler (per CONTEXT.md Claude's Discretion grant)" + - "ClassNTP has only 2 harmonics (not 3) — NTP is a minimal timing signal; 2 harmonics satisfy test requirement and match timbral intent" +metrics: + duration: "~15 minutes" + completed_date: "2026-03-26" + tasks_completed: 2 + files_created: 6 + files_modified: 2 +--- + +# Phase 02 Plan 01: Synth Foundation — Config, Oscillator, and Layer Summary + +**One-liner:** Phase-accumulator additive oscillator with EMA amplitude smoothing and whisper floor for 11 traffic-class drone layers, tested via TDD. + +## What Was Built + +### synth/config.go +Defines the frequency/harmonic/pan configuration table for all 11 traffic classes. Key constants: `SampleRate=44100`, `WhisperFloor=0.03`, `GainPerLayer=1/11`. Each class has a `FreqConfig` with `BaseHz` in 60-800 Hz, 2-3 `HarmonicDef` entries (ratio + amplitude), and a stereo pan position in [-1, 1]. + +Frequency assignments follow musical intervals (D-02/D-03): ICMP=65 Hz (deep bass), DNS=110 Hz, HTTPS=175 Hz, HTTP=220 Hz, SSH=330 Hz, SMTP=440 Hz, NTP=520 Hz, DHCP=600 Hz, other-TCP=700 Hz, other-UDP=780 Hz. ClassUnknown=437 Hz (detuned 3 Hz below SMTP for perceptible beating, per D-04). + +### synth/oscillator.go +Phase-accumulator oscillator. `Advance(harmonics []HarmonicDef) float64` sums weighted sine partials and normalizes by total weight. Phase advances by `freq/sampleRate` per sample with subtraction wrap (`o.phase -= 1.0`), not `math.Mod`, for performance. + +### synth/layer.go +`Layer` wraps an oscillator with EMA amplitude dynamics. `UpdateTarget(count, maxCount)` sets target amplitude: unseen layers stay at 0.0; seen layers floor at `WhisperFloor` and scale linearly to 1.0 at max count. `AdvanceSample()` advances the oscillator and the EMA (`currentAmp += alpha * (target - current)`). `EMAAlpha(tau, sr)` computes the per-sample coefficient for a given time constant in seconds. + +### Tests (12 passing) +- Config: `TestAllClassesHaveConfig`, `TestFrequenciesInRange`, `TestFrequenciesUnique`, `TestHarmonicsNonEmpty`, `TestPanPositionsInRange` +- Oscillator: `TestOscillatorAdvance`, `TestOscillatorPhaseWrap`, `TestOscillatorDistinctFreqs` +- Layer: `TestEMAAmplitudeRise`, `TestEMAAmplitudeDecay`, `TestWhisperFloor`, `TestWhisperFloorNotSeenIsZero` + +## Commits + +| Task | Commit | Description | +|------|--------|-------------| +| 1 — environment setup | dc7aed2 | chore(02-01): install gcc, ffprobe, and go-lame dependency | +| 2 — tests (RED) | bb13527 | test(02-01): add failing tests for synth config, oscillator, and layer | +| 2 — implementation (GREEN) | 1aaa15d | feat(02-01): implement synth config, oscillator, and layer | + +## Deviations from Plan + +None — plan executed exactly as written. + +## Known Stubs + +None — all config entries are fully wired with real frequency/harmonic/pan values. No placeholder data. + +## Self-Check: PASSED + +- synth/config.go: FOUND +- synth/oscillator.go: FOUND +- synth/layer.go: FOUND +- synth/config_test.go: FOUND +- synth/oscillator_test.go: FOUND +- synth/layer_test.go: FOUND +- Commit dc7aed2: FOUND +- Commit bb13527: FOUND +- Commit 1aaa15d: FOUND +- `go test ./synth/...`: 12 tests PASS +- `CGO_ENABLED=1 go build ./...`: PASS +- go.mod contains go-lame v0.0.9: VERIFIED