PsyMP3 is a music player written in C++ for Linux, the BSDs, macOS and Windows that shows a live spectrum analyzer of whatever it is playing. It plays MP3, AAC, FLAC, Vorbis, Opus, ALAC, AC-3, Dolby TrueHD and more. Files can be standalone or inside Ogg, Matroska, MP4 or AVI containers, and most decoders are built in, so it needs few outside libraries. Around the visualizer is a software-drawn interface in the style of Windows 3.1, with a menu bar and movable windows for the playlist, equalizer and track information. It also shows synced lyrics, scrobbles to Last.fm, and shows what's playing in Discord. On Linux and the BSDs, builds with D-Bus support can also be controlled from the desktop's media keys and now-playing widgets through MPRIS; on macOS, PsyMP3 does the same through Now Playing.
- Real-time FFT spectrum visualizer with adjustable intensity, decay, and draw modes
- A faithful Windows 3.1-style in-app UI: menu bar, movable windows (Playlist Manager, Equalizer, Media Information, About), buttons, checkboxes, radio buttons, drop-down lists, text fields, scrollbars, and dialogs — all software-rendered, and usable from the keyboard
- Wide format support through a modular demuxer/codec architecture, with most codecs built in so they work with no external libraries
- Plays local files, or an
http:///https://address (File → Open URL...); files can also be dragged onto the window - Internet radio: Icecast and SHOUTcast stations, HLS stations, and the
.pls/.m3u/.xspf/.asx"listen" links stations hand out, with song titles, reconnection after a drop, and per-song scrobbling - Synced lyrics display (
.lrcfiles) - Album art from the file's tags, shown in place of the spectrum
- Last.fm scrobbling (Web Services API 2.0), MPRIS desktop control, and Discord Rich Presence
- Session persistence: with Persist Playlist enabled, PsyMP3 reopens your playlist at the track you were playing
Contact: segin2005@gmail.com
- Windows 10 or later
- Official builds are cross-compiled with llvm-mingw (x86_64, i686, and ARM64), statically linked against SDL3; building under MSYS2 is also possible
- Releases also carry separate builds for Windows XP:
winxp(32-bit, needs a CPU with SSE2) andwinxp64(XP x64 and Server 2003 x64)
- macOS 14 (Sonoma) or later on Apple Silicon, macOS 15 (Sequoia) or later on Intel. These are the oldest versions the Homebrew libraries bundled into the app support.
- Official builds are a universal
PsyMP3.appin a.dmg, built by the macOS app workflow. The app is not signed with a Developer ID or notarized, so the first time you open it, macOS refuses; allow it under System Settings → Privacy & Security → Open Anyway.
Core dependencies (always required):
- SDL3 3.0 or later (
sdl3) - FreeType2 (
freetype2) - HarfBuzz (
harfbuzz) — shapes Arabic and the Indic scripts - taglib 1.6 or later (
taglib; taglib 2.x works too) - OpenSSL 1.0 or later (
openssl) - libcurl 7.20.0 or later (
libcurl)
Optional codec dependencies (auto-detected; each can be disabled at build time):
- libogg (
ogg) — required for Vorbis, Opus, Speex and Ogg FLAC (container parsing) - libopus (
opus) — Opus - FDK-AAC (
fdk-aac) — the whole AAC family: AAC-LC, HE-AACv1, HE-AACv2 and xHE-AAC / MPEG-D USAC. Note that it is not packaged everywhere: Debian keeps it innon-free, openSUSE in Packman, and Ubuntu inuniverse. Fedora ships only the strippedfdk-aac-free, against which PsyMP3 builds without AAC rather than decoding HE-AAC at half its bandwidth. - speex 1.2 or later (
speex) — Speex
Bundled codecs (vendored, no external dependency):
- FLAC — native decoder (no libFLAC needed)
- Vorbis — stb_vorbis (
third_party/stb; needs only libogg for the container) - MP3 — minimp3 (
third_party/minimp3) - MP2 — kjmp2 (
third_party/kjmp2) - ALAC — Apple's reference decoder (
third_party/alac) - MLP / Dolby TrueHD — bundled decoder (
third_party/mlp), derived from truehdd © 2025 Rainbaby (Apache-2.0) - AC-3 and E-AC-3 (Dolby Digital and Dolby Digital Plus) — written in tree from ATSC A/52
- G.722 — written in tree from the ITU-T Recommendation
- G.711 µ-law/A-law, and raw PCM formats
Optional integration dependencies:
- D-Bus 1.0 or later (
dbus-1) — MPRIS desktop media control - A GUI toolkit for the native file-open/save dialog. Configure probes, in
order, and uses the first one found:
Qt 6 (
Qt6Widgets) → Qt 5 (Qt5Widgets) → Qt 4 (QtGui) → Qt 3 (no pkg-config; opt in with--with-qt3-dir=PREFIX) → GTK 4 (gtk4) → GTK+ 3 (gtk+-3.0) → GTK+ 2 (gtk+-2.0). Without any of these (or with--disable-filedialog), the file dialogs are unavailable but PsyMP3 still builds, and plays files given on the command line, dragged onto it, or opened by URL. Windows builds use the system's own file dialog and need no toolkit, and so do macOS builds, through SDL3.
- A C++17 compiler: GCC (10 is the oldest checked) or Clang. The build is autotools only; there is no MSVC project.
pkg-config(or pkgconf)- Optional, for
make check: RapidCheck (property-based tests, enabled with--enable-rapidcheck)
Building from git needs these as well, to generate configure:
autoconf2.69 or later, which providesautoconfandautoheaderautomake1.10 or later, which providesautomakeandaclocalautoconf-archive, forAX_CXX_COMPILE_STDCXX_17. Nothing reports it missing:autoreconfsucceeds and leaves the macro inconfigureas a bare word, soconfigurenever turns on C++17 and the build fails later with C++17 errors.pkg-configagain, this time for thepkg.m4macros (PKG_CHECK_MODULES) it installs into aclocal's directory
libtool is not needed.
From git, or from GitHub's "Source code" downloads, which are snapshots of
the repository and do not include configure:
./generate-configure.sh
./configure
make -j$(nproc)Use generate-configure.sh to generate configure rather than running
autoreconf yourself. Besides running autoreconf -fiv, it:
- installs the repository's git hooks (
core.hooksPath=.githooks). The pre-commit hook advances the build number inres/psymp3.rc, which has to go up with every commit. - deletes what an earlier run generated (
configure,aclocal.m4, everyMakefile.in,autom4te.cache) first, so nothing stale is left behind - stops early if
aclocal,automake,autoconforautoheaderis missing, and checks afterwards that./configure --helpruns
autogen.sh is a symbolic link to it, for tools that expect that name.
From a make dist tarball, configure is already there:
./configure
make -j$(nproc)Install the Xcode Command Line Tools (xcode-select --install) for the
compiler, and Homebrew for the libraries. Then:
brew install autoconf automake autoconf-archive pkgconf \
sdl3 taglib freetype harfbuzz openssl@3 curl libogg opus fdk-aac speex
# OpenSSL and curl are keg-only: Homebrew keeps them off pkg-config's path.
export PKG_CONFIG_PATH="$(brew --prefix openssl@3)/lib/pkgconfig:$(brew --prefix curl)/lib/pkgconfig"
./generate-configure.sh
./configure
make -j$(sysctl -n hw.ncpu)
./src/psymp3Run it from the top of the source tree, where it finds its font and other
data in res/. The program built this way loads its libraries from Homebrew,
so it runs only on a Mac that has them. To build a self-contained
PsyMP3.app and .dmg instead, see Distribution packages.
On macOS, configure always uses SDL3's file dialog, which is the system's own Open and Save panels, and builds PsyMP3's Now Playing and menu bar support (Objective-C++ against AppKit and MediaPlayer). D-Bus and MPRIS are not used.
Build Options:
--enable-flac/--enable-vorbis/--enable-opus/--enable-aac/--enable-speex/--enable-g722/--enable-g711— per-codec toggles (default: yes).--enable-alawand--enable-mulawswitch the two G.711 codecs separately.--enable-mp2/--enable-ac3/--enable-truehd— the codecs that need nothing external: MPEG Layer II through the bundled kjmp2, AC-3 and E-AC-3 written in tree from ATSC A/52, and MLP/Dolby TrueHD through the vendored decoder (default: yes). Disabling one leaves its files unplayable: nothing registers the codec, and nothing claims the format.--enable-matroska— the Matroska and WebM container, parsers and all (default: yes). Disabling it leaves.mka,.mkvand.webmunreadable.--enable-mpris— MPRIS desktop integration over D-Bus (default: auto)--disable-filedialog— build without the native file dialog, even if a toolkit is installed--with-qt3-dir=PREFIX— use Qt 3 for the file dialog (see above)--enable-final— unity build: all sources in one translation unit (much faster full rebuilds; used for release builds)--enable-release— a release build, which leaves out the development-only test window (theHkey). The default follows the version: yes for a release, beta or RC, no for a-CURRENTdevelopment snapshot.--enable-optimize— optimize aggressively (-O3,NDEBUG) and strip debug symbols (default: no). Independent of--enable-release, so a release can still be built with its symbols.--enable-static-binary— fully static, self-contained executable (used for the Windows release builds)--enable-test-harness— build the test harness (default: yes on Unix; no on Windows and in--enable-finalbuilds)--enable-rapidcheck— build the property-based tests, which need RapidCheck--enable-asan/--enable-ubsan/--enable-tsan— sanitizer builds
package/ holds native packaging. The .deb and .rpm packages, the
AppImage and the Flatpak are built for every push by the
Linux packages workflow, and the macOS app by
the macOS app workflow; the Arch package is
built by hand with makepkg:
| Format | Targets |
|---|---|
.deb |
Debian 13 (trixie), Ubuntu 26.04 LTS |
.rpm |
Fedora, openSUSE Tumbleweed |
.pkg.tar.zst |
Arch Linux (package/arch/PKGBUILD) |
.AppImage |
any x86_64 distribution with glibc 2.35 or later (Ubuntu 22.04, Linux Mint 21, and newer) |
.dmg |
macOS: a PsyMP3.app for Apple Silicon (macOS 14+) and Intel (macOS 15+) |
./package/dpkg/build-deb.sh # -> package/dpkg/out/*.deb
./package/rpm/build-rpm.sh # -> package/rpm/out/*.rpm
(cd package/arch && makepkg) # -> package/arch/*.pkg.tar.zst
./package/appimage/build-appimage.sh --docker # -> package/appimage/out/*.AppImage
./package/mac/build-app.sh --deps # on macOS -> package/mac/out/PsyMP3.app and *.dmgOn macOS, build-app.sh builds PsyMP3 against Homebrew's libraries
(--deps installs them, and dylibbundler) and copies those libraries into
the app, so the result runs on Macs without Homebrew. It builds for the Mac
it runs on: an Apple Silicon Mac makes an Apple Silicon app, an Intel Mac an
Intel one. A universal app takes one of each, joined by
./package/mac/make-universal.sh ARM64/PsyMP3.app X86_64/PsyMP3.app, which
is what the macOS app workflow does. The app is signed ad hoc, as Apple
Silicon requires, but not with a Developer ID.
All of these build from what is committed, so commit before packaging. See package/README.md for the dependency-installation one-liners and how the version label is mapped to a legal package version.
Pass the paths of audio files or playlists (.m3u/.m3u8, .pls, .xspf,
.asx) as program arguments; they are played in order. Once running, open
files with File → Open Tracks..., drag them onto the window, or play an
http:// or https:// address with File → Open URL....
Open a station's address, or its "listen" link, with File → Open URL..., drag it onto the window, or put it in a playlist.
- Icecast and SHOUTcast (including SHOUTcast v1's
ICY 200 OK) stations sending MP3, AAC (ADTS) or Ogg (Vorbis, Opus, FLAC). The song titles a station announces are shown as they change, also over MPRIS and Discord, and each song is scrobbled to Last.fm on its own. Chained Ogg stations, which start a new stream for each song, play on across the changes; when a song (or an ad) comes at another sample rate or channel count, the audio device is reopened for it, with a short gap. - Cover art a station sends, or links, is shown as the song's: in the
album art window, Album Art Mode and over MPRIS. That is ICY's
StreamArtworkorStreamUrl(Radio Paradise sends each song's cover, SomaFM its logo), iHeart'samgArtworkURL, pictures in HLS segments' ID3 tags, and each chained Ogg link's own. A song the station sends no picture for shows none. - HLS stations (
.m3u8) whose segments are packed AAC or MP3, as iHeart sends. MPEG-TS, fragmented-MP4, byte-range and encrypted segments are not supported. - Listen links in
.pls,.m3u/.m3u8,.xspfand.asx: the first entry that answers is played. - A station that drops is reconnected to, with growing waits, up to five failures in a row; one that goes silent for 30 seconds is given up.
- A station has no length: the progress bar is drawn full, seeking is off,
and the timer shows
elapsed/--:--.--.
| Container | Extensions | Audio it can carry |
|---|---|---|
| MPEG audio | .mp3, .mp2, .mpa |
MP3, MP2 |
| FLAC | .flac |
FLAC |
| Ogg | .ogg, .oga, .opus |
Vorbis, Opus, FLAC, Speex |
| MP4 / QuickTime | .m4a, .mp4, .mov, .3gp |
AAC (LC, HE-AAC v1/v2, xHE-AAC), ALAC, MP3, FLAC, AC-3, E-AC-3, TrueHD, PCM |
| Matroska / WebM | .mka, .mkv, .webm |
AAC, Vorbis, Opus, FLAC, ALAC, MP2, MP3, AC-3, E-AC-3, MLP / TrueHD, PCM |
| RIFF | .wav, .bwf, .avi |
PCM, G.711, G.722, MP2, MP3, AC-3 (AVI: the audio track only) |
| AIFF | .aif, .aiff, .aifc |
PCM, G.711 |
| Dolby | .ac3, .eac3, .thd, .mlp |
AC-3, E-AC-3, MLP / Dolby TrueHD |
| ADTS | .aac, .adts |
AAC (LC, HE-AAC v1/v2) |
| Raw | .pcm, .raw, .al, .ul, .g722, .au |
PCM, G.711 µ-law/A-law, G.722 |
Playlists in .m3u and .m3u8 are read and written; .pls, .xspf and
.asx (also .wax, .wvx) are read.
PsyMP3 has a full mouse-driven UI — a menu bar (File, Playback,
Settings, Help — the Alt+F/P/S/H mnemonics work) plus movable in-app windows
like the Playlist Manager, Equalizer, and Media Information — and everything
is also reachable from the keyboard.
| Key | Action |
|---|---|
ESC, Q |
Quit PsyMP3 |
Space |
Pause (or resume) playback |
R |
Restart the current track from the beginning |
N / P |
Next / previous track |
Left / Right |
Seek backward / forward (hold to keep seeking) |
Up / Down |
Volume up / down |
S |
Toggle shuffle |
E |
Cycle loop mode (Shift+E opens the Equalizer) |
Shift+P |
Playlist Manager |
A |
Album Art Mode: the cover in place of the spectrum (see Album Art) |
F1 |
About PsyMP3 |
F |
Cycle FFT draw mode |
G |
Toggle 2× zoom |
Y |
Show or hide lyrics |
0–4 |
Spectrum intensity |
Z / X / C |
Spectrum decay (fast/normal/slow) |
Ctrl+O |
Open tracks (replaces playlist) |
I / L |
Queue tracks next / play a track now |
Ctrl+S |
Save playlist |
Ctrl+F4 |
Close the active in-app window |
Tab / Shift+Tab |
Move between the controls of the active window |
On macOS, Ctrl+O and Ctrl+S are ⌘O and ⌘S, and the macOS menu bar
adds Mac shortcuts of its own (⌘U Open URL, ⌘←/⌘→ previous and next
track, ⌘↑/⌘↓ volume, and more), shown beside its items.
Ctrl+O, I and L open a file dialog, so they need a build with one. These
keys are the player's own: while a text field or another control in a dialog
has focus, the keys go to it instead.
PsyMP3 can show the cover embedded in the playing file's tags in place of the
spectrum analyzer: Playback → Album Art Mode, or A. The cover is drawn
at the full height of the area below the menu bar, and the space on either
side is filled with a heavily blurred copy of the same cover. It follows the
track as it changes. The setting is remembered between runs; press A again
to get the spectrum back.
The cover keeps its proportions: it is scaled, up or down, to the largest size that fits, so a cover that is not square is never stretched. A track with no cover shows "No album art".
Covers must be JPEG or PNG, and at most 8192 pixels on a side. Only art
embedded in the file is shown: PsyMP3 does not look for image files such as
cover.jpg in the track's folder, and does not download covers for this
display. Decoding uses the bundled stb_image (third_party/stb), so no image
library is needed.
Synced lyrics, when a track has them, are drawn over the cover as they are
over the spectrum; Y (Settings → Show Lyrics) hides them.
-h,--help- Print usage, including the list of debug channels-v,--version- Print version and licensing information--licenses- Print the copyright and third-party license texts--fft=MODE- Start in an FFT draw mode:mat-og,vibe-1,neomat-inorneomat-out--scale=FACTOR- Set the spectrum's scale factor--decay=FACTOR- Set the spectrum's decay factor--debug=CHANNELS- Enable debug logging (comma-separated channels, orall)--logfile=FILE- Write debug logs to the specified file--unattended-quit- Quit when playback ends--no-mpris-errors- Don't show on-screen notifications for MPRIS errors
PsyMP3 scrobbles through the Last.fm Web Services API 2.0 with its own registered API key. The easiest way to set it up is in the app: Settings → Last.fm Credentials... — enter your username and password, press Test to verify, and OK to save. The password is only needed once: after the first successful login PsyMP3 saves a permanent session key to the configuration file and removes the password from it. If you later revoke PsyMP3's access on Last.fm, enter your password again under Settings → Last.fm Credentials....
Configuration lives in:
- Linux/Unix and macOS:
~/.config/psymp3/lastfm.conf(or under$XDG_CONFIG_HOME/psymp3/when that is set) - Windows:
%APPDATA%\PsyMP3\lastfm.conf
and can also be created by hand:
# Last.fm configuration
username=your_lastfm_username
password=your_lastfm_passwordScrobbles and now-playing updates include MusicBrainz recording IDs when your files are tagged with them (e.g. by MusicBrainz Picard), and failed submissions are cached and retried across sessions.
PsyMP3 implements MPRIS (Media Player Remote Interfacing Specification) for desktop media-control integration — play/pause/seek from your desktop environment, media keys, and now-playing applets (Linux/BSD only).
With Discord running on the same machine, PsyMP3 shows what you're listening to as a Discord activity: artist in the header, track and album on the card, a live progress bar, and album art from the Cover Art Archive (via your files' MusicBrainz tags, or a live MusicBrainz lookup for untagged files). Toggle it under Settings → Discord Presence. No Discord SDK or account linking is required.
To run the full test suite:
make checkFor detailed testing information, see TESTING.md.
Unicode Support: Unicode ID3 tags are supported. PsyMP3 renders UI text through the built-in FreeType path, with HarfBuzz shaping each run and a vendored SheenBidi resolving direction, so complex scripts are laid out properly rather than drawn one codepoint at a time, left to right.
The bundled vera.ttf (DejaVu Sans) covers rather more than Latin, Greek and
Cyrillic. It also carries Armenian, Georgian, Lao, Hebrew, N'Ko and the Arabic
script — Arabic itself along with Persian, Sindhi, Sorani Kurdish and Uyghur,
and most of Urdu and Pashto. Arabic letters join properly with the bundled
font: shaping selects the contextual forms, and the renderer composites
overlapping glyph boxes so the stroke that joins one letter to the next
survives instead of being overwritten by its neighbour. Hebrew and N'Ko read
right to left.
Scripts that DejaVu Sans does not cover draw as empty boxes — Chinese, Japanese and Korean are the most common example, along with many Indic and Southeast Asian scripts, among others — until you give PsyMP3 a second font.
extra.ttf is an optional second font. PsyMP3 uses it for any character
vera.ttf cannot draw, so a single file can add whichever languages you need.
Any TrueType or OpenType font works; a family with broad coverage, such as
Noto, covers most scripts at once. Without an extra.ttf, nothing changes.
Where PsyMP3 looks for it:
| Platform | Location |
|---|---|
| Windows | next to psymp3.exe; otherwise extra.ttf or res\extra.ttf in the working directory |
| Linux/BSD | the installed data directory, $(prefix)/share/psymp3/data/extra.ttf (/usr/local/share/psymp3/data for a default install); otherwise res/extra.ttf in the working directory, for running from the source tree |
On Linux/BSD the environment variable PSYMP3_DATADIR, when set, names the
data directory in place of the installed one. The AppImage sets it to the copy
inside itself, which cannot be written to, so with the AppImage use
res/extra.ttf in the working directory or point PSYMP3_DATADIR at a
directory of your own holding vera.ttf, psymp3.rgba and your extra.ttf.
How it works alongside vera.ttf:
- It adds to the bundled font rather than replacing it. On Windows that
includes the copy of
vera.ttfbuilt into the executable, so no rebuild is needed. - Anything
vera.ttfcan draw keepsvera.ttf, so adding a font for one language does not restyle the rest of the interface. - One exception: scripts that are shaped or reordered. For right-to-left
scripts such as Arabic and Hebrew, and scripts that combine or rearrange
characters, such as the Indic ones,
extra.ttfis used wherever it covers the script, even for charactersvera.ttfalso has. A font added for one language can therefore change how those scripts look, if it happens to cover them too. They render correctly with DejaVu Sans alone, so this changes which typeface you get, not whether the text is readable.
Replacing vera.ttf itself still works too. On Windows, a vera.ttf next to
the executable or in the working directory overrides the built-in copy.
PsyMP3 2.x is a complete rewrite. The 1.x series was written in FreeBASIC; 2.x is written in C++17 and runs on Linux, the BSDs, macOS and Windows.
PsyMP3 was developed since 2009 using a mixture of hand-written and AI-generated code.
