Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

222 Commits

Folders and files

Repository files navigation

SoundsLike.fm

Describe a song in plain words — instruments, mood, tempo, era, where you heard it — and get its name.

A community index of how songs sound. Nobody uploads audio: your browser reads your files, identifies each one by acoustic fingerprint (AcoustID + MusicBrainz), and boils it down to a 2 KB vector (LAION CLAP, run in the browser with WebGPU). Only the vector and the artist / title / album text are sent. Searching turns your sentence into the same kind of vector and ranks every stored song against it.

What the server stores, and what it never stores: web/legal.html.

Layout

  • web/ — the site. app.js (search + folder scan), worker.js (Chromaprint via WASM + CLAP via transformers.js), tones.js (the two-tone technicolor palette), water.js (a port of hyprwater), wasm/ (the fingerprinter).
  • server/ — FastAPI. SQLite, a brute-force vector index in RAM, the CLAP text tower on ONNX Runtime (CPU). Runs on a Raspberry Pi.
  • fingerprint-wasm/ — Chromaprint (rusty-chromaprint) compiled to WebAssembly.
  • deploy/ — the Pi install script and systemd unit.

Run it

cd server && python -m venv .venv && .venv/bin/pip install -r requirements.txt
VIBEFIND_DATA=../data ACOUSTID_KEY=<your key from acoustid.org/new-application> .venv/bin/python -m uvicorn app:app --port 8080

Open http://localhost:8080. The text model (~240 MB) downloads on the first search; the browser downloads the audio model (~143 MB) on the first scan.

On a Raspberry Pi: deploy/pi-install.sh, then the unit in deploy/describesong.service.

Tests

server/tests/run_all.sh            # everything, ~1 min; --offline skips the live part

Two kinds, on purpose:

  • Deterministic parts are unit-tested — test_names.py (is this word a name? 40 cases) and test_braces.py (what do the braces under the bar say? 38 cases). They exec the real functions from app.py against a fake catalogue. Seconds, no network.
  • Ranking is asserted as properties, not ranks — live_invariants.py hits the live site and checks what must hold at any index size: every row above a divider is by the named artist, the number never climbs down a page, word order does not change a name search, every top row of a "female singer" search carries the voice badge, & pages without repeats, the old domain redirects, API answers are gzipped. Exact ranks are not asserted anywhere, because the index grows every hour and they drift with it.
  • Descriptions are generated, not hand-picked — live_descriptions.py builds 160 descriptions from the site's own sound vocabulary (mood + genre, tempo + genre, instrument + mood + era, hyphenated spellings too) and asserts none of them is read as a name. The hand-written cases are the ones somebody thought of; this finds the ones nobody did — it found two on its first day.
  • bench_search.py is the trend line: 18 described targets and where each lands. Read it after a change; do not make it pass.

Licences

  • Code: AGPL-3.0. If you run a modified copy as a service, you must offer its source to your users.
  • The database of vectors and labels: ODbL — use it for anything, share improvements to the database itself alike.
  • Model weights: LAION CLAP (CC0). Fingerprints: Chromaprint (LGPL) via rusty-chromaprint.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages