Your lossless library and your streaming apps, played untouched to your DAC.
A native Linux music player that is also a UPnP / OpenHome network receiver.
Features · Screenshots · Install · Stream from your phone · Bit-perfect · How it's built · FAQ · Roadmap
Most Linux players either sound right or look right. ricercar tries to do both:
- It never touches your samples. Every track goes to an exclusive
hw:ALSA device at its native rate and bit depth: no mixer, no resampling, no volume maths. A format the DAC can't take is refused, never quietly converted. - It shows the signal path instead of just claiming bit-perfect. The chain (source → processing → output format → DAC) sits under the seek bar at all times; one click opens every hop and flags anything that changes the samples.
- It is a real desktop app. Album grid, artist pages, synced lyrics, queue, playlists, radio and search, native and fast, with no webview and no Electron.
- It plays what your phone streams. Control points such as BubbleUPnP, Symfonium or Linn Kazoo can push your NAS, or a service they support, to ricercar the way they would to a hi-fi network streamer (protocol-tested; real-app reports welcome).
ricercar is inspired by QBZ but is a clean-room project with no QBZ code. The core contains no private or unofficial streaming-service API. Catalogues reach it through standard UPnP / OpenHome, with your own subscription in your own app, or through a source plugin you install yourself: a separate program the core only talks to through a documented protocol (docs/plugins.md). The core ships no service code, keys or plugins.
|
|
|
|
Screenshots use a synthetic demo library (generated tones and artwork).
They are rendered with RICERCAR_SNAPSHOT, see Development.
Every release ships
ready-made packages. The .deb, .rpm, .AppImage and tarball exist for
x86_64 and aarch64; the Arch package is x86_64 only (on aarch64
Arch, build it from source with dist/arch/PKGBUILD):
| Your system | Package | Install |
|---|---|---|
| Debian, Ubuntu, Mint, Pop!_OS… | .deb |
sudo apt install ./ricercar_*.deb |
| Fedora, openSUSE Tumbleweed / Leap 16, RHEL / Alma / Rocky 10+ | .rpm |
sudo dnf install ./ricercar-*.rpm (zypper install on openSUSE) |
| Arch, Manjaro, EndeavourOS, CachyOS, Omarchy | .pkg.tar.zst |
sudo pacman -U ricercar-*.pkg.tar.zst |
| Anything else | .AppImage |
chmod +x ricercar-*.AppImage && ./ricercar-*.AppImage |
Packages need glibc 2.35 or newer (Ubuntu 22.04, Debian 12, Fedora 36, RHEL 10 and later).
To check a download, verify the signed checksum list with
minisign and the key in
dist/minisign.pub, then the file itself:
minisign -Vm SHA256SUMS -P RWSLPLWZ/M4/9X1orGjyBkKYA7BmzgxxI8dveJ8YVcSQVrOpjinxS9fV
sha256sum --check --ignore-missing SHA256SUMSArch / Manjaro / Omarchy
sudo pacman -S --needed rust clang alsa-lib fontconfig libxkbcommon
git clone https://github.com/ricercar-player/ricercar && cd ricercar
cargo build --releaseOr build the package: cd dist/arch && makepkg -si.
Debian / Ubuntu
# the distribution's cargo is too old: install Rust 1.92+ with https://rustup.rs
sudo apt install libasound2-dev libfontconfig1-dev libxkbcommon-dev pkg-config clang libclang-dev
git clone https://github.com/ricercar-player/ricercar && cd ricercar
cargo build --releaseFedora
sudo dnf install cargo clang alsa-lib-devel fontconfig-devel libxkbcommon-devel
git clone https://github.com/ricercar-player/ricercar && cd ricercar
cargo build --releaseRust 1.92 or newer is required. The binaries end up in target/release/:
| binary | what it is |
|---|---|
ricercar |
the desktop app (--headless for no window) |
ricercar-daemon |
headless player + UPnP + MPRIS, for a dedicated box |
ricercar-cli |
remote control over MPRIS |
Desktop integration: copy dist/ricercar.desktop to
~/.local/share/applications/ and dist/ricercar.svg to
~/.local/share/icons/hicolor/scalable/apps/.
The systemd user unit (dist/ricercar.service, also in the release tarball
under lib/systemd/user/) starts /usr/bin/ricercar-daemon. If you run the
binaries from somewhere else, such as an unpacked tarball or ~/.local/bin,
fix ExecStart= before copying the unit to ~/.config/systemd/user/.
Packaging ricercar for a distribution
The official packages install an empty marker file,
/usr/share/ricercar/self-update, which lets About → Check for updates
replace the installed .deb / .rpm / pacman package in place. Distribution
packages should not ship that file: without it the app only tells users
that a new version exists and leaves upgrades to the package manager.
Setting RICERCAR_NO_SELF_UPDATE=1 in the environment disables in-place
updates as well.
Install dist/io.github.ricercar_player.ricercar.metainfo.xml into
/usr/share/metainfo/, and the third-party notices into
/usr/share/licenses/ricercar/: THIRD-PARTY-LICENSES (written to
target/ by dist/third-party-licenses.sh, which needs
cargo-about),
crates/ricercar-ui/assets/fonts/OFL.txt and
crates/ricercar-ui/assets/icons/LICENSE (as icons-LICENSE).
./target/release/ricercar. Your XDG music folder (usually~/Music) is indexed automatically; add others in Settings → Library.- Pick your DAC in Settings → Audio output.
hw:devices are marked BIT-PERFECT;default/pipewireare marked SHARED (they go through the system mixer). - Press play. The green dot on the chain line under the seek bar means bit-perfect.
./target/release/ricercar --print-devices # list outputsricercar shows up on your network as a renderer, just like a hardware streamer. Your phone app handles sign-in and browsing, and ricercar fetches the audio itself.
flowchart LR
phone["📱 Phone app<br/>BubbleUPnP · Symfonium · Kazoo"]
service[("Streaming service<br/>or NAS")]
ric["🖥️ ricercar<br/>decode · no resampling"]
dac["🔊 DAC<br/>hw: exclusive"]
phone -- "UPnP / OpenHome<br/>commands only" --> ric
phone -. "your subscription" .- service
service -- "FLAC over HTTP" --> ric
ric -- "bit-perfect PCM" --> dac
- Start ricercar on the PC wired to your DAC (desktop app or daemon).
- In your phone app, choose ricercar as the renderer. With OpenHome (BubbleUPnP, Kazoo…) the queue lives on the PC and your phone can sleep.
- Play anything the app can reach. ricercar's player bar, MPRIS and the signal-path view show exactly what reaches the DAC.
See docs/CONTROLS.md for the control-point compatibility matrix and what the protocol tests cover.
Phone app doesn't see ricercar, or sees it at a strange address? On machines
with a VPN, Docker or virtual machines, ricercar is announced on every
interface. Pick your home network under Settings → Network → Network
interface (or interface = "eth0" in [network], --interface eth0 on
the command line): ricercar then listens and announces there only. If that
interface goes away (cable unplugged, Wi-Fi down), sharing pauses and comes
back on its own when the interface has an address again.
For an always-on audio box:
systemctl --user enable --now ricercar # uses dist/ricercar.serviceWhen the output is a hw: device, the volume is at 100 %, ReplayGain is off
and nothing is muted, samples reach the kernel untouched:
- the device is opened at the track's native rate and channel count, and a mismatch is refused, not resampled;
- the container holds every bit (16-bit audio may travel zero-padded in S32 if that is all the DAC accepts, which is still bit-perfect);
- a rate change between tracks drains and reopens the device; within one rate, gapless is sample-exact.
The signal-path view marks each hop green (untouched) or amber (altered: software volume, ReplayGain, a shared device…). The pipeline tests compare decoded output byte for byte against ffmpeg references for every container.
| Keys | Action | Keys | Action | |
|---|---|---|---|---|
| Space | Play / pause | Ctrl F or Ctrl K | Search | |
| Ctrl → / ← | Next / previous | Ctrl L | Now playing & lyrics | |
| → / ← | Seek ± 10 s | Ctrl Q | Queue | |
| Ctrl ↑ / ↓ | Volume | Alt ← | Back | |
| Esc | Close menu / panel |
Tab moves between controls, Space or Enter activates, and the arrows adjust sliders and choices.
Everything is editable in Settings. It is stored in
~/.config/ricercar/config.toml, and command-line flags override it for
one run.
[audio]
device = "hw:1,0" # see --print-devices
replaygain = "off" # off | track | album | auto
preamp_db = 0.0
restore_session = true
continuous_playback = false # more tracks from a plugin radio when the queue ends
[library]
roots = ["/home/me/Music", "/mnt/nas/flac"]
watch = true
[network]
name = "Living room" # name shown in phone apps
renderer = true # UPnP AV + OpenHome renderer
media_server = true # share the library over UPnP
interface = "eth0" # serve on this interface only; omit for all
[ui]
theme = "dark" # dark | light
accent = "#d4a35a"
adaptive_colors = true # tint the UI from the album cover
notifications = true
tray = true
close_to_tray = false
language = "" # en, fr, de, es, it, ja; empty follows the system
[scrobble]
listenbrainz_token = ""
lastfm_api_key = "" # your own Last.fm API account…
lastfm_secret = "" # …and its secret (the sign-in fills the session)
[online]
lyrics = true # lrclib.net when no local lyrics exist
cover_art = true # MusicBrainz / Cover Art Archive for missing covers
radio = true # Radio Browser directory (Radio page)
plugin_catalog = true # community plugin catalogue (GitHub)
updates = true # new release and plugin updates, once a day
[[plugins]] # one table per plugin, see docs/plugins.md
id = "example"
command = "/usr/local/bin/example-plugin"
enabled = true
[plugins.settings] # values of the settings the plugin declaresCommand line
ricercar [FILE|URI]... [--headless] [--config FILE] [--device NAME] [--name NAME]
[--db PATH] [--library DIR]... [--interface IFACE] [--no-mpris] [--no-upnp]
[--no-session]
ricercar --print-devices
ricercar --help | --version # ricercar-daemon takes the same flags
ricercar-cli status | play | pause | toggle | stop | next | prev
ricercar-cli open FILE|URI seek ±SECONDS volume [0..1]
ricercar-cli shuffle [on|off] repeat [none|track|playlist] metadata
Only one instance owns the DAC: ricercar song.flac while ricercar is
running hands the file to the running instance.
Where things are stored
| path | content |
|---|---|
~/.config/ricercar/config.toml |
settings |
~/.local/share/ricercar/library.db |
library index, stats, playlists |
~/.local/share/ricercar/session.json |
queue & position |
~/.local/share/ricercar/radio.json |
saved radio stations |
~/.local/share/ricercar/ui-state.json |
window size, last page, sorts, DAC capabilities |
~/.local/state/ricercar/ricercar.log |
log (3 × 2 MB, rotated) |
~/.local/share/ricercar/plugins/<id>/ |
a plugin's own data (ricercar never reads it) |
~/.local/share/ricercar/plugin-bin/<id>/ |
plugins installed from the hub |
~/.cache/ricercar/ |
cover thumbnails, lyrics, stream spool, update check (update.json), plugin caches (plugins/<id>/) |
ricercar works fully offline. Its optional online features contact only:
| service | used for | toggle |
|---|---|---|
| lrclib.net | synced lyrics | Settings → Online extras |
| MusicBrainz / Cover Art Archive | missing album covers | Settings → Online extras |
| Radio Browser | the Radio page | opening the Radio page · radio = false in [online] |
| ListenBrainz / Last.fm | scrobbling | only with your own credentials |
| GitHub (raw.githubusercontent.com) | community plugin catalogue | opening the Plugins page · Settings → Online extras |
| a plugin author's download host | the plugin binary | only when you click Install or Update |
| GitHub (api.github.com, raw.githubusercontent.com) | new ricercar release, plugin updates (at most once a day at startup) | Settings → Online extras → Updates |
| GitHub (github.com release files) | the new ricercar release | only when you click Check for updates or Update now (Settings → About) |
No telemetry, no account, and never a streaming-service API in ricercar itself. Plugins you declare are separate programs: what they contact is up to them. ricercar tells them the interface language, so they can translate their pages, and, only for plugins that ask for it, what you play (see their settings to turn that off).
ricercar is written largely with AI coding assistants. You would guess it from a commit history that moves this fast, so it is better said here.
The assistants write most of the code. The maintainer sets the design, decides what goes in, tries it on real DACs and phone apps, and answers for every release. "It compiles" is never the bar: what protects you are checks that don't care who or what wrote the code.
- Bit-perfect is tested, not claimed. Golden tests capture exactly what would reach ALSA and compare it, byte for byte, with an independent ffmpeg decode, in every container (S16, S24_3LE, S24, S32).
- The network side is tested against the protocols. UPnP AV, OpenHome and MediaServer have their own integration tests (SSDP, SOAP, GENA events).
- Every push runs CI: formatting,
clippy -D warnings, the full test suite, a release build, and validation of the desktop entry and AppStream metadata. - Releases are built by CI, never on a personal machine, smoke-tested, and their checksums are signed with minisign.
- No hidden network traffic: Privacy lists every host ricercar can contact. There is no telemetry.
Found a bug? Please open an issue with the diagnostic report (Settings → About). It is the fastest way to get it fixed, whoever wrote the line.
flowchart TB
ui["ricercar-ui<br/><sub>Slint desktop app</sub>"]
daemon["ricercar-daemon<br/><sub>startup · scrobbler · plugin lyrics · headless</sub>"]
cli["ricercar-cli"]
core["ricercar-core<br/><sub>library · queue controller · covers · config · plugin host · updater</sub>"]
audio["ricercar-audio<br/><sub>symphonia decode · ALSA sink · engine</sub>"]
upnp["ricercar-upnp<br/><sub>SSDP · AVTransport · OpenHome · ContentDirectory</sub>"]
mpris["ricercar-mpris"]
online["ricercar-online<br/><sub>ListenBrainz · Last.fm · lrclib · radio · cover art</sub>"]
ui --> daemon
daemon --> core & upnp & mpris & online
upnp --> core
mpris --> core
core --> audio
cli -. D-Bus .-> mpris
| crate | role |
|---|---|
ricercar-audio |
decode + sink pipeline, engine thread, HTTP spooling with Range seeking |
ricercar-core |
SQLite/FTS5 library, tags, covers, queue controller, config, source-plugin host and hub catalogue, updater |
ricercar-upnp |
SSDP / HTTP / SOAP / GENA, AVTransport, OpenHome, MediaServer, interface selection |
ricercar-mpris |
org.mpris.MediaPlayer2 on the session bus |
ricercar-online |
scrobbling, lyrics, radio directory, cover art |
ricercar-daemon |
shared startup, scrobbler, plugin lyrics, diagnostic report, headless binary |
ricercar-ui |
Slint desktop app (ricercar binary) |
ricercar-cli |
MPRIS remote control |
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
dbus-run-session -- cargo test --workspace --locked # 320+ tests- Your speakers are safe: tests only use
nullandfile:sinks; no audio is sent to hardware duringcargo test. - Screenshots without a display:
RICERCAR_SNAPSHOT=out/ ricercar --device null --no-upnp --no-mpris --library <dir>renders the main views with Slint's software renderer and writes PNGs. - Translations: one table per language in
crates/ricercar-ui/tools/(fr,de,es,it,ja.json, keyed by the English text) serves both the Slint catalogues and the Rust strings; runpython3 crates/ricercar-ui/tools/gen_po.pyafter changing UI text. Tests check that every language has every string, and CI that the catalogues are up to date.
Is this a streaming-service client?
No. ricercar itself never talks to a streaming service's API. Your phone app, used with your own subscription, sends ricercar a plain stream URL over UPnP or OpenHome, the way it would to a network streamer.
ricercar can also run source plugins: separate programs, written by third parties and installed by you, that bring a catalogue and hand ricercar playable URLs (docs/plugins.md). The community hub lists them with links to their authors; it hosts no plugin code and reviews none. A plugin runs with your permissions: install only plugins you trust, and check that they respect the terms of the service they use.
Why is my track "altered" and not bit-perfect?
Open the signal-path view (click the chain line under the seek bar). Common
causes: volume below 100 %, ReplayGain enabled, mute, or a shared output
(default, pipewire, pulse) instead of a hw: device.
My DAC refuses a track.
With a hw: device, ricercar refuses a rate or bit depth that the DAC can't
play natively rather than resampling it. Pick the pipewire / default
output if you prefer conversion over refusal.
Does it work with PipeWire?
Yes. Selecting a hw: device takes the card exclusively while ricercar
plays and releases it on stop. Choose pipewire if you want to share the
card with other apps (not bit-perfect). Bluetooth headphones and other
outputs that only exist in PipeWire are listed by name, also shared.
My phone app doesn't see ricercar.
Check that the phone and the computer are on the same network, and that the renderer is on (Settings → Network). With a VPN, Docker or virtual machines, pick your home network under Settings → Network → Network interface so ricercar announces itself there.
Can I run it on a Raspberry Pi without a screen?
Yes. Use ricercar-daemon (or ricercar --headless) with the systemd user
unit in dist/, and control it from your phone over UPnP / OpenHome.
- Bit-perfect ALSA engine, gapless, native-rate switching
- UPnP AV + OpenHome renderer, UPnP MediaServer
- Desktop app: library, lyrics, queue, playlists, radio, six languages
- Scrobbling, MPRIS, tray, headless daemon
- Device capabilities panel (rates and formats your DAC accepts)
- Source plugins and community hub: settings, lyrics, navigation, actions, service playlists, details, radio
- Signed releases (minisign) and in-app updates
- Network interface choice, keyboard navigation, AppStream metadata
- Reports from real control points (help wanted)
- Optional parametric EQ / convolution (clearly marked non bit-perfect)
- DSD over PCM (DoP), CUE sheets
- Composer / work views for classical music
- AppImage
- Flatpak
Issues and pull requests are welcome. The most useful contribution right now is a compatibility report: your phone app, its version, your DAC, and what worked or broke (see docs/CONTROLS.md). Please follow CONTRIBUTING.md, and note that this repository does not host any code that bypasses a streaming service's official API.
Built on symphonia, Slint, lofty, rusqlite and zbus. Typeface Inter (SIL OFL), icons Lucide (ISC). Data from MusicBrainz, Cover Art Archive, LRCLIB and Radio Browser. Thanks to the QBZ project for showing what a Linux hi-fi player can be.
MIT © ricercar contributors. See AUTHORS.
ricercar is an independent open-source project. It is not affiliated with, endorsed by, or connected to the record label Ricercar (Outhere) or any streaming service. "Ricercar" is used in its old musical sense: a contrapuntal study, literally "to search".











