first commit
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# chromagram
|
||||
|
||||
## Purpose
|
||||
|
||||
`chromagram.ts` folds a spectral frame into the twelve pitch classes used by Western tonal analysis. Each magnitude bin is mapped to a pitch class via `pitchClass = round(12 * log2(freq / A4)) mod 12` and accumulated into a 12-element `Float32Array`. The chromagram is the shared substrate for both key-finding and chord template matching in this package.
|
||||
|
||||
The module relies on the vendored real FFT in `./yin.ts` so the chromagram path stays self-contained and does not require `@suaveplan/audio-analysis-spectrum` at runtime.
|
||||
|
||||
## Features
|
||||
|
||||
- `chromagramFromFrame(frame, sampleRate, minFreq?)` — per-frame 12-bin pitch-class profile.
|
||||
- `normaliseChroma(chroma)` — in-place max-normalisation; idempotent on all-zero vectors.
|
||||
- `accumulateChroma(acc, add)` — in-place sum, clamped to the shorter length so callers can pass differently sized buffers safely.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { chromagramFromFrame } from "@suaveplan/audio-analysis-pitch/algorithms/chromagram";
|
||||
|
||||
const chroma = chromagramFromFrame(frame, 48_000);
|
||||
console.log("strongest pitch class:", chroma.indexOf(Math.max(...chroma)));
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
accumulateChroma,
|
||||
chromagramFromFrame,
|
||||
normaliseChroma,
|
||||
} from "@suaveplan/audio-analysis-pitch/algorithms/chromagram";
|
||||
|
||||
async function aggregateChroma(stream: AsyncIterable<Float32Array>, sr: number) {
|
||||
const acc = new Float32Array(12);
|
||||
for await (const frame of stream) {
|
||||
accumulateChroma(acc, chromagramFromFrame(frame, sr));
|
||||
}
|
||||
normaliseChroma(acc);
|
||||
return acc;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `chromagramFromFrame(frame: Float32Array, sampleRate: number, minFreq = 30): Float32Array` (length 12).
|
||||
- `normaliseChroma(chroma: Float32Array): Float32Array` — in-place, returns the same buffer.
|
||||
- `accumulateChroma(acc: Float32Array, add: Float32Array): Float32Array` — clamped to `min(acc.length, add.length)`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Frames shorter than eight samples short-circuit to an all-zero chromagram. Energy below `minFreq` (default 30 Hz) and at or above the Nyquist is dropped to suppress hum and aliasing. All operations are O(N) over the FFT magnitude vector. Buffers are caller-owned — the module never allocates on the hot path beyond the result.
|
||||
Reference in New Issue
Block a user