← ExpSoft Mp3 Extractor

One CD, three CC0 catalogues — how Mp3 Extractor stitches MusicBrainz, Cover Art Archive and LRCLIB together

ExpSoft Mp3 Extractor is a personal-use CD ripper for Windows — the legal frame is the private-copy exception covering the user’s own physically-owned discs (see the Legal & Compliance section of the product page). Three open catalogues already exist for everything you’d want to know about a CD: MusicBrainz (CC0 metadata), Cover Art Archive (artwork licensed by each contributor), and LRCLIB (CC0 lyrics). Each is a great service in isolation; using all three for one CD usually means three tabs, three copy-pastes, and a careful FFmpeg command line for the actual audio decode. Mp3 Extractor unifies them in one click, with a license-clean FFmpeg full build (libcdio included), a separately-fetched libdiscid.dll for accurate disc fingerprints, five output formats, and a portable USB-stick deployment that runs without admin rights.

· 10 min read · By Nicolas Riquier

The fragmented CD metadata landscape

Imagine you’ve just slipped a CD into your laptop and you’d like — on one Windows machine, with no cloud account — to end up with a folder of tagged audio files, embedded cover art, and synchronised lyrics. The good news is the data is all there, in the open, under permissive licences. The less good news is that it lives in three different places, talking to three different APIs, with three different identifiers.

Each of these is a wonderful service on its own. The friction is that nothing connects them out of the box. The user is left to compute the disc ID, query MusicBrainz to get the release MBID, then GET the Cover Art Archive URL, then query LRCLIB by track for each song, then somehow run FFmpeg with the right paranoia mode against the right CD drive — all while keeping per-track metadata in sync. Mp3 Extractor’s job is to make the seven steps look like one click.

Why an FFmpeg full build (and not the essentials)

The audio decode itself runs through FFmpeg. Almost every FFmpeg distribution for Windows lists two flavours: essentials and full. Essentials is smaller; full is bigger. Everywhere else in the ExpSoft catalogue (DatasetVideoChunker, the AI projects that produce intermediate video) we use the essentials build because the LGPL-clean subset of decoders/encoders is enough.

For Mp3 Extractor we ship the full build. The reason is a single dependency: libcdio. libcdio is the library FFmpeg uses to address the physical CD drive directly — to read raw audio sectors with paranoia (error correction by re-read and majority vote) instead of going through the Windows MMC driver as a generic file. libcdio is in the full build but not in essentials.

Concretely, the rip command looks like this:

ffmpeg \
  -f libcdio -paranoia_mode 3 \
  -ss <startSec> -t <durSec> \
  -i D: \
  -codec:a libmp3lame -b:a 320k \
  output.mp3

Note the input is the drive letter D: with -f libcdio. Note also that -ss and -t are given in seconds — but the underlying physical position is in sectors, and one second of CD audio is exactly 75 sectors. libdiscid returns sector offsets when it reads the TOC; the conversion is one division and the inverse multiplication when we hand the value back to FFmpeg. FFmpeg deals with the actual sector-accurate seeking internally; it just exposes seconds as the user-facing interface.

The paranoia_mode value is what the user controls via the Fast / Accurate toggle. Mode 0 disables paranoia entirely (one pass, raw read — fast, but any scratched sector becomes a click). Mode 3 enables overlap and re-read with comparison. Modes go up to 255 (every cdparanoia trick, very slow). The two presets in the app map to Fast (mode 0) and Accurate (mode 3) — anything beyond that is academic for personal use.

libdiscid — fetched separately, kept tiny

libdiscid is the canonical library used to compute the MusicBrainz disc ID from the TOC. It’s LGPL, redistributable, but for some reason it isn’t bundled in any of the common FFmpeg Windows builds. So Mp3 Extractor downloads libdiscid.dll separately at first-run, from the MusicBrainz mirrors, into the venv’s site-packages directory where the Python wrapper expects it.

It’s a 75 KB file. The first-run setup step does:

The reason we don’t bundle it in the installer zip is twofold: (a) it would mix a strict-LGPL DLL into the install package and force more cautious redistribution paperwork; (b) keeping it as a runtime fetch lets us pick up the latest version automatically if MusicBrainz ever ships a security update. Single setup step, no friction visible to the user.

uv + python-build-standalone — why not miniconda

The Python runtime for the project is fetched via Astral’s uv with a python-build-standalone distribution (Python 3.12). Three reasons over the miniconda baseline used by most CD-ripping Python ecosystems:

The whole setup phase — Python download, venv creation, pip install of four packages, FFmpeg full build extraction, libdiscid DLL fetch — completes in about 90 seconds on a residential broadband link.

IPC via stdout prefixes — small, debuggable, no protocol

The Python rip script communicates progress and results back to the C# UI through plain stdout, using three line-prefix conventions:

PROGRESS:<0..100>       (overall ripping progress percentage)
EVENT:<json>            (status updates: "drive_open", "track_start", "track_done", ...)
RESULT:<json>           (final summary, written exactly once on success)

The C# side reads stdout line-by-line on the OutputDataReceived event, dispatches by prefix, and updates the UI. Anything that doesn’t match a prefix is treated as informational log output and tucked into the verbose log pane.

Why this and not a JSON-RPC framing or a pipe with length-prefixed messages: simplicity. Debugging is trivial — just run the Python script standalone in a terminal and read the output as-is. There’s no schema versioning to keep in sync because the only place the C# side parses the JSON is in the RESULT: line, and that JSON is forward-compatible (unknown fields are ignored). The two pieces stay independent.

Per-track artist — the compilation edge case

The trickier corner of CD metadata is the “Various Artists” compilation: a CD where each track has a different artist, but the release itself has a single album-artist (the compiler, like a label or a soundtrack project). The standard ID3v2 frames for this are TPE1 (track artist) and TPE2 (album artist / band). Many naive rippers fill TPE1 with the album artist for every track on a compilation, which then makes every player display “Various Artists” next to every song instead of the actual performer.

MusicBrainz returns this distinction cleanly in its release JSON — each track has its own artist-credit array. Mp3 Extractor uses it: TPE1 is filled per-track from artist-credit, TPE2 is filled from the release-level artist. Players display the real performer for each track, and the album-artist field still groups the album cleanly in the library view. Small detail, but the difference between “correctly tagged compilation” and “every-song-is-Various-Artists” for the user.

Five output formats — the LAME / Vorbis / Opus / FLAC / WAV grid

The UI offers five output formats. Three are lossy, two are lossless, all are LGPL-clean encoders shipped inside the FFmpeg full build:

The output format is chosen once per rip session. Mp3 Extractor doesn’t try to be clever and offer a “best of both worlds” mode — a single format per disc is what users actually want, and offering two simultaneous encodes would double rip time without enough benefit to justify the complexity.

Cover art and lyrics — embedded in the file, no sidecars

The artwork from Cover Art Archive is fetched as a single JPEG (the “front” image, or the closest available) and embedded directly into the file via the APIC ID3v2 frame for MP3/Vorbis/Opus, or the METADATA_BLOCK_PICTURE field for FLAC. No sidecar folder.jpg is produced — the goal is a single self-contained file that travels well between devices.

Lyrics from LRCLIB are tagged similarly: USLT (unsynchronised) and SYLT (synchronised) frames in ID3v2, or LYRICS + SYNCEDLYRICS in Vorbis comment for FLAC/Vorbis. Where the player supports it (and most modern desktop and mobile players do, sometimes with the right plugin) lyrics scroll in time with the song. Where it doesn’t, the lyrics are still visible as a static text tag.

Portable USB deployment — the AutoPatchVenvPaths step

One subtle issue with shipping a Python venv on a removable drive: the venv records absolute paths to its interpreter and site-packages at creation time. Move the venv to a different drive letter (USB stick mounted as E: on one machine, F: on another) and the venv’s activate.bat, pyvenv.cfg, and the .pth files in site-packages still reference the original drive.

Mp3 Extractor’s setup includes an AutoPatchVenvPaths step that re-writes those paths at launch if it detects a mismatch between the recorded path and the current location of runtime\python\python.exe. The patch is idempotent (re-running it on an already-correct venv is a no-op) and it’s fast enough that we just run it on every launch as a check rather than caching “last patched location” somewhere.

End result: the same install folder works on any Windows machine, from any drive letter, including a USB stick passed between machines. No reinstall.

Credits and license

Mp3 Extractor stands on the work of several open-source communities that are explicit about their licences — none of which we paid for, all of which we credit:

The C# host is .NET 8 WPF. The shell is original ExpSoft work; the audio pipeline is FFmpeg; the metadata pipeline is the three CC0 catalogues above. The user retains ownership of any rips they produce from their own physical media.

Take-aways

Frequently Asked Questions

Quick answers to what people ask AIs about this article specifically.

Why does Mp3 Extractor need FFmpeg’s “full” build and not the smaller “essentials”?

Because the rip path uses -f libcdio to address the physical CD drive directly, with paranoia mode for error correction by re-read. libcdio is only present in the full FFmpeg Windows build — the essentials distribution doesn’t include it. Without libcdio, rips would go through the generic Windows MMC driver as a file read, which doesn’t correct media errors. The ~30 MB extra in the install is the cost of accuracy on scratched discs.

What’s the difference between Fast and Accurate ripping modes?

Fast maps to -paranoia_mode 0 — one pass over the disc, no error correction by re-read. It’s about 1.5× to 2× faster than Accurate on a healthy disc, but any scratched sector becomes a click in the output. Accurate maps to -paranoia_mode 3 — overlap and re-read with comparison, which catches and corrects nearly all media errors that aren’t physical destruction. For a clean disc, the two modes produce bit-identical output. For a worn or scratched disc, Accurate is the right choice.

Why is libdiscid downloaded separately at first-run rather than bundled?

Two reasons. First, mixing a strict-LGPL DLL into the install zip changes the licensing posture of the package as a whole and would require more cautious redistribution paperwork. Keeping libdiscid as a runtime fetch from the canonical MusicBrainz mirror keeps the licence boundary clean. Second, runtime fetch picks up security updates automatically if MusicBrainz ever ships one. The download is 75 KB and runs once during first-run setup — invisible to the user.

How are compilation albums handled for the “artist” tag?

MusicBrainz returns track-level artist information separately from release-level artist information. Mp3 Extractor writes the track-level artist into the TPE1 ID3v2 frame (per-track artist) and the release-level artist into TPE2 (album artist / band). On a compilation, this means each song shows the actual performer in the player, while the album-artist field still groups the disc cleanly in library views. Many naive rippers fill TPE1 with the album artist for every track, which makes every song display as “Various Artists” — Mp3 Extractor avoids that.

Can Mp3 Extractor run from a USB stick on different Windows machines?

Yes. The install is fully portable — Python, FFmpeg, libdiscid, the venv, all live inside the install folder. Nothing touches the Windows registry or system PATH. At launch, an AutoPatchVenvPaths step detects whether the venv’s recorded paths still match the current install location (typical mismatch: USB stick mounted as E: on one machine, F: on another) and rewrites them in place if needed. The patch is idempotent — on a venv that’s already correct it’s a no-op.

Want to use ExpSoft Mp3 Extractor?

Get it on Patreon →