Files
skills/docs/ui/react/react-audio-fingerprint/src/fingerprint/constellation/constellation.md
2026-05-29 08:20:56 +01:00

2.7 KiB
Raw Blame History

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 / 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

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 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.