core fingerprinting and matching pipeline is functional, cloud storage and message brokers to decouple the multi-store write pipelines are in development
Shazam like audio fingerprinting system built from scratch in C# and .NET 8. Given a YouTube URL, downloads the audio, generates audio fingerprint and stores it. Given a short audio snippet as hashes it identifies the song using time-coherent offset voting, it is similar but simplified algorithm which Shazam uses.
No third-party fingerprinting libraries or API's used. The entire pipeline — STFT, peak detection, hash generation, and voting is custom implemented.
POST /api/song?url={youtubeUrl}
Pipeline for Youtube URL to Audio fingerprint, Audio Metadata:
- Extracts metadata (title, artist, duration) from the YouTube URL.
- Checks for duplicates — skips if the song is already indexed.
- Downloads the audio file to local disk. (In future bucket or different kind of storage will be included, this is just for testing at the moment)
- Runs the fingerprinting pipeline:
- STFT with Hann windowing -> frequency spectrum over time, Generates spectogram which is represented as 2D array, Hann Window
- 2D local maxima detection -> (time, freq) kept if it's strict maximum within
(2·timeRadius + 1) × (2·freqRadius + 1)and exceeds minimum db threshholdfloat threshold = -60f; - Combinatorial hashing - each peak is paired with nearby peaks to generate
(frequency1, frequency2, timeDelta)hashes, hash algorithm just contains simple bit shiftingpublic uint Hash => ((uint)Freq1 << 20) | ((uint)Freq2 << 10) | (uint)DeltaTime;
- Stores all hashes in Redis under the
fingerprint:prefix, each mapping to the song ID and time offset. Uses redis persistence - Stores song metadata in MS SQL Server.
POST /api/recognize
Accepts a dictionary of { hash -> queryOffset } from a recorded audio snippet and runs voting:
- For each hash, fetches candidate entries from Redis.
- For each candidate, computes
timeDelta = storedOffset - queryOffset- this represents where in the original song the snippet was recorded from. - Votes are accumulated per
(songId, timeDelta)pair. A high vote count for a specific delta means the snippet consistently aligns with one song at one position. - The
(songId, timeDelta)pair with the most votes wins. - Song metadata is fetched from MS SQL Server by the winning
songIdand returned.
This approach should be inherently noise-robust — a few bad hashes should not break matching because only consistent time-alignment accumulates votes. Well at least that's what this Research Paper claims. ¯_(ツ)_/¯
Clean Architecture with the following layers:
- API -
SongController,RecognizeController - Application -
servicesandinterfaces: Youtube, Audio Fingerprint and Song matching services - Domain - Just includs models
no bussines logic in here - Infrastructure - Redis fingerprint repository, MSSQL song repository
- .NET 8 — ASP.NET Core Web API, Clean Architecture
- Redis — fingerprint hash storage (
fingerprint:{hash}keys, persistent) - MS SQL Server + EF Core — song metadata
- STFT + Hann windowing — custom spectral analysis implementation
| Data | Store |
|---|---|
| Fingerprint hashes | Redis (fingerprint: prefix) |
| Song metadata | MS SQL Server |
| Audio files | Local disk (D:) — cloud bucket is planned in future |
- RabbitMQ to decouples the multi step storage pipeline (disk, MSSQL, Redis)
- Cloud storage for audio files (S3-compatible bucket)
- Improved peak detection tuning for noisy recordings