Skip to content
Doppel
Home

How it works

Doppel finds songs that match the feel of one you love, by mixing what the crowd plays together with a model that actually listens. Here’s the thinking behind it, how it runs, and the proof the listening step earns its keep.

Two designs died first

Doppel is what’s left after two reasonable-looking ideas didn’t pan out. One broke on the outside world, one broke on real people. It kept what each of them taught.

First try

Ask an AI to read the audio

The first version had an AI look at a song’s tempo and key from Spotify’s data. Two things killed it. Spotify shut those numbers off to new apps in 2024, and more to the point, asking an AI to judge how a song sounds asks it to do something it can’t: it has never actually heard the song. That’s where today’s rule came from: the AI explains the picks, it never chooses them.

Second try

Build from a free music library

The next version listened to a library of free-to-use songs ahead of time and matched against that. The math worked and the product didn’t: ask for something like a chart hit and you get thirty songs by artists you’ve never heard of. It was right and useless.

What stuck

Use the crowd and the sound

The fix was to let two so-so signals cover for each other. The crowd (from Last.fm and ListenBrainz) cheaply suggests songs people treat as similar, and re-sorts them by what actually sounds alike. The crowd keeps the picks recognizable. The listening keeps them honest. Neither is good enough on its own.

Why it’s practical

It remembers what it hears

Instead of listening to a giant library up front, it only listens to the songs a search actually turns up (at most 75), and . So its memory grows on its own. That one choice is why the same code answers a familiar song in about 12 seconds and a brand-new one in about 12 minutes: the only difference is how much it already knew.

What makes it different

It does four things at once that no single tool does together: lean on the crowd, judge the actual sound, let you nudge by mood, and explain each pick in plain words.

Spotify / Applego by what's already popular
Last.fmknow your taste, but never listen to the song
Chosic / Spotalikethin wrappers over Spotify's data
Maroofylisten, but it's a black box: no reasons, no controls

Where it doesn’t win:Doppel won’t beat Spotify for a casual “play me something similar.” It’s built for the deliberate kind of digging: “I love this exact song, what gives it that feel, and what else has it.” Saying where it loses is part of saying what it’s for.

The calls behind it

Each of these was a real fork in the road, where the option not taken was perfectly reasonable. The note says why the other one won. This part is the engineering, if you want it.

Combine by rankover combine raw scores

Last.fm’s and ListenBrainz’s scores aren’t on the same scale, so it combines them by rank position instead of raw numbers.

A model that listensover hand-coded audio measurements

Two songs at the same tempo and key can feel nothing alike (deep house vs garage rock). A model that learned from real audio catches texture that simple measurements miss.

Match the exact recordingover match the song in general

Folding a live or acoustic take into the studio version turns up matches you didn’t mean. Only a true re-release of the same recording gets filtered out.

Check two IDsover trust one ID

It checks both IDs, because the same recording once showed up twice under one Deezer id with two different MusicBrainz ids.

Count, don’t guessover estimate the time up front

It picks the fast path or slow path by simply counting how many songs it hasn’t heard yet, rather than trying to guess how long the run will take.

Keep it in Postgresover add a separate vector database

Postgres already holds the data and the logs, so the audio fingerprints live there too. One database, nothing extra to run.

What’s not built yet

Most of these come from the same choice to keep this a saved, no-live-backend showcase: a whole batch of hardening is planned on purpose rather than built. Listing what isn’t finished is part of being straight about it.

  • Harder-to-guess job linksthe live job link is a simple counter today; making it unguessable is a known to-do
  • Login and rate limits on the APIthere's no public endpoint yet, so neither is built. Planned, not done.
  • Per-request database connectionsneeded once many people hit it at once; the single-worker setup doesn't need it yet
  • Same-artist near-matchesa track by the same artist can still show up. By design, that's a fair match.

How it runs, start to finish

It all runs as one path. The same code answers a familiar song in about 12 seconds and a brand-new one in about 12 minutes. The only difference is how many songs it has to listen to fresh.

the crowdthe soundthe final list
  1. Ask the crowd
    pull each song’s “similar tracks” from Last.fm and ListenBrainz (200 to 300)
  2. Merge the lists
    dedupe, then blend them with
  3. Look up the top 75
    resolve each against MusicBrainz, then verify a preview on Deezer (~1 a second)
  4. Listen to the new ones
    the model turns each preview into an , saved so it never re-listens
  5. Score and blend
    compare each embedding by ; fold in your mood at 30% if you added one
  6. Pick the top 10
    rank by the blended score; crowd picks fill any gap
  7. Write the why
    one batched call writes a note per pick. It never ranks.
the crowd the sound the final list the write-up

Does the listening actually help?

These charts come straight from one real test run (eval-full-20260527-083852) over every one of the 19benchmark songs. It’s a check on what the engine does, not a scoreboard. There’s no official “right answer” to grade against, so nothing here claims to beat anyone. It just shows the behavior.

19/19songs scored by sound, across 8 genres·typically found this share0.987

It works across every genre

a real test run, not a scoreboard

How close the top matches sound, broken out by genre. Jazz clusters tightest, electronic spreads widest, but every genre lands solidly in range. So it isn't only good at one kind of music.

Pop
0.8350.919
R&B
0.7560.870
Hip-hop
0.6850.930
Indie
0.7590.946
Electronic
0.4900.883
Jazz
0.9040.956
Pre-2000
0.6770.851
Non-English
0.7860.906

scale: 0.30 to 1.00, the range real music falls in

Sound and mood live on different scales

a real test run, not a scoreboard

Sound scores cluster high, mood scores cluster low, and they barely overlap. That's exactly why the two get put on the same scale before they're blended. You can't fairly add up numbers that mean different things.

How alike they sound
0.4900.956
Mood match
0.1500.372

Same 0.30 to 1.00 scale. The gap between the bars is the whole reason for putting them on one scale first.

Listening really changes the order

a real test run, not a scoreboard

Line up the crowd's order against the order after listening (top 10): they share only about 2 of the 10 (between 0 and 5), and the typical song moves about 3.4 places (up to 4.4). The listening is doing real work, not just rubber-stamping the crowd.

~2
of the top 10 stay, after listening
3.4
places the typical song moves
Take Five · The Dave Brubeck Quartetkept 4/10 · moved 4
  1. 1Alphanumeric by Lee Konitz
  2. 2Red Pepper Blues by Art Pepper
  3. 3Three to Get Ready by Dave Brubeck
HUMBLE. · Kendrick Lamarkept 3/10 · moved 2.6
  1. 1DNA. by Kendrick Lamar
  2. 2Magnolia by Playboi Carti
  3. 3Stir Fry by Migos
Strobe · deadmau5kept 3/10 · moved 3.6
  1. 1Opus by Eric Prydz
  2. 2Create by OVERWERK
  3. 3Virus (How About Now) by Martin Garrix