first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
# pitch-detector
## Purpose
`pitch-detector.ts` exposes the `PitchDetector` class — the Analysis Op plugin (plugin slot 3 in the `@suaveplan/audio-*` family) that estimates the fundamental frequency of an `AudioDocument`. It supports whole-document analysis (`analyze`), streaming refinement (`analyzeStream`), and synchronous single-block analysis (`analyzeBlock`) for real-time visualisation.
Three estimators are selectable per call — YIN (default), McLeod, and cepstrum — letting callers pick the right trade-off for the material at hand without coupling to a different package.
## Features
- Three pitch algorithms behind the `algorithm` option.
- Configurable frequency range via `minFreq` / `maxFreq` and frame size.
- `AbortSignal` support across all three entry points.
- Zod boundary validation on every options object.
- OpenTelemetry spans per detector run, counter for total runs, histograms for run and block duration.
- Stable error codes (`INVALID_OPTIONS`, `ABORTED`, `UNSUPPORTED_FORMAT`, `INSUFFICIENT_DATA`) all routable through `AudioAnalysisError`.
## Usage: Basic
```ts
import { PitchDetector } from "@suaveplan/audio-analysis-pitch";
const detector = new PitchDetector();
const result = await detector.analyze(doc);
console.log(result.pitch, "Hz", "midi:", result.midiNote);
```
## Usage: Advanced
```ts
import { PitchDetector } from "@suaveplan/audio-analysis-pitch";
const detector = new PitchDetector();
const controller = new AbortController();
const opts = { algorithm: "mcleod" as const, minFreq: 50, maxFreq: 1_000, signal: controller.signal };
const out: number[] = [];
for await (const r of detector.analyzeStream(doc, opts)) {
out.push(r.pitch);
if (out.length >= 100) controller.abort();
}
```
## API Reference
- `class PitchDetector { name: "pitch-detector"; version: string; description: string; analyze(doc, opts?); analyzeStream(doc, opts?); analyzeBlock(block, ctx) }`.
- `interface PitchDetectorOptions { algorithm?, minFreq?, maxFreq?, frameSize?, hopSize?, signal? }`.
- `interface PitchResult extends AnalysisResult { op: "pitch-detector"; pitch; midiNote; confidence; timestamp; duration }`.
## Implementation Notes
`analyze` aggregates results by keeping the highest-confidence pitch across all frames. `analyzeStream` yields per-block estimates with a running max confidence so the stream is non-decreasing in expectation. Both honour an `AbortSignal` checked at every block boundary. `analyzeBlock` is allocation-light: it skips the Zod schema (the block path is hot) and uses the package defaults.