EKO
The native macOS player for your Navidrome, Subsonic and local library — a real Rust audio engine wrapped in a neumorphic interface, playing every track at its own sample rate, untouched. Bit-perfect, and it proves it.
What it does
- Native bit-perfect playback at the file's own sample rate (FLAC, ALAC, WAV, AIFF, MP3, AAC).
- Automatic device rate-switching — the OS output follows the music, no resampling.
- A live signal path with an honest bit-perfect seal.
- Real 10-band biquad EQ, software volume, a Rust FFT spectrum.
- Local files + Navidrome / Subsonic streaming through one engine.
- Output device picker, a mini player, light & dark themes.
Installation
Grab a release, or build from source (see Building).
# clone & install $ git clone https://github.com/reactivepixels/eko.git $ cd eko && npm install
First run
Launch EKO and choose a source from the top bar:
- Local — point EKO at a folder of music; it scans tags and builds a library.
- Server — connect to your Navidrome / Subsonic server with its URL and your credentials.
Pick an album, hit play, and open the deck to see the signal path and EQ.
Architecture
EKO is a Tauri 2 app: a Rust core for all audio, and a React + TypeScript frontend for the UI. Everything plays through one native engine — there is no Web Audio path.
// the audio pipeline
file / Navidrome stream
→ symphonia decode
→ resample only if needed · EQ (biquad) · volume
→ cpal output @ the file's sample rate
→ CoreAudio: device set to match → your DAC
- Engine (
src-tauri/src/engine.rs) — streaming decode into a growing buffer, a real-time cpal callback, and a Rust FFT spectrum. - CoreAudio (
src-tauri/src/coreaudio.rs) — sets the output device's hardware sample rate to the file's, and reads it back so the seal is honest. - Frontend — Zustand store mirrors engine state; the UI is all in
src/player/.
Bit-perfect
"Bit-perfect" means the samples in the file reach your DAC unchanged. Most players resample everything to one system rate first; EKO doesn't. It outputs the file's exact rate and switches the device to match — so nothing in macOS resamples behind your back.
The path stays bit-perfect when volume is at 100%, the EQ is flat or off, and the device supports the file's rate. Touch any of those and EKO tells you — it never claims bit-perfect when it isn't.
Verify it yourself
Open Audio MIDI Setup while playing different-rate tracks — you'll see the device's Format follow the music (44.1 → 48 → 96 kHz). That's EKO matching the rate.
Signal path
The deck shows a live chain from source to output, with a seal that lights only when the path is pristine:
When EQ or volume is engaged, the seal switches to a warning glyph and spells out what's altering the signal (EQ, VOLUME, RESAMPLED).
Output & DAC
Click the OUTPUT node in the signal path to choose a device. EKO sets that device's hardware sample rate to match each track and remembers your choice. While playing, EKO owns the device rate (like Roon / Audirvana).
Equalizer
A true 10-band biquad EQ (60 Hz – 16 kHz) with a preamp and presets. Drag a band or pick a preset. Flat = bypassed, so EQ never costs you bit-perfect when you're not using it.
Keyboard
| Space / K | Play / pause |
| ← → | Seek ∓5s (J/L = ∓10s) |
| N / B | Next / previous track |
| ↑ ↓ | Volume up / down |
| M | Mute |
Building
# run in development (hot reload) $ npm run tauri dev # produce a distributable .app $ npm run tauri build
Project layout
src-tauri/src/ engine.rs # native audio engine coreaudio.rs # macOS device rate-matching metadata.rs # tags + cover art src/ audio/ # engine bridge store/ # Zustand state player/ # UI + neu.css
Contributing
PRs welcome. The moat is fidelity and design — keep changes faithful to the neumorphic language, and never break the bit-perfect bypass. See CONTRIBUTING.md and docs/ in the repo for the full picture and what's next.
EKO · MIT licensed · The native Mac player for your self-hosted music.