Menu

Inside ADC: A Deep Analysis of the Codec

Inside ADC: A Deep Analysis of the Codec

Stylized view of a waveform getting quantized
Category:
Article
Tags:
ADC
Languages:
ENJA
Signature:
Download

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.82
  • v0.84 rev.0

The 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.

First, What ADC Actually Is

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:

  1. split the signal into a handful of frequency bands
  2. try to predict the next sample in each band from previous samples
  3. quantize the error
  4. entropy-code the result

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:

  • an 8-band QMF-ish filter bank
  • per-band adaptive prediction
  • adaptive quantization driven by a global MxB
  • a homemade binary arithmetic or range coder

The biggest changes between the two versions are the container, framing, and state-handling strategy.

ADC v0.82: The Original Shape

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:

  • ADC supposedly "operates directly on the raw audio waveform"
  • the new 8-band version supposedly offers much finer and more "surgical" control
  • VBR is presented as the codec's native, most efficient mode
  • "quality over perfect reconstruction" is framed as a deliberate perceptual upgrade
  • and the whole thing is said to be competitive with, or even better than, codecs like AAC and LC3

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.

File Format

The v0.82 spec points to a very simple container:

  • a 32-byte header
  • one continuous arithmetic-coded payload after that

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.)

Signal Path

At a high level, v0.82 appears to do this:

  1. read 16-bit or 24-bit PCM
  2. optionally convert stereo to mid-side
  3. split the signal into 8 critically sampled subbands
  4. run a 4-tap predictor inside each band
  5. quantize the residual with an adaptive step size
  6. encode the resulting symbols with a context-based binary arithmetic coder

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"]

The Filter Bank

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:

  • low / high
  • then those halves again
  • then those halves again

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:

  • plaid or chessboard aliasing in sweeps
  • mirrored energy around subband boundaries
  • a very audible notch around 13.8 kHz

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.

Prediction And Quantization

Once each subband sample is produced, v0.82 feeds it into a tiny adaptive predictor.

It's basically:

  • 4 taps of predictor history
  • a reconstructed sample history
  • an adaptive quantizer step
  • some dither

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.

VBR And Bitrate Control

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 kbps
  • Opus behaves like a normal constrained VBR encoder: usually near target, sometimes a bit above, sometimes a bit below
  • ADC overshoots badly at the start, then spends the rest of the file slowly walking back down toward the requested rate

The first few points tell the story really clearly:

LengthOpus averageADC averageOpus added bitrateADC added bitrate
10s65 kbps94 kbps65 kbps94 kbps
20s67 kbps79 kbps68 kbps64 kbps
30s65 kbps74 kbps62 kbps62 kbps
60s66 kbps69 kbps70 kbps66 kbps
120s66 kbps67 kbps62 kbps60 kbps
256s65 kbps65 kbps61 kbps69 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:

  • the beginning gets more bits than requested
  • the average slowly drifts downward
  • later segments often get stingier treatment
  • and the subjective quality also keeps getting worse as playback continues

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]

Entropy Coding

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.

Why v0.82 Falls Apart

v0.82 has three major structural problems.

1. Broken QMF behavior

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."

2. Continuous state propagation

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.

3. No real seeking structure

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.

ADC v0.84 rev.0: Same Core, New Packaging

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.

The Container Changed A Lot

Unlike v0.82, v0.84 rev.0 no longer looks like one endless blob.

The format seems to have:

  • a fixed 0x54-byte global header
  • the magic ADCS
  • then a sequence of explicit frames

Each frame appears to contain:

  • payload size
  • 0x20 bytes of step-size state
  • 0x80 bytes of predictor state
  • 0x80 bytes of more history/state
  • 16-bit count
  • 16-bit MxB
  • 16-bit checksum
  • payload bytes

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 .-> H84

What Actually Stayed The Same

For all the changes to the file format, the coding core still looks basically familiar:

  • 8 subbands
  • small per-band predictor
  • local adaptive step sizes
  • global MxB floor
  • binary arithmetic coding

So 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."

The Random Access Story

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:

  1. scans the frame records
  2. skips a hard-coded 0x120 bytes while looking for timing data
  3. reads a 16-bit count
  4. accumulates count << 3
  5. divides by sample rate to estimate time
  6. stores one file offset per computed second

That'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.

The -h Flag Is Apparently Doing Nothing

One 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...

The Checksum Is Weak

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:

  • there is a real feature
  • but it is implemented in the flimsiest, most fragile way possible

I guess I could have just written that and ended the entire series with that note.

What Changed Between v0.82 and v0.84 rev.0

Since this article is about both versions, let's make the comparison explicit.

Areav0.82v0.84 rev.0What it really means
Container32-byte header plus one continuous payload0x54-byte header plus explicit frames0.84 is trying to become streamable
MagicADC\0ADCSNew container identity
RestartabilityNone in practicePossible at frame boundariesBetter than 0.82, but still coarse
SeekingEffectively impossible without replaying from startApproximate frame-based seekingImprovement, but nowhere near "0 ms" magic
Side informationMinimal upfront headerMassive state snapshot every frameBetter restartability, worse overhead
Core front end8-band QMFstill 8-band QMFSame family, same limitations
Predictionsmall adaptive per-band predictorsame basic ideaNot a reinvention
Quantizer controlMxB-driven adaptive step controlsame MxB logic remainsSame knob, different wrapper
Entropy codercontext-based binary arithmetic codersame homemade style coderSame concept, still primitive
Integrity checknot meaningfully framedweak 16-bit checksum per frameNew feature, weak execution
Streaming claimmarketing fantasypartially implementedThe claim moved closer to reality, but only partially

What Did Not Change

The things that made ADC questionable in the first place do not seem to have been replaced by something fundamentally better.

It Is Still A Coarse Subband Codec

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.

It Still Lacks Evidence of Serious Psychoacoustics

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.

It Still Looks Crude Internally

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.

So What Is ADC, After All This?

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:

  • coarse frequency resolution
  • rough adaptive behavior
  • inefficient overhead
  • fragile framing choices
  • no demonstrated reason to believe it outperforms established codecs

Roadmap

This article is the third of a series of articles focused on debunking ADC and its claims.

Article map

The following articles will be published over time. They will become links as each article is published.

  1. Revolutionary Codec or Overhyped Experiment?
  2. "Audio DNA" and Other Things that Mean Nothing
  3. Inside ADC: A Deep Analysis of the Codec <- you are here
  4. The Spectrograms Don't Lie: ODG and Where the Bits Actually Go
  5. Bonus: The SIC Image Codec and the Same Pattern of Overclaiming

Closing

After 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.