153 lines
5.2 KiB
Markdown
153 lines
5.2 KiB
Markdown
# OpenSpec Change: enterprise-audio-analysis-beat
|
|
|
|
- **Change ID**: enterprise-audio-analysis-beat
|
|
- **Package**: `@suaveplan/audio-analysis-beat`
|
|
- **Category**: universal
|
|
- **Target path**: `packages/media/audio/audio-analysis-beat`
|
|
- **Status**: PROPOSED
|
|
- **Date**: 2026-05-14
|
|
- **Design**: `./design.md`
|
|
- **Spec delta**: `./specs/audio-analysis-beat/spec.md`
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Deliver `@suaveplan/audio-analysis-beat` on the genesis branch from scratch at enterprise quality. Beat and tempo detection plugin for the universal audio analysis framework. Detects BPM, beat locations, and onset times from `AudioDocument` streams using energy-based and spectral-flux algorithms, with optional comb-filter tempo estimation and beat-grid alignment.
|
|
|
|
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. The old `enterprise-browser-audio-engine` openspec was browser-only and did not include beat detection.
|
|
|
|
---
|
|
|
|
## Available workspace deps on genesis
|
|
|
|
| Package | Role |
|
|
|---|---|
|
|
| `@suaveplan/audio-core` (`workspace:^`) | `AudioDocument`, `BlockProcessor`, `BlockContext` |
|
|
| `@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 BeatDetectorOptions {
|
|
minBpm?: number // default 60
|
|
maxBpm?: number // default 200
|
|
algorithm?: 'energy' | 'spectral-flux' | 'comb' // default 'energy'
|
|
}
|
|
|
|
interface BeatResult extends AnalysisResult {
|
|
bpm: number
|
|
beats: Float64Array // beat timestamps (seconds)
|
|
onsets: Float64Array // onset timestamps (seconds)
|
|
confidence: number // 0..1
|
|
}
|
|
|
|
class BeatDetector implements AnalysisOp {
|
|
readonly name = 'beat-detector'
|
|
readonly description = 'Detect tempo and beat locations'
|
|
|
|
constructor(options?: BeatDetectorOptions)
|
|
|
|
analyze(doc: AudioDocument, opts?: BeatDetectorOptions): Promise<BeatResult>
|
|
analyzeStream(doc: AudioDocument, opts?: BeatDetectorOptions): AsyncGenerator<BeatResult>
|
|
analyzeBlock(block: Float32Array[], ctx: BlockContext): BeatResult
|
|
}
|
|
```
|
|
|
|
### Error codes
|
|
|
|
```ts
|
|
type BEATErrorCode =
|
|
| 'AUDIO_ANALYSIS_BEAT.INVALID_OPTIONS'
|
|
| 'AUDIO_ANALYSIS_BEAT.EMPTY_DOCUMENT'
|
|
| 'AUDIO_ANALYSIS_BEAT.NO_BEATS_DETECTED'
|
|
|
|
const AUDIO_ANALYSIS_BEAT_ERROR_METADATA: Readonly<Record<BEATErrorCode, CodeMetadata>>
|
|
function registerAudioAnalysisErrorCodes(): void
|
|
```
|
|
|
|
### Zod schemas
|
|
|
|
```ts
|
|
BeatDetectorOptionsSchema
|
|
BeatResultSchema
|
|
```
|
|
|
|
---
|
|
|
|
## New additions for genesis
|
|
|
|
1. **Three algorithms** — energy ODF (fast, from existing block stats), spectral flux (FFT-based, higher precision), comb-filter tempo estimation.
|
|
2. **Beat grid alignment** — phase-align detected onsets to a regular grid after tempo is known.
|
|
3. **Streaming refinement** — `analyzeStream()` yields partial results that refine as more audio is processed.
|
|
4. **Block-level real-time** — `analyzeBlock()` returns instantaneous onset detection for visualization.
|
|
5. **OTel instrumentation** — span `audio.analysis.beat`, counter `audio.analysis.beat.runs_total`, histogram `audio.analysis.beat.duration_ms`.
|
|
6. **Property-based tests** — synthetic metronome input yields exact BPM, silence yields no beats with graceful fallback.
|
|
7. **Benchmark suite** — analyze 1-minute track, analyze 10-minute track.
|
|
|
|
---
|
|
|
|
## File layout
|
|
|
|
```text
|
|
packages/media/audio/audio-analysis-beat/
|
|
package.json
|
|
tsconfig.json
|
|
vitest.config.ts
|
|
src/
|
|
index.ts
|
|
error-codes.ts
|
|
detector/
|
|
beat-detector.ts
|
|
beat-detector.md
|
|
beat-detector.types.ts
|
|
beat-detector.test.ts
|
|
index.ts
|
|
algorithms/
|
|
energy-odf.ts
|
|
energy-odf.md
|
|
energy-odf.test.ts
|
|
spectral-flux.ts
|
|
spectral-flux.md
|
|
spectral-flux.test.ts
|
|
comb-tempo.ts
|
|
comb-tempo.md
|
|
comb-tempo.test.ts
|
|
beat-grid.ts
|
|
beat-grid.md
|
|
beat-grid.test.ts
|
|
index.ts
|
|
__benchmarks__/
|
|
beat.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. All four already exist on genesis.
|
|
|
|
### Affected dependents
|
|
|
|
No dependents in this batch (verified by `bunx turbo ls --filter=...@suaveplan/audio-analysis-beat`). `@suaveplan/audio-analysis-beat` is a leaf Analysis Op plugin — no other package in this 13-change audio batch depends on it. It is consumed at runtime by application/timeline code that registers it as a sidecar analysis op (e.g. auto-mixing in `@suaveplan/audio-plugins-fx`, visualisation in a future `react-audio-player`, batch analysis in `@suaveplan/audio-cli`) — those consumers depend on `@suaveplan/audio-core`'s `AnalysisOp` interface, not on this package directly, and none are created or modified by this change.
|