#!/usr/bin/env python3 """Write, or check, the vectors of the neural audio route: wai-rs/tests/vectors/neural_audio/. One vector for each capability whose payload SPEC §5 pins (*Payloads of the neural audio codecs*): `wai.neural.encodec24`, `wai.neural.encodec48`, `wai.neural.dac16` and `wai.neural.dac24`. Each directory holds decoder.onnx a tiny decoder with the model's geometry and its decoder contract: the model's codebook count Q, codebooks of 1024, a hop of 320, its channels; inputs audio_codes int64 [1, 1, Q, T] and audio_scales float [1], output audio_values float [1, C, T*320 - d] (d = 8 for DAC 16 and 24 kHz, whose decoders give 8 samples fewer, else 0). Its network is not the model's: a code c of codebook i adds c*A[i] + B[i] to the frame's latent z (a row holding 1024 adds nothing), and sample k of the frame on channel ch is tanh(z * W[ch][k]) * scale, the last d samples dropped. A, B and W are dyadic, so every value before the tanh is exact in float32. vector.wai a WAI1 envelope of the capability, pinned to decoder.onnx, whose payload is seeded codes in the pinned layout (some codebooks only, so the route must mark the others unused; for encodec48, two chunks with their own scales). expected.f32 the decode at the samples meta.json selects, every channel of each, as little-endian float32, computed here in Python from the payload and the decoder's parameters: the second implementation of the route, which reads the payload, fills the codebooks, runs the network and joins the chunks by the model's linear overlap-add on its own. meta.json what the vector is, and which samples expected.f32 holds: index i where i % every == 0 or i lies in an overlap region. The ONNX files are written here, protobuf field by field, so the generator needs nothing but the standard library and its bytes are the same on every machine. python3 -I tools/wai_neural_audio_vectors.py # write the vectors python3 -I tools/wai_neural_audio_vectors.py --check # rebuild them and compare --check exits 0 when every committed file is what the generator writes (expected.f32 within 1e-6, since it holds a libm tanh), 1 otherwise. """ import hashlib import json import math import os import struct import sys HERE = os.path.dirname(os.path.abspath(__file__)) OUT = os.path.join(HERE, "..", "wai-rs", "tests", "vectors", "neural_audio") K = 1024 # entries per codebook; the value that marks a codebook not used HOP = 320 # name: capability, sample rate, channels, model codebooks Q, codebooks carried q, frames of each # chunk, samples per channel n, chunk scales (None: no chunks), chunk stride, the samples the # decoder gives fewer than frames*320 (DAC 16 and 24 kHz: 8), seed VECTORS = { "encodec24": ("wai.neural.encodec24", 24000, 1, 32, 8, [5], 1523, None, 0, 0, 1), "encodec48": ("wai.neural.encodec48", 48000, 2, 16, 4, [150, 6], 49340, [0.75, 0.5], 47520, 0, 4), "dac16": ("wai.neural.dac16", 16000, 1, 12, 5, [4], 1201, None, 0, 8, 2), "dac24": ("wai.neural.dac24", 24000, 1, 32, 32, [3], 950, None, 0, 8, 3), } # ---- the decoder's parameters ------------------------------------------------------------- def params(Q, C): """A[i] = a/2^16, B[i] = b/2^8, W[ch][k] = w/2^4: |z| < 4 in steps of 2^-16, and z*W takes at most 22 significant bits, so every value before the tanh is exact in float32.""" A = [[1, -2, 3, -4, 4, -3, 2, -1][i % 8] / 65536.0 for i in range(Q)] B = [(((i * 5) % 17) - 8) / 256.0 for i in range(Q)] W = [[(((k * 3 + ch * 5) % 31) - 15) / 16.0 for k in range(HOP)] for ch in range(C)] return A, B, W # ---- protobuf, as much of onnx.proto as the decoder needs --------------------------------- def varint(v): out = bytearray() v &= (1 << 64) - 1 while True: b = v & 0x7F v >>= 7 if v: out.append(b | 0x80) else: out.append(b) return bytes(out) def fv(field, v): return varint(field << 3) + varint(v) def fb(field, b): if isinstance(b, str): b = b.encode() return varint((field << 3) | 2) + varint(len(b)) + b FLOAT, INT64, BOOL = 1, 7, 9 def tensor(name, dtype, dims, raw): # TensorProto: dims = 1, data_type = 2, name = 8, raw_data = 9. return b"".join(fv(1, d) for d in dims) + fv(2, dtype) + fb(8, name) + fb(9, raw) def f32s(xs): return b"".join(struct.pack("> 30)) * 0xBF58476D1CE4E5B9) & ((1 << 64) - 1) z = ((z ^ (z >> 27)) * 0x94D049BB133111EB) & ((1 << 64) - 1) yield z ^ (z >> 31) def chunks_of(q, frames, seed): """Each chunk's codes: q rows of its frame count, codebook-major.""" g = splitmix64(seed) return [[[next(g) % K for _ in range(t)] for _ in range(q)] for t in frames] def payload(q, frames, n, scales, chunks): if scales is None: head = struct.pack(" 1e-6: print(f"{name}/{fname}: {len(g)} values, max |diff| {worst:.2e}; want {len(w)} within 1e-6") bad += 1 elif got != want: print(f"{name}/{fname}: differs from what the generator writes") bad += 1 print(f"{name}: {'checked' if check else 'written'}") return 1 if bad else 0 if __name__ == "__main__": sys.exit(main(sys.argv))