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

2.6 KiB
Raw Blame History

fingerprint-matcher — Time-offset histogram match scoring

(no submodules)

Purpose

FingerprintMatcher scores a query fingerprint against a corpus of candidate fingerprints using the classic Shazam time-offset histogramming technique. For every hash that appears in both query and candidate, the matcher accumulates (candidateOffset − queryOffset) into a 10 ms-wide histogram bucket; the heaviest bucket count is the match score and its midpoint is the alignment offset. Results sort by descending score, ready for ranked display.

Features

  • match(query, corpus) returns ranked MatchResult[].
  • matchOne(query, candidate) returns the best bin only — useful for unit tests and direct pairwise comparison.
  • Configurable binWidthSec (default 0.01 s).
  • Hash-index pre-step keeps the cost at O(|query| + |candidate|) per pair.
  • Wraps iteration-time corpus failures in REACT_AUDIO_FINGERPRINT.MATCH_FAILED.
  • Empty inputs return zero-scored results without throwing.

Usage: Basic Example

import { FingerprintMatcher } from "@suaveplan/react-audio-fingerprint/fingerprint/fingerprint-matcher";

const ranked = new FingerprintMatcher().match(queryFp, corpus);
console.log(ranked[0]?.id, ranked[0]?.score);

Usage: Advanced Example

Drive a tighter alignment window for short clips:

import { FingerprintMatcher } from "@suaveplan/react-audio-fingerprint/fingerprint/fingerprint-matcher";

const m = new FingerprintMatcher();
const one = m.matchOne(queryFp, candidateFp, { binWidthSec: 0.005 });
console.log(one.score, one.offsetSec, one.matchedHashCount);

API Reference

  • class FingerprintMatcher.
  • match(query, corpus, opts?): MatchResult[].
  • matchOne(query, candidate, opts?): MatchOneResult.
  • MatchResult = { id, score, offsetSec, matchedHashCount }.
  • CorpusLike = { values(): Iterable<{ id; fingerprint }> }.
  • MatcherOptions = { binWidthSec?: number } (default 0.01).

Implementation Notes

A candidate's hash table is built lazily on each call — caching is left to callers because corpora are typically streamed. Hash indices use Map<number, number[]> since duplicate hashes inside one fingerprint are common (the same constellation pair can recur at different times). The histogram is also a Map<number, number> because the bucket range is unbounded in principle. Bucket midpoints (rather than left edges) keep the reported offset symmetric around the true alignment. The matcher is pure — given the same inputs it produces the same outputs — so callers can safely memoise results keyed by (queryFp, corpusVersion).