Skip to content

Make nightcore and vaporwave rate-independent - #17

Merged
Isma-L154 merged 1 commit into
mainfrom
fix/effect-sample-rate
Aug 21, 2026
Merged

Make nightcore and vaporwave rate-independent#17
Isma-L154 merged 1 commit into
mainfrom
fix/effect-sample-rate

Conversation

@Isma-L154

Copy link
Copy Markdown
Owner

Closes #8

The bug

asetrate reinterprets a stream's declared sample rate rather than scaling it, so hardcoding 48000 made the actual speed factor 48000 * N / <source rate> — different for every track.

Measured with real FFmpeg, a 2-second tone through the nightcore preset:

Source rate Before After Intended
48 kHz 1.250x 1.250x 1.250x
44.1 kHz 1.361x 1.250x 1.250x
32 kHz 1.875x 1.250x 1.250x
22.05 kHz 2.721x 1.250x 1.250x

44.1 kHz is extremely common — CD-derived uploads and much of SoundCloud — so most tracks were running about 9% too fast, and low-rate uploads (older or spoken-word content) came out unrecognisable. vaporwave was wrong in the same way in the opposite direction.

The fix

Normalise to 48 kHz before asetrate, which makes the hardcoded constant correct by construction:

-"nightcore":  "asetrate=48000*1.25,aresample=48000",
+"nightcore":  "aresample=48000,asetrate=48000*1.25,aresample=48000",

The leading aresample is load-bearing, so there is a comment on it explaining why — it looks redundant otherwise and is exactly the kind of thing that gets "cleaned up" later.

Verification

A wrong filter string looks perfectly reasonable on inspection and only manifests as audio, so the tests render a real tone through FFmpeg and measure the output. Duration comes from a byte count of raw 16-bit mono at 48 kHz — no ffprobe needed.

tests/test_effect_filters.py adds 31 tests:

  • nightcore holds 1.25x and vaporwave holds 0.8x across 48/44.1/32/22.05 kHz sources.
  • test_the_hardcoded_form_really_was_rate_dependent pins the old behaviour (1.25x / 1.36x / 2.72x), documenting why the fix exists rather than leaving it as a claim in a commit message.
  • Every preset is valid FFmpeg — a typo would otherwise surface only as silence during playback.
  • Every non-speed effect leaves duration untouched, and every preset actually produces audio.

180 passed overall.

CI

The workflow now installs FFmpeg. Without it these tests skipif themselves, which would let a broken filter sail through green CI — the opposite of what the suite is for. pytest -ra is also added so any skip that does occur is visible in the log instead of hiding in a dot.

Notes for review

  • Only nightcore and vaporwave use asetrate; the other six presets (EQ, echo, karaoke, 8D) are rate-independent already and are unchanged.
  • Pitch and speed stay coupled, as before — this PR fixes correctness, not the feature. Decoupling them would need rubberband, which is a heavier dependency and a separate decision.

asetrate reinterprets a stream's declared sample rate rather than scaling it,
so hardcoding 48000 made the speed factor 48000*N/<source rate> - different for
every track. Measured with real FFmpeg:

  source     before      after     intended
  48000 Hz   1.250x      1.250x    1.250x
  44100 Hz   1.361x      1.250x    1.250x
  32000 Hz   1.875x      1.250x    1.250x
  22050 Hz   2.721x      1.250x    1.250x

44.1 kHz is extremely common (CD-derived uploads, much of SoundCloud), so most
tracks were running ~9% fast, and low-rate uploads were unrecognisable.

Normalising to 48 kHz before asetrate makes the constant correct by
construction.

Adds tests that render a tone through each preset and measure the result, since
a wrong filter string looks perfectly reasonable and only manifests as audio.
They also assert every preset is valid FFmpeg and that the non-speed effects
leave duration untouched. CI now installs FFmpeg so these run rather than
skipping, and pytest -ra surfaces any skip that does happen.

Closes #8
@Isma-L154
Isma-L154 merged commit 0a90877 into main Aug 21, 2026
3 checks passed
@Isma-L154
Isma-L154 deleted the fix/effect-sample-rate branch August 21, 2026 01:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nightcore/vaporwave hardcode a 48 kHz source, so the speed change is wrong for other sample rates

1 participant