first commit
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
# `constellation` — Pair-hash construction over detected peaks
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The constellation module converts a list of spectrogram peaks into a stable,
|
||||
hashable fingerprint by pairing each anchor peak with several subsequent peaks
|
||||
inside a fixed target zone. Each pair `(binA, binB, Δframes)` is packed into a
|
||||
32-bit integer; the resulting `(hash, timeOffsetSec)` records form the
|
||||
fingerprint that the matcher consumes. This is the classic Shazam construction
|
||||
described by Wang (2003) without any modifications.
|
||||
|
||||
## Features
|
||||
|
||||
- 32-bit packed hash with explicit `binA[12] | binB[12] | dt[8]` layout.
|
||||
- `packHash` / `unpackHash` round-trip helpers for diagnostics and tests.
|
||||
- Configurable `fanout`, `targetZoneFrames`, `minDeltaFrames` via Zod schema.
|
||||
- Deterministic output sorted by anchor `timeOffsetSec`.
|
||||
- Empty-input safe (no peaks → empty fingerprint, no throw).
|
||||
- Validates `hopSamples` / `sampleRate` and rejects non-positive grids with
|
||||
`ReactAudioFingerprintError(INVALID_OPTIONS)`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { buildConstellation } from "@suaveplan/react-audio-fingerprint/fingerprint/constellation";
|
||||
|
||||
const fp = buildConstellation(peaks, 512, 48_000);
|
||||
console.log(fp.length, fp[0]?.hash);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Tighten the target zone for short percussive clips:
|
||||
|
||||
```ts
|
||||
import { buildConstellation } from "@suaveplan/react-audio-fingerprint/fingerprint/constellation";
|
||||
|
||||
const fp = buildConstellation(peaks, 256, 48_000, {
|
||||
fanout: 8,
|
||||
targetZoneFrames: 80,
|
||||
minDeltaFrames: 2,
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `buildConstellation(peaks, hopSamples, sampleRate, opts?): Fingerprint`.
|
||||
- `Fingerprint = ReadonlyArray<{ hash: number; timeOffsetSec: number }>`.
|
||||
- `packHash(binA, binB, dt): number` — 32-bit pack.
|
||||
- `unpackHash(h): { binA; binB; dt }` — inverse.
|
||||
- `ConstellationOptionsSchema` — Zod schema with defaults `fanout=5`,
|
||||
`targetZoneFrames=200`, `minDeltaFrames=1`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The Δt field is clamped to 8 bits, which limits the effective target zone to
|
||||
255 hop-frames regardless of the schema value. At the default 512-sample hop
|
||||
and 48 kHz sample rate this is ~2.72 seconds — well inside the classic
|
||||
constellation target-zone width. Hashes are unsigned 32-bit integers; the
|
||||
`>>> 0` at the end of `packHash` reinterprets the bitwise result, which is
|
||||
otherwise a signed 32-bit integer in JavaScript's number type. Output sorting
|
||||
makes equal-fingerprint comparison trivial (`JSON.stringify` round-trip is
|
||||
enough for byte equality). Pair construction is O(`peaks × fanout`) because
|
||||
each anchor stops emitting once the fanout cap is hit or the target zone is
|
||||
exhausted.
|
||||
Reference in New Issue
Block a user