Vixen
02b45cc4
csharp
public static class Adpcm

Four bits a sample, decoded with an add and a table lookup.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

It solves a different problem from Vorbis and Opus, which is why it is worth having alongside them. They give ten to one and cost real processor time per voice, plus decoder state per voice, plus a priming delay before the first sample comes out. That is the right trade for a five-minute music track and the wrong one for a footstep. A game has thousands of short sounds — footsteps, impacts, weapon foley, interface clicks — all resident, all starting at unpredictable moments, many playing at once. Sixty-four Opus decoders for that is not a thing anybody does.

Four to one, for almost nothing. Each sample is stored as a four-bit difference from the last one, scaled by a step size that the decoder adapts as it goes — loud passages get a coarse step and quiet ones a fine step, which is what "adaptive" names and what makes four bits sound far better than four bits has any right to. Decoding is an add, a shift and two table lookups.

Blocks, because a sound has to start instantly. The adaptation makes every sample depend on the one before it, so a stream decoded from the middle would be wrong until it happened to converge. Each block therefore begins with the exact sample and step it starts from, which costs four bytes per channel per block and buys random access — a loop point, a seek, or simply starting the sound at all without decoding from the beginning.

This is IMA ADPCM, the one everybody has. Not because it is the best of the family — it is not — but because it is what tools produce, what console SDKs accelerated, and what a .wav file with format tag 0x11 contains. A better-sounding variant nobody can author for is worth less than a good-enough one every pipeline already emits.

Methods (6)

  • public static int BlockBytes(int samplesPerBlock, int channels)

    How many bytes a block of a given size takes.

  • public static int BlockFrames(int blockBytes, int channels)

    How many frames fit in a block of a given size.

  • public static int Decode(int code, ref Adpcm.State state)

    Turns one four-bit code into the next sample.

  • public static int Encode(int sample, ref Adpcm.State state)

    Turns one sample into a four-bit code, and advances the state exactly as the decoder will.

  • public static byte[] Compress(ReadOnlySpan<float> samples, int channels, int samplesPerBlock = 505)

    Compresses interleaved audio into blocks.

  • public static int Decompress(ReadOnlySpan<byte> block, int channels, int samplesPerBlock, Span<float> destination)

    Decodes one block into interleaved samples.

Used by (2)

  • AdpcmStreamDecoderVixen.Audio
  • AdpcmTestsVixen.Audio.Tests