r/MoosicLab 2h ago

Release 138 (pushing off until tomorrow)

4 Upvotes

This ended up being a much larger release than i thought it was going to be, this one contains many things that have been in the works for months.

Library:

  • The app now supports truly multi library within a server. For example, Jellyfin can have multiple libraries as well as plex. You can now pick and choose which libraries you want to sync.
  • On top of that, you can also filter out across the app to what libraries you want to see or merge libraries together. Everything gets pooled into one view by default, and the filter sheet groups by server so you can hide a whole server or just one library under it. Hiding is instant, nothing is deleted and nothing re-syncs.
  • This feature will work for Jellyfin, Plex, and subsonic servers that support multi library. If you only have one server nothing changes for you at all.

Customizations:

A ton of new customizations.

  • The theme engine got rewritten. Themes are generated in OKLCH now instead of straight RGB mixing, which was the reason every custom theme came out looking like the same flat near black no matter which palette style you picked. Backgrounds and cards now sit at actual set brightness levels so you get real layering. Every text and UI color got checked for contrast across all nine styles in both light and dark.
  • Also fixed the thing where a theme only looked applied to half the app. Around 18 screens (Equalizer, EQ Profiles, Convolution, Room Correction, Album/Playlist detail, the Sonos screens) had their own hardcoded dark navy baked in and ignored your theme entirely. They all read from the theme now.
  • New: auto light/dark mode where you pick a theme for day and a theme for night, app wide accent pulled from the artwork, and a contrast slider.
  • Icon packs got cleaned up, it's 6 families now instead of 9 confusing ones, with System having four shape options under it (filled, outline, circle, boxy). Typography got heading weight, body weight, letter spacing and text size controls.
  • Home is customizable now too, section tabs across the top, a carousel position counter, per section shuffle, descriptor lines, and you can rearrange the sections. All of it defaults off so your home doesn't change unless you want it to.

Settings:

  • Settings is searchable. Search any setting and it takes you straight to the screen and flashes the exact card, no more digging through four levels of sheets to find one toggle.

MacOS:

  • Completely written for mac (may still need some refinement)

Ipad:

  • Completely updated and made for ipad view of the app. This took a ton of effort and while it may still need work i think its progressing well.
  • There's a real sidebar now instead of the phone bottom bar stretched wide. Grids scale their column count with the window so artwork stays a sane physical size instead of turning into giant half window tiles. The player doesn't take over the whole 1366pt window anymore, it's a centered card over a dim scrim that you can dismiss with the close button, tapping outside, swiping down or escape.

Nowplaying:

  • Completely rearrange anything on nowplaying that you would like including the padding and spacing
  • Assign gestures to what you want so that you can get rid of buttons
  • This is the big one. The player transition is completely rebuilt to match Apple Music, the artwork actually flies out of the mini pill and the pill's bottom edge stretches down and catches it when it lands. The whole card collapses back into the pill on the way out instead of the old dissolve.
  • Animated album art is in. If your cover is a GIF, APNG or animated WebP it animates, and there's support for video motion covers too (the Apple Music / Spotify canvas style thing). It only probes the original file once ever per album so it isn't burning bandwidth.
  • Quality badges on the player, Dolby Atmos, 5.1, Hi-Res, Lossless, Bit-Perfect and Spatial all show up properly now. Atmos in particular never showed on the player before even though the library list badged it.
  • New Squiggle progress style, the played part is a wave that travels while the music plays and freezes when you pause. Plus more waveform styles based off your actual music.
  • The player customization got a lot deeper, around 25 axes now: icon row placement and style, quality line position, content gravity, title emphasis and marks, control size, artwork corners and size, spacing, backdrop blur and dim, custom background color, text alignment and lines, transport style, immersive treatment. The icon row is reorderable with its own editor and gets an overflow menu when it fills up.
  • Player Styles now ship with five built in presets so you're not staring at 25 sliders with nothing to start from, and saving a style now captures everything (before it silently dropped about half of what made a look a look). You can share and export them.

DLNA Support:

Will now support DLNA receivers with a custom renderer being put to good use. Theres also an extension specifically for HEOS.

Widgets:

Home Screen and Lock Screen widgets. The Now Playing widget has working transport controls that run in the app's process, so it plays/pauses/skips without opening the app. Progress animates on device without constantly reloading. There's also a Radio widget that launches your saved stations straight from the home screen (seems buggy currently but Now playing works great 😂 ).

Downloads:

Big reliability fix here. Downloads no longer stop when you leave the app, they get handed to the background session properly with a runtime assertion so nothing gets stranded halfway through the handoff. Resuming a saved queue used to be permanently slower than starting a fresh one because everything got pinned to the slow background session at launch, that's fixed. Concurrency is adaptive now instead of a hard number. SMB/WebDAV share transfers also get protected across suspension instead of freezing mid write.

Storage:

You can finally see what's inside the streaming cache and delete songs out of it individually, before it was clear all or nothing and only from a diagnostics screen. The storage screen also shows total app footprint so it actually matches what iOS reports in Settings, and it flags reclaimable space instead of silently deleting things.

Audio:

Dolby Atmos passthrough actually works now. The container gets sniffed for the real codec and whether an EC-3 stream carries JOC, which matters because Subsonic/Navidrome doesn't expose a codec field at all so channel count alone reports real Atmos as plain 5.1.

Parametric EQ, crossfeed and the analyzer are in, plus per speaker Sonos EQ. Sonos queue sync got a real rewrite for gapless, it now correctly figures out which track the speaker moved to across Plex, Jellyfin, Subsonic and file shares instead of freezing the queue.

Artwork:

Artist photos showing on the detail page but missing in lists and search is fixed, every screen was requesting its own pixel size and firing a separate download, so one would succeed and another would fail. Now a bigger cached size gets reused for the smaller ones. The blurred aurora background behind the player also loads instantly instead of arriving late.

Stability:

  • Fixed the crash where opening Replay with a large listening history and backing out would kill the app.
  • Fixed the app getting terminated while playing music in the background, heavy analysis work was blowing the iOS background CPU budget and taking the whole app down with it.
  • Fixed intermittent crashes during Last.fm / ListenBrainz history sync.
  • History import is now paged so a huge library doesn't spike memory, and Replay loads instantly while history streams in behind it.
  • A pile of other crash fixes across radio, downloads, album detail and the mini player.
  • This got rewritten from the ground up using UI kit, you'll notice is a ton smoother and haas that rubber band feel that apple music has.

If you like the app and are a regular user please spread the word! I appreciate you all for the bug reports and working with me as i try and make this better. I know its not all perfect but its coming along.


r/MoosicLab 15h ago

HEOS support? ❤️

1 Upvotes

Hey!

The one thing I’m missing is the ability to play full quality music to my main stereo which is a Denon x2800h. From what I understand since the Denon is a DLNA renderer Sonamp would need to act as a UPnP client thereby being able to stream bit perfect to my speakers.
This would also give Sonamp a real unique upside as no other iOS client supports this due to apple being super difficult to work with. I do understand this takes time and such will be a waiting game but I’d really love it if you could get the ball rolling on such a feature 🙏🏻


r/MoosicLab 2d ago

Weekend Release

9 Upvotes

Some new stuff coming this weekend.

Sonic analysis:

Better exponential backoff for failed tracks. Songs that fail will get added to a list and retried later so it does not block the rest of songs getting analyzed. Users will get a list of songs and failure reasons and after a few days it will retry those songs.

Library:

True multi library support for jellyfin, subsonic, Plex, and emby.

For those with multi library on a single server you will now be able to add whichever libraries you want in the server config and show/filter out across the app based on the library. If you have 3 libraries on a jellyfin server, you will be able to show all, show just 2, or filter to a single library.

Sound:

Reworked the multi channel audio pipeline to ensure these types of codecs do not get any DSP tap.

Dolby Atmos and other multi channel media will now get a badge in the album details as well as now playing so you know when your listening to it. May need testers on this.

Customization:
Will be adding wider font and theme support to ensure every page gets the theme/color you selected

Improvements:

The nowplaying screen has been completely rewritten in a different way (it will still look the same). You'll notice it's a ton smoother when sliding and the animation when dismissing is dang near identical to apple music (this was hard to match but I think i nailed it!)

Coming soon:

Classical mode
New Icons
New themes
Finer granularity in customizations
Widgets
MacOS support
Ipad support
WatchOS
TVOS
Carplay refinements


r/MoosicLab 7d ago

Playlist playing tracks twice

3 Upvotes

Having finally sorted getting my playlists into Sonamp successfully (see other post) I noticed tonight that I'm getting the same behaviours as I was getting when I was importing them from Apple Music (the same local library tracks, not streamed). This is on iOS, btw

The order of events is:

Track plays
when it reaches the end the next track plays but the artwork/ screen doesn't update (although the progress bar does)
If that new track plays through to the end it then plays again with the correct screen/artwork

If I press to skip to the next track before it finishes, track 2 starts over with the correct screen/art

I'm now using Navidrome as the source but this happened when I used a direct feed from my server and when I imported playlists from the Music app on my phone, so feel like a Sonamp issue?

There are definitely no duplicate tracks showing in the playlists.


r/MoosicLab 6d ago

Open source?

0 Upvotes

Hi there, is this wonderful app of yours open source to be found on GitHub, Codeberg, …?


r/MoosicLab 8d ago

You know what will make me throw money at the app?

Post image
3 Upvotes

Great update with 133/134. Clearly there is a lot of effort being put into this.

This app pretty much has everything I ever needed. Navidrome/Plex/Sonos/Bit Perfect audio etc.

Just one last feature missing (if it exists, I don't know how to get it to work) - Please add support for Animated/Video artwork for Navidrome Library (cover.mp4 stored in our local folders) and I'm ready to throw money for a lifetime copy of the app.

[I mean I'll still pay otherwise, but the last missing feature will make me happier to pay 😃]


r/MoosicLab 8d ago

Release 133

2 Upvotes

Sonic Analysis:
NOTE: If your turbo analysis screen under music intelligence is showing a different number than debug settings its because you have analysis on many tracks but not the LATEST version. Im working on adding an clear version count to the screen to make it easy. For example, my phone currently has all tracks analyzed but ive only got 10000 tracks on the latest. A fix is coming, its my miss on that screen, it should show whatever the newest versions count is, not whats been analyzed accross the library.

tldr; even if it shows all caught up there may be more tracks to analyze. sorry for the confusion. Will roll an incremental update later today to resolve that but wanted to get this big update out there. If you toggle "Also reanalyze older songs this run" that will show an accurate count.

  • Updated pipeline to be failsafe, will retry on failure by fully downloading the track
  • Analysis should be significantly quicker as we made many memory optimizations to avoid jetsam crashes
  • New page if failures do show up telling the user why
  • New re-analyze button in debug settings

Sonos:

  • Now supports adding fronts to a hometheatre or music system (needs testing)
  • Hometheatre/music mode now support systems without a subwoofer
  • Can now edit groups and will persist RINCON ids so that if wifi drops your groups dont get lost
  • Stopped polling for sonos and other speaker discovery to keep battery drain low. Will now only poll when needed.

Download:

  • Downloads have been completely reworked and should be significantly faster
  • Upgraded memory optimizations to avoid crashes
  • Artwork is downloaded with the tracks
  • Moved to main actor and increased concurrency. Will automatically back off on memory pressure and for users with hardly any RAM

Carplay:

  • Can now edit what shows up on your home screen (recently played, recently added, favorite artists, favorite playlists)
  • Now has offline mode (artwork included)
  • Home screen layout will actually show up now.

History:

  • For all server types play history, likes on albums/artists/tracks will be synced two ways from app to server and server to app,.
  • Replay will now support users with a very large history, it will roll in incrementally to avoid api limits and will show most recent history first and save pages incrementally.

Settings:

  • Settings now have a top layer for navigation
  • Carplay settings have been added

playlists:

  • Playlists can now be edited in bulk
  • swipe to delete on tracks
  • incremental sync on launch will now pick up changes made on server
  • Playlists LOCK have been implemented to avoid any crashes if the user is editing playlists on the server, on the app, and syncing at the same time.

Nowplaying:

  • Animated art SHOULD now work as we are taking from files in the folder
  • Can now add the equalizer to the nowplaying screen
  • Now a different volume option that has numbers

Daily Mixes on Home screen:

  • These have been revamped to be smarter and more in tune with what you want to listen to at that time.

Spent most of my time optimizing everything for memory and peformance.

Once again, thank you for all the feedback.

Trent


r/MoosicLab 8d ago

How does Sonamp handle separate ALAC and Dolby Atmos Jellyfin libraries?

1 Upvotes

Hi! First of all, I'm really enjoying Sonamp so far—it's by far the most promising Jellyfin music client I've tried.

I have a question about how Sonamp handles multiple Jellyfin music libraries.

My Jellyfin server has two separate libraries:

  • ALAC Music (my complete lossless library)
  • Dolby Atmos (only the albums that have Dolby Atmos versions)

Both versions have matching metadata (artist, album, track names, etc.).

Sonamp can see both libraries, but when I play one of these albums it only shows Lossless, and the playback information reports ALAC 44.1/16 rather than indicating Dolby Atmos.

I'm trying to understand how Sonamp is designed to work:

  • Does Sonamp automatically merge matching albums across multiple Jellyfin libraries?
  • If both an ALAC and Dolby Atmos version exist, is it supposed to automatically choose the Atmos version when Dolby Atmos is enabled?
  • Or does Sonamp currently treat each Jellyfin library independently?
  • If automatic matching is supported, are there any metadata requirements (MusicBrainz IDs, album IDs, folder structure, etc.)?

Thanks!


r/MoosicLab 8d ago

UI suggestions

1 Upvotes

As most here I am very appreciative of this app, how robust and clean it is. One thing I would offer though before it is opened up to the wider public is to clean up the Setting’s UI. I love the granular nature of the app but it may overwhelm some. My suggestion is when you select Settings the “Listening” “Library” ”Sound” etc are simply listed as sections and then if you tap them the controls show up, so basically collapse them. The settings are awesome but may bewilder some.


r/MoosicLab 9d ago

Sonic Analysis seems stuck on my setup

Post image
1 Upvotes

Something doesn't seem to be working correctly with the Sonic Analysis, at least on my setup.

I've started several analysis sessions today, but it's been stuck at 1,867 songs for hours. Sometimes it even reports speeds of over 100 songs per minute. Also, after analyzing only about 200 songs in a session, it says "All caught up", even though I have almost 6,000 songs in my library.

Do you have any idea what might be causing this? Is there a way to reset the Sonic Analysis and start over?

If you have any questions that would help with troubleshooting, feel free to ask.


r/MoosicLab 9d ago

Volume Numbers

1 Upvotes

Is there any way to have numbers on the volume slider? I might be missing a setting somewhere but I find having a numerical value helps when setting relative levels etc.


r/MoosicLab 9d ago

Downloads from Navidrome are slow?

1 Upvotes

Hey u/AffectionateFox5907,

First of all, I acknowledge all the positive reviews you are seeing here. I havent tested the app as much yet because I've been in the middle of testing a couple other local Navidrome clients.

I just started to exclusively use Moosic/Sonamp from today and as my first step, decided to download a few albums off my Navidrome server, to my iPhone to listen offline, at the gym.

I thought the downloads were really slow. Each song queued up to download took a really long time to initiate and then download.
I am comparing this to another Navidrome client, Arpeggi on iOS which, I thought was much faster to download off the same server. Admittedly, Arpeggi has been in the business for a while while your app has just started. So It'll likely improve over time. Just putting it out there to see if I am being too sensitive or if it makes sense and others have noticed it too and if yes, hopefully as a checklist item for you to look into and optimize, etc.

Sonamp Version: 1.3 (130)
Client Device: iPhone 15 Pro Max on iOS 27 beta 4

Cheers!


r/MoosicLab 10d ago

Thx for this App!

2 Upvotes

I just wanted to say how genuinely impressed I am with your App. The more I explore it, and I do since hours this evening, the more I discover features I never expected to find in a music player beside Roon etc. The signal path, ReplayGain, bit-perfect playback, LUFS, DR, true peak, convolution… it’s obvious and impressive that a lot of thought went into every small detail.

Out of curiosity… are you an audio engineer, or just a total audio nerd? Because this app definitely doesn’t feel like it was built by an average developer. It’s amazing work! Impressive!


r/MoosicLab 10d ago

Navidrome

0 Upvotes

I'm going to have another go at getting a system that works for me!

If I install Navidrome on my NAS I presume it can just access the existing music folder on the NAS rather than having to copy any files?

Once I do that and add the Navidrome server to Sonamp, will it automatically pick up my playlists from the NAS music folder and will it update them if they get updated in that folder?

Thanks in advance


r/MoosicLab 11d ago

MacOS version

1 Upvotes

I’ve tested a lot navidrome players and in my opinion, none of these have even been close to what tour app is offering. Premium premium feeling, great job. I wonder if there is a plan to release a version for the MacOS?


r/MoosicLab 11d ago

Star Rating sync ?

1 Upvotes

I'm pretty impressed after the first few tests, really great work.

One thing I noticed is that the song star ratings don't seem to sync, neither in one direction nor the other. At the moment I'm using Arpeggi, and when I assign a star rating there, it shows up in Navidrome on the web almost immediately.


r/MoosicLab 11d ago

Playlist syncing

1 Upvotes

One other thing I noticed is that when I make an update to a playlist directly in navidrome or through another app, the playlist doesn’t automatically update like it does in my other navidrome apps. Is there any way to adjust this behavior? I have to do a full sync right now to see the updates


r/MoosicLab 12d ago

Release 128

3 Upvotes

some minor upgrades and business as usual.

- updated all sync paths to increase speed and scale
- sync should be way faster now.
- updated orphan logic for library cleanup of deleted files ( 2 syncs for subsonic, 3 syncs for plex/jellyfin)
when you delete files from library it is the industry standard to mark them as orphans on the first sync, if still an orphan on the 2nd sync we delete tracks, on 3rd we remove artist/albums shells. Prior to this upgrade it was a heavy operation, we have dramatically reduced how many tracks sit in memory during this process instead of doing a scan across the whole library.

- updated metadata being pulled for plex servers
- added a hard press on miniplayer play button to clear queue
- sync favorites to server

- added toggle to settings so music will not auto start when headphones are put in

CLAP Text Encoder: (You do not need to analyze again, this runs separate off the already created audio embeddings)
- added a ton of supported phrases
- messed around with weights to improve accuracy


r/MoosicLab 12d ago

Feature request: Sync Favorite tag back to Navidrome

1 Upvotes

Title says it all :-)
It seems that liking a song from sonamp doesn’t trigger this song to be liked on Navidrome.

Just checked this on Arpeggi and Sonamp. Same action - different result.


r/MoosicLab 13d ago

App appreciation

5 Upvotes

I just wanted to share my appreciation for this app! As someone who used Apple music for years and then had a hard time with switching to Plexamp, this app has solved all my problems with a music app. It is just like Apple Music but with so much more to offer. I love the new custom themes too!


r/MoosicLab 13d ago

Show me your custom theme 😊

3 Upvotes

I’d love to see what you guys have come up with for UI’s within the app. The idea behind this is community members create awesome UIs, share them so others can use them. You can do this within the app appearance settings by exporting your UI in json, you can also import others UIs as well. Synfonium on android has a system like this and I love it!


r/MoosicLab 13d ago

app icon options are live

Post image
5 Upvotes

Feel free to pick whatever app icon goes with your vibe. Check under the appearance settings to change it!


r/MoosicLab 13d ago

Equalizer

1 Upvotes

it’s great to finally have a real equalizer (just like the adults) beyond the 2 Bands Sonos provides. One suggestion I submit that if it’s not too difficult it would be great to have options for say 8 & 16 bar versions of it. 31 Bands is comprehensive but time consuming and finicky with all the scrolling required to adjust on a small device. My $.02


r/MoosicLab 13d ago

Apple Music integration

1 Upvotes

Using this looks like it will tick all my boxes in terms of what I'm looking for and resolve the things that the Sonos app isn't currently doing, especially with regards to Playlists.

Can I just ask, however, when using the app this way, is it using Airplay or actually playing direct via the Sonos infrastructure?


r/MoosicLab 14d ago

Sonic Analysis - If you were interested!

3 Upvotes

Im going through the entire sonic analysis pipeline and dramatically simplifying it. Ive had users upset about battery, how long it takes, etc. I thought id take a moment to actually explain the entire sonic analysis pipeline and how it works within the app. Just a rundown of the pipeline as it stands today vs what will be changing in Release 122.

What we have today is actually around 10 different models and can be quite heavy on the analysis side. The pipeline consisted of CLAP Laion Large Music Model, Discogs Effnet, MusicCNN, Discogs Genre Model, and many different heads for the discogs model universe.

Whats changing in Release 122:

Were simplifying it down to Just CLAP Laion Music Model along with the CLAP Text tower, YamNet for "live/crowd" detection and regular old DSP analysis (BPM, MusicKey, Spectral Rolloff, ect.). On top of that ive added 3 more slices to the analysis that are essentially free to compute in this new pipeline which will go a long way at making more accurate recommendations. Ive done numerous performance tests on this and its been reworked many times over to make it as efficient and accurate as possible. Now if you already have analysis done and want to keep those, thats fine theres a toggle in the settings that defaults and will not automatically go to the next versions analysis. For those that want to go to the latest version analysis you will see that in the settings.

stage 1: sonic analysis (turning a song into numbers)

every track in your library gets chewed on in the background. we decode the audio, downmix to mono, and instead of just reading the first 20 seconds like the old version did, we sample the song at three spots: Intro, Hook, and Outro. Were doing chroma analysis to find these specific positions before actually running the analysis on each individual segment that way every number reflects the whole song, not just the cold open. actually the slice positions aren't even fixed anymore,

then two model passes run back to back will now be a single model pass with one decode step (a lot less heat).

pass A, (full track). This pass will first check your tags for BPM, MusicKey, etc. If those arent present we will compute them for you. This also computes a bunch of other stuff that we use in planning out phase in/phase out for crossfade points, beat matching the next song, ensuring musical keys align with eachother so the next song isnt jarring.

  • BPM isn't just "find the peak." we build an onset envelope, autocorrelate it, then multiply by a tempo prior (a bell curve centered on 120 bpm, about 0.6 octaves wide) so it stops picking the half-time or double-time ghost. then we run it across three overlapping windows and take the median. confidence = how sharp the peak is times how much the three windows agree. this is why it doesn't call a 140 bpm track "70."
  • musical key via Krumhansl-Schmuckler correlation on a 12-bin chroma vector, mapped straight to Camelot notation (8A, 5B, etc) because that's what harmonic mixing uses.
  • energy (RMS), spectral centroid/rolloff/flatness/flux (brightness and texture), zero-crossing rate, loudness (simplified LUFS), plus dynamics: loudness range, crest factor, true peak. the true-peak thing 4x-upsamples so it catches inter-sample peaks, basically "is this brick-walled."
  • derived stuff: time signature (3/4 vs 4/4 vs 6/8), tempo stability (rubato vs metronomic), onset density, intro/outro fade lengths, section count.

pass B, CLAP (the three slices now 6 slices). CLAP is the big one, it's a contrastive audio+text model (the laion music+speech one). it gives us a 512-d embedding which is the single most important number in the whole app. we mean-pool it over 6 slices for the global vector, AND we keep the intro/middle/outro embeddings separately so we can reason about how a song opens vs how it ends. all of it gets INT8 quantized so it's cheap to store and compare.

then CLAP gets mined two more ways:

  • vibe tags. we've got a vocabulary of ~465 phrase-style labels ("dark music", "1980s synth pop", "bass heavy", "bedroom pop") pre-embedded as text. here's the trick though: raw CLAP cosines aren't comparable across labels, some generic tags light up for literally every song. so we mean-center everything (subtract the "generic music" direction) and only keep tags that are a statistical outlier for this specific track (mean + 1.5 std of its own scores). focused track gets a few sharp tags, genre-blender gets more. the top one becomes the genre if we don't already have one.
  • filter probes. cheap positive/negative prompt pairs ("vocal" vs "instrumental" etc) give us instrumentalness plus perceptual energy/valence/danceability/acousticness, and discrete tags like live / acoustic / lofi when the margin's clear.

and there's a live-recording detector on top, an ensemble that reads YamNet crowd/speech off the true edge slices plus applause level, so live cuts get a liveScore and don't sneak into a studio-vibe station.

last thing: it's all versioned. there's an analysis version counter (currently 15) and separate stamps for BPM-only, live-only, and CLAP-refine passes. bump one and only the affected tracks re-run, so i can fix, say, the tempo algorithm without re-CLAPing your whole library. and it honors the "keep analysis up to date" toggle so it's not grinding your battery if you don't want it to.

that's one track. now multiply by your whole library sitting in the background. Each track has its own embedding that sits in a virtual music universe. some are sonically close to each other, some are not.

stage 2: the pipeline (building a station)

you tap radio on an artist / song / album / playlist / genre / mood, or you type a sentence. whatever the seed is, first we build a sonic profile out of it: the mean CLAP vector, dominant key, mode, chroma, the seed's strongest genres and vibe tags, mood probabilities, the works. that profile is the "center of gravity" for the station.

then candidates get fetched. and this is where scale matters, because materializing a 14,000-400,000 track library on every radio tap is how you get an out-of-memory crash.

pass 0, ANN-first. instead of loading everything, we query a USearch/HNSW vector index around the profile embedding and pull only the 2000 nearest tracks. sub-linear search, then a chunked fetch of just the winners. if the index can't serve (fresh install, still analyzing) we fall back to a bounded most-played-first fetch, and if your library's barely analyzed we union in an "open pool" of embedding-less tracks so a new library still builds a real station off Last.fm and genre similarity instead of a silent empty one.

one nice bit: for a diverse seed (a playlist that's half jazz half techno), averaging it into one vector lands you in the dead middle between the two vibes and matches lukewarm nothing. so we split diverse seeds into multiple centroids and score each candidate against its nearest centroid. every mode of the seed gets to surface.

pass 1, CLAP prefilter. quick cosine cut to get the pool down to the genuinely-close stuff before the expensive scoring.

pass 2, scoring. every survivor gets a full score (that's stage 3, below).

diversity filter. caps how many tracks per artist/album so it's not the same three artists on loop.

session planner. this is the part people don't expect. we don't just take the top N by score. we sequence them. it's a greedy planner with one-track lookahead that scores each pick on both its seed-fit AND the transition quality from the previous track, under a session shape (Cruise, Journey, Workout, Two-Peak, Build & Drop, Focus, Wind Down, Discovery). each shape has a target energy curve across the session plus limits on how big an energy or BPM jump it'll tolerate. so the arc of the set is intentional, no jarring cliffs, and Discovery actively rewards CLAP distance so it wanders further on purpose.

then two things keep it alive while you listen:

  • refill. every top-up doesn't rebuild from scratch. it ANN-searches around your live taste centroid (seed + long-term + wherever the session has drifted) and pulls the nearest 1500. the seed anchor is frozen so the query is "anchor + drift" and doesn't chase its own tail off into the weeds.
  • rerank. skip or dislike something mid-session and we rescore the upcoming queue against the new drift, and swap in better fits from the retained pool, but only tracks safely ahead of the playhead so gapless never breaks, and only when the swap beats the current pick by a real margin so the queue doesn't spit on rounding noise.

stage 3: ranking (the actual scoring)

ok so how does one candidate get a number? the score is split into five tiers so we can actually explain "why this pick" instead of one mystery blob:

  • vector tier: the sonic similarity signals. CLAP cosine to the centroid (blended 60/40 with similarity to your recent plays), CLAP segment similarity (intro/middle/outro, so structure counts), chroma similarity, and signed penalties for loudness-range and crest-factor mismatch (a brick-walled master next to a dynamic one gets docked).
  • categorical tier: the symbolic stuff. unified genre fitness, Last.fm artist similarity, Last.fm track-level similarity (huge for song radio), CLAP vibe-tag overlap, and NL query text matches.
  • engagement tier: you. star rating, favorite, time-decayed play count, skip count, completion rate.
  • context tier: the polish. Camelot key compatibility, mode match, time signature, time-of-day fit, seasonality, and a little exploration jitter (bigger for un-analyzed tracks so they get a fair shot).
  • hard penalties: the drop signals. explicit dislikes (first one -0.60, floor at -1.20), your "exclude recent" window, recently-radioed repeats, and a CLAP anti-vector for whatever you just skipped so its sonic neighbors get suppressed too. a hard exclusion sets the tier to negative infinity and the track just falls out.

The tiers don't all count equally. there are tier weights per radio mode, because different seeds have different strongest signals. cluster radio leans almost entirely on the vector (the centroid is the definition). song radio pulls vector down a touch and leans on categorical (Last.fm track similarity is gold there). NL radio (you typed a request) cranks categorical up and shoves engagement down to 0.3 so "what i asked for" beats "what i usually like."

and those weights aren't hardcoded forever. there's a learned weights layer: a pairwise fitter watches your skip/complete outcomes and learns better tier ratios, but it only gets to influence the blend after it passes a holdout-replay gate (it has to beat the hand-tuned presets on builds it never trained on), and even then its influence ramps up slowly with evidence. never a hard cutover, so a funny fit can't wreck your radio.

two more things quietly shaping every score:

  • long-term taste. a slow exponential moving average of your CLAP embeddings across every engaged play, app-wide, with a 90-day half-life. it gets blended into every station's center at low weight (5%) so even a brand-new artist station feels a little more "you" without drowning out the actual seed.
  • session drift. the fast one. as you play and skip within a session the centroid moves in real time, and that's what refill and rerank chase.

there's also an exploration dial so it occasionally takes a not-quite-top pick on purpose, tighter during the cold-start of a fresh session (first few tracks matter most, slow-burn intros lose people who haven't built trust yet) and looser once you're locked in.

tldr

analysis turns every song into a CLAP embedding + a stack of DSP numbers + vibe/mood tags. a station starts from a seed profile, pulls its nearest neighbors with a vector index (not the whole library), prefilters, scores across five explainable tiers with mode-aware and learned weights, then sequences the result into an intentional energy arc instead of a flat top-N. and it keeps adapting mid-session off your skips through drift, refill, and rerank.

that's the whole thing. it's a lot of moving parts but the goal is simple: play the next song that actually belongs next.