---
title: minimax_h3_audio_vae
---

<div class="python-reference">
<a id="fastvideo.mlx_runtime.minimax_h3_audio_vae-classes"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_audio_vae-functions"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE-functions"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_audio_vae"></a>
<p>MiniMax-H3 audio VAE (DAC encoder + BigVGAN decoder) for Apple Silicon MLX.</p>
<p>Faithful port of <code>fastvideo/models/vaes/minimax_h3_audio.py</code>:</p>
<ul>
<li><strong>Encoder</strong>: plain-Snake residual units (dilations 1/3/9), strided
  down-sampling blocks, then the attention projection block — causal
  multi-head attention over the latent stream with q/v biases and a forced
  zero k bias, head averaging, average pooling into <code>latent_channels</code>
  streams, output projection, and a GeGLU MLP.</li>
<li><strong>Decoder</strong>: 1x1 projection back to the trunk width, BigVGAN with
  weight-normalized ConvTranspose1d upsampling, AMP residual blocks with
  SnakeBeta behind alias-free Kaiser-window up/down sampling, final SnakeBeta</li>
<li>conv, and the [-1, 1] clamp.</li>
<li>Kaiser-window low-pass filters exactly as released; released filter buffers
  are used when present so numerics do not depend on window construction.</li>
</ul>
<p>Waveforms are float32 in [-1, 1] at 32 kHz. Stereo latents <code>(2, 32, N)</code>
decode independently while preserving channel order and duration. Production
code never imports PyTorch; torch parity references live only in tests.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.init_logger"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.init_logger</code></h2>
<pre class="doc-signature"><code>init_logger(name: str) -&gt; _FastvideoLogger</code></pre>
<p>The main purpose of this function is to ensure that loggers are
retrieved in such a way that we can be sure the root fastvideo logger has
already been configured.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MiniMaxH3AudioVAEConfigView"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MiniMaxH3AudioVAEConfigView</code></h2>
<pre class="doc-signature"><code>MiniMaxH3AudioVAEConfigView(encoder_dim: int = 64, encoder_rates: tuple&#91;int, ...&#93; = (2, 4, 4, 5, 5), latent_dim: int = 2048, latent_channels: int = 32, num_attention_heads: int = 8, decoder_dim: int = 1024, decoder_rates: tuple&#91;int, ...&#93; = (5, 5, 2, 2, 2, 2, 2), decoder_kernel_sizes: tuple&#91;int, ...&#93; = (9, 9, 4, 4, 4, 4, 4), resblock_kernel_sizes: tuple&#91;int, ...&#93; = (3, 7, 11), resblock_dilation_sizes: tuple&#91;tuple&#91;int, ...&#93;, ...&#93; = ((1, 3, 5), (1, 3, 5), (1, 3, 5)), sampling_rate: int = 32000, latents_mean: tuple&#91;float, ...&#93; | None = None, latents_std: tuple&#91;float, ...&#93; | None = None)</code></pre>
<p>Architecture constants (defaults mirror the released audio_vae/config.json).</p>

<details><summary>Source</summary><pre><code>@dataclass(frozen=True)
class MiniMaxH3AudioVAEConfigView:
    &quot;&quot;&quot;Architecture constants (defaults mirror the released audio_vae/config.json).&quot;&quot;&quot;

    encoder_dim: int = 64
    encoder_rates: tuple&#91;int, ...&#93; = (2, 4, 4, 5, 5)
    latent_dim: int = 2048
    latent_channels: int = 32
    num_attention_heads: int = 8
    decoder_dim: int = 1024
    decoder_rates: tuple&#91;int, ...&#93; = (5, 5, 2, 2, 2, 2, 2)
    decoder_kernel_sizes: tuple&#91;int, ...&#93; = (9, 9, 4, 4, 4, 4, 4)
    resblock_kernel_sizes: tuple&#91;int, ...&#93; = (3, 7, 11)
    resblock_dilation_sizes: tuple&#91;tuple&#91;int, ...&#93;, ...&#93; = ((1, 3, 5), (1, 3, 5), (1, 3, 5))
    sampling_rate: int = 32000
    latents_mean: tuple&#91;float, ...&#93; | None = None
    latents_std: tuple&#91;float, ...&#93; | None = None

    @classmethod
    def from_vae_dir(cls, vae_dir: str | Path) -&gt; MiniMaxH3AudioVAEConfigView:
        config = json.loads((Path(vae_dir) / &quot;config.json&quot;).read_text())
        return cls(
            encoder_dim=int(config&#91;&quot;encoder_dim&quot;&#93;),
            encoder_rates=tuple(int(v) for v in config&#91;&quot;encoder_rates&quot;&#93;),
            latent_dim=int(config&#91;&quot;latent_dim&quot;&#93;),
            latent_channels=int(config&#91;&quot;latent_channels&quot;&#93;),
            num_attention_heads=int(config&#91;&quot;num_attention_heads&quot;&#93;),
            decoder_dim=int(config&#91;&quot;decoder_dim&quot;&#93;),
            decoder_rates=tuple(int(v) for v in config&#91;&quot;decoder_rates&quot;&#93;),
            decoder_kernel_sizes=tuple(int(v) for v in config&#91;&quot;decoder_kernel_sizes&quot;&#93;),
            resblock_kernel_sizes=tuple(int(v) for v in config&#91;&quot;resblock_kernel_sizes&quot;&#93;),
            resblock_dilation_sizes=tuple(tuple(int(d) for d in group) for group in config&#91;&quot;resblock_dilation_sizes&quot;&#93;),
            sampling_rate=int(config&#91;&quot;sampling_rate&quot;&#93;),
            latents_mean=tuple(float(v) for v in config&#91;&quot;latents_mean&quot;&#93;) if &quot;latents_mean&quot; in config else None,
            latents_std=tuple(float(v) for v in config&#91;&quot;latents_std&quot;&#93;) if &quot;latents_std&quot; in config else None,
        )

    @property
    def hop_length(self) -&gt; int:
        return math.prod(self.encoder_rates)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MiniMaxH3AudioVAEConfigView.from_vae_dir"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MiniMaxH3AudioVAEConfigView.from_vae_dir</code></h3>
<pre class="doc-signature"><code>from_vae_dir(vae_dir: str | Path) -&gt; MiniMaxH3AudioVAEConfigView</code></pre>

<details><summary>Source</summary><pre><code>@classmethod
def from_vae_dir(cls, vae_dir: str | Path) -&gt; MiniMaxH3AudioVAEConfigView:
    config = json.loads((Path(vae_dir) / &quot;config.json&quot;).read_text())
    return cls(
        encoder_dim=int(config&#91;&quot;encoder_dim&quot;&#93;),
        encoder_rates=tuple(int(v) for v in config&#91;&quot;encoder_rates&quot;&#93;),
        latent_dim=int(config&#91;&quot;latent_dim&quot;&#93;),
        latent_channels=int(config&#91;&quot;latent_channels&quot;&#93;),
        num_attention_heads=int(config&#91;&quot;num_attention_heads&quot;&#93;),
        decoder_dim=int(config&#91;&quot;decoder_dim&quot;&#93;),
        decoder_rates=tuple(int(v) for v in config&#91;&quot;decoder_rates&quot;&#93;),
        decoder_kernel_sizes=tuple(int(v) for v in config&#91;&quot;decoder_kernel_sizes&quot;&#93;),
        resblock_kernel_sizes=tuple(int(v) for v in config&#91;&quot;resblock_kernel_sizes&quot;&#93;),
        resblock_dilation_sizes=tuple(tuple(int(d) for d in group) for group in config&#91;&quot;resblock_dilation_sizes&quot;&#93;),
        sampling_rate=int(config&#91;&quot;sampling_rate&quot;&#93;),
        latents_mean=tuple(float(v) for v in config&#91;&quot;latents_mean&quot;&#93;) if &quot;latents_mean&quot; in config else None,
        latents_std=tuple(float(v) for v in config&#91;&quot;latents_std&quot;&#93;) if &quot;latents_std&quot; in config else None,
    )</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.kaiser_sinc_filter1d"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.kaiser_sinc_filter1d</code></h2>
<pre class="doc-signature"><code>kaiser_sinc_filter1d(cutoff: float, half_width: float, kernel_size: int) -&gt; np.ndarray</code></pre>
<p>NumPy replica of the released Kaiser-windowed sinc low-pass.</p>
<details><summary>Source</summary><pre><code>def kaiser_sinc_filter1d(cutoff: float, half_width: float, kernel_size: int) -&gt; np.ndarray:
    &quot;&quot;&quot;NumPy replica of the released Kaiser-windowed sinc low-pass.&quot;&quot;&quot;
    half_size = kernel_size // 2
    attenuation = 2.285 * (half_size - 1) * math.pi * (4 * half_width) + 7.95
    if attenuation &gt; 50.0:
        beta = 0.1102 * (attenuation - 8.7)
    elif attenuation &gt;= 21.0:
        beta = 0.5842 * (attenuation - 21)**0.4 + 0.07886 * (attenuation - 21.0)
    else:
        beta = 0.0
    window = np.kaiser(kernel_size, beta).astype(np.float32)  # periodic=False semantics
    if kernel_size % 2 == 0:
        time = np.arange(-half_size, half_size, dtype=np.float32) + 0.5
    else:
        time = np.arange(kernel_size, dtype=np.float32) - half_size
    filter_ = 2 * cutoff * window * np.sinc(2 * cutoff * time)
    filter_ /= filter_.sum()
    return filter_.astype(np.float32)</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE</code></h2>
<pre class="doc-signature"><code>MLXMiniMaxH3AudioVAE(weights: dict&#91;str, Any&#93;, config: MiniMaxH3AudioVAEConfigView, *, include_encoder: bool = True)</code></pre>
<p>DAC-style posterior encoder plus BigVGAN waveform decoder.</p>

<details><summary>Source</summary><pre><code>class MLXMiniMaxH3AudioVAE:
    &quot;&quot;&quot;DAC-style posterior encoder plus BigVGAN waveform decoder.&quot;&quot;&quot;

    def __init__(self, weights: dict&#91;str, Any&#93;, config: MiniMaxH3AudioVAEConfigView, *, include_encoder: bool = True):
        self.weights = weights
        self.config = config
        self.has_encoder = include_encoder
        self.latent_channels = config.latent_channels
        mean = config.latents_mean if config.latents_mean is not None else &#91;0.0&#93; * config.latent_channels
        std = config.latents_std if config.latents_std is not None else &#91;1.0&#93; * config.latent_channels
        self._latents_mean = np.asarray(mean, dtype=np.float32).reshape(1, -1, 1)
        self._latents_std = np.asarray(std, dtype=np.float32).reshape(1, -1, 1)

    # -- normalization --------------------------------------------------

    def normalize_latents(self, latents):
        return (latents - mx.array(self._latents_mean)) / mx.array(self._latents_std)

    def denormalize_latents(self, latents):
        return latents * mx.array(self._latents_std) + mx.array(self._latents_mean)

    def _filter(self, key: str) -&gt; mx.array:
        &quot;&quot;&quot;Released filter buffer flattened to (K,) (they ship as (1, 1, K)).&quot;&quot;&quot;
        try:
            return mx.reshape(self.weights&#91;key&#93;, (-1, ))
        except KeyError as exc:
            raise KeyError(f&quot;H3 audio VAE is missing released filter buffer &#x27;&#123;key&#125;&#x27;&quot;) from exc

    # -- encoder ----------------------------------------------------------

    def encode(self, waveform):
        &quot;&quot;&quot;Mono waveform (1, 1, S) -&gt; posterior mean/logvar each (1, C, N).&quot;&quot;&quot;
        if not self.has_encoder:
            raise RuntimeError(&quot;This MLX H3 audio VAE was loaded without encoder weights.&quot;)
        cfg = self.config
        w = self.weights
        samples = waveform.shape&#91;-1&#93;
        right_pad = math.ceil(samples / cfg.hop_length) * cfg.hop_length - samples
        if right_pad &gt; 0:
            waveform = mx.pad(waveform, ((0, 0), (0, 0), (0, right_pad)))

        x = _conv1d(waveform,
                    _wn_weight(w&#91;&quot;encoder.block.0.weight_v&quot;&#93;, w&#91;&quot;encoder.block.0.weight_g&quot;&#93;),
                    w&#91;&quot;encoder.block.0.bias&quot;&#93;,
                    padding=3)
        dim = cfg.encoder_dim
        for index, stride in enumerate(cfg.encoder_rates, start=1):
            prefix = f&quot;encoder.block.&#123;index&#125;&quot;
            dim *= 2
            # Three residual units with dilations 1, 3, 9 at dim//2 channels.
            for unit, dilation in enumerate((1, 3, 9)):
                p = f&quot;&#123;prefix&#125;.block.&#123;unit&#125;&quot;
                residual = _snake(x, w&#91;f&quot;&#123;p&#125;.block.0.alpha&quot;&#93;)
                residual = _conv1d(residual,
                                   _wn_weight(w&#91;f&quot;&#123;p&#125;.block.1.weight_v&quot;&#93;, w&#91;f&quot;&#123;p&#125;.block.1.weight_g&quot;&#93;),
                                   w&#91;f&quot;&#123;p&#125;.block.1.bias&quot;&#93;,
                                   padding=((7 - 1) * dilation) // 2,
                                   dilation=dilation)
                residual = _snake(residual, w&#91;f&quot;&#123;p&#125;.block.2.alpha&quot;&#93;)
                residual = _conv1d(residual, _wn_weight(w&#91;f&quot;&#123;p&#125;.block.3.weight_v&quot;&#93;, w&#91;f&quot;&#123;p&#125;.block.3.weight_g&quot;&#93;),
                                   w&#91;f&quot;&#123;p&#125;.block.3.bias&quot;&#93;)
                pad = (x.shape&#91;-1&#93; - residual.shape&#91;-1&#93;) // 2
                if pad &gt; 0:
                    x = x&#91;..., pad:-pad&#93;
                x = x + residual
            x = _snake(x, w&#91;f&quot;&#123;prefix&#125;.block.3.alpha&quot;&#93;)
            x = _conv1d(x,
                        _wn_weight(w&#91;f&quot;&#123;prefix&#125;.block.4.weight_v&quot;&#93;, w&#91;f&quot;&#123;prefix&#125;.block.4.weight_g&quot;&#93;),
                        w&#91;f&quot;&#123;prefix&#125;.block.4.bias&quot;&#93;,
                        stride=stride,
                        padding=math.ceil(stride / 2))
        snake_index = len(cfg.encoder_rates) + 1
        conv_index = len(cfg.encoder_rates) + 2
        x = _snake(x, w&#91;f&quot;encoder.block.&#123;snake_index&#125;.alpha&quot;&#93;)
        hidden = _conv1d(x,
                         _wn_weight(w&#91;f&quot;encoder.block.&#123;conv_index&#125;.weight_v&quot;&#93;,
                                    w&#91;f&quot;encoder.block.&#123;conv_index&#125;.weight_g&quot;&#93;),
                         w&#91;f&quot;encoder.block.&#123;conv_index&#125;.bias&quot;&#93;,
                         padding=1)

        projected = _ct(self._attention_projection(_ct(hidden, 0, 2, 1)), 0, 2, 1)
        mean = _conv1d(projected, w&#91;&quot;mean_proj.weight&quot;&#93;, w&#91;&quot;mean_proj.bias&quot;&#93;)
        logvar = _conv1d(projected, w&#91;&quot;logs_proj.weight&quot;&#93;, w&#91;&quot;logs_proj.bias&quot;&#93;)
        return mean, logvar

    def _attention_projection(self, hidden):
        &quot;&quot;&quot;MiniMaxH3AudioAttnProjection over (B, S, latent_dim).&quot;&quot;&quot;
        cfg = self.config
        w = self.weights
        num_heads = cfg.num_attention_heads
        head_dim = hidden.shape&#91;-1&#93; // num_heads
        batch, seq_len, _ = hidden.shape

        normed = _layer_norm(hidden, w&#91;&quot;pre_block.norm1.weight&quot;&#93;, w&#91;&quot;pre_block.norm1.bias&quot;&#93;)
        bias = mx.concatenate(&#91;w&#91;&quot;pre_block.attn.q_bias&quot;&#93;, w&#91;&quot;pre_block.attn.zero_k_bias&quot;&#93;, w&#91;&quot;pre_block.attn.v_bias&quot;&#93;&#93;)
        qkv = _linear(normed, w&#91;&quot;pre_block.attn.qkv.weight&quot;&#93;, bias)
        qkv = qkv.reshape(batch, seq_len, 3, num_heads, head_dim)
        query = _ct(qkv&#91;:, :, 0&#93;, 0, 2, 1, 3)  # (B, H, S, Dh)
        key = _ct(qkv&#91;:, :, 1&#93;, 0, 2, 1, 3)
        value = _ct(qkv&#91;:, :, 2&#93;, 0, 2, 1, 3)

        scores = (query @ _ct(key, 0, 1, 3, 2)) * head_dim**-0.5
        causal_mask = mx.triu(mx.ones((seq_len, seq_len), dtype=mx.bool_), k=1)
        scores = mx.where(causal_mask&#91;None, None&#93;, mx.array(-np.inf, dtype=scores.dtype), scores)
        attn_weights = mx.softmax(scores, axis=-1)
        attended = attn_weights @ value  # (B, H, S, Dh)
        attended = _ct(attended, 0, 2, 1, 3).mean(axis=2)  # head mean -&gt; (B, S, Dh)

        out_dim = cfg.latent_channels
        pool_factor = attended.shape&#91;-1&#93; // out_dim
        if attended.shape&#91;-1&#93; % out_dim != 0:
            raise ValueError(&quot;Attention head dimension must pool evenly into latent channels.&quot;)
        pooled = attended.reshape(batch, seq_len, out_dim, pool_factor).mean(axis=-1)
        attn_out = _linear(pooled, w&#91;&quot;pre_block.attn.proj.weight&quot;&#93;, w&#91;&quot;pre_block.attn.proj.bias&quot;&#93;)

        projected = _linear(_layer_norm(hidden, w&#91;&quot;pre_block.norm3.weight&quot;&#93;, w&#91;&quot;pre_block.norm3.bias&quot;&#93;),
                            w&#91;&quot;pre_block.proj.weight&quot;&#93;, w&#91;&quot;pre_block.proj.bias&quot;&#93;) + attn_out
        mlp_in = _layer_norm(projected, w&#91;&quot;pre_block.norm2.weight&quot;&#93;, w&#91;&quot;pre_block.norm2.bias&quot;&#93;)
        # GeGluMlp carries its own inner LayerNorm before w0/w1.
        mlp_normed = _layer_norm(mlp_in, w&#91;&quot;pre_block.mlp.norm.weight&quot;&#93;, w&#91;&quot;pre_block.mlp.norm.bias&quot;&#93;)
        gate = _gelu_tanh(_linear(mlp_normed, w&#91;&quot;pre_block.mlp.w0.weight&quot;&#93;, w&#91;&quot;pre_block.mlp.w0.bias&quot;&#93;))
        value_mlp = _linear(mlp_normed, w&#91;&quot;pre_block.mlp.w1.weight&quot;&#93;, w&#91;&quot;pre_block.mlp.w1.bias&quot;&#93;)
        mlp_out = _linear(gate * value_mlp, w&#91;&quot;pre_block.mlp.w2.weight&quot;&#93;, w&#91;&quot;pre_block.mlp.w2.bias&quot;&#93;)
        return projected + mlp_out

    # -- decoder ----------------------------------------------------------

    def decode(self, latents):
        &quot;&quot;&quot;Latents (B, 32, N) -&gt; waveforms (B, 1, S) clamped to &#91;-1, 1&#93;.&quot;&quot;&quot;
        cfg = self.config
        w = self.weights
        hidden = _conv1d(latents, w&#91;&quot;dec_in_proj.weight&quot;&#93;, w&#91;&quot;dec_in_proj.bias&quot;&#93;)
        hidden = _conv1d(hidden,
                         _wn_weight(w&#91;&quot;decoder.conv_pre.weight_v&quot;&#93;, w&#91;&quot;decoder.conv_pre.weight_g&quot;&#93;),
                         w&#91;&quot;decoder.conv_pre.bias&quot;&#93;,
                         padding=3)
        num_resblocks = len(cfg.resblock_kernel_sizes)
        for index, (rate, kernel) in enumerate(zip(cfg.decoder_rates, cfg.decoder_kernel_sizes, strict=False)):
            weight = _wn_weight(w&#91;f&quot;decoder.ups.&#123;index&#125;.0.weight_v&quot;&#93;, w&#91;f&quot;decoder.ups.&#123;index&#125;.0.weight_g&quot;&#93;)
            hidden = _conv_transpose1d(hidden,
                                       weight,
                                       w&#91;f&quot;decoder.ups.&#123;index&#125;.0.bias&quot;&#93;,
                                       stride=rate,
                                       padding=(kernel - rate) // 2)
            residual_sum = None
            for j in range(num_resblocks):
                out = self._amp_block(hidden, f&quot;decoder.resblocks.&#123;index * num_resblocks + j&#125;&quot;,
                                      cfg.resblock_kernel_sizes&#91;j&#93;, cfg.resblock_dilation_sizes&#91;j&#93;)
                residual_sum = out if residual_sum is None else residual_sum + out
            if residual_sum is None:
                raise RuntimeError(&quot;H3 audio VAE decoder has no residual blocks.&quot;)
            hidden = residual_sum / num_resblocks
        alpha = w&#91;&quot;decoder.activation_post.act.alpha&quot;&#93;
        beta = w&#91;&quot;decoder.activation_post.act.beta&quot;&#93;
        up_filter = self._filter(&quot;decoder.activation_post.upsample.filter&quot;)
        down_filter = self._filter(&quot;decoder.activation_post.downsample.lowpass.filter&quot;)
        hidden = _activation1d(hidden, alpha, beta, up_filter, down_filter)
        hidden = _conv1d(hidden,
                         _wn_weight(w&#91;&quot;decoder.conv_post.weight_v&quot;&#93;, w&#91;&quot;decoder.conv_post.weight_g&quot;&#93;),
                         w.get(&quot;decoder.conv_post.bias&quot;),
                         padding=3)
        return mx.clip(hidden, -1.0, 1.0)

    def _amp_block(self, x, prefix: str, kernel_size: int, dilations: tuple&#91;int, ...&#93;):
        &quot;&quot;&quot;MiniMaxH3AudioAMPBlock: per dilation, act -&gt; conv1 -&gt; act -&gt; conv2 + skip.&quot;&quot;&quot;
        w = self.weights
        for j, dilation in enumerate(dilations):
            pad1 = (kernel_size * dilation - dilation) // 2
            pad2 = (kernel_size - 1) // 2
            up1 = self._filter(f&quot;&#123;prefix&#125;.activations.&#123;2 * j&#125;.upsample.filter&quot;)
            down1 = self._filter(f&quot;&#123;prefix&#125;.activations.&#123;2 * j&#125;.downsample.lowpass.filter&quot;)
            residual = _activation1d(x, w&#91;f&quot;&#123;prefix&#125;.activations.&#123;2 * j&#125;.act.alpha&quot;&#93;,
                                     w&#91;f&quot;&#123;prefix&#125;.activations.&#123;2 * j&#125;.act.beta&quot;&#93;, up1, down1)
            residual = _conv1d(residual,
                               _wn_weight(w&#91;f&quot;&#123;prefix&#125;.convs1.&#123;j&#125;.weight_v&quot;&#93;, w&#91;f&quot;&#123;prefix&#125;.convs1.&#123;j&#125;.weight_g&quot;&#93;),
                               w&#91;f&quot;&#123;prefix&#125;.convs1.&#123;j&#125;.bias&quot;&#93;,
                               padding=pad1,
                               dilation=dilation)
            up2 = self._filter(f&quot;&#123;prefix&#125;.activations.&#123;2 * j + 1&#125;.upsample.filter&quot;)
            down2 = self._filter(f&quot;&#123;prefix&#125;.activations.&#123;2 * j + 1&#125;.downsample.lowpass.filter&quot;)
            residual = _activation1d(residual, w&#91;f&quot;&#123;prefix&#125;.activations.&#123;2 * j + 1&#125;.act.alpha&quot;&#93;,
                                     w&#91;f&quot;&#123;prefix&#125;.activations.&#123;2 * j + 1&#125;.act.beta&quot;&#93;, up2, down2)
            residual = _conv1d(residual,
                               _wn_weight(w&#91;f&quot;&#123;prefix&#125;.convs2.&#123;j&#125;.weight_v&quot;&#93;, w&#91;f&quot;&#123;prefix&#125;.convs2.&#123;j&#125;.weight_g&quot;&#93;),
                               w&#91;f&quot;&#123;prefix&#125;.convs2.&#123;j&#125;.bias&quot;&#93;,
                               padding=pad2)
            x = residual + x
        return x</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.normalize_latents"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.normalize_latents</code></h3>
<pre class="doc-signature"><code>normalize_latents(latents)</code></pre>

<details><summary>Source</summary><pre><code>def normalize_latents(self, latents):
    return (latents - mx.array(self._latents_mean)) / mx.array(self._latents_std)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.denormalize_latents"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.denormalize_latents</code></h3>
<pre class="doc-signature"><code>denormalize_latents(latents)</code></pre>

<details><summary>Source</summary><pre><code>def denormalize_latents(self, latents):
    return latents * mx.array(self._latents_std) + mx.array(self._latents_mean)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.encode"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.encode</code></h3>
<pre class="doc-signature"><code>encode(waveform)</code></pre>
<p>Mono waveform (1, 1, S) -&gt; posterior mean/logvar each (1, C, N).</p>
<details><summary>Source</summary><pre><code>def encode(self, waveform):
    &quot;&quot;&quot;Mono waveform (1, 1, S) -&gt; posterior mean/logvar each (1, C, N).&quot;&quot;&quot;
    if not self.has_encoder:
        raise RuntimeError(&quot;This MLX H3 audio VAE was loaded without encoder weights.&quot;)
    cfg = self.config
    w = self.weights
    samples = waveform.shape&#91;-1&#93;
    right_pad = math.ceil(samples / cfg.hop_length) * cfg.hop_length - samples
    if right_pad &gt; 0:
        waveform = mx.pad(waveform, ((0, 0), (0, 0), (0, right_pad)))

    x = _conv1d(waveform,
                _wn_weight(w&#91;&quot;encoder.block.0.weight_v&quot;&#93;, w&#91;&quot;encoder.block.0.weight_g&quot;&#93;),
                w&#91;&quot;encoder.block.0.bias&quot;&#93;,
                padding=3)
    dim = cfg.encoder_dim
    for index, stride in enumerate(cfg.encoder_rates, start=1):
        prefix = f&quot;encoder.block.&#123;index&#125;&quot;
        dim *= 2
        # Three residual units with dilations 1, 3, 9 at dim//2 channels.
        for unit, dilation in enumerate((1, 3, 9)):
            p = f&quot;&#123;prefix&#125;.block.&#123;unit&#125;&quot;
            residual = _snake(x, w&#91;f&quot;&#123;p&#125;.block.0.alpha&quot;&#93;)
            residual = _conv1d(residual,
                               _wn_weight(w&#91;f&quot;&#123;p&#125;.block.1.weight_v&quot;&#93;, w&#91;f&quot;&#123;p&#125;.block.1.weight_g&quot;&#93;),
                               w&#91;f&quot;&#123;p&#125;.block.1.bias&quot;&#93;,
                               padding=((7 - 1) * dilation) // 2,
                               dilation=dilation)
            residual = _snake(residual, w&#91;f&quot;&#123;p&#125;.block.2.alpha&quot;&#93;)
            residual = _conv1d(residual, _wn_weight(w&#91;f&quot;&#123;p&#125;.block.3.weight_v&quot;&#93;, w&#91;f&quot;&#123;p&#125;.block.3.weight_g&quot;&#93;),
                               w&#91;f&quot;&#123;p&#125;.block.3.bias&quot;&#93;)
            pad = (x.shape&#91;-1&#93; - residual.shape&#91;-1&#93;) // 2
            if pad &gt; 0:
                x = x&#91;..., pad:-pad&#93;
            x = x + residual
        x = _snake(x, w&#91;f&quot;&#123;prefix&#125;.block.3.alpha&quot;&#93;)
        x = _conv1d(x,
                    _wn_weight(w&#91;f&quot;&#123;prefix&#125;.block.4.weight_v&quot;&#93;, w&#91;f&quot;&#123;prefix&#125;.block.4.weight_g&quot;&#93;),
                    w&#91;f&quot;&#123;prefix&#125;.block.4.bias&quot;&#93;,
                    stride=stride,
                    padding=math.ceil(stride / 2))
    snake_index = len(cfg.encoder_rates) + 1
    conv_index = len(cfg.encoder_rates) + 2
    x = _snake(x, w&#91;f&quot;encoder.block.&#123;snake_index&#125;.alpha&quot;&#93;)
    hidden = _conv1d(x,
                     _wn_weight(w&#91;f&quot;encoder.block.&#123;conv_index&#125;.weight_v&quot;&#93;,
                                w&#91;f&quot;encoder.block.&#123;conv_index&#125;.weight_g&quot;&#93;),
                     w&#91;f&quot;encoder.block.&#123;conv_index&#125;.bias&quot;&#93;,
                     padding=1)

    projected = _ct(self._attention_projection(_ct(hidden, 0, 2, 1)), 0, 2, 1)
    mean = _conv1d(projected, w&#91;&quot;mean_proj.weight&quot;&#93;, w&#91;&quot;mean_proj.bias&quot;&#93;)
    logvar = _conv1d(projected, w&#91;&quot;logs_proj.weight&quot;&#93;, w&#91;&quot;logs_proj.bias&quot;&#93;)
    return mean, logvar</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.decode"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.MLXMiniMaxH3AudioVAE.decode</code></h3>
<pre class="doc-signature"><code>decode(latents)</code></pre>
<p>Latents (B, 32, N) -&gt; waveforms (B, 1, S) clamped to [-1, 1].</p>
<details><summary>Source</summary><pre><code>def decode(self, latents):
    &quot;&quot;&quot;Latents (B, 32, N) -&gt; waveforms (B, 1, S) clamped to &#91;-1, 1&#93;.&quot;&quot;&quot;
    cfg = self.config
    w = self.weights
    hidden = _conv1d(latents, w&#91;&quot;dec_in_proj.weight&quot;&#93;, w&#91;&quot;dec_in_proj.bias&quot;&#93;)
    hidden = _conv1d(hidden,
                     _wn_weight(w&#91;&quot;decoder.conv_pre.weight_v&quot;&#93;, w&#91;&quot;decoder.conv_pre.weight_g&quot;&#93;),
                     w&#91;&quot;decoder.conv_pre.bias&quot;&#93;,
                     padding=3)
    num_resblocks = len(cfg.resblock_kernel_sizes)
    for index, (rate, kernel) in enumerate(zip(cfg.decoder_rates, cfg.decoder_kernel_sizes, strict=False)):
        weight = _wn_weight(w&#91;f&quot;decoder.ups.&#123;index&#125;.0.weight_v&quot;&#93;, w&#91;f&quot;decoder.ups.&#123;index&#125;.0.weight_g&quot;&#93;)
        hidden = _conv_transpose1d(hidden,
                                   weight,
                                   w&#91;f&quot;decoder.ups.&#123;index&#125;.0.bias&quot;&#93;,
                                   stride=rate,
                                   padding=(kernel - rate) // 2)
        residual_sum = None
        for j in range(num_resblocks):
            out = self._amp_block(hidden, f&quot;decoder.resblocks.&#123;index * num_resblocks + j&#125;&quot;,
                                  cfg.resblock_kernel_sizes&#91;j&#93;, cfg.resblock_dilation_sizes&#91;j&#93;)
            residual_sum = out if residual_sum is None else residual_sum + out
        if residual_sum is None:
            raise RuntimeError(&quot;H3 audio VAE decoder has no residual blocks.&quot;)
        hidden = residual_sum / num_resblocks
    alpha = w&#91;&quot;decoder.activation_post.act.alpha&quot;&#93;
    beta = w&#91;&quot;decoder.activation_post.act.beta&quot;&#93;
    up_filter = self._filter(&quot;decoder.activation_post.upsample.filter&quot;)
    down_filter = self._filter(&quot;decoder.activation_post.downsample.lowpass.filter&quot;)
    hidden = _activation1d(hidden, alpha, beta, up_filter, down_filter)
    hidden = _conv1d(hidden,
                     _wn_weight(w&#91;&quot;decoder.conv_post.weight_v&quot;&#93;, w&#91;&quot;decoder.conv_post.weight_g&quot;&#93;),
                     w.get(&quot;decoder.conv_post.bias&quot;),
                     padding=3)
    return mx.clip(hidden, -1.0, 1.0)</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.mlx_h3_audio_vae_from_file"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.mlx_h3_audio_vae_from_file</code></h2>
<pre class="doc-signature"><code>mlx_h3_audio_vae_from_file(weights_path: str | Path, *, include_encoder: bool = True, config: MiniMaxH3AudioVAEConfigView | None = None, component_dir: str | Path | None = None) -&gt; MLXMiniMaxH3AudioVAE</code></pre>
<p>Load the released audio VAE from its single safetensors file.</p>
<p>The released checkpoint is ~605 MB fp32; it is read whole (bounded) and
kept at release precision.</p>
<details><summary>Source</summary><pre><code>def mlx_h3_audio_vae_from_file(weights_path: str | Path,
                               *,
                               include_encoder: bool = True,
                               config: MiniMaxH3AudioVAEConfigView | None = None,
                               component_dir: str | Path | None = None) -&gt; MLXMiniMaxH3AudioVAE:
    &quot;&quot;&quot;Load the released audio VAE from its single safetensors file.

    The released checkpoint is ~605 MB fp32; it is read whole (bounded) and
    kept at release precision.
    &quot;&quot;&quot;
    weights_path = Path(weights_path)
    if config is None:
        if component_dir is None:
            component_dir = weights_path.parent
        config = MiniMaxH3AudioVAEConfigView.from_vae_dir(component_dir)
    arrays = mx.load(str(weights_path))
    wanted_prefixes: tuple&#91;str, ...&#93; = (&quot;dec_in_proj.&quot;, &quot;decoder.&quot;, &quot;mean_proj.&quot;, &quot;logs_proj.&quot;)
    if include_encoder:
        wanted_prefixes += (&quot;encoder.&quot;, &quot;pre_block.&quot;)
    weights: dict&#91;str, Any&#93; = &#123;&#125;
    for key in arrays:
        if key.startswith(wanted_prefixes):
            weights&#91;key&#93; = arrays&#91;key&#93;
    del arrays
    gc.collect()
    mx.clear_cache()
    required = &#91;&quot;dec_in_proj.weight&quot;, &quot;decoder.conv_pre.weight_v&quot;, &quot;decoder.conv_post.weight_v&quot;&#93;
    if include_encoder:
        required.extend(
            (&quot;mean_proj.weight&quot;, &quot;logs_proj.weight&quot;, &quot;pre_block.attn.qkv.weight&quot;, &quot;encoder.block.0.weight_v&quot;))
    missing = &#91;key for key in required if key not in weights&#93;
    if missing:
        raise KeyError(f&quot;H3 audio VAE is missing required tensors: &#123;missing&#125;&quot;)
    return MLXMiniMaxH3AudioVAE(weights, config, include_encoder=include_encoder)</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_audio_vae.mlx_h3_audio_vae_from_dir"><code>fastvideo.mlx_runtime.minimax_h3_audio_vae.mlx_h3_audio_vae_from_dir</code></h2>
<pre class="doc-signature"><code>mlx_h3_audio_vae_from_dir(component_dir: str | Path, *, include_encoder: bool = True, storage_dtype: str = &#x27;fp32&#x27;) -&gt; MLXMiniMaxH3AudioVAE</code></pre>
<p>Load from the released component directory (audio_vae/).</p>
<details><summary>Source</summary><pre><code>def mlx_h3_audio_vae_from_dir(component_dir: str | Path,
                              *,
                              include_encoder: bool = True,
                              storage_dtype: str = &quot;fp32&quot;) -&gt; MLXMiniMaxH3AudioVAE:
    &quot;&quot;&quot;Load from the released component directory (audio_vae/).&quot;&quot;&quot;
    if storage_dtype != &quot;fp32&quot;:
        raise ValueError(f&quot;H3 audio VAE numerics require storage_dtype=&#x27;fp32&#x27;, got &#123;storage_dtype!r&#125;.&quot;)

    component_dir = Path(component_dir)
    single = component_dir / &quot;diffusion_pytorch_model.safetensors&quot;
    if not single.exists():
        raise FileNotFoundError(f&quot;No audio VAE safetensors under &#123;component_dir&#125;&quot;)
    return mlx_h3_audio_vae_from_file(single, include_encoder=include_encoder, component_dir=component_dir)</code></pre></details>
</div>
