"""Audio front-end for DiffusionGemma. Two designs were tried: * encoder-free raw-waveform projection (Gemma-4-12B-Unified style) — FAILED to ground on content with a frozen/LoRA backbone: a shallow projector can't do acoustic feature extraction, and a frozen LLM (never trained on audio) can't either. WER plateaued at ~94% (fluent but audio-ignoring). * frozen Whisper encoder + lightweight projector (this file) — the encoder supplies acoustic→linguistic features the frozen LLM can actually read; only the projector (+ decoder LoRA) trains. This is the working path. The Whisper encoder (open, MIT, frozen) is a feature extractor, NOT a decoder — the diffusion LLM still performs recognition via its denoising mechanism. """ from __future__ import annotations import torch import torch.nn as nn SAMPLE_RATE = 16000 WHISPER_HOP = 160 # 10 ms mel hop @ 16 kHz WHISPER_MEL_FRAMES = 3000 # Whisper always pads/trims to 30 s WHISPER_ENC_FRAMES = 1500 # encoder downsamples mel by 2 def audio_out_len(n_frames: int, subsample_factor: int) -> int: """Audio-token count the projector emits for `n_frames` encoder frames. Shared by projector and collator so the number of