wai: the int_codec audio trained on a generated signal, and every corpus states its provenance #184

Merged
dcharlot merged 10 commits from wai/audio-provenance into main 2026-10-07 21:26:28 -04:00
68 changed files with 1257 additions and 249 deletions

View file

@ -63,6 +63,8 @@ on:
- 'wai/extensions/moq-streaming-format.md'
- 'wai/extensions/jwp-receipts.md'
- 'wai/wai-web/**'
# The audio provenance check below reads the corpora above with this tool.
- 'wai/tools/wai_audio_provenance_check.py'
- '.github/workflows/wai-conformance.yml'
pull_request:
paths:
@ -94,6 +96,8 @@ on:
- 'wai/extensions/moq-streaming-format.md'
- 'wai/extensions/jwp-receipts.md'
- 'wai/wai-web/**'
# The audio provenance check below reads the corpora above with this tool.
- 'wai/tools/wai_audio_provenance_check.py'
- '.github/workflows/wai-conformance.yml'
# No global `shell:` default. The Windows runner is a host executor whose
@ -268,9 +272,10 @@ jobs:
# tests/manifest_builders.rs: the manifest types are #[non_exhaustive], and the
# builders write the JSON a struct literal wrote; members the types keep only
# as `extra` (and `security`) survive a round trip.
- name: Carriage conformance and the wai CLI (wrap, registry export)
# corpus_provenance: every corpus README states where its content comes from.
- name: Carriage conformance, the wai CLI (wrap, registry export) and corpus provenance
working-directory: wai/wai-rs
run: cargo test --no-default-features --test carriage --test manifest_builders --test cli_wrap_intent --test cli_registry
run: cargo test --no-default-features --test carriage --test manifest_builders --test cli_wrap_intent --test cli_registry --test corpus_provenance
# tests/cli_http.rs runs `wai http publish`, `codecs`, `origin` and `bench` as a user
# does: objects named by their content hash with their head proofs, a sequence's union
# and floor, the origin's headers, ranges and If-Range on loopback, and a fetch by
@ -382,6 +387,24 @@ jobs:
shell: bash
working-directory: wai
run: python3 pin-conformance/pin_verify.py pin-conformance
# Every committed audio vector must come from a seeded generator. This check reads
# each one to PCM (each audio base's stage 0 in the staged corpus, each measured
# source over one, each spatial-audio source, every audio file under wai/) and
# fails if any correlates above 0.5, at any lag, with a recording in the reference
# set the host has: its system sound directory, or the directories named in
# WAI_AUDIO_REFERENCE_DIRS. A generated signal stays near 0.2; a lossy coding of a
# recording is near 1. A host with no reference set, or no converter to read it,
# prints why and skips: the linux legs skip, the macOS leg checks.
- name: No committed audio vector is a coding of a reference recording (unix)
if: matrix.os != 'windows'
shell: bash
working-directory: wai
run: |
if command -v python3 >/dev/null 2>&1; then
python3 tools/wai_audio_provenance_check.py
else
echo "audio provenance: SKIPPED — no python3 on this host"
fi
# OER's second implementation is portable C, not Rust. Rebuild it from source and
# require its output to match the pinned corpus byte for byte: the kernel is
# deterministic, and wai_oer_vectors above has already verified the pinned copy,

View file

@ -6,6 +6,35 @@ wire format may change and such changes are recorded here.
## v0.4.0 — current
### The int_codec model and vectors: trained and coded on a generated signal
- The int_codec model and vectors are now trained and coded on a generated signal;
earlier revisions used a third-party recording.
- `tools/wai_int_audio_export.py` reads no audio file. It writes its training signal
and the clip it codes from a seed (16 kHz mono: tones, chirps, noise bursts and
speech-like formant sweeps), in integer arithmetic, so a seed gives the same samples
on every machine; `--signal-only` writes one with the Python standard library alone.
Training is seeded from the same seed with deterministic algorithms and a fixed
thread count: two runs gave byte-identical files. The seed and the command are in
[`wai-rs/tests/vectors/int_audio/README.md`](wai-rs/tests/vectors/int_audio/README.md).
- Regenerated through their generators: `wai-rs/tests/vectors/int_audio/` (the model,
both bitstream forms, `audio.json`, `sha256.json`); `int-payload-conformance`'s
`vectors.json` and its thirteen `wia1_*` refusal fixtures; the staged-delivery case
`audio_int_codec_1l` and `index.json`; the staged-measurement audio title,
`goldens.json` and `sim/results.json`. The `WIA1` format, the capability and the
model's shape are unchanged. `wai_int_payload_vectors` now reads the place of a
`WIA1`'s first table from the payload's header for the two fixtures that change it, so
they keep their meaning on tables of another length (on the earlier vector the
offsets are the same).
- `tools/wai_audio_provenance_check.py`, run by CI: every committed audio vector is read
to PCM and correlated, at every lag, with the reference recordings the CI host has;
above 0.5 it fails, and a host with none skips it and says so.
- Every corpus states its content's provenance: a `**Provenance.**` line in each
`*-conformance/README.md` (OER/2's settled corpus aside) and a row per directory in
`wai-rs/tests/vectors/README.md`, required by `tests/corpus_provenance.rs`.
CONTRIBUTING states the rule. Two vectors are flagged there as not generated and to
be replaced: `int_video`'s `video_real` and `neural-conformance`'s `photo`.
### Staged tracks over MoQ: a track per layer, a receipts track per track, delivery timeouts per hop, chains that recover
- **Re-read against the drafts.** [moq-streaming-format](extensions/moq-streaming-format.md)

View file

@ -70,6 +70,21 @@ generator (the `wai_*_vectors gen` binaries and the export tools in
[`tools/`](tools/)), never by hand. A test whose comment says its hex must never
be edited to make it pass means exactly that.
### Corpus content: where it comes from
Corpus content is generated in this repository, by a generator from a seed or a
formula, or it is an input whose source and licence are recorded and whose licence
permits redistribution. An image, a recording or footage that was not made here and
has no such licence is not committed, as content or as training data.
Every corpus states its provenance: each `*-conformance/README.md` in a line that
begins `**Provenance.**`, and `wai-rs/tests/vectors/README.md` in a row for each
vector directory. The line names the generator and its input, and for an input not
generated here, its source and licence. A word such as "synthetic" is not a
provenance line. `wai-rs/tests/corpus_provenance.rs` requires the line in every
corpus, and `tools/wai_audio_provenance_check.py`, which CI runs, fails when a
committed audio vector correlates with a reference recording the host has.
### Independent implementations
Conformance is defined by the committed corpora (`*-conformance/`) and the

View file

@ -6,6 +6,8 @@ layout, a conforming sink MUST produce the identical canonical PCM,
hence the identical BLAKE3 — on every machine, no tolerance parameter.
The audio counterpart of replay-equivalence.
**Provenance.** Generated here: `wai_audio_vectors gen` writes every scene and its sources, square-wave tones built in code. No recording.
All vectors mix to the mandatory `stereo` floor under the
`wai.det.fixed64` numeric profile, `wai.audio.pan.sqrt_constpower` pan,
`wai.audio.dist.inverse_clamped` distance. Sources are deterministic

View file

@ -10,6 +10,8 @@ quaternion + scale, all `wai.det.fixed64`); the forward-kinematics
composition into world space and the skinning of a `wai.mesh.glb` are
the sink's presentation, never in the hash.
**Provenance.** Generated here: `wai_avatar_vectors gen` writes every vector from rigs and motion authored in code. No capture.
The container is the worlds `WWLD`; the sim is `wai.world.sim.skeletal0`
(the identity step — a pose changes only when a signed op sets a joint).
Mutations: `CREATE` / `DELETE` / `SET_ROTATION` / `SET_TRANSLATION` /

View file

@ -0,0 +1,14 @@
# byte-exact-conformance — cross-architecture byte equality
A crate that compiles WAI's pure-integer decode paths (the rANS entropy coder and the
integer fixed-point syntheses, `#[path]`-included from `wai-rs`) without the system
codec libraries, so the byte-equality matrices (`.github/workflows/wai-byte-equality.yml`,
and *cross-arch byte-equality* in `wai-conformance.yml`) run them on every OS and
architecture. `cargo test --release` here decodes the committed vectors and the
staged-delivery corpus to the goldens in `src/*_golden.rs`, generated once on a
reference machine, and must match them on every machine.
**Provenance.** The goldens are digests of decodes of the vectors under
[`../wai-rs/tests/vectors/`](../wai-rs/tests/vectors/) and of the staged-delivery
corpus; that directory's README states each vector's provenance. Among them, the
`int_video` half-pel clip (`video_real`) is not generated content (see there).

View file

@ -5,6 +5,8 @@ an HTTP cache that fronts an origin serving the objects of
[`http-conformance/`](../http-conformance/), and reports, per cache label and version,
whether the configuration meets each rule.
**Provenance.** Written here: the tests, the driver and the controls are the code in this directory, and the objects a run fetches are `http-conformance`'s (see its provenance). No media of its own.
| file | what |
|---|---|
| `tests.json` | the tests: id, rule, level (MUST or informative) and what each checks |

View file

@ -6,6 +6,8 @@ Conformance for [typed receipt classes and the soft binding class](../extensions
`operating-point`, `stage`, `delivery-gap` and `reconstruct-session`, and recovery
through a soft binding under the ancestor rule.
**Provenance.** Generated here by `wai_claim_vectors`, from fixed seeds and fixed values (below). No media.
Each vector declares **one outcome**: `accept` — with the claim's `link_hash`, which
pins the canonical form, or for a recovery the ancestor it attests — or `reject` at a
named §3.1 step with a named reason. A verifier that rejects for another reason, or at

View file

@ -9,6 +9,8 @@ non-physics world whose sim (`wai.world.sim.feed0`) is the identity
step; convergence comes entirely from applying typed-field updates in
the canonical total order.
**Provenance.** Generated here: `wai_feed_vectors gen` writes every vector from feeds authored in code. No recorded data.
The container is the worlds `WWLD`; the node is a record of
self-describing typed cells (`Int` i64, `Fixed` Q32.32, `Text` UTF-8).
Mutations: `CREATE` / `DELETE` / `SET_CELL` (LWW) and `ADD_INT` /

View file

@ -7,6 +7,8 @@ tick || the interpolated camera pose)` — hence the identical per-frame
hashes and the identical Merkle root over them, on every machine, no
tolerance parameter.
**Provenance.** Generated here: `wai_film_vectors gen` writes every vector from shots authored in code. No footage.
A film composes two things already proven elsewhere: the embedded world's
**replay-equivalence** (every sink agrees on the state hash at every tick —
the `world-conformance/` corpus) and the `wai.det.fixed64` camera track

View file

@ -7,6 +7,8 @@ the identical canonical `u8` buffer (per-channel interleaved
machine, no tolerance parameter. The touch counterpart of
replay/mixdown-equivalence, with the tick replaced by the haptic sample.
**Provenance.** Generated here: `wai_haptic_vectors gen` writes every vector from envelopes authored in code. No recording.
All vectors reconstruct in the `wai.det.fixed64` floor (Fx linear
interpolation of the keyframed envelope → u8). Signals are
self-contained (no external sources), so each vector is just a `.whap`

View file

@ -16,6 +16,8 @@ reference adaptation policies. Two implementations check every case and must agr
`../claim-conformance/_blake3.py` (BLAKE3 from its specification) and
`../registry/capabilities.json` (the published registry export).
**Provenance.** Generated here by `wai_http_vectors`, from a staged-delivery case and from the frozen sources `src/SOURCES.json` lists, each encoded once by an encoder of its format: pictures of the `int_mlicpp` vector's generated 64×64 pattern, AV1 colour-bar test patterns, and a clip of a square moving over a gradient. The test patterns and the clip are generated content whose generators are not in this tree. None is a recording or a photograph.
## Files
| path | what |

View file

@ -6,6 +6,8 @@ Vectors for the payload formats SPEC §5 pins to the WAI-native integer codecs
for `wai.neural.int_hyper`, `WIA1` for `wai.audio.int_codec` and `WIS1` for
`wai.splat.int_codec`.
**Provenance.** Generated here: `wai_int_payload_vectors gen` converts the vectors under `../wai-rs/tests/vectors/` and changes them for the refusal fixtures; `tests/vectors/README.md` states each vector's provenance. One payload indexed here is not generated content: `video_real` (`int_video`) codes a third-party image (see there).
**Code-equivalence.** A conforming sink decodes every payload to the output digests
its vector states, and refuses every fixture with the code it states, from the
extension's closed list (§8).

View file

@ -59,7 +59,7 @@
"name": "audio",
"capability": "wai.audio.int_codec",
"payload": "wai-rs/tests/vectors/int_audio/audio_bitstream.wia1",
"payload_sha256": "b45e727525f06ac1ac5a5a7121886c85a7c33613451acbb482c20e37f3c79055",
"payload_sha256": "e4343c9468f6c7b652f911e24e273223ef14feaa7014df014f2d99e9f28e1b3b",
"converted_from": {
"json": "wai-rs/tests/vectors/int_audio/audio_bitstream.json",
"sample_rate": "wai-rs/tests/vectors/int_audio/audio.json"

View file

@ -11,6 +11,8 @@ read as signed only where a signed statement restates it; one chain for each key
track; and an object whose receipt is checked without its envelope reported as
`inclusion-verified`, never as delivered.
**Provenance.** Generated here by `wai_jwp_vectors`, from fixed seeds (below). No media.
## Files
| file | what it is |

View file

@ -7,6 +7,8 @@ because its synthesis is pure `i64` arithmetic (integer transposed
convolutions + arithmetic-shift requantize + integer ReLU), not float ONNX.
Two sinks honoring the spec produce the same bytes on every architecture.
**Provenance.** `gradient`, `bloom` and `facade` are generated here by `wai_int_synth_vectors` from a fixed SplitMix64 sequence. `photo` is not: it codes a third-party picture that was not made for this repository and has no recorded licence for redistribution, and its decoder was trained on images that are not recorded. It is to be replaced by generated content.
The float decoders (`bmshj2018`, `mbt2018_mean`, `elic`, `mlicpp`, …) are
deliberately **not** here: their ONNX synthesis is float, so two conforming
sinks on different hardware may differ in the low bits — a byte-equality
@ -44,9 +46,9 @@ is reproducible without a float RNG:
- `facade` — 16×16 latent, 3 ch → ×2 → ×2 → refine = 72×72 RGB, three
layers, two ReLUs (a deeper integer stack).
And one **real trained model on a real photograph**:
- `photo` — a 128×128 macOS *Sonoma* landscape, encoded to a 6,156-byte int8
latent (96×8×8) + a four-layer integer decoder **trained on real images**
And one **real trained model**, on a third-party picture (see *Provenance*, above):
- `photo` — a 128×128 third-party picture, encoded to a 6,156-byte int8
latent (96×8×8) + a four-layer integer decoder trained on images the corpus does not record
(`tools/wai_int_synth_real.py`: float-train + post-training quantization with
per-layer activation-scale calibration). Reconstruction ≈ 21.6 dB at ~3 bpp.
This is the honest scope of int_synth: a pure integer transposed-conv decoder
@ -54,8 +56,8 @@ And one **real trained model on a real photograph**:
that the decode is bit-identical on every machine**. At `gen` time the Rust
decoder is cross-checked against the tool's python integer-forward
(`ref_rgb.bin`) to max|Δ|=0, and the frozen `rgb_hash` then enforces the same
bytes on every platform in CI — a real trained model, a real photo, decoded
identically everywhere.
bytes on every platform in CI — a real trained model, decoded identically
everywhere.
## Running

View file

@ -4,6 +4,8 @@ Vectors for [`extensions/packaging.md`](../extensions/packaging.md): the policy,
digest and what it may ask a packager to emit (§3), how a source is cut into pieces
(§4), and the integer video payloads a packager writes (§5.5).
**Provenance.** Generated here: the `wai-pack` fixture generator (`wai-pack/src/fixture.rs`, `wai-pack/src/conformance.rs`) writes every frame from integer functions of the frame and pixel index, and a package's floor is an AV1 coding of those frames. No footage.
- `policy/` — policies a packager accepts (every rung one it may emit, §3.6), and
`expected.json`: each policy's effective canonical JSON and
digest (`eq-defaults-a.toml` also with `royalty_free_only` forced on, the one way an

View file

@ -2,6 +2,8 @@
Vectors for the parameter-set pin (SPEC.md §3.1, §4, §7, §7.1).
**Provenance.** Generated here by `wai_pin_vectors`; the parameter-set files under `sets/` are stand-in bytes written for the corpus. No media.
**Reason-equivalence.** A conforming verifier reports exactly the declared outcome
for every case:

View file

@ -4,6 +4,8 @@ Statevector-equivalence for the `wai.quantum.circuit` extension: given the same
`WQC` circuit, a conforming sink MUST reconstruct the identical fixed-point
statevector — **hash equality, no tolerance**.
**Provenance.** Generated here by `wai_quantum_vectors` from circuits authored in code. No media.
`vectors/*.wqc` plus `expected_hashes.json` are the pinned corpus. They are the
one reference all three surfaces are checked against, rather than being checked
against each other.

View file

@ -0,0 +1,15 @@
# quantum-ops-conformance — calibration and job receipts
The corpus of the quantum-ops extension: `wai.quantum.calibration` and `wai.quantum.job`
receipts, portable JSON signed with Ed25519 over a BLAKE3 Merkle root. Each vector is a
`vectors/<name>.json` receipt and the `artifacts/` bytes it content-addresses;
`expected_hashes.json` pins every `receipt_hash`. A third party parses the JSON,
recomputes the Merkle root, enforces the grant's joule ceiling, verifies the signature,
checks each content hash against the artifact bytes and, for a job, the calibration
cross-link.
**Provenance.** Generated here by `wai_quantum_ops_vectors gen`, from pinned demonstration
signing keys and fixed content. No media.
cd ../wai-rs
cargo run --no-default-features --features quantum_ops --bin wai_quantum_ops_vectors -- verify ../quantum-ops-conformance

View file

@ -345,6 +345,15 @@ What was checked (the claim rests on these, not on the argument alone):
*width*, not on trained values, with one exception that is visible below:
activation magnitude selects the IGDN arithmetic path.
> **Correction (2026-10-07).** The int_audio vector timed here was trained on,
> and coded, a third-party recording, not content made for the repository. It
> has been replaced: the int_audio model and vector are now trained and coded on
> a signal `tools/wai_int_audio_export.py` generates from a seed. The model has
> the same shape (16 channels, 512 latent samples, 8192 output samples); the
> row's figures are for the earlier vector, and the current one's time can
> differ through its activations (the exception above) and the length of its
> rANS stream.
## 4. Results
### Whole decoders

View file

@ -8,6 +8,8 @@ parameter. The music counterpart of spatial audio's
mixdown-equivalence, with the recorded sound objects replaced by note
events.
**Provenance.** Generated here: `wai_score_vectors gen` writes every score from notes authored in code. No recording.
The reference synth is trig-free: a phase accumulator drives a
piecewise-linear oscillator (saw / square / triangle / pulse) shaped by
a linear ADSR envelope, all in the `wai.det.fixed64` floor. Pitch is

View file

@ -5,6 +5,8 @@ Conformance for [key discovery, signing authority and module authorisation](../e
verifier reports beside a receipt's or claim's verdict, and the checks a sink runs
before it runs a decoder or reconstruct module.
**Provenance.** Generated here by `wai_signer_vectors`, from published one-byte seeds (below). No media.
Each vector declares **one verdict**, set from the text in the generator and never
copied from a verifier. A verifier that reaches another verdict — another level, step,
reason, head or anchor path — does not conform.

View file

@ -96,10 +96,10 @@ receipt for it, so that step 5 requires `delivered-verified` of its layers.
the f64 form's rounding near a half.
- `index.json` — the cases and their final clip hashes.
**The content is synthetic**: pictures, frames and PCM computed by integer functions in
the generator. The bases of the integer codecs are the committed vectors under
[`../wai-rs/tests/vectors/`](../wai-rs/tests/vectors/), decoded against their
parameter sets with their pins; the `wai.video.int_motion` bases are coded by the
**Provenance.** Generated here: pictures, frames and PCM computed by integer functions
in the generator. The bases of the integer codecs are the committed vectors under
[`../wai-rs/tests/vectors/`](../wai-rs/tests/vectors/), each generated too (that
directory's README states how), decoded against their parameter sets with their pins; the `wai.video.int_motion` bases are coded by the
library's keyframe-0 reference encoder (`int_payload::encode_wiv1_zero_motion`, which
`wai stage base` also runs: zero motion, one block per frame), and the PNG
and FLAC bases are written by small writers in the generator (stored deflate with

View file

@ -5,7 +5,7 @@
"bases": [
{
"file": "base.wai",
"object": "d45db2bc98dd38873553beb15fdb026a4e6b7fd7c8c7dbe4f4a0b6fcc0709a54",
"object": "751a7ca553e0dbf039f5bd98be79af34baf436e37afc1a1765fd9eedbfe20660",
"decoded_via": "wai.audio.int_codec",
"via_fallback": false,
"attested": false,
@ -23,7 +23,7 @@
}
],
"stage0": "stage0.bin",
"stage0_sha256": "b8ff83a442c112661ec7a41d6e51cb32559510a699a0e9bb37fa301f8952978a",
"stage0_sha256": "4b0344c87c67fc30b7d977ae2077fc310822199598e5d2f9f8fc06314b3a2875",
"decode": {
"kind": "int",
"set": {
@ -35,8 +35,8 @@
"files": [
{
"file": "L1.wai",
"object": "e462824f3bf3827ec4d8861e1c93f64fabf2bec20303013347eee7a271f968a2",
"bytes": 19375
"object": "5541cb6893420d23696e929a00e3a7aa7b755d2d7ffcd6254944e8401b85a9fc",
"bytes": 28759
}
],
"config": {
@ -67,7 +67,7 @@
[],
[
{
"object": "e462824f3bf3827ec4d8861e1c93f64fabf2bec20303013347eee7a271f968a2",
"object": "5541cb6893420d23696e929a00e3a7aa7b755d2d7ffcd6254944e8401b85a9fc",
"envelope": null,
"detail": null,
"held_for_base": false,
@ -84,7 +84,7 @@
"units": [
{
"stage": 1,
"producer": "e462824f3bf3827ec4d8861e1c93f64fabf2bec20303013347eee7a271f968a2",
"producer": "5541cb6893420d23696e929a00e3a7aa7b755d2d7ffcd6254944e8401b85a9fc",
"frozen": false,
"tier": "decode-equivalence",
"shape": [
@ -92,10 +92,10 @@
1,
1
],
"stage_sha256": "b9ca33fc990f6a28c479c4a8193dca0bd9faa1d8dedf9cef9614513da4b1d0bd"
"stage_sha256": "f48dd33054661c4da9c14449579b54fd2bd0c52408829468a4ddc76a945ecc23"
}
],
"clip_sha256": "ec7a4ad312d40a6ebdb33a5b55df02967415c3eb8f065c72e427d1a189b8810d",
"clip_sha256": "3a20087e9668f23d47584467849d2d4c1c5fc99bb099b02227759f8ab42bcf3c",
"n_units": 1
}
]

View file

@ -64,7 +64,7 @@
"name": "audio_int_codec_1l",
"about": "a pinned wai.audio.int_codec base, then an identity layer",
"clip_sha256": [
"ec7a4ad312d40a6ebdb33a5b55df02967415c3eb8f065c72e427d1a189b8810d"
"3a20087e9668f23d47584467849d2d4c1c5fc99bb099b02227759f8ab42bcf3c"
]
},
{

View file

@ -60,9 +60,9 @@ identity (Appendix D). Across the corpus: the record-wide deduplication totals (
with a short timeout (`fifo-timeout-short`), and `fifo` decode on one worker, whose
stall passes the bound of the same plan with `base-first` decode (`strict-window`).
**The content is synthetic.** Each base is a committed vector under
[`../wai-rs/tests/vectors/`](../wai-rs/tests/vectors/), as the staged-delivery corpus
wraps it: a `wai.neural.int_hyper` picture, a `wai.video.int_hyper` clip, a
**Provenance.** Generated here. Each base is a committed vector under
[`../wai-rs/tests/vectors/`](../wai-rs/tests/vectors/), generated too (that directory's
README states how), as the staged-delivery corpus wraps it: a `wai.neural.int_hyper` picture, a `wai.video.int_hyper` clip, a
`wai.audio.int_codec` clip and a `wai.splat.int_codec` attribute tensor, each pinned to
its parameter set. Each source is the base's output with fine detail added by integer
functions of position, channel and a seed (for audio, two triangle waves), raised to the

View file

@ -5,35 +5,35 @@
{
"unit": 0,
"layers": 1,
"out_sha256": "b8ff83a442c112661ec7a41d6e51cb32559510a699a0e9bb37fa301f8952978a"
"out_sha256": "4b0344c87c67fc30b7d977ae2077fc310822199598e5d2f9f8fc06314b3a2875"
},
{
"unit": 0,
"layers": 2,
"out_sha256": "7cf4ee1daabc1f8779252bb3e02f16ba2ab2d8a65b374c8cbb1c3c3354121cdd"
"out_sha256": "f6d16fa64e91ca80f593b2f598680e4e95af1b0b982e88f7cf1187fadf7ede85"
},
{
"unit": 0,
"layers": 3,
"out_sha256": "02c3e3540210f1e5fce2b9f75d38e74d9b877cf17f2233b7825a8a10b823c64c"
"out_sha256": "5f2b20307a79713c3c8975e3cfbc5a2fa9accc3bd651f570078dfd51a808def9"
},
{
"unit": 0,
"layers": 4,
"out_sha256": "8405e88c07e18cd93aecd578493cb3ff060c98be1790ebca0edeb0d1af1c512a"
"out_sha256": "5acb4b0f4839b79f10506e5c2d17637b5895a94bc4b46694a4bcee49c192b095"
}
],
"references": [
{
"label": "one layer, q 1",
"out_sha256": [
"8405e88c07e18cd93aecd578493cb3ff060c98be1790ebca0edeb0d1af1c512a"
"5acb4b0f4839b79f10506e5c2d17637b5895a94bc4b46694a4bcee49c192b095"
]
},
{
"label": "one layer, q 8",
"out_sha256": [
"9b34a3dcbc301e180a7a675b3304ed57ddee43858863e113a55455a926d614e8"
"676f2597f1e3106b56cfb6798771abb7dc6b06733ee9d1f95e5dcf627b67525b"
]
}
]

View file

@ -18,7 +18,7 @@
],
"source": {
"file": "source.bin",
"sha256": "8405e88c07e18cd93aecd578493cb3ff060c98be1790ebca0edeb0d1af1c512a"
"sha256": "5acb4b0f4839b79f10506e5c2d17637b5895a94bc4b46694a4bcee49c192b095"
},
"references": [
{

View file

@ -4,15 +4,15 @@
"fixtures": [
{
"title": "audio",
"content_id": "dd64e04d02388d970bf07a6759ea97f073e2329abcb03acb910d5d0a25ac8462",
"content_id": "b07e34629aab67de9a625cc04b3662cbb730bcaf1312190f449078969da79676",
"framing": "registered",
"unit_class": "pcm16",
"unit_us": 512000,
"bases": [
{
"object": "d45db2bc98dd38873553beb15fdb026a4e6b7fd7c8c7dbe4f4a0b6fcc0709a54",
"object": "751a7ca553e0dbf039f5bd98be79af34baf436e37afc1a1765fd9eedbfe20660",
"capability": "wai.audio.int_codec",
"pin": "98b382c92112660a7d3909f07da831125fcdb75a548aa0cf64ad17a0901bd9ef",
"pin": "132958122b251869ad6725d24a2bb96e2733daaf3e09ef65ebc7af6f46030855",
"tier": "decode-equivalence",
"first_unit": 0,
"capture_us": null,
@ -23,7 +23,7 @@
"objects": [
{
"file": "staged-conformance/cases/audio_int_codec_1l/base.wai",
"object": "d45db2bc98dd38873553beb15fdb026a4e6b7fd7c8c7dbe4f4a0b6fcc0709a54",
"object": "751a7ca553e0dbf039f5bd98be79af34baf436e37afc1a1765fd9eedbfe20660",
"capability": "wai.audio.int_codec",
"base": 0,
"layer": 0,
@ -34,13 +34,13 @@
"counted": {
"header": 12,
"manifest": 338,
"payload": 1444,
"total": 1794
"payload": 2648,
"total": 2998
}
},
{
"file": "staged-measure-conformance/fixtures/audio/L01.wai",
"object": "14c630b04c617542d3df5a40b398c2fa5c960d6020f84a961046ff5f7831dc69",
"object": "a57b31df6e0982f99d2dce2b71d1c840a054ac77044f3eda42e6239abb13b6ee",
"capability": "wai.audio.int_refine",
"base": 0,
"layer": 1,
@ -57,7 +57,7 @@
},
{
"file": "staged-measure-conformance/fixtures/audio/L02.wai",
"object": "4f935f7fade9bd09ba65d65fca37083e18b57c6251c4f1ded91d7bab2c1640b0",
"object": "149cf3636040d0aa2df34c5a0a841d7789320e7cad2801609c50a2bd13c4b50a",
"capability": "wai.audio.int_refine",
"base": 0,
"layer": 2,
@ -74,7 +74,7 @@
},
{
"file": "staged-measure-conformance/fixtures/audio/L03.wai",
"object": "ed29fe08a0e7aafba5c71016408cbab959ddcda07914ee0ca08cc58f2d7cf549",
"object": "042b901f77c6510cbc27bf8d1370762d26eac51b2cb705949f4ffdfee923bacf",
"capability": "wai.audio.int_refine",
"base": 0,
"layer": 3,
@ -90,16 +90,16 @@
}
}
],
"bfpf_min": 1794,
"bfpf_min": 2998,
"prefixes": [
{
"layers": 1,
"stage_counted": 1794,
"counted": 1794,
"stage_counted": 2998,
"counted": 2998,
"per_base": [
{
"stage_counted": 1794,
"counted": 1794
"stage_counted": 2998,
"counted": 2998
}
],
"units": 1,
@ -109,59 +109,59 @@
{
"layers": 2,
"stage_counted": 10351,
"counted": 12145,
"counted": 13349,
"per_base": [
{
"stage_counted": 10351,
"counted": 12145
"counted": 13349
}
],
"units": 1,
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "5600413",
"ref_energy": "77076760253"
"sse": "5600292",
"ref_energy": "2886011628499"
},
"vs_final": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "5600413",
"ref_energy": "77076760253"
"sse": "5600292",
"ref_energy": "2886011628499"
}
},
{
"layers": 3,
"stage_counted": 6859,
"counted": 19004,
"counted": 20208,
"per_base": [
{
"stage_counted": 6859,
"counted": 19004
"counted": 20208
}
],
"units": 1,
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "89997",
"ref_energy": "77076760253"
"sse": "89988",
"ref_energy": "2886011628499"
},
"vs_final": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "89997",
"ref_energy": "77076760253"
"sse": "89988",
"ref_energy": "2886011628499"
}
},
{
"layers": 4,
"stage_counted": 6831,
"counted": 25835,
"counted": 27039,
"per_base": [
{
"stage_counted": 6831,
"counted": 25835
"counted": 27039
}
],
"units": 1,
@ -169,36 +169,36 @@
"kind": "pcm16",
"n_samples": 16384,
"sse": "0",
"ref_energy": "77076760253"
"ref_energy": "2886011628499"
},
"vs_final": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "0",
"ref_energy": "77076760253"
"ref_energy": "2886011628499"
}
}
],
"decoders": [
{
"capability": "wai.audio.int_codec",
"pin": "98b382c92112660a7d3909f07da831125fcdb75a548aa0cf64ad17a0901bd9ef",
"object": "d45db2bc98dd38873553beb15fdb026a4e6b7fd7c8c7dbe4f4a0b6fcc0709a54"
"pin": "132958122b251869ad6725d24a2bb96e2733daaf3e09ef65ebc7af6f46030855",
"object": "751a7ca553e0dbf039f5bd98be79af34baf436e37afc1a1765fd9eedbfe20660"
},
{
"capability": "wai.audio.int_refine",
"pin": null,
"object": "14c630b04c617542d3df5a40b398c2fa5c960d6020f84a961046ff5f7831dc69"
"object": "a57b31df6e0982f99d2dce2b71d1c840a054ac77044f3eda42e6239abb13b6ee"
},
{
"capability": "wai.audio.int_refine",
"pin": null,
"object": "4f935f7fade9bd09ba65d65fca37083e18b57c6251c4f1ded91d7bab2c1640b0"
"object": "149cf3636040d0aa2df34c5a0a841d7789320e7cad2801609c50a2bd13c4b50a"
},
{
"capability": "wai.audio.int_refine",
"pin": null,
"object": "ed29fe08a0e7aafba5c71016408cbab959ddcda07914ee0ca08cc58f2d7cf549"
"object": "042b901f77c6510cbc27bf8d1370762d26eac51b2cb705949f4ffdfee923bacf"
}
],
"presentations": [
@ -211,7 +211,7 @@
1,
1
],
"out_sha256": "b8ff83a442c112661ec7a41d6e51cb32559510a699a0e9bb37fa301f8952978a",
"out_sha256": "4b0344c87c67fc30b7d977ae2077fc310822199598e5d2f9f8fc06314b3a2875",
"vs_source": null,
"vs_final": null
},
@ -224,18 +224,18 @@
1,
1
],
"out_sha256": "7cf4ee1daabc1f8779252bb3e02f16ba2ab2d8a65b374c8cbb1c3c3354121cdd",
"out_sha256": "f6d16fa64e91ca80f593b2f598680e4e95af1b0b982e88f7cf1187fadf7ede85",
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "5600413",
"ref_energy": "77076760253"
"sse": "5600292",
"ref_energy": "2886011628499"
},
"vs_final": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "5600413",
"ref_energy": "77076760253"
"sse": "5600292",
"ref_energy": "2886011628499"
}
},
{
@ -247,18 +247,18 @@
1,
1
],
"out_sha256": "02c3e3540210f1e5fce2b9f75d38e74d9b877cf17f2233b7825a8a10b823c64c",
"out_sha256": "5f2b20307a79713c3c8975e3cfbc5a2fa9accc3bd651f570078dfd51a808def9",
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "89997",
"ref_energy": "77076760253"
"sse": "89988",
"ref_energy": "2886011628499"
},
"vs_final": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "89997",
"ref_energy": "77076760253"
"sse": "89988",
"ref_energy": "2886011628499"
}
},
{
@ -270,69 +270,69 @@
1,
1
],
"out_sha256": "8405e88c07e18cd93aecd578493cb3ff060c98be1790ebca0edeb0d1af1c512a",
"out_sha256": "5acb4b0f4839b79f10506e5c2d17637b5895a94bc4b46694a4bcee49c192b095",
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "0",
"ref_energy": "77076760253"
"ref_energy": "2886011628499"
},
"vs_final": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "0",
"ref_energy": "77076760253"
"ref_energy": "2886011628499"
}
}
],
"output_root": "b2241df38a1249d823c0896c8570826b1ee9417718cd776fa8fff50ad6709d43",
"output_root": "a58dad8b2bb96f08080e1f6705ebff84d097e1e992d387fa8d76615518487a28",
"leaf_count": 4,
"overhead": [
{
"label": "staged",
"counted": 25835,
"counted": 27039,
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "0",
"ref_energy": "77076760253"
"ref_energy": "2886011628499"
},
"out_sha256": [
"8405e88c07e18cd93aecd578493cb3ff060c98be1790ebca0edeb0d1af1c512a"
"5acb4b0f4839b79f10506e5c2d17637b5895a94bc4b46694a4bcee49c192b095"
]
},
{
"label": "one layer, q 1",
"counted": 32145,
"counted": 33349,
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "0",
"ref_energy": "77076760253"
"ref_energy": "2886011628499"
},
"out_sha256": [
"8405e88c07e18cd93aecd578493cb3ff060c98be1790ebca0edeb0d1af1c512a"
"5acb4b0f4839b79f10506e5c2d17637b5895a94bc4b46694a4bcee49c192b095"
]
},
{
"label": "one layer, q 8",
"counted": 19137,
"counted": 20341,
"vs_source": {
"kind": "pcm16",
"n_samples": 16384,
"sse": "89997",
"ref_energy": "77076760253"
"sse": "89989",
"ref_energy": "2886011628499"
},
"out_sha256": [
"9b34a3dcbc301e180a7a675b3304ed57ddee43858863e113a55455a926d614e8"
"676f2597f1e3106b56cfb6798771abb7dc6b06733ee9d1f95e5dcf627b67525b"
]
}
],
"dedup": {
"objects": 8,
"unique": 6,
"referenced_bytes": 77117,
"stored_bytes": 73529
"referenced_bytes": 80729,
"stored_bytes": 74733
}
},
{
@ -1815,8 +1815,8 @@
"dedup": {
"objects": 46,
"unique": 32,
"referenced_bytes": 129930,
"stored_bytes": 112383
"referenced_bytes": 133542,
"stored_bytes": 113587
}
}
}

View file

@ -5606,25 +5606,25 @@
{
"id": "base.wai",
"sent_first_us": 20000,
"arrived_us": 40718,
"arrived_us": 41200,
"state": "delivered"
},
{
"id": "L01.wai",
"sent_first_us": 20718,
"arrived_us": 44859,
"sent_first_us": 21200,
"arrived_us": 45341,
"state": "delivered"
},
{
"id": "L02.wai",
"sent_first_us": 24859,
"arrived_us": 47603,
"sent_first_us": 25341,
"arrived_us": 48085,
"state": "delivered"
},
{
"id": "L03.wai",
"sent_first_us": 27603,
"arrived_us": 50336,
"sent_first_us": 28085,
"arrived_us": 50818,
"state": "delivered"
}
],
@ -5632,34 +5632,34 @@
[
0,
1,
44718
45200
],
[
0,
2,
46859
47341
],
[
0,
3,
49603
50085
],
[
0,
4,
52336
52818
]
],
"bfpf_sched": 11394,
"tfpf_us": 44718,
"bfpf_sched": 12598,
"tfpf_us": 45200,
"tffs_us": [
44718,
46859,
49603,
52336
45200,
47341,
50085,
52818
],
"offered": 25835,
"delivered": 25835,
"offered": 27039,
"delivered": 27039,
"dropped": 0,
"abandoned": 0,
"never_sent_capped": 0,
@ -5681,12 +5681,12 @@
{
"id": "base.wai",
"sent_first_us": 20000,
"arrived_us": 44485,
"arrived_us": 47495,
"state": "delivered"
},
{
"id": "L01.wai",
"sent_first_us": 24485,
"sent_first_us": 27495,
"arrived_us": null,
"state": "abandoned"
},
@ -5707,21 +5707,21 @@
[
0,
1,
48485
51495
]
],
"bfpf_sched": 2994,
"tfpf_us": 48485,
"bfpf_sched": 4198,
"tfpf_us": 51495,
"tffs_us": [
48485,
51495,
null,
null,
null
],
"offered": 25835,
"delivered": 1794,
"dropped": 13690,
"abandoned": 10351,
"offered": 27039,
"delivered": 2998,
"dropped": 14441,
"abandoned": 9600,
"never_sent_capped": 0,
"missed": 0,
"stall_us": [
@ -5741,13 +5741,13 @@
{
"id": "base.wai",
"sent_first_us": 20000,
"arrived_us": 44485,
"arrived_us": 47495,
"state": "delivered"
},
{
"id": "L01.wai",
"sent_first_us": 24485,
"arrived_us": 70363,
"sent_first_us": 27495,
"arrived_us": 73373,
"state": "delivered"
},
{
@ -5767,24 +5767,24 @@
[
0,
1,
48485
51495
],
[
0,
2,
72363
75373
]
],
"bfpf_sched": 1794,
"tfpf_us": 48485,
"bfpf_sched": 2998,
"tfpf_us": 51495,
"tffs_us": [
48485,
72363,
51495,
75373,
null,
null
],
"offered": 25835,
"delivered": 12145,
"offered": 27039,
"delivered": 13349,
"dropped": 13690,
"abandoned": 0,
"never_sent_capped": 0,
@ -5806,25 +5806,25 @@
{
"id": "base.wai",
"sent_first_us": 20000,
"arrived_us": 40718,
"arrived_us": 41200,
"state": "delivered"
},
{
"id": "L01.wai",
"sent_first_us": 20718,
"arrived_us": 44859,
"sent_first_us": 21200,
"arrived_us": 45341,
"state": "delivered"
},
{
"id": "L02.wai",
"sent_first_us": 24859,
"arrived_us": 47603,
"sent_first_us": 25341,
"arrived_us": 48085,
"state": "delivered"
},
{
"id": "L03.wai",
"sent_first_us": 27603,
"arrived_us": 50336,
"sent_first_us": 28085,
"arrived_us": 50818,
"state": "delivered"
}
],
@ -5832,34 +5832,34 @@
[
0,
1,
44718
45200
],
[
0,
2,
46859
47341
],
[
0,
3,
49603
50085
],
[
0,
4,
52336
52818
]
],
"bfpf_sched": 11394,
"tfpf_us": 44718,
"bfpf_sched": 12598,
"tfpf_us": 45200,
"tffs_us": [
44718,
46859,
49603,
52336
45200,
47341,
50085,
52818
],
"offered": 25835,
"delivered": 25835,
"offered": 27039,
"delivered": 27039,
"dropped": 0,
"abandoned": 0,
"never_sent_capped": 0,

View file

@ -45,5 +45,5 @@ their metrics. Every value here is a string or an integer, the same on every mac
readers and requires the members; and validates every report, and the Event-mode
reports together, requiring no error.
The content is synthetic: session ids, content hashes and timestamps are fixed values
chosen for the corpus.
**Provenance.** Generated here: session ids, content hashes and timestamps are fixed
values chosen for the corpus. No recorded traffic.

View file

@ -0,0 +1,482 @@
#!/usr/bin/env python3
"""Fail if a committed audio vector is a coding of a recording in a reference set.
Every audio vector in this tree must come from a seeded generator. This check finds
the ones that do not, by content: it decodes or reads each committed audio vector to
PCM and computes its normalised cross-correlation, at every lag, against every
recording in a reference set the host has. A vector that correlates above the
threshold (0.5 by default) with any reference fails the check. A generated signal
correlates with an unrelated recording at a few hundredths; a lossy coding of a
recording correlates with it near 1.
python3 tools/wai_audio_provenance_check.py [--wai DIR] [--threshold T]
[--ref DIR]... [--pcm PATH:RATE[:CH]]...
Run from `wai/` (or pass `--wai`). Python standard library only.
**The reference set** is every audio file under each `--ref` directory, under each
directory in `WAI_AUDIO_REFERENCE_DIRS` (separated by the platform's path separator),
and under the host's system sound directory (`/System/Library/Sounds`) when it exists.
Each reference is converted to mono PCM at the analysis rate by the host's audio
converter (`afconvert`, else `ffmpeg`); raw `.s16` references are read as 16 kHz mono.
When the set is empty, or no converter can read any of it, the check prints why and
exits 0: it is skipped, not passed.
**The committed audio vectors** are found by rule, not listed, so a new one is
covered when it lands:
- each base of a staged-delivery case (`staged-conformance/cases/*/case.json`) that
decodes through a `wai.audio.*` capability: its stage 0 (`stage0.bin`, the decoded
PCM, i16 interleaved), at the sample rate its payload states (a `WIA1` header's
`sr`, a FLAC stream's STREAMINFO);
- each staged-measurement title over such a base
(`staged-measure-conformance/fixtures/*/title.json`): its source (`source.bin`), at
the base's rate scaled by the source's length over the base's;
- each spatial-audio source (`audio-conformance/vectors/*.sources.bin`), at the rate
its scene (`.wscn`) states;
- every file with an audio extension (`.wav`, `.aif`, `.aiff`, `.flac`, `.s16`, …)
anywhere under `wai/`;
- and every `--pcm PATH:RATE[:CH]` given (raw s16le, CH channels interleaved).
A signal shorter than a quarter of a second at the analysis rate, or silent, is listed
and not judged: over so few samples a generated tone can match a recorded one by
chance (a 50 ms pair of triangle waves reaches 0.5 against a low recorded tone).
A learned-codec vector (`wai-rs/tests/vectors/*/audio_model.bin` beside a
`sha256.json`) is covered through its decode: the check requires that the decoded
PCM's SHA-256 its sidecar states is the stage 0 of a staged-delivery case above, so
the PCM it scans is that vector's output. A codec vector with no such case fails.
Exit status: 0 when every vector is under the threshold or the check is skipped;
1 when a vector correlates above it, or a codec vector's decode is not covered.
"""
import argparse
import cmath
import glob
import hashlib
import json
import math
import os
import re
import shutil
import struct
import subprocess
import sys
import tempfile
import wave
ANALYSIS_RATE = 8000 # Hz: every signal is compared here, mono
SYSTEM_SOUNDS = '/System/Library/Sounds'
AUDIO_EXT = {'.wav', '.wave', '.aif', '.aiff', '.aifc', '.flac', '.mp3', '.ogg', '.opus',
'.m4a', '.caf', '.s16', '.pcm'}
SKIP_DIRS = {'.git', 'target', 'node_modules', 'jpeg-ai-ref', '__pycache__'}
MIN_SAMPLES = ANALYSIS_RATE // 4 # a quarter second: a shorter signal is listed, not judged
# ---- PCM helpers --------------------------------------------------------------------
def i16le(b):
n = len(b) // 2
return list(struct.unpack(f'<{n}h', b[:2 * n]))
def channels(pcm, ch):
return [pcm[c::ch] for c in range(ch)]
def lowpass_taps(cut, n=63):
"""A Hann-windowed sinc low-pass, cut-off `cut` in cycles per input sample."""
m = n // 2
taps = []
for k in range(n):
x = k - m
s = 2 * cut if x == 0 else math.sin(2 * math.pi * cut * x) / (math.pi * x)
taps.append(s * (0.5 - 0.5 * math.cos(2 * math.pi * k / (n - 1))))
g = sum(taps)
return [t / g for t in taps]
def resample(x, rate):
"""Resample `x` from `rate` to the analysis rate: low-pass, then linear interpolation."""
if rate == ANALYSIS_RATE or not x:
return [float(v) for v in x]
if rate > ANALYSIS_RATE:
taps = lowpass_taps(0.45 * ANALYSIS_RATE / rate)
m = len(taps) // 2
n = len(x)
y = []
for i in range(n):
acc = 0.0
lo, hi = max(0, i - m), min(n, i + m + 1)
for j in range(lo, hi):
acc += taps[j - i + m] * x[j]
y.append(acc)
else:
y = [float(v) for v in x]
step = rate / ANALYSIS_RATE
out, t = [], 0.0
while t <= len(y) - 1:
i = int(t)
f = t - i
out.append(y[i] if f == 0 or i + 1 >= len(y) else y[i] * (1 - f) + y[i + 1] * f)
t += step
return out
# ---- correlation ----------------------------------------------------------------------
_TW = {}
def fft(a, inverse=False):
"""In-place iterative radix-2 FFT of a list of complex numbers (len a power of 2)."""
n = len(a)
j = 0
for i in range(1, n):
bit = n >> 1
while j & bit:
j ^= bit
bit >>= 1
j |= bit
if i < j:
a[i], a[j] = a[j], a[i]
key = (n, inverse)
if key not in _TW:
sgn = 1 if inverse else -1
_TW[key] = [cmath.exp(sgn * 2j * math.pi * k / n) for k in range(n // 2)]
tw = _TW[key]
size = 2
while size <= n:
half = size // 2
stride = n // size
for start in range(0, n, size):
for k in range(half):
u = a[start + k]
v = a[start + k + half] * tw[k * stride]
a[start + k] = u + v
a[start + k + half] = u - v
size *= 2
if inverse:
for i in range(n):
a[i] /= n
return a
def spectrum(x, n):
return fft([complex(v) for v in x] + [0j] * (n - len(x)))
def prefix_sq(x):
p = [0.0]
for v in x:
p.append(p[-1] + v * v)
return p
def best_ncc(xa, fa, pa, xb, fb, pb, n):
"""max over lags of |Σ a[i]·b[i+lag]| / sqrt(Σ a² · Σ b²), both sums over the
overlap, among lags whose overlap is at least half the shorter signal."""
la, lb = len(xa), len(xb)
prod = [fa[k].conjugate() * fb[k] for k in range(n)]
c = fft(prod, inverse=True) # c[lag mod n] = Σ a[i] b[i+lag]
need = max(1, min(la, lb) // 2)
best, at = 0.0, 0
for lag in range(-(la - 1), lb):
i0, i1 = max(0, -lag), min(la, lb - lag) # a's overlapping range
if i1 - i0 < need:
continue
ea = pa[i1] - pa[i0]
eb = pb[i1 + lag] - pb[i0 + lag]
if ea <= 0 or eb <= 0:
continue
r = abs(c[lag % n].real) / math.sqrt(ea * eb)
if r > best:
best, at = r, lag
return best, at
# ---- the reference set --------------------------------------------------------------
def converter():
if shutil.which('afconvert'):
return 'afconvert'
if shutil.which('ffmpeg'):
return 'ffmpeg'
return None
def read_wav(path):
"""(samples per channel list, rate) for PCM 8/16/24/32-bit or float32 WAV; raises on
anything else."""
with open(path, 'rb') as f:
b = f.read()
if b[:4] != b'RIFF' or b[8:12] != b'WAVE':
raise ValueError('not RIFF/WAVE')
pos, fmt, data = 12, None, None
while pos + 8 <= len(b):
cid, size = b[pos:pos + 4], struct.unpack('<I', b[pos + 4:pos + 8])[0]
body = b[pos + 8:pos + 8 + size]
if cid == b'fmt ' and len(body) >= 16:
fmt = struct.unpack('<HHIIHH', body[:16])
elif cid == b'data':
data = body
pos += 8 + size + (size & 1)
if fmt is None or data is None:
raise ValueError('no fmt or data chunk')
tag, ch, rate, _, _, bits = fmt
if ch < 1 or ch > 64 or rate < 1:
raise ValueError(f'{ch} channels at {rate} Hz')
if tag == 1 and bits == 16:
x = i16le(data)
elif tag == 1 and bits == 8:
x = [(v - 128) * 256 for v in data]
elif tag == 1 and bits == 24:
x = [int.from_bytes(data[i:i + 3], 'little', signed=True) >> 8 for i in range(0, len(data) - 2, 3)]
elif tag == 1 and bits == 32:
x = [v >> 16 for v in struct.unpack(f'<{len(data) // 4}i', data[:len(data) // 4 * 4])]
elif tag == 3 and bits == 32:
x = [v * 32767 for v in struct.unpack(f'<{len(data) // 4}f', data[:len(data) // 4 * 4])]
else:
raise ValueError(f'format tag {tag}, {bits} bits')
x = x[:len(x) // ch * ch]
return channels(x, ch), rate
def convert(conv, src, tmp):
"""Mono s16 WAV at the analysis rate, via the host's converter."""
out = os.path.join(tmp, hashlib.sha256(src.encode()).hexdigest()[:16] + '.wav')
if conv == 'afconvert':
cmd = ['afconvert', '-f', 'WAVE', '-d', f'LEI16@{ANALYSIS_RATE}', '-c', '1', src, out]
else:
cmd = ['ffmpeg', '-v', 'error', '-y', '-i', src, '-ac', '1', '-ar', str(ANALYSIS_RATE),
'-c:a', 'pcm_s16le', out]
subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
chans, rate = read_wav(out)
return resample(chans[0], rate)
def references(dirs, conv, tmp):
refs, notes = [], []
for d in dirs:
for root, _, files in os.walk(d):
for f in sorted(files):
p = os.path.join(root, f)
ext = os.path.splitext(f)[1].lower()
if ext not in AUDIO_EXT:
continue
try:
if ext == '.s16':
with open(p, 'rb') as fh:
x = resample(i16le(fh.read()), 16000)
elif conv:
x = convert(conv, p, tmp)
else:
chans, rate = read_wav(p)
x = resample(chans[0], rate)
except Exception as e: # noqa: BLE001 — an unreadable reference is reported
notes.append(f'reference unreadable, skipped: {p} ({e})')
continue
refs.append((p, x))
return refs, notes
# ---- the committed audio vectors ----------------------------------------------------
def envelope_payload(b):
"""The payload of a WAI1 envelope: magic, u32 manifest length, manifest, then the
payload (a u32 length, or to the end)."""
if b[:4] != b'WAI1':
return None
mlen = struct.unpack('<I', b[4:8])[0]
rest = b[8 + mlen:]
if len(rest) >= 4:
plen = struct.unpack('<I', rest[:4])[0]
if plen <= len(rest) - 4:
return rest[4:4 + plen]
return rest
def payload_rate(p):
"""The sample rate a payload states: a WIA1 header's `sr`, or a FLAC STREAMINFO's."""
if p is None:
return None
if p[:4] == b'WIA1' and len(p) >= 12:
return struct.unpack('<I', p[8:12])[0]
i = p.find(b'fLaC')
if i >= 0 and len(p) >= i + 8 + 13:
si = p[i + 8:i + 8 + 34] # STREAMINFO body
return (si[10] << 12) | (si[11] << 4) | (si[12] >> 4)
return None
def staged_bases(wai):
"""(case dir, base index) → (pcm, channels, rate, stage0 sha256) for audio bases."""
out = {}
for cj in sorted(glob.glob(os.path.join(wai, 'staged-conformance/cases/*/case.json'))):
case = json.load(open(cj))
d = os.path.dirname(cj)
for bi, base in enumerate(case.get('bases', [])):
if not str(base.get('decoded_via', '')).startswith('wai.audio.'):
continue
units = base.get('units') or [{}]
shape = units[0].get('shape') or [0, 1, 1]
ch = int(shape[2]) if len(shape) > 2 else 1
with open(os.path.join(d, base['stage0']), 'rb') as f:
s0 = f.read()
with open(os.path.join(d, base['file']), 'rb') as f:
rate = payload_rate(envelope_payload(f.read()))
out[(os.path.relpath(d, wai), bi)] = (i16le(s0), ch, rate, hashlib.sha256(s0).hexdigest())
return out
def vectors(wai, extra):
"""[(name, [channel samples], rate)], notes, failures."""
vs, notes, fails = [], [], []
bases = staged_bases(wai)
for (case, bi), (pcm, ch, rate, _) in bases.items():
name = f'{case}/stage0 (base {bi})'
if not rate:
fails.append(f'{name}: no sample rate in its payload')
continue
vs.append((name, channels(pcm, ch), rate))
for tj in sorted(glob.glob(os.path.join(wai, 'staged-measure-conformance/fixtures/*/title.json'))):
t = json.load(open(tj))
for b in t.get('bases', []):
key = (b.get('case'), b.get('base', 0))
if key not in bases:
continue
pcm, ch, rate, _ = bases[key]
src = os.path.join(os.path.dirname(tj), t['source']['file'])
with open(src, 'rb') as f:
x = i16le(f.read())
if not rate:
continue
r = round(rate * len(x) / len(pcm))
vs.append((os.path.relpath(src, wai), channels(x, ch), r))
for sb in sorted(glob.glob(os.path.join(wai, 'audio-conformance/vectors/*.sources.bin'))):
with open(sb, 'rb') as f:
b = f.read()
scene = sb[:-len('.sources.bin')] + '.wscn'
m = re.search(rb'"sample_rate":(\d+)', open(scene, 'rb').read()) if os.path.exists(scene) else None
rate = int(m.group(1)) if m else 48000
n, pos = struct.unpack('<I', b[:4])[0], 4
for k in range(n):
h, ln = b[pos:pos + 32].hex()[:12], struct.unpack('<I', b[pos + 32:pos + 36])[0]
pos += 36
vs.append((f'{os.path.relpath(sb, wai)}#{k} ({h}…)', [i16le(b[pos:pos + 2 * ln])], rate))
pos += 2 * ln
for root, dirs, files in os.walk(wai):
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
for f in sorted(files):
ext = os.path.splitext(f)[1].lower()
if ext not in AUDIO_EXT:
continue
p = os.path.join(root, f)
try:
if ext in ('.s16', '.pcm'):
with open(p, 'rb') as fh:
vs.append((os.path.relpath(p, wai), [i16le(fh.read())], 16000))
else:
chans, rate = read_wav(p)
vs.append((os.path.relpath(p, wai), chans, rate))
except Exception as e: # noqa: BLE001
notes.append(f'not readable as PCM, listed only: {os.path.relpath(p, wai)} ({e})')
for spec in extra:
parts = spec.split(':')
p, rate = parts[0], int(parts[1])
ch = int(parts[2]) if len(parts) > 2 else 1
with open(p, 'rb') as f:
vs.append((p, channels(i16le(f.read()), ch), rate))
# A learned codec vector is covered by its decode, which must be a case's stage 0.
stage0 = {sha for (_, _, _, sha) in bases.values()}
for mb in sorted(glob.glob(os.path.join(wai, 'wai-rs/tests/vectors/*/audio_model.bin'))):
side = os.path.join(os.path.dirname(mb), 'sha256.json')
if not os.path.exists(side):
fails.append(f'{os.path.relpath(mb, wai)}: no sha256.json sidecar to tie its decode to a scanned PCM')
continue
sha = json.load(open(side)).get('audio', {}).get('sha256')
if sha not in stage0:
fails.append(f'{os.path.relpath(os.path.dirname(mb), wai)}: its decoded PCM (sha256 {sha}) is no '
'staged-delivery case\'s stage 0, so it is not scanned; add a case that decodes it')
else:
notes.append(f'{os.path.relpath(os.path.dirname(mb), wai)}: decode covered as a staged case\'s stage 0')
return vs, notes, fails
def main():
ap = argparse.ArgumentParser(description=__doc__.split('\n')[0])
ap.add_argument('--wai', default='.', help='the wai/ directory (default: .)')
ap.add_argument('--threshold', type=float, default=0.5)
ap.add_argument('--ref', action='append', default=[], help='a reference directory (repeatable)')
ap.add_argument('--pcm', action='append', default=[], help='PATH:RATE[:CH], raw s16le (repeatable)')
a = ap.parse_args()
wai = os.path.abspath(a.wai)
dirs = list(a.ref)
env = os.environ.get('WAI_AUDIO_REFERENCE_DIRS', '')
dirs += [d for d in env.split(os.pathsep) if d]
if os.path.isdir(SYSTEM_SOUNDS):
dirs.append(SYSTEM_SOUNDS)
dirs = [d for d in dirs if os.path.isdir(d)]
if not dirs:
print(f'audio provenance: SKIPPED — no reference set on this host ({SYSTEM_SOUNDS} is absent and '
'no --ref or WAI_AUDIO_REFERENCE_DIRS directory was given)')
return 0
conv = converter()
with tempfile.TemporaryDirectory() as tmp:
refs, rnotes = references(dirs, conv, tmp)
for n in rnotes:
print(f' note: {n}')
if not refs:
print(f'audio provenance: SKIPPED — the reference set ({", ".join(dirs)}) has no file this host can '
f'read (converter: {conv or "none; install afconvert or ffmpeg"})')
return 0
vs, notes, fails = vectors(wai, a.pcm)
print(f'audio provenance: {len(vs)} committed audio signals against {len(refs)} references '
f'({", ".join(dirs)}), at {ANALYSIS_RATE} Hz, threshold {a.threshold}')
for n in notes:
print(f' note: {n}')
rs = [(path, x, prefix_sq(x)) for path, x in refs]
ref_spec = {} # (reference, n) → its spectrum
over = []
for name, chans, rate in vs:
for ci, c in enumerate(chans):
x = resample(c, rate)
label = name + (f' ch{ci}' if len(chans) > 1 else '')
if len(x) < MIN_SAMPLES or not any(x):
print(f' {"-":>6} {label} ({len(x)} samples at {ANALYSIS_RATE} Hz'
f'{", silent" if not any(x) else ""}: too short or silent to judge)')
continue
px = prefix_sq(x)
best = (0.0, None, 0)
cache = {}
for path, y, py in rs:
n = 1 << (len(x) + len(y) - 1).bit_length()
if n not in cache:
cache[n] = spectrum(x, n)
if (path, n) not in ref_spec:
ref_spec[(path, n)] = spectrum(y, n)
r, lag = best_ncc(x, cache[n], px, y, ref_spec[(path, n)], py, n)
if r > best[0]:
best = (r, path, lag)
flag = 'FAIL' if best[0] > a.threshold else 'ok'
print(f' {best[0]:6.3f} {label} (rate {rate}; nearest {os.path.basename(best[1] or "-")} '
f'at lag {best[2]}) {flag}')
if best[0] > a.threshold:
over.append(f'{label}: {best[0]:.3f} with {best[1]}')
for f in fails:
print(f' FAIL: {f}')
for o in over:
print(f' FAIL: {o}')
if over or fails:
print(f'audio provenance: FAILED — {len(over)} signal(s) above {a.threshold}, {len(fails)} uncovered')
return 1
print('audio provenance: ok — no committed audio vector correlates with a reference above the threshold')
return 0
if __name__ == '__main__':
sys.exit(main())

View file

@ -3,77 +3,302 @@
INTEGER-exact decoder — the audio analog of `int_hyper`, extending "conformance is
a hash" to learned audio.
A neural audio codec (SoundStream/EnCodec-class) decodes through a FLOAT network,
so a ~1e-5 round-off makes the reconstructed waveform — and its hash — diverge
between machines: never receiptable. Here the synthesis is a stack of integer
1-D transposed convolutions + integer IGDN (per-out-channel int12 weights,
fixed-point activations, all i64), so the reconstructed PCM is byte-identical on
every machine (NeuralIntegerExact) — *sample-equivalence*, a portable PCM hash.
A neural audio codec decodes through a FLOAT network, so a ~1e-5 round-off makes the
reconstructed waveform — and its hash — diverge between machines: never receiptable.
Here the synthesis is a stack of integer 1-D transposed convolutions + integer IGDN
(per-out-channel int12 weights, fixed-point activations, all i64), so the
reconstructed PCM is byte-identical on every machine (NeuralIntegerExact) —
*sample-equivalence*, a portable PCM hash.
**The signal is generated here; the tool reads no audio file.** Both the training
signal and the test signal (the clip the vector codes) are written by `signal()`
below from a seed: 16 kHz, mono, signed 16-bit, a sequence of segments, each a tone
(one to three partials with an attack and a release), a chirp (a linear frequency
sweep), a noise burst (white noise, low-passed by a moving average or high-passed by
a difference) or a speech-like formant sweep (a harmonic series on a gliding,
vibrato-modulated pitch, shaped by three formant resonances that move between two
vowel targets), sometimes two overlaid, with short gaps. The generator is integer
arithmetic only — a SplitMix64 counter stream, a 32-bit phase accumulator, a
4096-entry sine table built by Bhaskara I's rational approximation — so a seed gives
the same samples on every machine and every Python. The training signal is stream 0
of the seed and the test signal stream 1: the codec is trained on one signal and
codes another of the same kind.
Pipeline (mirrors wai_sota_int_synth_export, in 1-D):
1. train g_a/g_s (Conv1d+GDN / ConvTranspose1d+IGDN) on a real clip (float; this
is the encoder, float is fine here — only the DECODE must be integer);
2. quantize the latent per channel (factorized prior, data-fit CDF + rANS, the
byte-exact match of the Rust RansDecoder);
3. PTQ g_s → integer (WAM1 binary), run an INTEGER reference decode (numpy,
mirroring the planned Rust i64 arithmetic) → int16 PCM → FNV-1a hash.
1. generate the training and test signals from the seed;
2. train g_a/g_s (Conv1d+GDN / ConvTranspose1d+IGDN) on the training signal (float;
this is the encoder, float is fine here — only the DECODE must be integer), with
torch seeded from the same seed, deterministic algorithms and a fixed thread
count, so a run on one host and torch build gives the same weights every time;
3. quantize the test signal's latent per channel (factorized prior, data-fit CDF +
rANS, the byte-exact match of the Rust RansDecoder);
4. PTQ g_s → integer (WAM1 binary), run an INTEGER reference decode (numpy,
mirroring the Rust i64 arithmetic) → int16 PCM → FNV-1a hash.
ffmpeg -i <real>.aiff -ac 1 -ar 16000 -f s16le audio.s16
python tools/wai_int_audio_export.py audio.s16 <out-dir>
python tools/wai_int_audio_export.py <out-dir> [--seed S] [--channels C]
[--samples N] [--steps K] [--train-seconds T]
python tools/wai_int_audio_export.py --signal-only <out.s16> [--seed S] [--stream 0|1]
[--samples N]
`--signal-only` writes one generated signal as raw s16le and needs nothing beyond the
Python standard library. The committed vector (`wai-rs/tests/vectors/int_audio/`) and
the site's demo clip are both exports of this tool; their commands are in that
directory's README.
"""
import sys, os, json, math, base64
import numpy as np, torch, torch.nn as nn, torch.nn.functional as F, warnings
warnings.filterwarnings('ignore')
from compressai.ans import RansEncoder
import argparse
import base64
import json
import math
import os
import struct
import sys
AFRAC = 12; WBITS = 12; SHIFT = 24; GF = 16 # same fixed-point as int_hyper
SR = 16000; T = 2048; C = 32; K = 5; STR = 2; NLAY = 4 # codec shape (16x downsample)
STEPS = 3500; MAXS = 0 # train steps; MAXS>0 caps #samples (small committed vector)
SR = 16000; T = 2048; K = 5; STR = 2; NLAY = 4 # codec shape (16x downsample)
LR = 1.5e-3; RATE_W = 8e-6
THREADS = 4 # fixed: CPU reductions depend on it
# ---- the generated signal (integer arithmetic only) ----------------------------------
M64 = (1 << 64) - 1
GOLDEN = 0x9E3779B97F4A7C15
TAB_BITS = 12
TAB_N = 1 << TAB_BITS
def _mix64(x):
"""SplitMix64's finalizer."""
x &= M64
x = ((x ^ (x >> 30)) * 0xBF58476D1CE4E5B9) & M64
x = ((x ^ (x >> 27)) * 0x94D049BB133111EB) & M64
return x ^ (x >> 31)
class Rng:
"""A SplitMix64 stream, keyed by (seed, stream)."""
def __init__(self, seed, stream):
self.s = _mix64(seed * GOLDEN + stream * 0xD1B54A32D192ED03)
def next(self):
self.s = (self.s + GOLDEN) & M64
return _mix64(self.s)
def int(self, lo, hi):
"""Uniform integer in [lo, hi]."""
return lo + self.next() % (hi - lo + 1)
def s16(self):
"""Uniform signed 16-bit value."""
return (self.next() >> 48) - 32768
def _sine_table():
"""sin(2π i / TAB_N) × 32767, by Bhaskara I's approximation, rounded half up:
sin(πp) ≈ 16 p (1 − p) / (5 − 4 p (1 − p)), p = u / half."""
half = TAB_N // 2
out = []
for i in range(TAB_N):
u = i % half
a = u * (half - u)
den = 5 * half * half - 4 * a
v = (2 * 32767 * 16 * a + den) // (2 * den)
out.append(v if i < half else -v)
return out
SINE = _sine_table()
def _inc(f_q8):
"""32-bit phase increment per sample for a frequency in Hz × 256."""
return (f_q8 << 24) // SR
def _osc(phase):
return SINE[(phase & 0xFFFFFFFF) >> (32 - TAB_BITS)]
def _envelope(n, attack, release):
"""Linear attack and release, Q15, length n."""
attack, release = max(1, min(attack, n // 2)), max(1, min(release, n // 2))
return [min(32767, (32767 * (i + 1)) // attack, (32767 * (n - i)) // release) for i in range(n)]
def _root64(x):
"""2^(x/64) in Q16, floored: the largest y with y^64 ≤ 2^(x + 16·64). Exact."""
lo, hi = 1 << 16, 1 << 17
while lo < hi:
mid = (lo + hi + 1) // 2
if mid ** 64 <= 1 << (x + 1024):
lo = mid
else:
hi = mid - 1
return lo
ROOT64 = [_root64(x) for x in range(64)]
def _log_freq(r, lo, hi):
"""A frequency in Hz × 256, log-uniform in [lo, hi] Hz: lo · 2^(k/64) for a random
k, drawn again while it is above hi."""
octaves = 0
while (lo << octaves) < hi:
octaves += 1
while True:
o, j = divmod(r.int(0, 64 * octaves), 64)
f = ((lo << o) * ROOT64[j]) >> 8
if f <= hi << 8:
return f
# Formant targets (F1, F2, F3) in Hz for five vowels.
VOWELS = [(730, 1090, 2440), (270, 2290, 3010), (300, 870, 2240), (530, 1840, 2480), (570, 840, 2410)]
def _tone(r, n):
out = [0] * n
for _ in range(r.int(1, 3)):
inc, amp, ph = _inc(_log_freq(r, 80, 3500)), r.int(4000, 16000), r.next() & 0xFFFFFFFF
for i in range(n):
out[i] += (amp * _osc(ph)) >> 15
ph += inc
env = _envelope(n, r.int(SR // 500, SR // 30), r.int(SR // 50, SR // 6))
return [(v * e) >> 15 for v, e in zip(out, env)]
def _chirp(r, n):
i0, i1 = _inc(_log_freq(r, 100, 6000)), _inc(_log_freq(r, 100, 6000))
amp, ph, out = r.int(8000, 20000), r.next() & 0xFFFFFFFF, []
for i in range(n):
out.append((amp * _osc(ph)) >> 15)
ph += i0 + (i1 - i0) * i // n
env = _envelope(n, r.int(SR // 500, SR // 50), r.int(SR // 100, SR // 20))
return [(v * e) >> 15 for v, e in zip(out, env)]
def _noise(r, n):
w = [r.s16() for _ in range(n + 16)]
kind = r.int(0, 2)
if kind == 0: # white
x = w[:n]
elif kind == 1: # low-passed: moving average
L = [2, 3, 5, 8, 13][r.int(0, 4)]
x = [sum(w[i:i + L]) // L for i in range(n)]
else: # high-passed: first difference
x = [(w[i + 1] - w[i]) >> 1 for i in range(n)]
env = _envelope(n, r.int(SR // 1000, SR // 200), r.int(SR // 50, SR // 5))
amp = r.int(4000, 14000)
return [(((v * amp) >> 15) * e) >> 15 for v, e in zip(x, env)]
def _formant(r, n):
"""A harmonic series on a gliding pitch with vibrato, each harmonic weighted by
three resonances 1 / (1 + ((f − F)/B)^2) whose centres move between two vowels."""
f0a = r.int(90, 240) << 8
f0b = (f0a * r.int(80, 125)) // 100
va, vb = VOWELS[r.int(0, 4)], VOWELS[r.int(0, 4)]
bw = (r.int(60, 110), r.int(90, 160), r.int(120, 220))
vib_inc, vib_depth = _inc(r.int(4, 7) << 8), r.int(5, 25) # depth in ‰
nh = max(1, (4800 << 8) // max(f0a, f0b))
ph0, vph, out = r.next() & 0xFFFFFFFF, r.next() & 0xFFFFFFFF, []
amps = [0] * nh
for i in range(n):
f0 = f0a + (f0b - f0a) * i // n
f0 += (f0 * vib_depth * _osc(vph)) // (1000 * 32767)
vph += vib_inc
if i % 32 == 0: # the weights at block rate
F = [va[j] + (vb[j] - va[j]) * i // n for j in range(3)]
for k in range(nh):
fk = ((k + 1) * f0) >> 8
g = 0
for j in range(3):
d = ((fk - F[j]) << 10) // bw[j]
g += (1 << 20) // (1024 + ((d * d) >> 10)) # Q10 resonance gain
amps[k] = (g * 1024) // (1024 + 256 * k) # spectral tilt
ph0 += _inc(f0)
acc = 0
for k in range(nh):
acc += amps[k] * _osc((k + 1) * ph0)
out.append(acc >> 15)
env = _envelope(n, r.int(SR // 200, SR // 20), r.int(SR // 50, SR // 10))
return [(v * e) >> 15 for v, e in zip(out, env)]
KINDS = [_tone, _chirp, _noise, _formant]
def signal(seed, stream, n):
"""n samples of the generated signal (a list of ints in the int16 range)."""
r = Rng(seed, stream)
out = []
while len(out) < n:
m = r.int(SR * 8 // 100, SR // 2) # a segment: 80–500 ms
seg = KINDS[r.int(0, 3)](r, m)
if r.int(0, 3) == 0: # sometimes a second, quieter kind
over = KINDS[r.int(0, 3)](r, m)
seg = [a + (b >> 2) for a, b in zip(seg, over)]
peak = max(1, max(abs(v) for v in seg))
target = r.int(6000, 28000)
seg = [(v * target) // peak for v in seg]
out += seg + [0] * r.int(0, SR // 25) # a gap: 0–40 ms
return [max(-32768, min(32767, v)) for v in out[:n]]
def s16le(x):
return struct.pack(f'<{len(x)}h', *x)
# ---- learned model (float; the encoder) -------------------------------------
class GDN1d(nn.Module):
"""1-D (inverse) generalized divisive normalization with a full C×C gamma.
Forward divides by sqrt(beta + gamma·x²); inverse multiplies — the exact form
crate::int_transform::igdn reproduces in integer (out = x·isqrt(norm))."""
def __init__(self, ch, inverse):
super().__init__()
self.inverse = inverse
self.rg = nn.Parameter(torch.randn(ch, ch) * 0.01) # raw → softplus → γ≥0
self.rb = nn.Parameter(torch.zeros(ch)) # raw → softplus → β≈1
def build_codec(C):
import torch
import torch.nn as nn
import torch.nn.functional as F
def gb(self):
return F.softplus(self.rg), F.softplus(self.rb + 1.0)
class GDN1d(nn.Module):
"""1-D (inverse) generalized divisive normalization with a full C×C gamma.
Forward divides by sqrt(beta + gamma·x²); inverse multiplies — the exact form
crate::int_transform::igdn reproduces in integer (out = x·isqrt(norm))."""
def __init__(self, ch, inverse):
super().__init__()
self.inverse = inverse
self.rg = nn.Parameter(torch.randn(ch, ch) * 0.01) # raw → softplus → γ≥0
self.rb = nn.Parameter(torch.zeros(ch)) # raw → softplus → β≈1
def forward(self, x): # x [N,C,T]
g, b = self.gb()
norm = b[None, :, None] + torch.einsum('ij,njt->nit', g, x * x)
return x * torch.sqrt(norm) if self.inverse else x / torch.sqrt(norm)
def gb(self):
return F.softplus(self.rg), F.softplus(self.rb + 1.0)
def forward(self, x): # x [N,C,T]
g, b = self.gb()
norm = b[None, :, None] + torch.einsum('ij,njt->nit', g, x * x)
return x * torch.sqrt(norm) if self.inverse else x / torch.sqrt(norm)
class Codec(nn.Module):
def __init__(self):
super().__init__()
ga, gs = [], []
for i in range(NLAY):
ga += [nn.Conv1d(1 if i == 0 else C, C, K, STR, K // 2), GDN1d(C, False)]
for i in range(NLAY):
last = i == NLAY - 1
gs += [nn.ConvTranspose1d(C, 1 if last else C, K, STR, K // 2, output_padding=STR - 1)]
if not last:
gs += [GDN1d(C, True)]
self.g_a, self.g_s = nn.Sequential(*ga), nn.Sequential(*gs)
class Codec(nn.Module):
def __init__(self):
super().__init__()
ga, gs = [], []
for i in range(NLAY):
ga += [nn.Conv1d(1 if i == 0 else C, C, K, STR, K // 2), GDN1d(C, False)]
for i in range(NLAY):
last = i == NLAY - 1
gs += [nn.ConvTranspose1d(C, 1 if last else C, K, STR, K // 2, output_padding=STR - 1)]
if not last:
gs += [GDN1d(C, True)]
self.g_a, self.g_s = nn.Sequential(*ga), nn.Sequential(*gs)
def forward(self, x):
y = self.g_a(x)
y_hat = y + (torch.rand_like(y) - 0.5) # STE quantization noise
return self.g_s(y_hat), y
def forward(self, x):
y = self.g_a(x)
y_hat = y + (torch.rand_like(y) - 0.5) # STE quantization noise
return self.g_s(y_hat), y
return Codec()
# ---- integer reference decode (numpy; mirrors the Rust i64 arithmetic) -------
def conv_t_1d_int(xi, wi, mult, bias, stride, pad, opad):
"""Integer 1-D transposed conv + per-out-channel (mult>>SHIFT)+bias — byte-for-
byte what Rust int_audio::conv_t_1d will do. xi [cin,T]; wi [cin,cout,k]."""
byte what Rust int_audio::conv_t_1d does. xi [cin,T]; wi [cin,cout,k]."""
import numpy as np
cin, cout, k = wi.shape; Tin = xi.shape[1]
To = (Tin - 1) * stride + k + opad - 2 * pad
Tp = To + 2 * pad
@ -88,6 +313,7 @@ def conv_t_1d_int(xi, wi, mult, bias, stride, pad, opad):
def igdn_int_1d(x, gi, bi):
"""Integer IGDN, the EXACT arithmetic of crate::int_transform::igdn (per-term
>>GF before the sum, isqrt at 2^AFRAC, (x·s)>>AFRAC). x [C,T] python-int."""
import numpy as np
Cc, Tt = x.shape
x2 = x * x # 2^(2·AFRAC)
norm = np.tile(np.array(bi, dtype=object)[:, None], (1, Tt)) # 2^(2·AFRAC)
@ -98,6 +324,7 @@ def igdn_int_1d(x, gi, bi):
def run_g_s_int(xi, layers):
import numpy as np
x = xi.astype(object)
for L in layers:
if L['type'] == 'convT':
@ -113,6 +340,7 @@ def run_g_s_int(xi, layers):
def to_pcm_i16(x_fixed):
"""[1,T] @ 2^AFRAC (≈[-1,1]) → int16 PCM, round-half-up, clamp. Matches Rust."""
import numpy as np
v = x_fixed[0]
num = v * 32767 + (1 << (AFRAC - 1))
pcm = num >> AFRAC # python>> floors (== i64 arith shift)
@ -121,12 +349,14 @@ def to_pcm_i16(x_fixed):
# ---- PTQ + entropy helpers ---------------------------------------------------
def q_weight_pc(w): # ConvTranspose1d [in,out,k] → per-OUT int12
import numpy as np
s = np.abs(w).max(axis=(0, 2), keepdims=True) / (2 ** (WBITS - 1) - 1) + 1e-12
wi = np.round(w / s).clip(-(2 ** (WBITS - 1)), 2 ** (WBITS - 1) - 1).astype(np.int64)
return wi, s.reshape(-1)
def fit_cdf(sym, lo, hi):
import numpy as np
n = hi - lo + 1
hist = np.bincount(np.asarray(sym, np.int64) - lo, minlength=n).astype(np.float64)
total = 1 << 16
@ -146,33 +376,41 @@ def fnv1a(buf):
return h
def main(src, outdir):
os.makedirs(outdir, exist_ok=True)
torch.manual_seed(0)
raw = np.fromfile(src, np.int16).astype(np.float32) / 32768.0
if MAXS:
raw = raw[:MAXS]
n = (len(raw) // T) * T
raw = raw[:n]
frames = torch.from_numpy(raw.reshape(-1, 1, T)) # [Nf,1,T]
def main(outdir, seed, C, nsamp, steps, train_seconds):
import numpy as np
import torch
import torch.nn.functional as F
from compressai.ans import RansEncoder
m = Codec()
opt = torch.optim.Adam(m.parameters(), 1.5e-3)
assert nsamp % T == 0, f'--samples must be a multiple of {T}'
os.makedirs(outdir, exist_ok=True)
torch.manual_seed(seed)
torch.use_deterministic_algorithms(True)
torch.set_num_threads(THREADS)
ntrain = (train_seconds * SR // T) * T
train = np.array(signal(seed, 0, ntrain), np.float32) / 32768.0
test_i16 = signal(seed, 1, nsamp)
raw = np.array(test_i16, np.float32) / 32768.0
frames = torch.from_numpy(train.reshape(-1, 1, T)) # [Nf,1,T]
m = build_codec(C)
opt = torch.optim.Adam(m.parameters(), LR)
# Keep the rate term tiny: the latent must stay O(1+) so integer rounding (the
# quantizer) preserves it — too much rate pressure collapses it below the grid.
for step in range(STEPS):
for step in range(steps):
xr, y = m(frames)
loss = F.mse_loss(xr, frames) + 8e-6 * y.abs().mean()
loss = F.mse_loss(xr, frames) + RATE_W * y.abs().mean()
opt.zero_grad(); loss.backward(); opt.step()
m.eval()
with torch.no_grad():
xr_f, _ = m(frames)
snr_f = 10 * np.log10((frames ** 2).sum() / ((xr_f - frames) ** 2).sum() + 1e-12)
print(f' (float recon SNR {float(snr_f):.1f} dB)')
print(f' (float recon SNR on the training signal {float(snr_f):.1f} dB)')
# full-signal latent → per-channel factorized symbols (s = round(y - median))
# the test signal's latent → per-channel factorized symbols (s = round(y - median))
with torch.no_grad():
xfull = torch.from_numpy(raw.reshape(1, 1, n))
xfull = torch.from_numpy(raw.reshape(1, 1, nsamp))
y = m.g_a(xfull)[0].numpy() # [C, L]
L = y.shape[1]
median = np.round(np.median(y, axis=1)) # integer-grid median
@ -214,7 +452,6 @@ def main(src, outdir):
bits = enc.encode_with_indexes(syms_flat, idx, cdfs, [len(cdfs[0])] * C, [lo] * C)
# WAM1 binary model
import struct
mb = bytearray(b'WAM1')
mb += struct.pack('<IIII', AFRAC, GF, SHIFT, len(layers))
for Lr in layers:
@ -237,16 +474,27 @@ def main(src, outdir):
json.dump({'pcm_fnv1a': pcm_hash, 'n_samples': int(len(pcm)), 'sample_rate': SR},
open(f'{outdir}/audio.json', 'w'))
pcm.tofile(f'{outdir}/audio_decoded.s16')
print(f'learned 1-D audio codec: {len(pcm)} samples @ {SR}Hz, C={C} L={L}, model {len(mb)}B, '
f'rANS {len(bits)}B -> integer-decode SNR {snr:.1f} dB, pcm_hash {pcm_hash}')
open(f'{outdir}/audio_source.s16', 'wb').write(s16le(test_i16))
print(f'learned 1-D audio codec (seed {seed}): {len(pcm)} samples @ {SR}Hz, C={C} L={L}, '
f'model {len(mb)}B, rANS {len(bits)}B -> integer-decode SNR {snr:.1f} dB, pcm_hash {pcm_hash}')
if __name__ == '__main__':
# optional: C MAXS STEPS (e.g. tiny committed vector: 16 8192 2500)
if len(sys.argv) > 3:
C = int(sys.argv[3])
if len(sys.argv) > 4:
MAXS = int(sys.argv[4])
if len(sys.argv) > 5:
STEPS = int(sys.argv[5])
main(sys.argv[1], sys.argv[2])
ap = argparse.ArgumentParser(description='Train and export the integer learned audio codec on a '
'generated signal (no audio input).')
ap.add_argument('outdir', nargs='?', help='where audio_model.bin, audio_bitstream.json and audio.json go')
ap.add_argument('--seed', type=int, default=1)
ap.add_argument('--channels', type=int, default=32, help='latent channels C')
ap.add_argument('--samples', type=int, default=32768, help='test-signal (coded clip) length, a multiple of 2048')
ap.add_argument('--steps', type=int, default=3500, help='training steps')
ap.add_argument('--train-seconds', type=int, default=8, help='training-signal length in seconds')
ap.add_argument('--signal-only', metavar='OUT.s16', help='write one generated signal and exit')
ap.add_argument('--stream', type=int, default=1, help='with --signal-only: 0 training, 1 test')
a = ap.parse_args()
if a.signal_only:
n = a.samples if a.stream == 1 else (a.train_seconds * SR // T) * T
open(a.signal_only, 'wb').write(s16le(signal(a.seed, a.stream, n)))
sys.exit(0)
if not a.outdir:
ap.error('outdir is required unless --signal-only is given')
main(a.outdir, a.seed, a.channels, a.samples, a.steps, a.train_seconds)

View file

@ -7,6 +7,8 @@ frame, hence the identical BLAKE3 — on every machine, no tolerance
parameter. The temporal counterpart of the static splat, with the
single cloud replaced by per-Gaussian keyframed tracks.
**Provenance.** Generated here: `wai_splat4d_vectors gen` writes every vector from clouds and tracks authored in code. No capture.
Each Gaussian carries a track of keyframes (`frame`, position, scale,
rotation quaternion, color, opacity, all `wai.det.fixed64`); the sink
interpolates linearly in the `Fx` floor at any frame. The frame hash is

View file

@ -23,8 +23,8 @@
//! not all trained models:
//!
//! - **trained:** int_synth photo, int_world, int_splat and int_audio (their export
//! tools train the float model, then quantize it; int_world and int_splat train
//! on procedurally generated content);
//! tools train the float model, then quantize it; int_world, int_splat and
//! int_audio train on generated content);
//! - **random weights:** the int_hyper tiny conditional codec
//! (`tools/wai_int_hyper_tiny_vector.py` draws its integer weights from a seeded
//! generator);

View file

@ -285,17 +285,21 @@ fn fixtures(t: &mut Tree) -> Vec<Fixture> {
fx(t, "wih1_order_exhausted_before_value", HYP, Some(short_z), None, "stream_exhausted", "decode");
fx(t, "wih1_unread_word", HYP, edit(&ih, &|b| { let l = get_u32(b, ih_ly); set_u32(b, ih_ly, l + 4); b.extend_from_slice(&[0; 4]) }), None, "stream_noncanonical", "decode");
// ── WIA1 ── (16 channels × 512, tables of 14)
// ── WIA1 ── (the header's n_ch at 12 and cdf_len at 28; the first table follows the
// n_ch medians, at 32 + 8·n_ch, and its last entry is the one that must be 65536)
let au_n = at(&au, wire::parse_wia1(&au).expect("audio parses").rans) - 4; // offset of L
let au_t0 = 32 + 8 * get_u32(&au, 12) as usize; // the first table
let au_cl = u16::from_le_bytes([au[28], au[29]]) as usize; // cdf_len
let au_last = au_t0 + (au_cl - 1) * 4; // the first table's last entry
fx(t, "wia1_json_form", AUD, None, Some(format!("{V}/int_audio/audio_bitstream.json")), "bad_magic", "parse");
fx(t, "wia1_under_splat", SPL, Some(au.clone()), None, "format_capability_mismatch", "parse");
fx(t, "wia1_afrac_zero", AUD, edit(&au, &|b| b[5] = 0), None, "field_range", "parse");
fx(t, "wia1_sr_zero", AUD, edit(&au, &|b| set_u32(b, 8, 0)), None, "field_range", "parse");
fx(t, "wia1_median_range", AUD, edit(&au, &|b| b[32..40].copy_from_slice(&((1i64 << 47) + 1).to_le_bytes())), None, "field_range", "parse");
fx(t, "wia1_cdf_malformed", AUD, edit(&au, &|b| set_u32(b, 160 + 13 * 4, 65_535)), None, "cdf_malformed", "parse");
fx(t, "wia1_cdf_malformed", AUD, edit(&au, &|b| set_u32(b, au_last, 65_535)), None, "cdf_malformed", "parse");
// §2's order: the tables are read one at a time, each present and then checked, so
// a malformed first table is cdf_malformed though the payload ends inside the second.
fx(t, "wia1_order_table_before_length", AUD, edit(&au, &|b| { set_u32(b, 160 + 13 * 4, 65_535); b.truncate(160 + 14 * 4 + 10) }), None, "cdf_malformed", "parse");
fx(t, "wia1_order_table_before_length", AUD, edit(&au, &|b| { set_u32(b, au_last, 65_535); b.truncate(au_t0 + au_cl * 4 + 10) }), None, "cdf_malformed", "parse");
fx(t, "wia1_too_large", AUD, edit(&au, &|b| { set_u32(b, 12, 65_536); set_u32(b, 16, 2_048) }), None, "too_large", "parse");
fx(t, "wia1_trailing", AUD, edit(&au, &|b| b.push(0)), None, "trailing", "parse");
fx(t, "wia1_afrac_model", AUD, edit(&au, &|b| b[5] = 11), None, "model_mismatch", "decode");

View file

@ -0,0 +1,73 @@
//! Every corpus states where its content comes from (CONTRIBUTING, *Corpus content*).
//!
//! Each `wai/*-conformance/` directory has a `README.md` with a line that begins
//! `**Provenance.**`, and `tests/vectors/README.md` has a row for every directory under
//! `tests/vectors/` whose provenance cell is not empty. A provenance line names the
//! generator that writes the content and the generator's input; an input not generated
//! in this repository is named with its source and its licence. The test holds the
//! line's presence, not its truth: that is a reviewer's, and for audio also
//! `tools/wai_audio_provenance_check.py`'s.
use std::path::PathBuf;
fn wai() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
}
/// The line a README states its provenance in, if it has one with text after the label.
fn provenance_line(readme: &str) -> Option<&str> {
readme
.lines()
.map(str::trim_start)
.find(|l| l.starts_with("**Provenance.**") && l.len() > "**Provenance.**".len() + 1)
}
#[test]
fn every_conformance_corpus_states_its_provenance() {
// OER/2 is settled: no change edits its documents or its corpus.
let settled = ["oer-conformance"];
let mut dirs: Vec<String> = std::fs::read_dir(wai())
.unwrap()
.flatten()
.filter(|e| e.path().is_dir())
.map(|e| e.file_name().to_string_lossy().into_owned())
.filter(|n| n.ends_with("-conformance"))
.collect();
dirs.sort();
assert!(dirs.len() > 10, "found {} corpora", dirs.len());
let mut missing = Vec::new();
for d in &dirs {
if settled.contains(&d.as_str()) {
continue;
}
match std::fs::read_to_string(wai().join(d).join("README.md")) {
Ok(text) if provenance_line(&text).is_some() => {}
Ok(_) => missing.push(format!("{d}/README.md has no `**Provenance.**` line")),
Err(_) => missing.push(format!("{d} has no README.md")),
}
}
assert!(missing.is_empty(), "corpora without a provenance line:\n {}", missing.join("\n "));
}
#[test]
fn every_vector_directory_states_its_provenance() {
let root = wai().join("wai-rs/tests/vectors");
let index = std::fs::read_to_string(root.join("README.md")).expect("tests/vectors/README.md");
let mut dirs: Vec<String> = std::fs::read_dir(&root)
.unwrap()
.flatten()
.filter(|e| e.path().is_dir())
.map(|e| e.file_name().to_string_lossy().into_owned())
.collect();
dirs.sort();
let mut missing = Vec::new();
for d in &dirs {
// A row: | `<dir>/` | <provenance> | …
let row = index.lines().find(|l| l.trim_start().starts_with(&format!("| `{d}/` |")));
let cell = row.and_then(|r| r.split('|').nth(2)).map(str::trim).unwrap_or("");
if cell.is_empty() {
missing.push(d.clone());
}
}
assert!(missing.is_empty(), "tests/vectors/README.md states no provenance for: {missing:?}");
}

View file

@ -0,0 +1,21 @@
# Committed vectors
The vectors the reference implementation's tests decode, and the conformance corpora
under `wai/*-conformance/` and the cross-architecture goldens are built on. A vector
changes only through its generator (CONTRIBUTING, *Vectors*).
**Provenance.** Each directory's row names the generator that writes it and the
generator's input. `tests/corpus_provenance.rs` requires a row for every directory.
| directory | provenance |
|---|---|
| `generate/` | Generated: `tools/wai_generate_model.py` writes the spectral model from an integer sine table and a word list. |
| `int_audio/` | Generated: `tools/wai_int_audio_export.py` trains the codec on a signal it generates from seed 1 and codes another signal from the same seed; it reads no audio file ([`int_audio/README.md`](int_audio/README.md)). |
| `int_hyper/` | Generated: `tools/wai_int_hyper_tiny_vector.py` draws the tiny conditional codec's integer weights from a seeded generator. No image. |
| `int_mlicpp/` | Generated: `tools/wai_int_mlicpp_export.py` (seed 20260929) codes an integer pattern of ramps, an xor texture and a disc with seeded weights; `tools/wai_int_mlicpp_set_form.py` writes its set-form twin. |
| `int_splat/` | Generated: `tools/wai_int_splat_export.py` trains on a seeded procedural cloud. |
| `int_video/` | `int_video.*` is generated by `tools/wai_int_video_encode.py` (a disc over a gradient), and `video_nk.*` by `tools/wai_int_video_keyframe_encode.py` (the `int_hyper` tiny keyframe, panned). `video_real.*` is **not** generated: `tools/wai_int_video_real_encode.py` pans over a third-party picture that was not made for this repository and has no recorded licence for redistribution. It is to be replaced by generated content. |
| `int_world/` | Generated: `tools/wai_int_world_export.py` trains on a seeded procedural world. |
| `int_world2/` | Generated: `tools/wai_int_world2_export.py` trains on seeded procedural backgrounds. |
| `jpegai/` | `test256.bin` is the output of the ISO/IEC 6048-1 reference encoder (BSD-3) for a 256×256 generated test image of gradients and blocks ([`jpegai/README.md`](jpegai/README.md)). |
| `staged_bounds/` | Constructed here for the bound tests: grey frames from a residual stream of zeros, and envelopes whose capability is refinement-only or companion-only ([`staged_bounds/README.md`](staged_bounds/README.md)). No image. |

View file

@ -0,0 +1,39 @@
# `wai.audio.int_codec` — the committed vector
**Provenance.** Generated here. The signal the codec is trained on, and the clip the
vector codes, are written by `tools/wai_int_audio_export.py` itself from a seed: 16 kHz,
mono, signed 16-bit, a sequence of tones, chirps, noise bursts and speech-like formant
sweeps. The tool reads no audio file. Apache-2.0, like the rest of the repository.
- `audio_model.bin` — the integer synthesis (`WAM1`): 16 latent channels, four
transposed convolutions with integer IGDN between them.
- `audio_bitstream.json` — the export's JSON form: the latent (16 × 512), its
per-channel tables and its rANS stream. `audio_bitstream.wia1` is the same bitstream
as a `WIA1` payload, converted by `wai_int_payload_vectors gen`.
- `audio.json` — the decoded PCM's FNV-1a, its sample count (8192) and its rate.
- `sha256.json` — the decoded PCM's SHA-256 (SPEC §7 *Digests*), written by
`WAI_WRITE_SHA256_SIDECARS=1 cargo test --test int_kernels_vectors int_audio_clip`
after the decode has reproduced `audio.json`'s FNV-1a.
**How it was made.** From `wai/`, with torch 2.14.1, numpy 1.26.4 and CompressAI 1.2.8
on an arm64 host:
python tools/wai_int_audio_export.py <out> --seed 1 --channels 16 --samples 8192 --steps 2500
then `audio_model.bin`, `audio_bitstream.json` and `audio.json` copied from `<out>`.
The seed is **1**: stream 0 of the seed is the training signal (8 s), stream 1 the coded
clip. Training is seeded from the same seed, with deterministic algorithms and four
threads. Two runs gave byte-identical files. A different host or torch build may train
to different weights; the committed files are what conformance checks, and their
decode is integer and the same everywhere.
The signal alone needs only the Python standard library:
python3 tools/wai_int_audio_export.py --signal-only clip.s16 --seed 1 --stream 1 --samples 8192
The site's demo clip is an export of the same tool with the same seed and the
command's defaults (32 channels, 32768 samples, 3500 steps).
**Checked.** `tools/wai_audio_provenance_check.py` correlates the decoded clip (the
staged-delivery case `audio_int_codec_1l`'s stage 0) against the reference recordings
the CI host has, and fails above 0.5.

View file

@ -1 +1 @@
{"pcm_fnv1a": "085b193909b3042a", "n_samples": 8192, "sample_rate": 16000}
{"pcm_fnv1a": "e5ff66ad1b86117c", "n_samples": 8192, "sample_rate": 16000}

View file

@ -1 +1 @@
{"n_ch": 16, "lat_len": 512, "t_out": 8192, "afrac": 12, "lo": -6, "cdfs": [[0, 1, 2, 3, 4, 5, 6, 65404, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 255, 1790, 4477, 8060, 11899, 15994, 50564, 52995, 56322, 60929, 64128, 65535, 65536], [0, 1, 2, 2433, 6528, 11135, 14590, 49541, 56579, 60290, 63873, 65408, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 41472, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65530, 65531, 65532, 65533, 65534, 65535, 65536]], "median_q": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4096, 0], "rans_b64": "etYG9QEAAAAZ0vuSWzgg8GEZB5zW3oezESVuYoARWGd+yezeXdBdidkZayqq2n1f3P8iNWEgLHGQ7iWl4NSxAj8O9necDFtFYOYAKo/DzaLmOkzC6tfuO63y92k3EcIwRRMHjdQjAi1+K5BDivfp3ycuhq+d4HuaPyWFGWD6p4n+HsK6uU/9u5x2IxyWMCs5K0VqX+5dNsWEXFF4Sm8Y/Mt04/sYeTs9d3CIvljRV7lk6dRvYmz7e7/KeCHN0RmtwsSvTHQ1acqT47otwcBwGCUAG0kn7e4bnu8fnvD7+tB78335QQspZbgXaJN35Su21jMBpUhzCYVdq8I5Vwy1dgQTLe/Bxg7OVviBB/rIYr5hy95NqexAdoohKfoOwsddftjaHPHWuwf5uNFFsZl9wFupJqFnc1HFlXLaOUFfdx7KOpF/HyHjKjXBBFCy5b1kNfSeTkawYtjBtw4WqRQ7uwCy2gPE0zpVm/wfQdKIfdVDB6X8TQoQ980+yzZCfoCo"}
{"n_ch": 16, "lat_len": 512, "t_out": 8192, "afrac": 12, "lo": -6, "cdfs": [[0, 1, 2, 3, 4, 5, 6, 65529, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 7811, 64123, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65529, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 1924, 63355, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65529, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 2050, 5505, 19582, 45698, 58239, 63869, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 1028, 32772, 52224, 65405, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 4483, 18304, 35324, 53633, 62463, 65278, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 9474, 22271, 39171, 54144, 64893, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 2178, 3329, 19965, 47105, 61694, 64893, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 6, 65529, 65530, 65531, 65532, 65533, 65534, 65535, 65536], [0, 3967, 7934, 11133, 15996, 21626, 26233, 33015, 40309, 45939, 53762, 56577, 60544, 65535, 65536], [0, 1, 2, 3, 1922, 10880, 22653, 41986, 53631, 63229, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 11650, 35197, 63612, 65531, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 7681, 17663, 26237, 39546, 54784, 65405, 65532, 65533, 65534, 65535, 65536], [0, 1, 2, 3, 4, 5, 2436, 33282, 57213, 65531, 65532, 65533, 65534, 65535, 65536]], "median_q": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4096, 4096, -4096], "rans_b64": "bh7fxT8AAAATELnUjf3O5eE8XGMF/sJWJaIlOwjg5Q6m3Q4X3ewuSNs28cUZsE7mhJR3RNRP6UC7HDfTHQEwCLUGqBry9mB0xLaXxuuSBjkKI4XjzUIn0v0jgDCAdGXp47PxXfaChT4s0U7/mA+KjLRJzGcawpnA0xRwgfVHzl8yEQs3Lz0gEbrnDP1eH5LgYuGhm3rr9ONe/0Pzgg8ueDYTkgYgCHsUsmhOnpumjTpkc28Mblcnf1+S5owQr+KX4Ydh75ejd7k0wE0JmWyyZknIAYWTrC9fcSnwZfuIGs2eyHzNW5KPKBKtByoGVF4In/cqV1zywnhyqf5oij87K11yE4IsWsImI3Ay346C0rG+Q5KVhST/USnzxkPt/izl6/z4ts4h/C4WEQ9o2T9VVbiDVo24XWNNjpSTw2kRJLx3fizkkcYUxUnC+FmepYb6kaLS/n/2lxquX/Ujgplb2pqDpGrWwAgCHcTNij96PGFHDfu19VBmsizQZsvlos5Opwk7LtTfJr+2bofB9thKPueG9uLEnf5OVt0PzSEMRYJ+t1SQaV/s5G0LDXq1v14RKevagbsJIRYLSFm8QbTV2IcBvCv7X6fWfe1zEsYuQXBSYzHVlb2XG1Rgw34AaL5jheA5URliccP9ciehjZEieG0hbkC6U7bHm1iL0aqjoW6Lpj4DKOrcPqo7BPa9vyxrxlLqbZThUA6oAghHtYkFLwa+gOJnfhkZwCg9zquMzPJ2+h3BmfjEyPFAqvtAEz95X48iBUfv5qxBjIaObD3AX88ui7hM4Z8nOnxgw4k/qeGCSI3dVd0TeE5HLb8SDqkgY8QiwxjHroAz4vNb6P7hK6r4fMTzXeupbgn6X5x+Ez5fFMaHzMzhZRjYt5Tf2gPi4WRkZhLvrACOsGugwTWVQLszQnApN6zDol5C9dQOBrxv9mmkjGTMx/isoAveVgr6ysJuSnkm/tbyyamfgS41GmrdBdRzTR6UNriuSO1s+lxnoBqdI3SLbnpRryifit2mRywFk7xzlvIfus/tTIDCFZa5AZzmRA9EvbZHYh8uWMHim1+eLmyzds3OEFEHLYuL9s7GcOg5IsxcjDUNlq5KEXEfTQ69U8WlIGckTwjJLnASv6rcfJQ/0p9r+NMcpKZuH7eqiKY7XTjZjkTPn5gqlNSYG0jY6eLK+NdkIk9d/K5OJTBS3BjvdkwFY2lJBhXsaCfFXxPmMp8V//U/+PnuRJf6TTxkQmM60SH5m9IcilxNBKpOKSTObD9C4skikkKDirdgGIr0QQQp8cC4Ne5kzBOvZlfUcd9B8E3rlQw8x7cPH/8VobcJqRTotUaIpnjBE1fbSFrEVQ750bTT2UsHM137BCZoovofJlma3puAtqd9HggazBj81hH9u5f1HPkmbtQrIOTyEfscB8VRJSuZf9KsKSPkWhyNbTesD16MopfA1WSGCuU9qjjMSGCCO91vkRsFQGFBW8v6xr3htOh/8l60kmDrY3JNQykSgKiWRbh9rlRTN4w4cAYtbErSYTZfwbmOD0HABwpUt7dZ7cmJBI8kdAXw/ziMMImTwu0KSxn2D+BXBCtyul08lcc7UNt35ebuFy1RpZ9yVsfaTQXwNLcqs5zCCCHJINEG8iOIuR6w2YSkFp5WcarOz7tRgN07A6NoebHOdgdkfH5AVKpLBsW6Fn9oZNCwRYgg641XDL8ld9S3GbGa3cj4mP/rqGjYBOtrgVqMqrCvU1hS4Vo/GdYkjn/1ZevBJJhD0YLcppAjFJJLA4WFCmmgLrkw0tjr86PmHeOznGLxMMk5Dph+4M7BOYGxIAkLxnlBDPeZCy2OF01wZME8wMdL0gHVHj0hld/asUQm8CBxyt9oA5pqSag+9Jdc6e8MGCqcytXMnZ7/E54KfP0niIlBxg0wODrdkJWvLBnpXGW7NrPqMBTek7UTwSyTOJePsIGcOdDWhjxTxnoDVY8DtYd+p5fJmg1j3s3HoifvmmwXppyJWrUf0F2OJmns5pxPE6W71dOB5WqP9hvW"}

View file

@ -1,6 +1,6 @@
{
"audio": {
"buffer": "PCM: signed 16-bit little-endian samples in output order, channels interleaved",
"sha256": "b8ff83a442c112661ec7a41d6e51cb32559510a699a0e9bb37fa301f8952978a"
"sha256": "4b0344c87c67fc30b7d977ae2077fc310822199598e5d2f9f8fc06314b3a2875"
}
}

View file

@ -6,6 +6,8 @@ MUST produce the identical BLAKE3 state hash at every checkpoint, on
every machine, under every permitted arrival order. Verification is
hash equality — there is no tolerance parameter.
**Provenance.** Generated here: `wai_world_vectors gen` writes every world from scenes authored in code. No capture.
Vectors run the registered sim capabilities `wai.world.sim.kinematic0`,
`wai.world.sim.ballistic0`, and `wai.world.sim.truss0` (the
solver-backed registrant: position-based dynamics, 8 Gauss–Seidel