109 lines
3.2 KiB
Python
Executable File
109 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""bit-exact verification — прогон всех свипов, побайтовое сравнение int24 PCM."""
|
|
|
|
import subprocess
|
|
import os
|
|
import glob
|
|
import wave
|
|
import struct
|
|
import sys
|
|
|
|
RENDERER = "/home/m/re-tools/dsp/harness"
|
|
TEST_ROOT = "/home/m/soothe-bt"
|
|
|
|
def read_wav24(path):
|
|
"""Read WAV24 file and return numpy array or list of int24 samples."""
|
|
with wave.open(path, 'rb') as w:
|
|
n = w.getnframes()
|
|
data = w.readframes(n * w.getnchannels())
|
|
sw = w.getsampwidth()
|
|
nc = w.getnchannels()
|
|
|
|
if sw == 3:
|
|
samples = []
|
|
for i in range(0, len(data), 3):
|
|
val = struct.unpack('<i', data[i:i+3] + b'\x00')[0]
|
|
if val & 0x800000:
|
|
val -= 0x1000000
|
|
samples.append(val)
|
|
return samples, nc
|
|
else:
|
|
return list(struct.unpack(f'<{len(data)//2}h', data)), nc
|
|
|
|
def run_harness(in_wav, out_wav):
|
|
"""Run harness.cpp renderer."""
|
|
cmd = [RENDERER, in_wav, out_wav]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
return result.returncode == 0
|
|
except Exception as e:
|
|
print(f"Error running {in_wav}: {e}")
|
|
return False
|
|
|
|
def compare_bytes(path1, path2):
|
|
"""Compare two WAV files byte-by-byte. Returns (match, diff_count, max_diff)."""
|
|
with wave.open(path1, 'rb') as w1, wave.open(path2, 'rb') as w2:
|
|
if w1.getparams() != w2.getparams():
|
|
return False, -1, -1
|
|
|
|
data1 = w1.readframes(w1.getnframes() * w1.getnchannels())
|
|
data2 = w2.readframes(w2.getnframes() * w2.getnchannels())
|
|
|
|
if len(data1) != len(data2):
|
|
return False, abs(len(data1) - len(data2)), -1
|
|
|
|
diff = sum(1 for i in range(len(data1)) if data1[i] != data2[i])
|
|
return diff == 0, diff, 0
|
|
|
|
def test_sweep(name):
|
|
"""Test single sweep: in.wav -> render -> out.wav, compare to ref.wav."""
|
|
in_wav = f"{TEST_ROOT}/{name}.wav"
|
|
ref_wav = f"{TEST_ROOT}/{name}_ref.wav"
|
|
out_wav = f"/tmp/out_{name}.wav"
|
|
|
|
if not os.path.exists(in_wav):
|
|
print(f"SKIP {name}: no input")
|
|
return None
|
|
|
|
if not run_harness(in_wav, out_wav):
|
|
print(f"FAIL {name}: renderer error")
|
|
return False
|
|
|
|
match, diff, max_diff = compare_bytes(ref_wav, out_wav)
|
|
|
|
if match:
|
|
print(f"PASS {name}")
|
|
return True
|
|
else:
|
|
print(f"FAIL {name}: {diff} byte differences")
|
|
return False
|
|
|
|
def main():
|
|
rpps = sorted(glob.glob(f"{TEST_ROOT}/*.rpp"))
|
|
print(f"Found {len(rpps)} RPP files")
|
|
|
|
passed = 0
|
|
failed = 0
|
|
skipped = 0
|
|
|
|
for rpp in rpps[:10]: # Test first 10
|
|
name = os.path.splitext(os.path.basename(rpp))[0]
|
|
wav = f"{TEST_ROOT}/{name}.wav"
|
|
|
|
if not os.path.exists(wav):
|
|
skipped += 1
|
|
continue
|
|
|
|
result = test_sweep(name)
|
|
if result is True:
|
|
passed += 1
|
|
elif result is False:
|
|
failed += 1
|
|
else:
|
|
skipped += 1
|
|
|
|
print(f"\nSummary: {passed} passed, {failed} failed, {skipped} skipped")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|