Repository navigation
Conversation
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. CodeRabbit Verify
|
This was referenced Oct 30, 2026
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
3 times, most recently
from
November 2, 2026 08:55
cbba6fa to
dd8ad2f
Compare
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
5 times, most recently
from
November 2, 2026 14:06
ab2a22e to
2d240b4
Compare
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
2 times, most recently
from
November 3, 2026 08:16
25f45d5 to
972558c
Compare
The new crate without any codec module: what every later codec plugs into. - Shared types: `AudioBuffer`, `AudioInfo`, `ChannelLayout`/`Speaker`, `AudioError`, `EncodeOptions` (built with `new` and `with_*`), `EncodeFormat`, `BitDepth`, `BwfInfo`, `SampleFormat`. - WAV/BWF/RF64 and AIFF/AIFF-C reading and writing from SoundCraft's `soundcraft-audio-io`, kept over EffectCraft's and FilmCraft's smaller writers (only it has BWF, dither, any speaker mask and streaming without a known length). `encode` and `FileEncoder` behind `pcm-encode`; `lossless-encode` and `encode` turn it on. - `decode`, `probe`, `tracks` and the streaming, seekable `Decoder` (feature `decode-native`). The native path reads WAV, AIFF, and PCM in MP4/MOV and Matroska through craft-media's demuxers, packet by packet, with edit lists and `CodecDelay`/`DiscardPadding` applied. `TrackDecoder` decodes PCM; each codec PR adds its codec to it. - symphonia 0.6 (MPL-2.0, used unmodified) behind the `symphonia` feature, part of `decode`: the fallback for every format with no native decoder yet. Its size fields are checked before it reads, and its panics are caught where they unwind. - `peaks`: the min/max/RMS pyramid for waveform drawing. Workspace: craft-media is a workspace dependency without default features, so an encode-only craft-audio does not build the MP4 demuxer, and `symphonia-bundle-flac` builds without overflow checks in dev profiles (its 32-bit LPC restore wraps on valid input). CI: `audio.yml`, with clippy per feature, rustdoc, WASM, MSRV, and the tests with ffmpeg oracles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
from
November 3, 2026 15:15
972558c to
57b055b
Compare
- Reading: AIFF that declares frames without an SSND chunk is Malformed; a Matroska PCM track's length counts from its first frame; seek targets saturate; an empty FLAC has one track; a failed header read is an Io error; deinterleave allocates fallibly; concealed silence is capped like a decoded packet, and symphonia's uses the damaged packet's own duration when known. - Peaks sum squares in f64, so loud float samples give a finite RMS. - Writing: .aifc maps to AIFF; BWF text is cut at a character boundary; a WAV byte rate past 32 bits is an error; the FileEncoder docs say nothing may follow the sink's position. - README: the Limits list says which codecs go through symphonia and which MP4 edit lists apply. - Tests for each, alias and dither coverage, and a FLAC case in the routing oracle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
from
November 3, 2026 16:29
57b055b to
5c49638
Compare
- Every header read is checked: `Native::open`, `native::tracks` and the no-symphonia error read it with `head_checked`. craft-media demuxer errors that are I/O failures (not a file ending early) are returned as `AudioError::Io` instead of sending the file to the other path. - A Matroska track's presented length runs from its first frame plus `CodecDelay` (unclamped, in timestamp ticks with the delay rounded to one) to its end. - symphonia's concealment allocates fallibly, and a damaged first packet is concealed when the demuxer gives its duration. `deinterleave` reserves its channel list fallibly too. - `TrackDecoder::conceal` documents its cap at the decode limit. - Tests: an I/O failure past the first 64 KiB, codec delay with the first block at -20, 0 and 50 ms (checked with `probe`), a seek back after an overshoot, and the loud-sample RMS value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
from
November 3, 2026 17:30
5c49638 to
0b802e3
Compare
Concealment allocates fallibly and fails with TooLarge when the silence would pass the 2^30-sample decode limit, instead of returning less than the packet's length. The native path, the README, the packets example and the doc example pass the error on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
from
November 3, 2026 17:44
0b802e3 to
5f2a2c2
Compare
- Concealed silence is held to the decode limit inside pcm::silence, so symphonia's path checks frames × channels too, and symphonia's decoded audio is copied into fallibly allocated planes. - TrackDecoder::reset forgets the last packet's length. - Without symphonia, a damaged MP4, Matroska or Ogg file (truncated, invalid, no moov) is Malformed instead of Unsupported; a feature the demuxer does not read still names the build. - Tests: an MP4 with no moov in a native-only build, conceal after a reset and past the limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
from
November 3, 2026 18:11
5f2a2c2 to
00d132c
Compare
- A file the native demuxers find damaged is Malformed with symphonia too, when symphonia calls it unsupported; before, an ftyp-only MP4 was Unsupported in symphonia builds. - symphonia's decoded blocks are held to the 2^30-sample decode limit before allocating. - Symph::seek forgets the last packet's length, so a lost packet after a seek is not concealed with the length of one before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FilmCraft's FLAC encoder behind `flac-encode`, kept over SoundCraft's: linear prediction, stereo decorrelation and the STREAMINFO MD5 give 0.1-37% smaller files on 12 test signals, and the output is bit-exact through `flac` and ffmpeg. It is 3-5x slower than SoundCraft's, still about 56x real time. `lossless-encode` is now `pcm-encode` plus `flac-encode`, and `EncodeFormat::Flac` writes it through `encode` and `FileEncoder`. With only one of the two features, the other's formats are refused as `Unsupported`. The tests that use FLAC files as decode fixtures (truncation, corruption, metadata bounds, zero-frame files, container preflight) come with it, as do the FLAC oracle tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FilmCraft's `filmcraft-aac` decoder as `craft_audio::aac` behind `aac-decode`, kept over symphonia's: the same quality (about 135 dB SNR against ffmpeg), and it decodes 5.1, which symphonia refuses. HE-AAC decodes as its AAC-LC core, upsampled 2x to the stream's rate. - `TrackDecoder` decodes AAC, including ADTS-framed packets without extradata (MPEG-TS, raw `.aac`). - The native read path takes AAC in MP4 and Matroska and raw ADTS streams (frame sync over the file, with resync after damage). - AAC errors convert into `AudioError`. The AAC module's shared parts (Huffman, MDCT, TNS, ICS) arrive whole as ported; their encoder half is unused until the encoder PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FilmCraft's AAC-LC encoder behind `aac-encode`: psychoacoustic model, window switching, M/S, TNS, bit reservoir, CBR and VBR, 1-8 channels, optional ADTS framing. `rayon` encodes channels in parallel. `aac::aac_order` maps WAV order to the encoder's input order. Settings the encoder cannot use are `aac::Error::InvalidSettings`, which converts to `AudioError::Encode`. `encode` now turns on `aac-encode`. Tests that need AAC streams written by our own encoder come with it: the encoder oracle and robustness tests, packet concealment, and `TrackDecoder` on ADTS without extradata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alehel
force-pushed
the
craft-audio-split/06-aac-encode
branch
from
November 3, 2026 19:54
00d132c to
80e604c
Compare
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.
Part 6 of 10 of #395, split in the order FredApps recommended there. Each PR in the stack targets
mainand builds on the one before it, so until the PRs below it merge, GitHub also shows their commits. This PR's own change is the last commit: 80e604c.What the series is for
SoundCraft, FilmCraft and EffectCraft each wrote their own audio encoders and decoders, and several overlap: three WAV/AIFF writers, two FLAC encoders, and FilmCraft's AAC and MP1/MP2 decoders next to symphonia's. The series moves them into craft-libs so each format has one implementation that every app uses. Where two implementations overlapped, both were measured against ffmpeg and the reference tools and the stronger one was kept; #395 has the comparison.
When all ten parts have merged:
CodecId,CodecParams,Container,ByteSource.CodecParamsand the testkit. The two codec crates never depend on each other, so audio-only apps such as SoundCraft never compile video code.%%{init: {"flowchart": {"htmlLabels": false}}}%% graph TD SC["SoundCraft"] --> A FC["Film-/EffectCraft"] --> A FC -.-> V A["craft-audio<br/>audio codecs, file I/O"] --> M V["craft-video<br/>video codecs (later)"] -.-> M M["craft-media<br/>containers, bit I/O, shared types"] classDef later stroke-dasharray: 5 5 class V laterDashed: the planned video crate.
No app changes in the series. Each app keeps its own codec code until it switches to craft-audio in its own follow-up. #395 has the full design, the comparison of overlapping implementations and the migration notes for apps.
The ten parts
All ten together are #395's final tree on current
main, plus one change from the review:actions/checkoutis pinned to a commit SHA inaudio.yml. Each PR builds, passes clippy for every feature set and passes its tests on its own.What this adds
FilmCraft's AAC-LC encoder behind
aac-encode, whichencodenow includes. It has a psychoacoustic model, window switching, M/S, TNS, a bit reservoir, CBR and VBR, 1–8 channels and optional ADTS framing.rayonencodes channels in parallel.aac::aac_ordermaps WAV order to the encoder's input order.aac::Error::InvalidSettings, which converts toAudioError::Encode.TrackDecoderon ADTS without extradata.Known issue in the ported code
From CodeRabbit on #395, ported unchanged from FilmCraft: the encoder accepts a NaN VBR quality. It will get its own issue and fix.
Testing
Run locally on this branch, as
audio.ymlruns them:cargo fmt --check-D warningsfor each feature in the workflow's loop on its own, and for all features-D warnings(all features,decode-native,lossless-encode)cargo check(all features,lossless-encode)cargo test -p craft-audio --all-featureswithCRAFT_MEDIA_REQUIRE_ORACLES=1and ffmpeg 9.0.2Not run locally: the MSRV job (1.95).
🤖 Generated with Claude Code