Skip to main content

retro-amp

retro-amp

English · Deutsch


Stars Forks Issues Pull Requests

Last Commit License Python Themes

A terminal music player with retro charm — built with Python and Textual. The themes come from textual-themes, the dialogs and widgets from textual-widgets. Both are separate libraries you can use in your own Textual app.

retro-amp — Pixel-perfect cover rendering Pixel-perfect cover rendering via TGP / Sixel — in the terminal.

BeBox Theme BeBox theme — folder browser, file table, lyrics, spectral visualizer

Classic Terminal Boing
Classic Terminal — phosphor green Boing — blue/orange
Brotkasten Theme Lyrics
Brotkasten — YouTube links Lyrics — original (English)

Installation

One-Click Installer

No dependencies needed — no Python, no Git.

Linux / macOS:

curl -fsSL https://github.com/michaelblaess/retro-amp/releases/latest/download/install.sh | bash

Windows (PowerShell as Administrator):

irm https://github.com/michaelblaess/retro-amp/releases/latest/download/install.ps1 | iex

Installation Paths

Platform Path
Linux ~/.local/bin/retro-amp
macOS /usr/local/bin/retro-amp
Windows C:\Program Files\retro-amp\retro-amp.exe

Optional Dependency

For M4A/AAC playback, ffmpeg is required. Without ffmpeg, all other formats play normally — only M4A/AAC is skipped (with a log message).

# Windows
choco install ffmpeg        # or: scoop install ffmpeg / winget install ffmpeg

# Linux
sudo apt install ffmpeg

# macOS
brew install ffmpeg

Run without installing (uv)

With uv installed, one line fetches and starts it:

uvx retro-amp ~/Music

Manual (Python >= 3.12)

pip install retro-amp
retro-amp

The latest state of main, before the next release:

uvx --from git+https://github.com/michaelblaess/retro-amp retro-amp ~/Music

From Source

Needs uv. bootstrap creates the .venv, installs all dependencies from uv.lock and the Nuitka build tool.

git clone https://github.com/michaelblaess/retro-amp.git
cd retro-amp
.\bootstrap.ps1     # Windows      (Linux/macOS: ./bootstrap.sh)
.\run.ps1           # start it      (Linux/macOS: ./run.sh)

Usage

retro-amp                     # Start with default music folder
retro-amp /path/to/music      # Start in a specific folder
retro-amp song.mp3            # Play a file directly
retro-amp --lang en           # Start with English UI
retro-amp --version           # Show version

Features

  • Folder browser — Left panel with directory tree, automatically filters audio files. Right-click opens a context menu: for folders play, expand/collapse, collapse all, add to playlist, set as music library, rename and delete - for files also favorite and automatic title completion
  • Quick-jump sidebar — At the top of the Files tab: Home, Music (= configured library), XDG folders (Downloads, Desktop, Documents, Pictures, Videos) and accessible drives. Clicking an entry switches the tree root temporarily — the persistent library stays untouched, the friendly label (e.g. 💾 C:\, 📁 Downloads) is also shown as the tree root. The sidebar starts collapsed as a single ▸ Quick access line - click it or press O to expand it; the state is remembered
  • Favorites view — All favorites as a tree, toggle with TAB. A track started there keeps playing within the favorites: when it ends, the next favorite in the list follows, not the next track of the album. Next, previous, shuffle and repeat apply to the favorites as well. Starting something from the file table or the folder tree afterwards switches back to playing the folder. The playing track carries a ▶ in the tree. "Play" in the context menu of the root plays all favorites from the top, on a group only the favorites of that folder. The transport bar shows, after the format info, which list is playing and the position in it (★ Favorites 3/19, for a playlist ♫ Name 2/5). In a narrow window the hint first shrinks to ★ 3/19 and then disappears, so the title stays readable
  • Context menus everywhere — Right-click an entry in favorites, history, search, playlists or the file table: play, add or remove favorite, add to playlist and "show in folder tree" (switches to the files tab and marks the file there). The file table also offers rename, delete and automatic title completion, the playlist tree "play playlist" and "remove from playlist". On group nodes expand/collapse and collapse all. Entries whose file has disappeared are greyed out
  • Playlist view — Playlists as a tree, play or remove songs directly
  • File table — Right panel with name, format, bitrate, duration, date and size (via mutagen). Clicking a column header sorts by that column, a second click reverses the direction. The ▲/▼ arrow marks the active sort, and the playback order follows the visible sort order.
  • Audio playback — MP3, M4A/AAC, OGG/Opus, FLAC, WAV, MOD/XM/S3M, SID (via pygame.mixer + pyogg + ffmpeg)
  • Spectral visualizer — Real FFT analysis, 5 display modes (Bars, Blocks, Scope, Matrix, LCD VU meter in cassette-deck style). Every mode takes its colors from the current theme; the old fixed rainbow is still available as a setting. Switch mode by right-clicking the visualizer or configure it in the "Visualizer" settings tab.
  • Studio look — All surfaces drawn by retro-amp itself derive their colors from the theme: level meter, LCD display, transport keys, position and volume bars, separators. Level behavior follows a real peak meter — decay in dB per second (independent of frame rate), peak hold, ring-out on stop instead of a frozen picture.
  • Synced lyrics — Time-stamped lyrics from lrclib.net, color-synced (played/current/upcoming), click-to-seek on any line, auto-scroll with a 3s timeout after manual scrolling
  • Liner notes — Wikipedia info on the current artist (key I), cached automatically
  • Album cover art — Embedded covers from audio tags (ID3, FLAC, MP4) or image files in the folder (cover.jpg, folder.jpg, etc.), rendered as Unicode half-blocks via Pillow
  • Global search with history — Search files across the whole library; clicking the search field shows the last 20 queries, typing filters matching entries and highlights hits (persisted in SQLite). Hits appear in the "Search" tab on the left as a tree, grouped by parent directory — when several hits share the same album folder, the path is shown only once. The search ignores accents and special characters: eternita finds Eternità, gruen and grun find Grün, dont stop finds Don't Stop, ac dc finds AC/DC
  • Cloud files - If a file is only stored online (Dropbox or OneDrive "online only") and cannot be fetched, retro-amp says so instead of reporting a misleading "corrupt mp3 file"
  • Playlists — Stored in the SQLite database, default playlist "Favorites". A track started in the playlist tree keeps playing within its playlist, just like the favorites. Markdown playlists from older versions are imported once at startup.
  • Shuffle & repeat — Shuffle mode (X) and Repeat Off/All/One (R), combinable
  • 41 retro themes — vintage 8-bit, terminal, Unix workstation, watch, comic-pulp and 80s-pastel palettes (see textual-themes)
  • Settings dialog — tabbed settings (key S): library default directory, cover renderer, visualizer mode, database journal mode, history, auto-title (MusicBrainz / AcoustID API key), language, plus a storage tab that opens the data folders (settings.json, database, caches)
  • Footer tooltips — hover over any key in the footer to see a full description of what the command does
  • Clickable links — links in the About dialog, Wikipedia source and YouTube panel open on a normal click (no Ctrl needed) and highlight on hover
  • Multilingual — German (default) and English, switchable via --lang or the Settings dialog (Language tab)
  • Session recovery — After a crash, the last track and folder are restored (without auto-play)
  • Crash guard — An unexpected error opens a dialog with a copyable error report instead of crashing the app — you decide whether to continue or quit
  • Debug log — Detailed log with artist/title, paths, events (key L). Right-click the log panel for a context menu — copy, export to a text file, or hide it. A splitter above the panel resizes it
  • File management — Rename (U) and delete (DEL) directly from the player
  • Auto-title (fill in missing titles) — For files that only carry a track number (01.mp3, Track 07.mp3), key G gathers title proposals from three sources — embedded ID3 tags, AcoustID audio fingerprint and the MusicBrainz tracklist — and shows a preview dialog before anything changes. Confirmed matches are preselected, the heuristic MusicBrainz tracklist is not. Accepted files are renamed to NN - Title.ext and the title is written into the tag; see the Auto-title section
  • Settings persistence — Volume, last folder, theme and language are saved
  • Resizable panels — The mouse can freely adjust the size between the file browser on the left and the file table/lyrics on the right (vertical splitter), as well as between file table and lyrics (horizontal splitter). The layout is persisted in settings.
  • File association — Double-click an audio file to open retro-amp directly
  • Single instance — A second double-click sends the track to the running instance
  • Terminal tab title — The terminal tab shows the playing track; set before Textual starts and updated live during playback

Keybindings

The key map is switchable (Settings -> Keyboard). There are two styles, and vim navigation can be added to either. Press ? at any time to see what is currently bound.

Without an explicit choice the operating system decides: the classic style on macOS, because the system claims several function keys, function keys everywhere else.

Classic (letters only)

Key Action
Space Play / Pause
+ - Volume
Z V B Previous track / Stop / Next track
< > Seek 5 seconds back / forward
/ Global search
O Expand / collapse quick access
TAB Cycle view: Files → Favorites → Playlists → History
↑ ↓ Navigate list
Enter Play track / Open folder
F Toggle favorite
P Playlist menu
U Rename file
G Auto-title (fill in missing titles)
DEL Delete file
T Cycle theme
S Settings
I Info / About
L Toggle debug log
C Copy debug log
X Toggle shuffle
R Repeat: Off → All → One
Q Quit
? Key binding overview

The transport keys Z V B follow Winamp. They are not listed in the footer because the control bar offers the same functions as buttons - clicking still works.

With function keys

The function key is added next to the letter, it does not replace it. So everything above still applies, with two exceptions: L and G move out of the way because vim navigation needs those letters.

Key Action
F1 Info / About
F2 Settings
F3 Global search
F4 or Alt+L Toggle debug log (no longer L)
F7 Playlist menu
F8 Rename file
F9 or Alt+G Auto-title (no longer G)
F10 Toggle favorite

F5 and F6 stay free. The sibling applications put refresh and details there, and retro-amp has neither.

Vim navigation

Optional, active in the file list and all trees while one of them has focus.

Key File list Tree
j k line up and down line up and down
Ctrl+U Ctrl+D page up and down page up and down
g G to start and end to start and end
h l column back and forth parent node, expand

In the classic style this takes the keys L and G away from the application. That is reported in the debug log, and the function key style has already moved both.

Custom bindings

In settings.json under keymap_custom, mapping an action to a list of keys:

"keymap_custom": { "cycle_theme": ["alt+t"], "toggle_log": ["f4"] }

Anything that goes wrong - an unknown action name, a key that takes the last one away from another action - is reported in the debug log.

File Association

retro-amp can be registered as the default player for audio files.

Windows (PowerShell):

powershell -ExecutionPolicy Bypass -File register-file-types.ps1

Windows (CMD):

register-file-types.bat

Linux:

./register-file-types.sh

Double-click an audio file to start retro-amp. If it is already running, the new track is sent to the existing instance (single-instance).

Themes

Press T to cycle through themes, or use the theme picker (Ctrl+P → "theme").

retro-amp registers all themes from the textual-themes package (41 themes — dark + light, from 8-bit through terminal phosphor to 80s-pastel and comic-pulp). The full gallery with a live carousel: michaelblaess.github.io/textual-themes.

Migrating from older versions: retro-amp 0.16+ migrates stored theme slugs automatically on load — anyone who previously had e.g. c64 as their favorite theme ends up on the renamed brotkasten without doing anything.

Spectral Visualizer

  • Real FFT-based analysis (stdlib cmath, no numpy)
  • 2048-point FFT with Hann window
  • 32 log-scaled frequency bands (20 Hz – 18 kHz)
  • Colors from the theme: the bands run as a gradient across the theme's three level colors, so an amber monitor gets an amber meter. The fixed rainbow (red → yellow → green → cyan → blue) remains available for Bars and Scope via the "Rainbow" checkbox in the Visualizer settings tab.
  • Peak meter behavior: bars fall at a fixed rate in dB per second, so the picture stays the same regardless of frame rate. A peak is held for at least one analysis window and then falls more slowly than the bar, which keeps the marker visible above it.
  • On stop the display rings out instead of freezing
  • 3-row multi-row display (24 height levels)
  • PCM loading in a background thread

Playlists

Playlists live in the SQLite database at ~/.retro-amp/retro-amp.db.

Earlier versions kept them as Markdown files in ~/.retro-amp/playlists/. Those are imported once at startup and removed afterwards — nothing to do by hand.

  • F — Add/remove a song to favorites
  • P — Playlist menu: create a new one, load an existing one, add a song

Auto-title

Files that only have a track number in the name (01.mp3, Track 07.mp3) can get their real titles filled in. Press G on a folder — retro-amp gathers proposals and shows a preview dialog (confirm / cancel) before touching anything. Rows without a reliable match stay unchanged.

Four sources, in order of certainty:

  1. Embedded ID3 tag — deterministic, preselected. A generic placeholder tag (Track 01, Untitled) is treated as missing so a real title can be found.
  2. AcoustID audio fingerprint — identifies the title from the actual audio (acoustid.org); the most reliable online source, preselected. Requires the fpcalc tool (Chromaprint) and a free Application API key (Settings → Auto-title). Off by default.
  3. MusicBrainz tracklist — matches folder = album and filename number = track against the MusicBrainz tracklist. This is heuristic — only an exact track-count match with plausible durations is accepted — so it is shown in yellow and not preselected; you confirm it. On by default.
  4. Filename fallback — last resort: if no source finds a title but the filename carries one (01 Jonny Controletti.mp3), the title is taken from the filename. Not preselected. On by default.

Accepted rows are renamed to NN - Title.ext and the title is written into the file's tag. When the filename already contains the title (only the tag was missing or generic), only the tag is written — the file is not renamed. The currently playing file is unloaded for the change and resumed at the same position; playlist and history paths are updated automatically.

Architecture

Clean architecture with a strict dependency rule:

src/retro_amp/
├── domain/           # Models, protocols — no external imports
│   ├── models.py     #   AudioTrack, PlayerState, Playlist
│   └── protocols.py  #   AudioPlayer, MetadataReader, PlaylistRepository
├── services/         # Business logic — imports domain/ only
│   ├── player_service.py
│   ├── playlist_service.py
│   └── metadata_service.py
├── infrastructure/   # Implementations — pygame, mutagen, JSON
│   ├── audio_player.py    # PygameAudioPlayer
│   ├── spectrum.py        # SpectrumAnalyzer (FFT)
│   ├── metadata_reader.py # MutagenMetadataReader + cover-art extraction
│   ├── sqlite_playlist_repository.py  # SqlitePlaylistRepository
│   ├── playlist_migration.py          # one-time import of old .md playlists
│   ├── settings.py        # JsonSettingsStore
│   ├── session.py         # Crash recovery (session.json)
│   └── single_instance.py # Single-instance lock + play request
├── widgets/          # Textual widgets
├── screens/          # Textual ModalScreens
├── i18n.py           # Internationalization (de/en)
├── locale/           # JSON language packs (de.json, en.json)
├── themes.py         # Re-export from textual-themes
└── app.py            # Composition root

Development

# Setup (uv: .venv + dev dependencies + Nuitka)
git clone https://github.com/michaelblaess/retro-amp.git
cd retro-amp
.\bootstrap.ps1     # Windows      (Linux/macOS: ./bootstrap.sh)

# Tasks (poethepoet, defined in pyproject.toml)
uv run poe test         # pytest
uv run poe typecheck    # mypy strict
uv run poe lint         # ruff
uv run poe run          # start retro-amp

Local build (standalone binary)

Nuitka compiles retro-amp to a native, self-contained binary that runs without a Python install (one distributable archive per OS). One script per OS; each runs uv sync first and writes to dist/:

.\compile-win64.ps1     # Windows -> dist/retro-amp-vX.Y.Z-win64.zip
./compile-linux.sh      # Linux   -> dist/retro-amp-vX.Y.Z-linux-x86_64.tar.gz
./compile-macos.sh      # macOS   -> dist/retro-amp-vX.Y.Z-macos-<arch>.tar.gz

Nuitka needs nuitka in the venv (uv pip install nuitka) and a C compiler — Windows: MSVC; Linux: gcc patchelf python3-dev; macOS: Xcode Command Line Tools. Nuitka does not cross-compile — build each OS on that OS.

Create a Release

git tag v0.4.0
git push origin v0.4.0
# GitHub Actions automatically builds the Windows/macOS/Linux installers

Tech Stack

Component Library
TUI framework Textual >= 8.2.6
Rich text Rich >= 13.0
Audio playback pygame.mixer >= 2.5
Audio metadata mutagen >= 1.47
Album cover art Pillow >= 10.0
Cover rendering (TGP/Sixel) textual-image >= 0.12
Themes textual-themes >= 0.8
UI widgets (about dialog, crash guard, settings dialog, search history, context menu, splitter) textual-widgets >= 0.25
Lyrics API lrclib.net (synced + plain)
Title lookup (fingerprint) AcoustID + Chromaprint fpcalc
Title lookup (tracklist) MusicBrainz
Testing pytest, pytest-asyncio, pytest-cov
Type checking mypy (strict)

Credits

Synced lyrics, album art rendering, and session recovery were inspired by ytm-player — a YouTube Music player built with Textual.

Multiple visualizer modes and the "player-first, keyboard-driven" UX approach were inspired by cliamp (cliamp.stream) by @bjarneo — a Winamp-inspired terminal player written in Go.

Pixel-perfect cover rendering via TGP (Kitty protocol) and Sixel is powered by the wonderful textual-image library by @lnqs — many thanks!

License

Apache License 2.0 — see LICENSE.

Author

Michael Blaess — GitHub

Metadata

Release files for retro-amp 0.35.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for retro-amp 0.35.1
File Size Uploaded
retro_amp-0.35.1.tar.gz 229.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for retro-amp 0.35.1
File Interpreter ABI Platform
retro_amp-0.35.1-py3-none-any.whl Python 3 none any Details

Total release size: 435.8 kB

Release files / retro_amp-0.35.1.tar.gz

Download URL retro_amp-0.35.1.tar.gz
Size 229.4 kB
Tags Source
SHA-256 checksum
How to use checksums
194957a725a9bcf8fba15db8030742e1ce639bdc72555dbc32d29bfae2cb4f8a
BLAKE2b-256 checksum
How to use checksums
d37550e36df7e3bbb1be7ed26208b7914908f139ab6e78deee8c72bd6f5b8f92
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / retro_amp-0.35.1-py3-none-any.whl

Download URL retro_amp-0.35.1-py3-none-any.whl
Size 206.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6b75cd165ec8a4721204ef734a0ff76db8e7cc83630b52cf2dba3ef155e66012
BLAKE2b-256 checksum
How to use checksums
aa3b3127fe5cafd6a733d268c8af3d1add3419fb6cb7d88c056f281d3a53f693
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.35.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page