Port the intensity stereo threshold table - #200
Merged
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #200 +/- ##
=======================================
Coverage 93.10% 93.11%
=======================================
Files 58 58
Lines 10263 10248 -15
=======================================
- Hits 9555 9542 -13
+ Misses 500 499 -1
+ Partials 208 207 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
FrantaBOT
approved these changes
Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
intensityStartBandwas a hand-written staircase with sixeffectiveKbpsranges returning 8/12/16/17/19/20, plus a ±1 deadband for hysteresis.libopus uses a table of 21 thresholds with per-entry hysteresis (
celt_encoder.c):This PR ports that table, hysteresis_decision (celt/bands.c), and the equiv_rate calculation that feeds it (celt_encoder.c:1926). equiv_rate also accounts for the per-packet overhead that libopus subtracts:
The hysteresis in libopus isn't symmetric: each entry has its own margin, and the margin is only applied when moving from prev. The old ±1 deadband isn't equivalent — it can move across multiple bands within a few frames and doesn't respect the per-entry margins.
Measurement
The intensity band is encoded in the bitstream, so I read it directly by decoding libopus packets with the pion decoder.
Across 3000 music frames at each bitrate, the value was constant, so the previous implementation disagreed completely at the affected rates:
Frame-by-frame agreement goes from 0.0% → 100% at 24, 32, and 64 kbps, and stays at 100% where the old implementation already matched.
At 48 and 128 kbps the old staircase happened to land on the right value. At the other rates it was off by one or two bands. Being too low matters because pion switches to intensity stereo earlier, discarding phase information in bands that libopus would still encode normally.
Dependency
The 24 kbps result also depends on the PR that accounts for the TOC byte in the payload budget. Without that change, equiv_rate is 24000 instead of 23600 and the table selects the next entry. The other bitrates are not affected by this
dependency.
Tests
TestIntensityBandForRate covers the six values against the output from opus_demo, and TestIntensityBandForRateHysteresis covers the per-entry hysteresis margin: at 24 kbps the band is 10, but when coming from band 9 it stays at 9 until the rate exceeds 26.
Reference issue
Part of #34.