2.7 KiB
constellation — Pair-hash construction over detected peaks
(no submodules)
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/unpackHashround-trip helpers for diagnostics and tests.- Configurable
fanout,targetZoneFrames,minDeltaFramesvia Zod schema. - Deterministic output sorted by anchor
timeOffsetSec. - Empty-input safe (no peaks → empty fingerprint, no throw).
- Validates
hopSamples/sampleRateand rejects non-positive grids withReactAudioFingerprintError(INVALID_OPTIONS).
Usage: Basic Example
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:
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 defaultsfanout=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.