From 7ced25ae703a62c2bcf6b479a1be3a522caf715e Mon Sep 17 00:00:00 2001 From: Markus Graf Date: Thu, 26 Mar 2026 17:11:11 +0100 Subject: [PATCH] docs(05): capture phase context --- .../05-CONTEXT.md | 86 +++++++++++++++++++ .../05-DISCUSSION-LOG.md | 58 +++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 .planning/phases/05-waveform-types-and-bank-decoupling/05-CONTEXT.md create mode 100644 .planning/phases/05-waveform-types-and-bank-decoupling/05-DISCUSSION-LOG.md diff --git a/.planning/phases/05-waveform-types-and-bank-decoupling/05-CONTEXT.md b/.planning/phases/05-waveform-types-and-bank-decoupling/05-CONTEXT.md new file mode 100644 index 0000000..81db9e8 --- /dev/null +++ b/.planning/phases/05-waveform-types-and-bank-decoupling/05-CONTEXT.md @@ -0,0 +1,86 @@ +# Phase 5: Waveform Types and Bank Decoupling - Context + +**Gathered:** 2026-03-26 +**Status:** Ready for planning + + +## Phase Boundary + +Extend the synthesis oscillator to support four waveform types (sine, square, sawtooth, triangle) using bandlimited additive synthesis, and decouple the OscillatorBank from the hardcoded `ClassFreqConfigs` global and `classify.AllClasses()` iteration — making it accept an injected config map instead. + + + + +## Implementation Decisions + +### Waveform Presets +- **D-01:** Use bandlimited additive synthesis with 8-12 partials per waveform type. Square wave uses odd harmonics (1,3,5,...,11), sawtooth uses all harmonics (1-12), triangle uses odd harmonics with 1/n^2 amplitude rolloff. This is the standard approach for aliasing-free waveform generation. +- **D-02:** Add a `WaveformType` enum to `FreqConfig` (`Sine`, `Square`, `Sawtooth`, `Triangle`). When waveform is set, generate the `[]HarmonicDef` from the preset formula. When waveform is unset/custom, use the existing hand-tuned `Harmonics` array. + +### Built-in Harmonics Migration +- **D-03:** (Claude's Discretion) Decide whether built-in classes keep their hand-tuned HarmonicDef arrays or migrate to waveform presets. Recommended approach: keep existing harmonics as-is for v1.0 classes (preserves sound character), default them to `WaveformType = ""` (custom). Waveform presets only take effect when explicitly set via config in Phase 6. + +### GainPerLayer Scaling +- **D-04:** Fix GainPerLayer now in Phase 5 — compute dynamically as `1.0 / float64(len(layers))` inside `NewBank` instead of using the hardcoded `NumLayers=14` constant. This establishes the correct foundation before Phase 7 adds dynamic class counts. + +### Bank Decoupling +- **D-05:** (Claude's Discretion) Change `NewBank` to accept a `map[classify.TrafficClass]FreqConfig` parameter instead of reading the `ClassFreqConfigs` global. This is the injection seam that Phase 6 will use to pass merged config. The existing `ClassFreqConfigs` var remains as the default map. + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### Synthesis Architecture +- `synth/oscillator.go` — Current sine-only Oscillator with phase accumulator and `Advance([]HarmonicDef)` +- `synth/config.go` — `FreqConfig`, `HarmonicDef`, `ClassFreqConfigs` global, constants (`SampleRate`, `NumLayers`, `GainPerLayer`) +- `synth/bank.go` — `NewBank(tau)` iterates `classify.AllClasses()` and reads `ClassFreqConfigs` global +- `synth/layer.go` — `Layer` with EMA smoothing, uses `FreqConfig` from config.go + +### Research +- `.planning/research/ARCHITECTURE.md` — Integration points and build order for v1.1 +- `.planning/research/PITFALLS.md` — Pitfall A3 (aliasing) and A6 (bank class mismatch) + +No external specs — requirements fully captured in decisions above. + + + + +## Existing Code Insights + +### Reusable Assets +- `Oscillator.Advance([]HarmonicDef)` — Already supports additive synthesis via harmonic series. Waveform presets just need different `[]HarmonicDef` arrays, not a new oscillator type. +- `FreqConfig` struct — Has `BaseHz`, `Harmonics`, `Pan`. Adding `WaveformType` field is backward-compatible. + +### Established Patterns +- Phase accumulator in `Oscillator` wraps at 1.0 — all harmonic ratios are integer multiples of the fundamental. +- `Layer` delegates to `Oscillator.Advance()` — waveform change is transparent to the layer. +- `ClassFreqConfigs` is a package-level `var` (not `const`) — can be replaced by parameter injection without breaking existing tests. + +### Integration Points +- `NewBank(tau)` → `NewBank(tau, configs map[TrafficClass]FreqConfig)` — single signature change +- `bank.RenderWindow()` iterates `classify.AllClasses()` — must iterate `b.layers` map keys instead +- `encode.RunSynthesis` calls `NewBank(1.0)` — will need to pass config map (Phase 6 concern, but seam established here) + + + + +## Specific Ideas + +No specific requirements — standard bandlimited synthesis approach with 8-12 partials as user requested. + + + + +## Deferred Ideas + +None — discussion stayed within phase scope. + + + +--- + +*Phase: 05-waveform-types-and-bank-decoupling* +*Context gathered: 2026-03-26* diff --git a/.planning/phases/05-waveform-types-and-bank-decoupling/05-DISCUSSION-LOG.md b/.planning/phases/05-waveform-types-and-bank-decoupling/05-DISCUSSION-LOG.md new file mode 100644 index 0000000..d98f618 --- /dev/null +++ b/.planning/phases/05-waveform-types-and-bank-decoupling/05-DISCUSSION-LOG.md @@ -0,0 +1,58 @@ +# Phase 5: Waveform Types and Bank Decoupling - Discussion Log + +> **Audit trail only.** Do not use as input to planning, research, or execution agents. +> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. + +**Date:** 2026-03-26 +**Phase:** 05-waveform-types-and-bank-decoupling +**Areas discussed:** Waveform presets, GainPerLayer scaling + +--- + +## Waveform presets + +### Harmonic richness + +| Option | Description | Selected | +|--------|-------------|----------| +| Bandlimited (8-12 partials) | Accurate waveform shapes, no aliasing. Standard for quality synthesis. | ✓ | +| Lightweight (4-6 partials) | Recognizably different but softer/rounder. Less CPU. | | +| You decide | Claude picks based on Nyquist and ambient use case | | + +**User's choice:** Bandlimited (8-12 partials) +**Notes:** None + +### Built-in class harmonics + +| Option | Description | Selected | +|--------|-------------|----------| +| Keep current harmonics | Built-in classes retain hand-tuned arrays. Waveform presets only via config. | | +| Migrate to sine preset | Switch to pure fundamental. Simpler but loses v1.0 character. | | +| You decide | Claude picks best approach for preserving v1.0 sound | ✓ | + +**User's choice:** You decide (Claude's Discretion) +**Notes:** None + +--- + +## GainPerLayer scaling + +| Option | Description | Selected | +|--------|-------------|----------| +| Fix now in Phase 5 | Compute dynamically as 1/len(layers). Clean foundation for Phase 7. | ✓ | +| Defer to Phase 7 | Keep NumLayers=14 constant. Fix when user classes land. | | +| You decide | Claude picks timing based on complexity | | + +**User's choice:** Fix now in Phase 5 +**Notes:** None + +--- + +## Claude's Discretion + +- Built-in class harmonics migration strategy (D-03) +- Bank config injection API design (D-05) + +## Deferred Ideas + +None