Encode, decode and plot audio with 10 neural audio codecs and audio VAEs (DAC, EnCodec, SNAC, Stable Audio Open, Music2Latent, ACE-Step and more), all through one interface. Useful for looking inside each model's latent space and comparing them side by side.
Python
27
5 commits
updated Sep 29, 2026
▶ Listen to every model — plots and decoded audio for all 13 encoders, built by build_site.py.
Paper, code and weights for every model: awesome-codec-architectures.
Batched, plot-ready encode / decode for neural audio codecs (NACs) and audio VAEs, behind one interface.
Takes audio at any sample rate, returns every internal representation as a plottable [B, D, T] feature,
and decodes codes or latents back to audio aligned with the input.
import librosa
from utils import encoder_models as em
waves, sr = librosa.load("song.wav", sr=None) # mono [T] at the file's own sample rate
enc = em.DACEncoder()
out = enc.encode(waves, sr=sr) # waves: audio as [T], [B, T] or [B, C, T]
out["codes"].plot() # any representation: .tensor, .shape, .fps, .plot()
audio = enc.decode(out["codes"]) # [B, C, T] at the input's sample rate and length
audio = enc.decode(out["quantized_z"]) # or the decoder's continuous input
See example.py for a tour and batch_example.py for encoding a folder of audio files.
Python 3.10, torch 2.7.1 / CUDA 12.6. requirements.txt is the full pip freeze.
conda create -n audio_codecs python=3.10 pip -y
conda activate audio_codecs
export PYTHONNOUSERSITE=1 # keep ~/.local packages out
python -m pip install "numpy==1.26.4" "protobuf==3.19.6" "stable-audio-tools==0.0.20" "descript-audio-codec==1.0.0"
python -m pip install pytorch_lightning snac music2latent diffusers "git+https://github.com/facebookresearch/dacvae"
pytorch_lightning. EnCodec and εar-VAE need nothing extra.| Model | Load | Kind | Audio | Frame rate |
|---|---|---|---|---|
| DAC | em.DACEncoder() | RVQ codec | 44.1 kHz mono | 86.1 |
| EnCodec 32 kHz (default) | em.EnCodecEncoder() | RVQ codec | 32 kHz mono | 50 |
| EnCodec 24 kHz | em.EnCodecEncoder("facebook/encodec_24khz") | RVQ codec | 24 kHz mono | 75 |
| SNAC 44 kHz (default) | em.SNACEncoder() | multi-scale RVQ codec | 44.1 kHz mono | 14.4–114.8 |
| SNAC 32 kHz | em.SNACEncoder("hubertsiuzdak/snac_32khz") | multi-scale RVQ codec | 32 kHz mono | 10.4–83.3 |
| Stable Audio Open VAE | em.SAOEncoder() | VAE | 44.1 kHz stereo | 21.5 |
| SAME-L | em.SAMLEncoder() | autoencoder | 44.1 kHz stereo | 10.8 |
| Music2Latent | em.Music2LatentEncoder() | consistency autoencoder | 44.1 kHz mono | 10.8 |
| DACVAE | em.DACVAEEncoder() | VAE | 48 kHz mono | 25 |
| ACE-Step 1.5 VAE | em.ACEStep15Encoder() | VAE | 48 kHz stereo | 25 |
| ACE-Step v1 music DCAE | em.ACEStepDCAEEncoder() | mel autoencoder + vocoder | 44.1 kHz stereo | 10.8 |
| εar-VAE v2 48 kHz (default) | em.EARVAEEncoder() | VAE | 48 kHz stereo | 50 |
| εar-VAE 44.1 kHz | em.EARVAEEncoder("ear_vae_44k") | VAE | 44.1 kHz stereo | 43.1 |
Frame rate is frames per second of the returned features. Every constructor also takes device (default "cuda:0")
and batch_size (default 8 for the codecs, 4 for the autoencoders, 1 for SAME-L).
| Model | Representation | Shape | Decodable | min | max | mean | sd |
|---|---|---|---|---|---|---|---|
| DAC | encoder_z | [B, 1024, T] | ✓ quantized first | −12.42 | 11.92 | 0.01 | 2.50 |
latents | [B, 72, T] (9 codebooks × 8) | ✓ quantized first | −13.71 | 13.04 | −0.06 | 2.95 | |
codes | [B, 9, T] | ✓ default | 1 | 1023 | — | — | |
quantized_z | [B, 1024, T] | ✓ | −19.23 | 16.96 | 0.04 | 3.65 | |
| EnCodec 32 kHz | encoder_z | [B, 128, T] | ✓ quantized first | −12.57 | 15.25 | −0.12 | 2.57 |
codes | [B, 4, T] | ✓ default | 8 | 2044 | — | — | |
quantized_z | [B, 128, T] | ✓ | −12.57 | 13.74 | −0.10 | 2.46 | |
| EnCodec 24 kHz | encoder_z | [B, 128, T] | ✓ quantized first | −16.48 | 20.81 | −0.53 | 4.51 |
codes | [B, 32, T] | ✓ default | 0 | 1023 | — | — | |
quantized_z | [B, 128, T] | ✓ | −16.65 | 20.77 | −0.53 | 4.51 | |
| SNAC 44 kHz | encoder_z | [B, 1024, T] | ✓ quantized first | −44.36 | 67.42 | −0.01 | 2.94 |
codes | [B, 4, T] (4 levels) | ✓ default | 9 | 4085 | — | — | |
quantized_z | [B, 1024, T] | ✓ | −26.76 | 24.43 | −0.01 | 2.46 | |
| SNAC 32 kHz | encoder_z | [B, 1024, T] | ✓ quantized first | −34.78 | 71.89 | −0.03 | 2.88 |
codes | [B, 4, T] (4 levels) | ✓ default | 2 | 4090 | — | — | |
quantized_z | [B, 1024, T] | ✓ | −26.42 | 24.23 | −0.02 | 2.45 | |
| Stable Audio Open VAE | mu | [B, 64, T] | ✓ default | −3.82 | 4.75 | −0.06 | 0.86 |
std | [B, 64, T] | ✗ | 0.0059 | 0.2401 | 0.0840 | 0.042 | |
sample | [B, 64, T] | ✓ | −3.82 | 4.75 | −0.06 | 0.87 | |
| SAME-L | pre_softnorm | [B, 256, T] | ✓ normalized first | −0.27 | 0.28 | 0.00 | 0.057 |
latent | [B, 256, T] | ✓ default | −3.13 | 3.14 | −0.03 | 0.63 | |
| Music2Latent | features | [B, 8192, T] | ✗ | −9.21 | 7.83 | −0.02 | 0.98 |
latent | [B, 64, T] | ✓ default | −3.49 | 3.21 | −0.14 | 0.99 | |
| DACVAE | mu | [B, 128, T] | ✓ default | −3.16 | 2.81 | 0.04 | 0.67 |
std | [B, 128, T] | ✗ | 0.0017 | 0.0072 | 0.0035 | 0.001 | |
sample | [B, 128, T] | ✓ | −3.17 | 2.81 | 0.04 | 0.67 | |
| ACE-Step 1.5 VAE | mu | [B, 64, T] | ✓ default | −3.24 | 2.86 | −0.06 | 0.83 |
std | [B, 64, T] | ✗ | 0.00011 | 0.00196 | 0.00036 | <0.001 | |
sample | [B, 64, T] | ✓ | −3.24 | 2.86 | −0.06 | 0.83 | |
| ACE-Step v1 music DCAE | latent | [B, 128, T] (8 × 16, flattened) | ✓ default | −3.19 | 2.06 | −0.17 | 0.72 |
| εar-VAE v2 48 kHz | mu | [B, 64, T] | ✓ default | −5.11 | 3.74 | −0.02 | 0.56 |
std | [B, 64, T] | ✗ | 0.00002 | 0.00065 | 0.00011 | <0.001 | |
sample | [B, 64, T] | ✓ | −5.11 | 3.74 | −0.02 | 0.56 | |
| εar-VAE 44.1 kHz | mu | [B, 64, T] | ✓ default | −4.12 | 5.71 | 0.05 | 0.89 |
std | [B, 64, T] | ✗ | 0.00003 | 0.00082 | 0.00019 | <0.001 | |
sample | [B, 64, T] | ✓ | −4.12 | 5.71 | 0.05 | 0.89 |
Shape is .tensor.shape: B clips, D dimensions, T frames at the frame rate (for SNAC, its finest rate).
min / max / mean / sd were measured on one 6-second stereo drum clip (1_rock_87_beat_4-4.wav, Groove MIDI
Dataset). Nothing is normalized: every representation is the model's own output on the model's own scale, so
these are a sanity check for your own features, not fixed bounds. Two things follow from them:
quantized_z at 3.65, about 6×
apart, so standardize per model before feeding several into one downstream model, distance or colour scale.codes are raw codebook indices. The full range is 0 to codebook size − 1 (1024 for DAC and EnCodec
24 kHz, 2048 for EnCodec 32 kHz, 4096 for SNAC); the min and max above are only what this clip used.The one representation carrying a scaling factor is ACE-Step v1 DCAE's latent, which has upstream MusicDCAE's
shift and scale applied, as MusicDCAE.encode returns it. Everything else is the bare encoder output, except
that std is softplus(scale), a standard deviation in natural units rather than the raw parameter. Input
audio is resampled and padded, never peak- or loudness-normalized.
Decodable says what enc.decode() does with that representation:
encode()
output.decode() first snaps it to the codebook, the same step
that produces codes, then decodes that. The audio is the same as decoding codes, not a more detailed version.latent only. decode() first runs pre_softnorm through the model's
SoftNorm, which turns it into latent, so the audio is the same as decoding latent.decode() raises a ValueError.Every encoder has the same two methods:
| Call | Parameters | Returns |
|---|---|---|
enc.encode(waves, sr, mono, seed) | waves: audio as [T], [B, T] or [B, C, T]sr=44_100: its sample ratemono=False: mix stereo down firstseed=0: item i draws its VAE sample from seed + i | A dict of EncodedFeatures, one per representation |
enc.decode(features, seed) | features: one feature, e.g. out["codes"], or the whole encode() output to decode enc.decode_defaultseed=0: stochastic decoders decode item i with seed + i | [B, C, T] audio at the input's sample rate and length |
Each EncodedFeature has:
| Member | What it is |
|---|---|
.tensor | [B, D, T] on the CPU: float32, or int64 for codes |
.shape | .tensor.shape |
.fps | Frames per second, from the actual output length |
.is_codes | True for integer tokens |
.numpy() | .tensor as a NumPy array |
.plot(mode="heatmap", index=0, ax=None) | Plots batch item index as a "heatmap", or its per-frame "mean" or "norm". Pass ax to draw into a subplot. Returns (fig, ax) |
[1, 2, T]; [2, T] is two mono clips. Audio is resampled to the
model's rate and right-padded to whole frames.seed + i, for VAE samples and the stochastic decoders (SNAC, SAME-L,
Music2Latent, DACVAE). Results don't depend on batch_size. To reproduce item 1 on its own, pass seed=1.Every model turns audio into frames, one every 1 / frame rate seconds. They differ in what a frame holds.
Tokens (DAC, EnCodec, SNAC). Each frame becomes a few integers, each an index into a learned codebook. They're chosen in stages: the first codebook approximates the frame and each next one encodes what's still missing. Neighbouring indices aren't similar sounds. Tokens are what audio language models (e.g. MusicGen) predict.
| Name | What it is |
|---|---|
codes | The tokens: [B, codebooks, T] integers |
encoder_z | The encoder's output before quantization; the most detailed view |
quantized_z | The vector rebuilt from the tokens (sum of the chosen codebook entries), which the decoder receives. Same information as codes |
latents (DAC) | The 8-dimension per-codebook vectors used to look up the nearest codebook entry |
Latents (continuous autoencoders). Each frame becomes a vector of real numbers. Nothing is rounded, so latents keep more detail, and similar sounds get nearby vectors.
VAEs (SAO, DACVAE, ACE-Step 1.5, εar-VAE) describe each frame as a small cloud of likely points:
| Name | What it is |
|---|---|
mu | The cloud's centre, the best estimate. Deterministic: use it for analysis and decoding |
std | The cloud's width per dimension (the model's uncertainty). Usually small |
sample | mu + std × noise, one seeded point from the cloud. Diffusion models train on these. Sounds almost the same as mu |
Other autoencoders (SAME-L, Music2Latent, ACE-Step v1 DCAE) output one plain latent per frame. Also exposed:
pre_softnorm (SAME-L, before the final normalization) and features (Music2Latent, before the bottleneck).
Fewer frames per second or fewer dimensions means more compression and less detail.
Each heading links to the model's entry in awesome-codec-architectures.
em.DACEncoder() # 44.1 kHz model (default)
em.DACEncoder(weights="path/to/weights_44khz.pth") # a local 44.1 kHz checkpoint
encoder_z [B, 1024, T] · latents [B, 72, T] (9 codebooks × 8) · codes [B, 9, T] · quantized_z [B, 1024, T]codes or quantized_z. Default: codes.encoder_z and latents decode too, but are quantized first, so they give the same audio as codes.em.EnCodecEncoder() # 32 kHz music model, MusicGen's tokenizer (default)
em.EnCodecEncoder(model_id="facebook/encodec_24khz") # 24 kHz general-audio model
encoder_z [B, 128, T] · codes [B, Q, T] · quantized_z [B, 128, T]codes or quantized_z. Default: codes.encoder_z decodes too, but is quantized first, so it gives the same audio as codes.em.SNACEncoder() # 44 kHz music model (default)
em.SNACEncoder(model_id="hubertsiuzdak/snac_32khz") # 32 kHz music model
encoder_z [B, 1024, T] · codes [B, 4, T] · quantized_z [B, 1024, T]codes stacks 4 levels, coarse to fine. Level i has 8, 4, 2, 1 times fewer frames and is repeated to the
finest rate, so codes[:, i, ::stride] recovers it.codes or quantized_z. Default: codes. The decoder adds noise, so it is seeded per item.encoder_z decodes too, but is quantized first, so it gives the same audio as codes.em.SAOEncoder()
mu · std · sample [B, 64, T]mu or sample. Default: mu.hf auth login.em.SAMLEncoder() # fp16 on CUDA, one clip at a time (default)
em.SAMLEncoder(half=False, batch_size=4) # fp32: batch-invariant, ~3.4 GB of weights
pre_softnorm [B, 256, T] (before SoftNorm) · latent [B, 256, T]latent. The decoder draws random numbers, so it is seeded per item.pre_softnorm decodes too, but goes through SoftNorm first, so it gives the same audio as latent.batch_size, hence the default of 1. Use half=False for larger batches.em.Music2LatentEncoder() # one-step decoding (default)
em.Music2LatentEncoder(denoising_steps=3) # more decoding steps
features [B, 8192, T] (before the bottleneck) · latent [B, 64, T]latent. Decoding starts from noise, so it is seeded per item.music2latent.inference.mixed_precision = False for the whole process.site-packages folder, not the Hugging Face cache.em.DACVAEEncoder() # facebook/dacvae-watermarked
mu · std · sample [B, 128, T]mu or sample. Default: mu.em.ACEStep15Encoder() # the vae/ subfolder of ACE-Step/Ace-Step1.5
mu · std · sample [B, 64, T]mu or sample. Default: mu.diffusers.AutoencoderOobleck.em.ACEStepDCAEEncoder() # music_dcae_f8c8 + music_vocoder of ACE-Step-v1-3.5B
latent [B, 128, T] (the model's [B, 8, 16, T] latent, flattened)latent to a mel spectrogram, then to audio with ACE-Step's HiFi-GAN vocoder.acestep package pins versions
(e.g. transformers==4.50.0) that clash with this environment.em.EARVAEEncoder() # 48 kHz v2 model (default)
em.EARVAEEncoder(variant="ear_vae_44k") # 44.1 kHz model
mu · std · sample [B, 64, T]mu or sample. Default: mu.Each wrapper was checked against the model's own reference pipeline on the same input (relative L2 difference):
| Model | Reference | Difference |
|---|---|---|
| DAC | DAC.encode → DAC.decode | 3e-7 |
| EnCodec 32 kHz / 24 kHz | EncodecModel(x, bandwidth=max) | 0 / 0 |
| SNAC | SNAC.decode(SNAC.encode(x)) | 0.9% = its own decode-to-decode noise |
| SAME-L | model.decode(model.encode(x)) | latents 0; audio 0.33% = its own decode-to-decode noise |
| ACE-Step 1.5 VAE | AutoencoderOobleck(x, sample_posterior=False) | 0 |
| ACE-Step v1 DCAE | upstream MusicDCAE.encode / .decode | 0 / 4e-6 |
| εar-VAE v2 | EAR_VAE.decode(EAR_VAE.encode(x, use_sample=False)) | 0 |
Every model was also round-tripped with 44.1 kHz stereo input, a different recording in each channel. Output length and rate matched the input, and each output channel matched its own input channel.
581 followers · starred Sep 2026
Encode, decode and plot audio with 10 neural audio codecs and audio VAEs (DAC, EnCodec, SNAC, Stable Audio Open, Music2Latent, ACE-Step and more), all through one interface. Useful for looking inside each model's latent space and comparing them side by side.
Python
27
5 commits
updated Sep 29, 2026
▶ Listen to every model — plots and decoded audio for all 13 encoders, built by build_site.py.
Paper, code and weights for every model: awesome-codec-architectures.
Batched, plot-ready encode / decode for neural audio codecs (NACs) and audio VAEs, behind one interface.
Takes audio at any sample rate, returns every internal representation as a plottable [B, D, T] feature,
and decodes codes or latents back to audio aligned with the input.
import librosa
from utils import encoder_models as em
waves, sr = librosa.load("song.wav", sr=None) # mono [T] at the file's own sample rate
enc = em.DACEncoder()
out = enc.encode(waves, sr=sr) # waves: audio as [T], [B, T] or [B, C, T]
out["codes"].plot() # any representation: .tensor, .shape, .fps, .plot()
audio = enc.decode(out["codes"]) # [B, C, T] at the input's sample rate and length
audio = enc.decode(out["quantized_z"]) # or the decoder's continuous input
See example.py for a tour and batch_example.py for encoding a folder of audio files.
Python 3.10, torch 2.7.1 / CUDA 12.6. requirements.txt is the full pip freeze.
conda create -n audio_codecs python=3.10 pip -y
conda activate audio_codecs
export PYTHONNOUSERSITE=1 # keep ~/.local packages out
python -m pip install "numpy==1.26.4" "protobuf==3.19.6" "stable-audio-tools==0.0.20" "descript-audio-codec==1.0.0"
python -m pip install pytorch_lightning snac music2latent diffusers "git+https://github.com/facebookresearch/dacvae"
pytorch_lightning. EnCodec and εar-VAE need nothing extra.| Model | Load | Kind | Audio | Frame rate |
|---|---|---|---|---|
| DAC | em.DACEncoder() | RVQ codec | 44.1 kHz mono | 86.1 |
| EnCodec 32 kHz (default) | em.EnCodecEncoder() | RVQ codec | 32 kHz mono | 50 |
| EnCodec 24 kHz | em.EnCodecEncoder("facebook/encodec_24khz") | RVQ codec | 24 kHz mono | 75 |
| SNAC 44 kHz (default) | em.SNACEncoder() | multi-scale RVQ codec | 44.1 kHz mono | 14.4–114.8 |
| SNAC 32 kHz | em.SNACEncoder("hubertsiuzdak/snac_32khz") | multi-scale RVQ codec | 32 kHz mono | 10.4–83.3 |
| Stable Audio Open VAE | em.SAOEncoder() | VAE | 44.1 kHz stereo | 21.5 |
| SAME-L | em.SAMLEncoder() | autoencoder | 44.1 kHz stereo | 10.8 |
| Music2Latent | em.Music2LatentEncoder() | consistency autoencoder | 44.1 kHz mono | 10.8 |
| DACVAE | em.DACVAEEncoder() | VAE | 48 kHz mono | 25 |
| ACE-Step 1.5 VAE | em.ACEStep15Encoder() | VAE | 48 kHz stereo | 25 |
| ACE-Step v1 music DCAE | em.ACEStepDCAEEncoder() | mel autoencoder + vocoder | 44.1 kHz stereo | 10.8 |
| εar-VAE v2 48 kHz (default) | em.EARVAEEncoder() | VAE | 48 kHz stereo | 50 |
| εar-VAE 44.1 kHz | em.EARVAEEncoder("ear_vae_44k") | VAE | 44.1 kHz stereo | 43.1 |
Frame rate is frames per second of the returned features. Every constructor also takes device (default "cuda:0")
and batch_size (default 8 for the codecs, 4 for the autoencoders, 1 for SAME-L).
| Model | Representation | Shape | Decodable | min | max | mean | sd |
|---|---|---|---|---|---|---|---|
| DAC | encoder_z | [B, 1024, T] | ✓ quantized first | −12.42 | 11.92 | 0.01 | 2.50 |
latents | [B, 72, T] (9 codebooks × 8) | ✓ quantized first | −13.71 | 13.04 | −0.06 | 2.95 | |
codes | [B, 9, T] | ✓ default | 1 | 1023 | — | — | |
quantized_z | [B, 1024, T] | ✓ | −19.23 | 16.96 | 0.04 | 3.65 | |
| EnCodec 32 kHz | encoder_z | [B, 128, T] | ✓ quantized first | −12.57 | 15.25 | −0.12 | 2.57 |
codes | [B, 4, T] | ✓ default | 8 | 2044 | — | — | |
quantized_z | [B, 128, T] | ✓ | −12.57 | 13.74 | −0.10 | 2.46 | |
| EnCodec 24 kHz | encoder_z | [B, 128, T] | ✓ quantized first | −16.48 | 20.81 | −0.53 | 4.51 |
codes | [B, 32, T] | ✓ default | 0 | 1023 | — | — | |
quantized_z | [B, 128, T] | ✓ | −16.65 | 20.77 | −0.53 | 4.51 | |
| SNAC 44 kHz | encoder_z | [B, 1024, T] | ✓ quantized first | −44.36 | 67.42 | −0.01 | 2.94 |
codes | [B, 4, T] (4 levels) | ✓ default | 9 | 4085 | — | — | |
quantized_z | [B, 1024, T] | ✓ | −26.76 | 24.43 | −0.01 | 2.46 | |
| SNAC 32 kHz | encoder_z | [B, 1024, T] | ✓ quantized first | −34.78 | 71.89 | −0.03 | 2.88 |
codes | [B, 4, T] (4 levels) | ✓ default | 2 | 4090 | — | — | |
quantized_z | [B, 1024, T] | ✓ | −26.42 | 24.23 | −0.02 | 2.45 | |
| Stable Audio Open VAE | mu | [B, 64, T] | ✓ default | −3.82 | 4.75 | −0.06 | 0.86 |
std | [B, 64, T] | ✗ | 0.0059 | 0.2401 | 0.0840 | 0.042 | |
sample | [B, 64, T] | ✓ | −3.82 | 4.75 | −0.06 | 0.87 | |
| SAME-L | pre_softnorm | [B, 256, T] | ✓ normalized first | −0.27 | 0.28 | 0.00 | 0.057 |
latent | [B, 256, T] | ✓ default | −3.13 | 3.14 | −0.03 | 0.63 | |
| Music2Latent | features | [B, 8192, T] | ✗ | −9.21 | 7.83 | −0.02 | 0.98 |
latent | [B, 64, T] | ✓ default | −3.49 | 3.21 | −0.14 | 0.99 | |
| DACVAE | mu | [B, 128, T] | ✓ default | −3.16 | 2.81 | 0.04 | 0.67 |
std | [B, 128, T] | ✗ | 0.0017 | 0.0072 | 0.0035 | 0.001 | |
sample | [B, 128, T] | ✓ | −3.17 | 2.81 | 0.04 | 0.67 | |
| ACE-Step 1.5 VAE | mu | [B, 64, T] | ✓ default | −3.24 | 2.86 | −0.06 | 0.83 |
std | [B, 64, T] | ✗ | 0.00011 | 0.00196 | 0.00036 | <0.001 | |
sample | [B, 64, T] | ✓ | −3.24 | 2.86 | −0.06 | 0.83 | |
| ACE-Step v1 music DCAE | latent | [B, 128, T] (8 × 16, flattened) | ✓ default | −3.19 | 2.06 | −0.17 | 0.72 |
| εar-VAE v2 48 kHz | mu | [B, 64, T] | ✓ default | −5.11 | 3.74 | −0.02 | 0.56 |
std | [B, 64, T] | ✗ | 0.00002 | 0.00065 | 0.00011 | <0.001 | |
sample | [B, 64, T] | ✓ | −5.11 | 3.74 | −0.02 | 0.56 | |
| εar-VAE 44.1 kHz | mu | [B, 64, T] | ✓ default | −4.12 | 5.71 | 0.05 | 0.89 |
std | [B, 64, T] | ✗ | 0.00003 | 0.00082 | 0.00019 | <0.001 | |
sample | [B, 64, T] | ✓ | −4.12 | 5.71 | 0.05 | 0.89 |
Shape is .tensor.shape: B clips, D dimensions, T frames at the frame rate (for SNAC, its finest rate).
min / max / mean / sd were measured on one 6-second stereo drum clip (1_rock_87_beat_4-4.wav, Groove MIDI
Dataset). Nothing is normalized: every representation is the model's own output on the model's own scale, so
these are a sanity check for your own features, not fixed bounds. Two things follow from them:
quantized_z at 3.65, about 6×
apart, so standardize per model before feeding several into one downstream model, distance or colour scale.codes are raw codebook indices. The full range is 0 to codebook size − 1 (1024 for DAC and EnCodec
24 kHz, 2048 for EnCodec 32 kHz, 4096 for SNAC); the min and max above are only what this clip used.The one representation carrying a scaling factor is ACE-Step v1 DCAE's latent, which has upstream MusicDCAE's
shift and scale applied, as MusicDCAE.encode returns it. Everything else is the bare encoder output, except
that std is softplus(scale), a standard deviation in natural units rather than the raw parameter. Input
audio is resampled and padded, never peak- or loudness-normalized.
Decodable says what enc.decode() does with that representation:
encode()
output.decode() first snaps it to the codebook, the same step
that produces codes, then decodes that. The audio is the same as decoding codes, not a more detailed version.latent only. decode() first runs pre_softnorm through the model's
SoftNorm, which turns it into latent, so the audio is the same as decoding latent.decode() raises a ValueError.Every encoder has the same two methods:
| Call | Parameters | Returns |
|---|---|---|
enc.encode(waves, sr, mono, seed) | waves: audio as [T], [B, T] or [B, C, T]sr=44_100: its sample ratemono=False: mix stereo down firstseed=0: item i draws its VAE sample from seed + i | A dict of EncodedFeatures, one per representation |
enc.decode(features, seed) | features: one feature, e.g. out["codes"], or the whole encode() output to decode enc.decode_defaultseed=0: stochastic decoders decode item i with seed + i | [B, C, T] audio at the input's sample rate and length |
Each EncodedFeature has:
| Member | What it is |
|---|---|
.tensor | [B, D, T] on the CPU: float32, or int64 for codes |
.shape | .tensor.shape |
.fps | Frames per second, from the actual output length |
.is_codes | True for integer tokens |
.numpy() | .tensor as a NumPy array |
.plot(mode="heatmap", index=0, ax=None) | Plots batch item index as a "heatmap", or its per-frame "mean" or "norm". Pass ax to draw into a subplot. Returns (fig, ax) |
[1, 2, T]; [2, T] is two mono clips. Audio is resampled to the
model's rate and right-padded to whole frames.seed + i, for VAE samples and the stochastic decoders (SNAC, SAME-L,
Music2Latent, DACVAE). Results don't depend on batch_size. To reproduce item 1 on its own, pass seed=1.Every model turns audio into frames, one every 1 / frame rate seconds. They differ in what a frame holds.
Tokens (DAC, EnCodec, SNAC). Each frame becomes a few integers, each an index into a learned codebook. They're chosen in stages: the first codebook approximates the frame and each next one encodes what's still missing. Neighbouring indices aren't similar sounds. Tokens are what audio language models (e.g. MusicGen) predict.
| Name | What it is |
|---|---|
codes | The tokens: [B, codebooks, T] integers |
encoder_z | The encoder's output before quantization; the most detailed view |
quantized_z | The vector rebuilt from the tokens (sum of the chosen codebook entries), which the decoder receives. Same information as codes |
latents (DAC) | The 8-dimension per-codebook vectors used to look up the nearest codebook entry |
Latents (continuous autoencoders). Each frame becomes a vector of real numbers. Nothing is rounded, so latents keep more detail, and similar sounds get nearby vectors.
VAEs (SAO, DACVAE, ACE-Step 1.5, εar-VAE) describe each frame as a small cloud of likely points:
| Name | What it is |
|---|---|
mu | The cloud's centre, the best estimate. Deterministic: use it for analysis and decoding |
std | The cloud's width per dimension (the model's uncertainty). Usually small |
sample | mu + std × noise, one seeded point from the cloud. Diffusion models train on these. Sounds almost the same as mu |
Other autoencoders (SAME-L, Music2Latent, ACE-Step v1 DCAE) output one plain latent per frame. Also exposed:
pre_softnorm (SAME-L, before the final normalization) and features (Music2Latent, before the bottleneck).
Fewer frames per second or fewer dimensions means more compression and less detail.
Each heading links to the model's entry in awesome-codec-architectures.
em.DACEncoder() # 44.1 kHz model (default)
em.DACEncoder(weights="path/to/weights_44khz.pth") # a local 44.1 kHz checkpoint
encoder_z [B, 1024, T] · latents [B, 72, T] (9 codebooks × 8) · codes [B, 9, T] · quantized_z [B, 1024, T]codes or quantized_z. Default: codes.encoder_z and latents decode too, but are quantized first, so they give the same audio as codes.em.EnCodecEncoder() # 32 kHz music model, MusicGen's tokenizer (default)
em.EnCodecEncoder(model_id="facebook/encodec_24khz") # 24 kHz general-audio model
encoder_z [B, 128, T] · codes [B, Q, T] · quantized_z [B, 128, T]codes or quantized_z. Default: codes.encoder_z decodes too, but is quantized first, so it gives the same audio as codes.em.SNACEncoder() # 44 kHz music model (default)
em.SNACEncoder(model_id="hubertsiuzdak/snac_32khz") # 32 kHz music model
encoder_z [B, 1024, T] · codes [B, 4, T] · quantized_z [B, 1024, T]codes stacks 4 levels, coarse to fine. Level i has 8, 4, 2, 1 times fewer frames and is repeated to the
finest rate, so codes[:, i, ::stride] recovers it.codes or quantized_z. Default: codes. The decoder adds noise, so it is seeded per item.encoder_z decodes too, but is quantized first, so it gives the same audio as codes.em.SAOEncoder()
mu · std · sample [B, 64, T]mu or sample. Default: mu.hf auth login.em.SAMLEncoder() # fp16 on CUDA, one clip at a time (default)
em.SAMLEncoder(half=False, batch_size=4) # fp32: batch-invariant, ~3.4 GB of weights
pre_softnorm [B, 256, T] (before SoftNorm) · latent [B, 256, T]latent. The decoder draws random numbers, so it is seeded per item.pre_softnorm decodes too, but goes through SoftNorm first, so it gives the same audio as latent.batch_size, hence the default of 1. Use half=False for larger batches.em.Music2LatentEncoder() # one-step decoding (default)
em.Music2LatentEncoder(denoising_steps=3) # more decoding steps
features [B, 8192, T] (before the bottleneck) · latent [B, 64, T]latent. Decoding starts from noise, so it is seeded per item.music2latent.inference.mixed_precision = False for the whole process.site-packages folder, not the Hugging Face cache.em.DACVAEEncoder() # facebook/dacvae-watermarked
mu · std · sample [B, 128, T]mu or sample. Default: mu.em.ACEStep15Encoder() # the vae/ subfolder of ACE-Step/Ace-Step1.5
mu · std · sample [B, 64, T]mu or sample. Default: mu.diffusers.AutoencoderOobleck.em.ACEStepDCAEEncoder() # music_dcae_f8c8 + music_vocoder of ACE-Step-v1-3.5B
latent [B, 128, T] (the model's [B, 8, 16, T] latent, flattened)latent to a mel spectrogram, then to audio with ACE-Step's HiFi-GAN vocoder.acestep package pins versions
(e.g. transformers==4.50.0) that clash with this environment.em.EARVAEEncoder() # 48 kHz v2 model (default)
em.EARVAEEncoder(variant="ear_vae_44k") # 44.1 kHz model
mu · std · sample [B, 64, T]mu or sample. Default: mu.Each wrapper was checked against the model's own reference pipeline on the same input (relative L2 difference):
| Model | Reference | Difference |
|---|---|---|
| DAC | DAC.encode → DAC.decode | 3e-7 |
| EnCodec 32 kHz / 24 kHz | EncodecModel(x, bandwidth=max) | 0 / 0 |
| SNAC | SNAC.decode(SNAC.encode(x)) | 0.9% = its own decode-to-decode noise |
| SAME-L | model.decode(model.encode(x)) | latents 0; audio 0.33% = its own decode-to-decode noise |
| ACE-Step 1.5 VAE | AutoencoderOobleck(x, sample_posterior=False) | 0 |
| ACE-Step v1 DCAE | upstream MusicDCAE.encode / .decode | 0 / 4e-6 |
| εar-VAE v2 | EAR_VAE.decode(EAR_VAE.encode(x, use_sample=False)) | 0 |
Every model was also round-tripped with 44.1 kHz stereo input, a different recording in each channel. Output length and rate matched the input, and each output channel matched its own input channel.
581 followers · starred Sep 2026