OpenPGP key: C8B4098974629448
Fingerprint: 2138 982C 8E27 ED36 CE60 36E3 C8B4 0989 7462 9448
This is part 3 of a series of articles about ADC. The previous articles are here and here.
In the first two articles, I focused mostly on the claims around ADC: the marketing copy, the vague buzzwords, the weird framing of MDCT as some kind of enemy to defeat, and the repeated use of language that sounds technical but actually aren't.
This time, we are finally doing the thing that should have been done from the beginning: looking at the codec itself.
For this article, I want to share my findings and observations for two publicly-released versions of the ADC encoder/decoder:
v0.82v0.84 rev.0The two versions are related, but not identical. Version 0.84 rev.0 is not a total rewrite--it is more like an attempt to repackage the same basic codec into a frame-based format with streaming and random-access ambitions.
So let's go through both.
Once you strip away the "audio DNA" wording and the anti-MDCT posturing, ADC is not some revolutionary new encoding technology never before seen in the history of audio coding.
It is, to put it simply, a subband predictor codec. That means:
That's it. Just a fairly old-school idea with extra marketing copy on top.
Both v0.82 and v0.84 rev.0 appear to share the same core structure:
MxBThe biggest changes between the two versions are the container, framing, and state-handling strategy.
Let's start with v0.82, because that's the version available when I first encountered this codec. It is also the version whose public messaging got much more aggressive. The January 3, 2026 website snapshot is useful here because it shows exactly how v0.82 was framed at the time:
That matters because when we compare those claims with what the bitstream and the binary actually do, the gap is not subtle.
The older release notes make that even more interesting. v0.80 was already talking about 8 subbands. Then v0.81 backed down to 4 and explicitly said the 8-subband development version was unstable and could introduce several decibels of audible noise. Then v0.82 jumped back to 8 subbands and reintroduced the whole thing as a major leap in quality and efficiency.
So even before analysis, there was already a visible pattern: admit instability, then relaunch the same broad idea with fresh confidence and bigger claims.
The v0.82 spec points to a very simple container:
That one is already a red flag. There are no per-frame headers, sync words, seek table, or even block markers in the bitstream. Without those, I'd find it really hard to even call this a container. The coding state just keeps rolling forward from the start of the file to the end. This matters because it immediately kills one of the recurring ADC talking points: random access. If your arithmetic coder state and your predictor state are both continuous for the whole file, then no, you do not have instant seeking. And yet the developers claim that this is the biggest problem in MDCT-based codecs, which in reality, is actually not a problem for MDCT-based codecs at all. (Yes, I know HE-AAC needs some pre-roll due to having a bit reservoir but that's AAC's thing, not MDCT's.)
At a high level, v0.82 appears to do this:
This is the kind of description that should have been on the website from the beginning. It is already much clearer than phrases like "redefining the DNA of audio compression." But of course it isn't. Because once you say it plainly, the family resemblance becomes obvious. ADC is not escaping the world of traditional audio coding. It is living inside it, specifically somewhere in the old subband-coder neighborhood, with a front end that feels closer in spirit to things like MP2 or SBC than to any imaginary post-MDCT future.
flowchart TD
PCM["PCM input<br>16/24-bit, mono or stereo"] --> JS["Optional mid/side transform"]
JS --> QMF["8-band QMF analysis"]
QMF --> PRED["Per-band 4-tap predictor"]
PRED --> QUANT["Adaptive quantization<br>with MxB floor"]
QUANT --> RANGE["Context-based binary arithmetic coder"]
RANGE --> BITSTREAM["ADC bitstream"]v0.82 seems to use a tree-structured 8-band QMF bank built from a 16-tap Johnston prototype. In plain English, it recursively splits the signal:
And that gives the final 8 subbands.
If ADC marketing were honest, it wouldn't say things like "staying pure in the time domain." It is just using a subband representation instead of an MDCT.
But the more serious problem is that the v0.82 implementation appears to get the QMF structure wrong in a very basic way. It seems that it does a naive even/odd sum-difference split without the required polyphase delay on one branch. That matters because QMF banks rely on precise phase relationships to cancel aliasing correctly. If you mess that up, the bank stops behaving like a proper near-perfect-reconstruction system and starts coloring the signal.
That lines up far too well with the actual behavior:
That 13.8 kHz number is not random, by the way. At 44.1 kHz with 8 uniform bands, one of the band boundaries lands right around there. So the weird hole in the spectrum is exactly where you would expect a broken crossover to show itself.
Once each subband sample is produced, v0.82 feeds it into a tiny adaptive predictor.
It's basically:
The predictor estimates the next value from recent reconstructed samples, then the codec quantizes the difference between the estimate and the actual subband sample. Again, this is not some revolutionary "how did nobody else think of this before!" unprecedented idea. It is a small predictive coder living after a subband split.
The controlling variable here is MxB, which seems to act as a floor for how small the effective step size is allowed to become. Bigger MxB means coarser quantization and fewer bits. Smaller MxB means finer quantization and more bits. So even the famous MxB name is less exciting than it sounds. It is not some mysterious new coding principle. It is basically a control knob for quantizer aggressiveness. I am guessing that this is how the codec controls the bitrate.
The January 3 website snapshot also leans hard on VBR, presenting it as ADC's natural sweet spot. So I checked how that actually behaves in practice.
I took Jean-Michel Jarre's "The Opening (movement 8)" (which the developer is so adamant in using) and encoded progressively longer cuts of it at a requested 64 kbps, then compared ADC against Opus. The easiest way to read the result is this:
WAV stays constant, as expected, at about 1411 kbpsOpus behaves like a normal constrained VBR encoder: usually near target, sometimes a bit above, sometimes a bit belowADC overshoots badly at the start, then spends the rest of the file slowly walking back down toward the requested rateThe first few points tell the story really clearly:
| Length | Opus average | ADC average | Opus added bitrate | ADC added bitrate |
|---|---|---|---|---|
| 10s | 65 kbps | 94 kbps | 65 kbps | 94 kbps |
| 20s | 67 kbps | 79 kbps | 68 kbps | 64 kbps |
| 30s | 65 kbps | 74 kbps | 62 kbps | 62 kbps |
| 60s | 66 kbps | 69 kbps | 70 kbps | 66 kbps |
| 120s | 66 kbps | 67 kbps | 62 kbps | 60 kbps |
| 256s | 65 kbps | 65 kbps | 61 kbps | 69 kbps |
So when asked for "64 kbps", ADC does not start at 64. It starts at roughly 94. Then, perhaps realizing it spent too much too early, it compensates later by dropping the average back down over time.
That does not prove by itself that bitrate control is the entire reason the codec gets worse as the song goes on. But it does line up with the listening impression surprisingly well:
In other words, the "native VBR sweet spot" looks a lot less like smart perceptual allocation and a lot more like a codec that panics at the start, then spends the rest of the file paying off the bill.
xychart-beta
title "Requested 64 kbps: average bitrate over progressively longer files"
x-axis ["10s", "20s", "30s", "60s", "120s", "256s"]
y-axis "kbps" 0 --> 100
line "Opus" [65, 67, 65, 66, 66, 65]
line "ADC" [94, 79, 74, 69, 67, 65]After quantization, v0.82 writes the symbols through a context-based binary arithmetic coder.
That is probably the one area where ADC's own description is the least misleading. I mean, yeah, I guess there is arithmetic coding, and yeah, that's kinda context adaptation. But nah, let's be honest here--that doesn't make the codec any special. The real question is whether the front end gives it something good to compress. If the prediction is rough, the quantization is crude, and the filter bank is already damaging the signal, then a tidy entropy coder at the end is just helping a failing system fail a little more efficiently.
v0.82 has three major structural problems.
The filter bank appears to be mathematically wrong in exactly the place where phase alignment matters most. The result is uncanceled aliasing and destructive interference at crossover points. In other words, "quality over perfect reconstruction" reads less like a bold design philosophy and more like a euphemism for "the reconstruction math is broken."
The predictor state and arithmetic-coder state appear to carry through the whole file without reset. That means the codec is not just compressing audio--it is also dragging its entire past behind it like luggage. If the predictor drifts into a bad state, that bad state poisons what comes next. Which, conveniently enough, is exactly what I observed earlier when encoded material got worse over time.
Because there are no proper frame boundaries or state checkpoints in the bitstream, the decoder cannot just jump in cleanly. To decode some later point in the file, it would need the predictor and coder state that only make sense after decoding everything before that point.
So the claim of "0 ms seeking" was not merely optimistic. It was technically upside down.
Now we get to the interesting part. By v0.84 rev.0, ADC is trying very hard to become a streaming codec. The binary literally prints Streaming & Random Access Mode Enabled. That sounds dramatic, but it also turns out to be only half true, if not less. I guess the audio quality has been proven to be inferior, and with nothing else to throw against MDCT-based codecs, the developer decided to go with "AAC and MP3 are not streamable!" (Let's ignore the fact that Opus is literally made to be streaming-optimized by day 1.)
The public notes around this period also promised "independent 1-second blocks", "full context reset", "zero-latency user experience", and "instantaneous seek-point stability". So again, the bar was not set by me. The bar was set by ADC's own release notes.
Unlike v0.82, v0.84 rev.0 no longer looks like one endless blob.
The format seems to have:
0x54-byte global headerADCSEach frame appears to contain:
That is a fixed overhead of 0x12a bytes before the actual compressed payload even begins.
So yes, v0.84 rev.0 is much more packetized than v0.82.
But look at the price. Instead of designing a compact frame format with minimal side information, ADC now appears to dump a huge chunk of decoder state into every frame. That is not what a sleek modern streaming codec looks like.
flowchart TB
subgraph V082["v0.82"]
direction TB
H82["32-byte header"]
P82["one continuous payload"]
S82["predictor + coder state rolls forward"]
H82 --> P82 --> S82
end
subgraph V084["v0.84 rev.0"]
direction TB
H84["0x54-byte global header"]
R1["frame 1 record"]
C1["payload size -> state snapshots -> count/MxB/checksum -> payload bytes"]
R2["frame 2 record"]
C2["payload size -> state snapshots -> count/MxB/checksum -> payload bytes"]
R3["frame 3 record"]
C3["payload size -> state snapshots -> count/MxB/checksum -> payload bytes"]
H84 --> R1 --> C1 --> R2 --> C2 --> R3 --> C3
end
S82 -. container redesign .-> H84For all the changes to the file format, the coding core still looks basically familiar:
MxB floorSo v0.84 rev.0 is not some fundamental architectural break from v0.82. It is the same basic idea repackaged into frame records.
This is why I would not describe v0.84 rev.0 as "ADC but fixed." I would describe it as "ADC learned that its old container could not support its marketing claims, so it wrapped the same codec in a heavier transport shell."
To be fair, v0.84 rev.0 does improve on v0.82 in one specific way: restartability. Because each frame carries a large snapshot of adaptive state, the decoder can in principle begin at a frame boundary without having to replay the entire file from zero. That is a real change. But it is not the same thing as clean, accurate, robust random access.
And notably, this does not really read like "full context reset" in the straightforward sense. It reads more like "ship a decoder checkpoint with every frame because the decoder still needs a lot of context."
The seek process seems to do the following:
0x120 bytes while looking for timing datacount << 3That's... not elegant.
It is not sample-accurate. It is not even internally consistent, because the scanner skips 0x120 bytes even though the fixed per-frame overhead appears to be 0x12a.
So yes, v0.84 rev.0 has a kind of random-access mode. It can get you somewhere close, though. Kind of.
-h Flag Is Apparently Doing NothingOne of my favorite small details in v0.84 rev.0 is the -h option.
The binary exposes it as a "high quality" mode. Such awesome. Very quality. Wow.
And yet, it appears to do nothing at all in this version. The parser sets a global flag, but there is no meaningful evidence that the encoder ever reads that flag afterwards. Behavioral tests also matched that conclusion. So if you were hoping for some hidden premium mode where the codec suddenly becomes competent, well...
v0.84 rev.0 also adds a per-frame integrity check, but again, the implementation sounds less impressive than the idea.
The recovered checksum is a tiny rolling 16-bit update, not a serious modern integrity mechanism. So even here, the pattern repeats:
I guess I could have just written that and ended the entire series with that note.
Since this article is about both versions, let's make the comparison explicit.
| Area | v0.82 | v0.84 rev.0 | What it really means |
|---|---|---|---|
| Container | 32-byte header plus one continuous payload | 0x54-byte header plus explicit frames | 0.84 is trying to become streamable |
| Magic | ADC\0 | ADCS | New container identity |
| Restartability | None in practice | Possible at frame boundaries | Better than 0.82, but still coarse |
| Seeking | Effectively impossible without replaying from start | Approximate frame-based seeking | Improvement, but nowhere near "0 ms" magic |
| Side information | Minimal upfront header | Massive state snapshot every frame | Better restartability, worse overhead |
| Core front end | 8-band QMF | still 8-band QMF | Same family, same limitations |
| Prediction | small adaptive per-band predictor | same basic idea | Not a reinvention |
| Quantizer control | MxB-driven adaptive step control | same MxB logic remains | Same knob, different wrapper |
| Entropy coder | context-based binary arithmetic coder | same homemade style coder | Same concept, still primitive |
| Integrity check | not meaningfully framed | weak 16-bit checksum per frame | New feature, weak execution |
| Streaming claim | marketing fantasy | partially implemented | The claim moved closer to reality, but only partially |
The things that made ADC questionable in the first place do not seem to have been replaced by something fundamentally better.
Whether you call it "QMF", "time-domain", or "native waveform compression", the reality is the same: the codec still works by splitting the signal into a small number of broad subbands and coding those with predictive tools. That does not put it in the same league as modern transform codecs. It just means it picked a different point in the design space, one with much coarser frequency resolution.
Nothing in either version suggests a mature psychoacoustic model. There are weighting choices and control heuristics, sure, but not the kind of fine-grained masking-aware machinery that makes modern lossy codecs actually efficient. So the core limitation remains: ADC is spending effort compressing a representation that is much less perceptually precise than what AAC, Opus, or xHE-AAC already work with.
Tiny band tables, small integer predictors, homemade coder, weak checksum, weird naming--oops, sorry, I can't judge non-technical things like the name of the codec. But yeah, none of this screams "state-of-the-art engineering." It's more like an experiment. By a person way too overconfident about it.
And that would have been perfectly fine, by the way, if it had been presented as an experiment. The problem is not that the codec is unconventional or rough around the edges. The problem is that it keeps being marketed as if it had already solved problems that other codecs already solved, yet its own internals still plainly struggle with.
At this point, the most honest description I can give is this:
ADC is an experimental subband predictive codec with a lot of ambition, a lot of state, and not enough discipline.
v0.82 looked like a monolithic predictor stream with a broken filter-bank front end and no real random access. v0.84 rev.0 looks like an attempt to patch over the practical usability problem by turning the stream into frames and serializing decoder state into each one. That is a real change, but it is not the same thing as a revolution in audio coding. I might say it's even closer to a workaround over unnecessary limitations that the developer imposed upon the codec, when other codecs do just fine with MDCT.
And because the underlying coding core still appears to be the same basic 8-band predictor idea, the codec still inherits the same broad weaknesses:
This article is the third of a series of articles focused on debunking ADC and its claims.
The following articles will be published over time. They will become links as each article is published.
<- you are hereAfter two articles of marketing nonsense, visiting the technical side is refreshing. Nothing in ADC screams "native sound" or "audio DNA". ADC is just a codec that is understandable, conventional in broad shape, and much less impressive than its own website wants it to sound.
That, I think, is the real lesson of looking inside ADC.
Once you actually trace the pipeline, the whole thing becomes less grandiose. v0.82 is a monolithic 8-band predictive coder with serious structural problems. v0.84 rev.0 adds frames, state snapshots, and a rough seeking scheme, but it does not escape the limitations and problems of the underlying design.
With this article, we are able to describe what ADC actually is, plainly. And plain descriptions have a way of ruining hype.