Currently Building / 02 Phase 1 complete

Acoustic Fingerprinting

Give it a short clip and it tells you which track it came from — even noisy, compressed, or recorded off a speaker. Shazam's algorithm, written out by hand.

GitHub ↗ Python · NumPy · SciPy DSP · SQLite

An audio identification engine. There are two ways to build one, and the point of the project is to build both and measure them against each other.

The DSP is written out from NumPy and SciPy rather than pulled from librosa — the STFT, the windowing, and the peak-picking are all in plain sight, because the whole exercise is being able to explain why each piece is there.

How the classical path works

Most of a song's spectrogram is redundant. What identifies it is a sparse set of standout points and how they're arranged.

  1. Spectrogram. Chop the signal into ~90 ms frames and transform each, giving a picture of frequency over time. Frame length is a trade-off: longer pins down pitch but blurs timing; 1024 samples at 11 kHz sits in the useful middle.
  2. Peaks. In each neighborhood, keep the loudest point and throw the rest away. These peaks survive noise, EQ, and MP3 compression — and reducing a dense image to a handful of points per second makes the rest cheap.
  3. Hashing. A single peak is a weak clue. A pair of peaks — two frequencies and the time between them — is far more specific and barely changes if the clip starts elsewhere. Each pair becomes an integer hash.
  4. Index & match. Every hash points back to its track and time in a SQLite table. To identify a clip, hash it the same way and check whether matches line up at one consistent time offset — a real match spikes; coincidences scatter and cancel.

Where it's at

Phase 1 — the classical fingerprinter — is complete and works end to end: index a directory of audio and identify clips against it from the command line. On a synthetic corpus of eight tracks, self-retrieval is 100%, and noisy 4-second excerpts still land on the right track.

Next up: a benchmark harness that degrades audio (noise, compression, pitch shift, time stretch) to measure where match rate falls off, then the embedding path, a hand-rolled HNSW index compared against FAISS, and streaming matching from multiple sources at once.

Explore

Read the code on GitHub ↗ — every parameter lives in one config.py with a note on why it's set the way it is.