# OpenSpec Change: enterprise-audio-analysis-pitch - **Change ID**: enterprise-audio-analysis-pitch - **Package**: `@suaveplan/audio-analysis-pitch` - **Category**: universal - **Target path**: `packages/media/audio/audio-analysis-pitch` - **Status**: PROPOSED - **Date**: 2026-05-14 - **Design**: `./design.md` - **Spec delta**: `./specs/audio-analysis-pitch/spec.md` --- ## Summary Deliver `@suaveplan/audio-analysis-pitch` on the genesis branch from scratch at enterprise quality. Pitch, key, and chord detection plugin for the universal audio analysis framework. Detects fundamental frequency, MIDI note numbers, musical key, and chord progressions from `AudioDocument` streams using YIN/McLeod pitch methods and chromagram-based key-finding. Runs identically in browser and server via `BlockProcessor` or direct stream iteration. --- ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. No prior source, no test results, no coverage data. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/audio-core` (`workspace:^`) | `AudioDocument`, `BlockProcessor`, `BlockContext` | | `@suaveplan/audio-analysis-spectrum` (`workspace:^`) | FFT, chromagram (optional — can include own FFT) | | `@suaveplan/error` (`workspace:^`) | `AudioError` base class; `AUDIO_ANALYSIS.*` codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/opentelemetry` (`workspace:^`) | OTel spans, counters, histograms | | `zod` (`catalog:forms`) | Zod schemas for option types | Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata` (all `catalog:testing`). --- ## Public API ### Core types ```ts interface PitchDetectorOptions { algorithm?: 'yin' | 'mcleod' | 'cepstrum' // default 'yin' minFreq?: number // default 20 maxFreq?: number // default 20000 } interface PitchResult extends AnalysisResult { pitch: number // fundamental frequency (Hz) midiNote: number // MIDI note number confidence: number // 0..1 } interface KeyDetectorOptions { profile?: 'krumhansl-schmuckler' | 'temperley' // default 'krumhansl-schmuckler' } interface KeyResult extends AnalysisResult { key: string // e.g. "C major", "F# minor" confidence: number chromagram: Float32Array // 12-bin pitch class distribution } interface Chord { timestamp: number duration: number root: string quality: string // "major", "minor", "dim", etc. confidence: number } interface ChordResult extends AnalysisResult { chords: Chord[] } class PitchDetector implements AnalysisOp { readonly name = 'pitch-detector' analyze(doc: AudioDocument, opts?: PitchDetectorOptions): Promise analyzeStream(doc: AudioDocument, opts?: PitchDetectorOptions): AsyncGenerator analyzeBlock(block: Float32Array[], ctx: BlockContext): PitchResult } class KeyDetector implements AnalysisOp { readonly name = 'key-detector' analyze(doc: AudioDocument, opts?: KeyDetectorOptions): Promise analyzeStream(doc: AudioDocument, opts?: KeyDetectorOptions): AsyncGenerator } class ChordDetector implements AnalysisOp { readonly name = 'chord-detector' analyze(doc: AudioDocument): Promise analyzeStream(doc: AudioDocument): AsyncGenerator } ``` --- ## New additions for genesis 1. **Three pitch algorithms** — YIN, McLeod pitch method, cepstrum; selectable per detection call. 2. **Key detection** — Krumhansl-Schmuckler and Temperley profiles on aggregated chromagram. 3. **Chord progression** — template matching on per-frame chromagram with smoothing. 4. **Streaming refinement** — pitch/key confidence improves as more audio is processed. 5. **OTel instrumentation** — spans per detector, counters, histograms. 6. **Property-based tests** — sine waves at known frequencies yield exact pitch, silence yields no pitch. 7. **Benchmark suite** — analyze 1-minute track for pitch, key, and chords. --- ## File layout ```text packages/media/audio/audio-analysis-pitch/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts detector/ pitch-detector.ts pitch-detector.md pitch-detector.types.ts pitch-detector.test.ts key-detector.ts key-detector.md key-detector.types.ts key-detector.test.ts chord-detector.ts chord-detector.md chord-detector.types.ts chord-detector.test.ts index.ts algorithms/ yin.ts yin.md yin.test.ts chromagram.ts chromagram.md chromagram.test.ts key-finding.ts key-finding.md key-finding.test.ts chord-matching.ts chord-matching.md chord-matching.test.ts index.ts __benchmarks__/ pitch.bench.ts tests/ integration.test.ts property.test.ts ``` --- ## Impact **Breaking changes**: none — fresh build, package does not yet exist on genesis. **Prerequisites**: `@suaveplan/audio-core`, `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/opentelemetry` published to Verdaccio. ### Affected dependents No dependents in this batch (verified by `bunx turbo ls --filter=...@suaveplan/audio-analysis-pitch`). `@suaveplan/audio-analysis-pitch` is a leaf Analysis Op plugin — no genesis package depends on it at the time of this change. It is consumed at runtime by application/timeline code registering it as an analysis op (e.g. `@suaveplan/audio-plugins-fx` auto-tune reading `PitchResult`, a React player surfacing `KeyResult.key`, `@suaveplan/audio-cli` batch analysis); those consumers land in later changes and are created against this package's spec delta, not retrofitted.