import os
import struct
import subprocess
import numpy as np
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
REF_DIR = os.path.join(ROOT, "target", "vorbis-ref")
REF = os.path.join(REF_DIR, "ref_enc_posix.exe")
OUT = os.path.join(REF_DIR, "fixtures")
def fnv64(data, h=0xCBF29CE484222325):
for b in data:
h ^= b
h = (h * 0x100000001B3) & 0xFFFFFFFFFFFFFFFF
return h
def synth(frames, channels, seed):
out = np.zeros(frames * channels, dtype=np.float32)
state = seed & 0xFFFFFFFF
k = 0
for i in range(frames):
for c in range(channels):
state = (state * 1664525 + 1013904223) & 0xFFFFFFFF
noise = ((state >> 16) & 0x7FF) - 1024
p = 97 + 13 * c
ph = i % p
tri = ph if ph < p // 2 else p - ph
x = noise * 3 + tri * 300 - (p // 4) * 300
if (i // 64) % 150 == 0:
x *= 8
out[k] = np.float32(x) / np.float32(32768.0)
k += 1
return out
def run_ref(rate, ch, q, pcm, chunk=1024):
os.makedirs(OUT, exist_ok=True)
fin = os.path.join(OUT, "in.f32")
fout = os.path.join(OUT, "out.pkt")
pcm.astype("<f4").tofile(fin)
subprocess.run([REF, str(rate), str(ch), repr(q), fin, fout, str(chunk)], check=True,
stderr=subprocess.DEVNULL)
b = open(fout, "rb").read()
pos = 8
pk = []
while pos < len(b):
n, g, _f = struct.unpack("<Iqb", b[pos:pos + 13])
pk.append((b[pos + 13:pos + 13 + n], g))
pos += 13 + n
return pk
def rust_bytes(b):
return "&[" + ", ".join("0x%02x" % x for x in b) + "]"
def main():
lines = [
"// @generated by tools/vorbis_encoder/make_fixtures.py from the C reference encoder",
"// (libvorbis 1.3.7, tools/vorbis_encoder/build_ref.sh's ref_enc_posix and ref_bitrate). Test-only data.",
"",
"/// (rate, channels, quality, id header, comment header, setup len, setup FNV-1a-64)",
"#[allow(clippy::type_complexity)]",
"pub(super) const HEADERS: &[(u32, u16, f32, &[u8], &[u8], usize, u64)] = &[",
]
silent = np.zeros(2048 * 2, dtype=np.float32)
for rate, ch, q in [(48000, 2, 0.5), (44100, 1, -0.1), (44100, 2, 1.0), (22050, 2, 0.3),
(8000, 1, 0.0), (96000, 2, 0.7), (32000, 1, 0.45), (11025, 2, 0.9)]:
pk = run_ref(rate, ch, q, silent[:2048 * ch])
lines.append(" (%d, %d, %r, %s, %s, %d, 0x%016x)," % (
rate, ch, q, rust_bytes(pk[0][0]), rust_bytes(pk[1][0]), len(pk[2][0]), fnv64(pk[2][0])))
lines.append("];")
lines.append("")
lines.append("/// (rate, channels, quality, frames, seed, chunk, packets, bytes, last granule, FNV-1a-64)")
lines.append("#[allow(clippy::type_complexity)]")
lines.append("pub(super) const ENCODES: &[(u32, u16, f32, usize, u32, usize, usize, usize, u64, u64)] = &[")
for rate, ch, q, frames, seed, chunk in [(44100, 2, 0.5, 30000, 1, 1024), (48000, 1, -0.1, 20000, 2, 512),
(48000, 2, 1.0, 12000, 3, 4096), (22050, 1, 0.3, 9000, 4, 100),
(44100, 2, 0.0, 1500, 5, 1024), (8000, 2, 0.6, 7000, 6, 333)]:
pcm = synth(frames, ch, seed)
pk = run_ref(rate, ch, q, pcm, chunk)
h = 0xCBF29CE484222325
nbytes = 0
for data, g in pk[3:]:
h = fnv64(struct.pack("<I", len(data)) + data + struct.pack("<Q", g & 0xFFFFFFFFFFFFFFFF), h)
nbytes += len(data)
lines.append(" (%d, %d, %r, %d, %d, %d, %d, %d, %d, 0x%016x)," % (
rate, ch, q, frames, seed, chunk, len(pk) - 3, nbytes, pk[-1][1], h))
lines.append("];")
lines.append("")
lines.append("/// (rate, channels, bits/s, quality) from libvorbis' vorbis_encode_setup_managed")
lines.append("pub(super) const BITRATES: &[(u32, u16, u32, Option<f32>)] = &[")
out = subprocess.run([os.path.join(REF_DIR, "ref_bitrate.exe")], check=True,
capture_output=True, text=True).stdout
for ln in out.split("\n"):
f = ln.split()
if not f:
continue
if f[3] == "none":
q = "None"
else:
v = np.float32(float(f[4]))
q = "Some(%s_f32)" % np.format_float_positional(v, unique=True, trim="0")
lines.append(" (%s, %s, %s, %s)," % (f[0], f[1], f[2], q))
lines.append("];")
path = os.path.join(
ROOT, "crates", "zvidlib-vorbis-encoder", "src", "vorbis_encoder", "test_fixtures.rs"
)
with open(path, "w", newline="\n") as fh:
fh.write("\n".join(lines) + "\n")
print("wrote", path)
if __name__ == "__main__":
main()