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.
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.
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.
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.
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.
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.
Last.fm’s and ListenBrainz’s scores aren’t on the same scale, so it combines them by rank position instead of raw numbers.
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.
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.
It checks both IDs, because the same recording once showed up twice under one Deezer id with two different MusicBrainz ids.
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.
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.
- Ask the crowdpull each song’s “similar tracks” from Last.fm and ListenBrainz (200 to 300)
- Merge the listsdedupe, then blend them with
- Look up the top 75resolve each against MusicBrainz, then verify a preview on Deezer (~1 a second)
- Listen to the new onesthe model turns each preview into an , saved so it never re-listens
- Score and blendcompare each embedding by ; fold in your mood at 30% if you added one
- Pick the top 10rank by the blended score; crowd picks fill any gap
- Write the whyone batched call writes a note per pick. It never ranks.
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.
It works across every genre
a real test run, not a scoreboardHow 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.
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 scoreboardSound 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.
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 scoreboardLine 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.
- 1Alphanumeric by Lee Konitz
- 2Red Pepper Blues by Art Pepper
- 3Three to Get Ready by Dave Brubeck
- 1DNA. by Kendrick Lamar
- 2Magnolia by Playboi Carti
- 3Stir Fry by Migos
- 1Opus by Eric Prydz
- 2Create by OVERWERK
- 3Virus (How About Now) by Martin Garrix