feat: add a real WMAv2 encoder - #7
Merged
Merged
Conversation
Implements WmaEncoder/WmaEncoderSession/WmaFrameEncoder/AsfContainerWriter, mirroring WmaDecoder's format exactly so this library's own encode/decode round-trips correctly (mono and independently-coded stereo). Shares exponent band/window/run-level table construction between encoder and decoder via WmaTables instead of decoder-local functions. Wires WmaEncoderSession into AudioCutter as a .wma Convert/Cut destination and flips WMA Encode to supported across README/llms.txt/llms-full.txt/docs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…bles WmaFrameEncoder had its own private copies of GetFrameLengthBits, BuildExponentBands, BuildSineWindow, and TotalGainToBits instead of the WmaTables versions WmaDecoder already uses. They were byte-for-byte identical so nothing was broken, but these four functions define the exact encoder/decoder bitstream contract -- an independent edit to one copy without the other would silently desync encode/decode with no compiler error, the same class of bug as the coefficient stop-code fix earlier in this branch. TotalGainToBits was also duplicated as a WmaDecoder-local function pre-dating this branch; moved it into WmaTables too so both sides share a single implementation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
WmaEncoder/WmaEncoderSession/WmaFrameEncoder/AsfContainerWriter, mirroringWmaDecoder's bitstream format exactly (gain, per-band exponents via the shared AAC scalefactor Huffman table, run-length+Huffman coefficient coding) so this library's own encode/decode round-trips correctly for mono and independently-coded stereo.WmaTables(moved out ofWmaDecoder's local functions).WmaEncoderSessionintoAudioCutteras a.wmaConvert/Cutdestination.Two real bugs were found and fixed via the round-trip tests before landing:
SolveTotalGainwas solving the frame's gain from the exponent value clamped toPowTable's representable range (~866000 max) instead of the true unclamped peak MDCT coefficient magnitude (Mdct.Forwardis unnormalized, so raw coefficients routinely reach into the millions for full-scale PCM). This produced grossly mis-scaled quantization.WriteCoefficientsunconditionally wrote a trailing STOP code, butWmaDecoder's coefficient loop terminates implicitly once its cumulative offset reachescoefsEnd— it never reads a STOP code in that case. Whenever a block's last coefficient beforecoefsEndwas itself nonzero, the extra STOP code was an unconsumed stray symbol that desynced everything decoded afterward (the next channel's exponents, or the next frame). This only surfaced under real broadband audio, not sparse single-tone test signals.Test plan
dotnet build --configuration Release— 0 warnings, 0 errorsdotnet test --configuration Release(net8.0/net9.0/net10.0) — 115 passed, 1 pre-existing skip, 0 failedWmaEncoderTest: mono round-trip SNR, stereo round-trip SNR, whole-buffer API smoke test, invalid-channel-count validationAudioCutterTest.Convert_WavToWma/Cut_WavToWmausing real (non-tone) fixture audio, exercising the coefficient path far more than a pure tone does🤖 Generated with Claude Code