From f4a917418ca76b4c207aec3e7899ab8d8e67dc70 Mon Sep 17 00:00:00 2001 From: revtex Date: Wed, 2 Sep 2026 18:39:22 -0400 Subject: [PATCH] Document the settings that make a recording identical to what Spotify sent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recording at 48 kHz from a stream that is 44.1 produces a file that looks completely healthy — right format, right depth, plays perfectly — and whose top 2 kHz is empty, because Windows resampled every track on the way through the virtual cable. That is one of four things on the path between Spotify and a finished recording that change the audio by default, and none of them is something Offstream can decide: they are settings in the Sound control panel and in Spotify. So the README now says which ones and why, rather than leaving "lossless in, lossless out" as an assumption that happens to be false out of the box. The four are the cable's sample rate, its bit depth, Spotify's loudness normalisation, and volume — which lives in four separate places, any one of which turns an exact copy into a scaled one. The bit depth entry is the one that needs its reason spelled out: Windows mixes in 32-bit float, so 24-bit integer is the largest depth that survives the trip unchanged, and both 32-bit and 16-bit are worse in opposite directions. Also documented: FLAC is the only format here that can be exact. MP3, AAC and Opus re-encode by definition, and Offstream's WAV profile is `pcm_s16le`, so WAV loses depth that FLAC keeps — which is not obvious from a format list where WAV and FLAC both read as "lossless". The check commands are three, and the middle one draws the spectrum rather than measuring a band. A band measurement was written first and was wrong in the worst way: `highpass=f=22200` sits above Nyquist on a 44.1 kHz file, so ffmpeg rejects the filter, passes the audio through unfiltered, and reports a healthy level — telling the reader their correctly configured recording had content above 22.2 kHz. The picture cannot misfire, and where the audio stops is easier to read off it than out of a decibel figure anyway. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 8 ++++++++ README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47d7678..fa1345b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,14 @@ phase plan these entries follow. elapsed clock whenever a recording timer is armed — it is set on the Advanced page and was then completely invisible on the page running it. +- **How to record a copy that is identical to what Spotify sent.** Four things on the path between + Spotify and a recording quietly change the audio, and every one of them is on by default: the + virtual cable resampling 44.1 kHz to 48, a bit depth that does not survive the Windows mixer, + Spotify's loudness normalisation, and four separate volume controls. Getting a bit-exact copy is + a matter of settings rather than of Offstream's capabilities, and the README now says which ones + and why — with three commands for checking a finished recording, because the failure this + catches produces a file that plays perfectly and measures wrong. + ### Fixed - **One notch of the wheel jumped three tracks in the session list.** The list of what has been diff --git a/README.md b/README.md index 54c20f2..caf2592 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,50 @@ The rest of the page, briefly: in only if you keep ffmpeg somewhere unusual. (The `C:\ffmpeg\bin\ffmpeg.exe` above is an example, not a requirement.) +## Recording a bit-exact copy + +Offstream writes down whatever the audio device hands it, so a recording is only as faithful as +the path in front of it. Four things on that path change the audio by default, and all four are +settings rather than limitations. + +| What changes it | Where | Set it to | +| --- | --- | --- | +| **Sample-rate conversion** | `mmsys.cpl` → Playback → **CABLE Input** → Properties → Advanced, *and* Recording → **CABLE Output** → Properties → Advanced | **44100 Hz on both.** They have to match each other, or Windows converts between them. Spotify's lossless tier streams at 44.1 kHz; a cable set to 48 kHz makes Windows resample every track on the way through. | +| **Bit depth** | The same two Advanced tabs | **24-bit.** Windows mixes in 32-bit float, and a 24-bit sample is the largest that survives that exactly — 32-bit integer does not, and 16-bit throws away depth the stream may be carrying. | +| **Loudness normalisation** | Spotify → Settings → Playback → **Normalize volume** | **Off.** It is on by default and applies gain before the audio ever leaves Spotify, so with it on the recording is a scaled copy however well the rest is set up. | +| **Volume, in four places** | Spotify's own slider; Windows Volume Mixer → Spotify; CABLE Input → Levels; CABLE Output → Levels | **100 % everywhere.** Any gain that is not exactly 1.0 is applied in floating point and rounded back on the way out. | + +Then two choices in Spotify and Offstream themselves: + +- **Spotify → Settings → Media Quality → Streaming quality: Lossless.** It is set per device, so set + it on the desktop app you are recording, not on your phone. Spotify falls back on a slow + connection and says so while it is playing — worth a glance before a long session. +- **Offstream: Format FLAC.** MP3, AAC and Opus re-encode by definition and can never be exact. + WAV cannot either, here: Offstream writes 16-bit WAV, so it loses depth that FLAC keeps. + +### Checking it worked + +```powershell +# 1. Sample rate and depth. Want 44100 / s32 / 24. +ffprobe -v error -select_streams a -show_entries stream=sample_rate,sample_fmt,bits_per_raw_sample ` + -of default=noprint_wrappers=1 "01 Your Track.flac" + +# 2. Draw the spectrum, then open spectrum.png and look at the top of it. +ffmpeg -v error -y -i "01 Your Track.flac" -lavfi "showspectrumpic=s=900x420:legend=1" spectrum.png + +# 3. Peak level, to catch anything still turning the volume down. +ffmpeg -v info -nostats -i "01 Your Track.flac" -af volumedetect -f null NUL +``` + +The picture is the one that catches the mistake you cannot hear. Audio stops dead at some +frequency, and where it stops tells you what the file really came from: + +| The spectrum runs to | And the file says | Meaning | +| --- | --- | --- | +| The top of the frame | `44100` | Right. Nothing resampled it. | +| ~22 kHz, with a dead band above it | `48000` | Windows resampled a 44.1 kHz stream. The file is a real 48 kHz file whose top 2 kHz is empty — match the cable to 44100 and record it again. | +| ~20 kHz | either | Not lossless. Check Spotify's streaming quality, and that it has not fallen back. | + ## Where things are kept | What | Where | @@ -240,6 +284,7 @@ handy for testing against a clean profile without disturbing your real one. | **"Offstream can't find ffmpeg"** | ffmpeg isn't installed or isn't on `PATH`. Run the winget command above, then **reopen the terminal** and restart Offstream. | | **A `SILENT` lamp on the display, and the meter is flat** | Offstream is listening to a different audio device than the one playing — the commonest way to record an hour of nothing. Check **Record from** on the Settings page. | | **A `CLIP` lamp on the display** | The audio reached full scale, so this track may be distorted. Turn Spotify's own volume down a little and record it again; the lamp clears when the next track starts. | +| **Recordings are 48 kHz, but Spotify streams lossless at 44.1** | The virtual cable is set to 48 kHz, so Windows resamples every track on the way through. See [Recording a bit-exact copy](#recording-a-bit-exact-copy). | | **Recordings include notification sounds, browser audio, everything** | Expected — you're recording the whole output device. Use VB-CABLE as described above to capture Spotify alone. | | **Files have no cover art** | No metadata provider is selected, or its key is missing. See [Better tags and cover art](#better-tags-and-cover-art). | | **Short files keep being thrown away** | That's the minimum-length setting doing its job. Lower it on the Settings page if you're recording something genuinely short. |