Files
MeshCore/test/test_gps_voice_generator.py
T

156 lines
7.6 KiB
Python

"""Validate speech-generation plans, fixed audio identity, and fixture encoding."""
from pathlib import Path
import hashlib
import shutil
import subprocess
import sys
import tempfile
import unittest
from test_button_voice_generator import parse_header, write_wav
ROOT = Path(__file__).resolve().parents[1]
POWERSHELL = shutil.which("pwsh") or shutil.which("powershell")
BASELINE_FILTER = (
"highpass=f=350,lowpass=f=3400,"
"silenceremove=start_periods=1:start_threshold=-45dB,areverse,"
"silenceremove=start_periods=1:start_threshold=-45dB,areverse,"
"volume=1.4,alimiter=limit=0.8:level=disabled,apad=pad_dur=0.05"
)
SELECTED_FILTER = (
"highpass=f=350,lowpass=f=3400,"
"silenceremove=start_periods=1:start_threshold=-45dB,areverse,"
"silenceremove=start_periods=1:start_threshold=-45dB,areverse,"
"acompressor=threshold=0.08:ratio=6:attack=5:release=70:makeup=4:knee=4:detection=rms,"
"volume=1.4,aresample=8000,alimiter=limit=0.12:level=disabled,apad=pad_dur=0.05"
)
# Independently pinned from approved Zira WAVs (rate -1 / compressed / peak
# 0.12 / 8 kHz), not from the header being tested or its voice-name metadata.
ZIRA_GPS_RECORDINGS = {
'gpsOn': ('8bb2571a94245c9df307857a072f5e8900e72976c81536dc02c25251da42ca7a', 9683),
'gpsOff': ('4dd8519110914aba97d84d2d1b72a20dec8bb8ed573aa167551d8e092af8ffcb', 9237),
}
class AssetTests(unittest.TestCase):
def test_production_gps_recordings_are_the_approved_zira_audio_and_metadata(self):
source = (ROOT / 'src/helpers/ui/GpsVoiceData.h').read_text(encoding='utf-8')
self.assertEqual([line for line in source.splitlines() if line.startswith('// Voice:')],
['// Voice: Microsoft Zira Desktop'])
arrays, clips = parse_header(source)
self.assertEqual(tuple(arrays), tuple(ZIRA_GPS_RECORDINGS))
self.assertEqual(tuple(clips), tuple(ZIRA_GPS_RECORDINGS))
for name, (fingerprint, samples) in ZIRA_GPS_RECORDINGS.items():
with self.subTest(recording=name):
self.assertEqual(hashlib.sha256(arrays[name]).hexdigest(), fingerprint)
self.assertEqual(clips[name], (name, name, samples, 8000))
def test_optional_voice_metadata_preserves_generic_pcm_fixture_encoding(self):
with tempfile.TemporaryDirectory() as temporary:
directory = Path(temporary)
on, off = directory / 'on.wav', directory / 'off.wav'
write_wav(on, [0, 0, 1, -1, 2, -2, 3, -3, 1000])
write_wav(off, [0, 1, -1, 2, -2, 3, -3, -1000])
outputs = []
for arguments in ((), ('--voice', 'Microsoft Zira Desktop')):
target = directory / ('selected.h' if arguments else 'plain.h')
result = subprocess.run(
[sys.executable, str(ROOT / 'scripts/generate_gps_voice.py'),
'--on', str(on), '--off', str(off), '--output', str(target), *arguments],
capture_output=True, text=True, timeout=30,
)
self.assertEqual(result.returncode, 0, result.stderr)
outputs.append(target.read_text(encoding='utf-8'))
self.assertNotIn('// Voice:', outputs[0])
self.assertIn('// Voice: Microsoft Zira Desktop\n', outputs[1])
self.assertEqual(parse_header(outputs[0]), parse_header(outputs[1]))
def test_powershell_forwards_selected_voice_to_encoder_metadata(self):
source = (ROOT / 'scripts/generate_gps_voice.ps1').read_text(encoding='utf-8')
invocation = next(line for line in source.splitlines()
if line.startswith('& python $gpsEncoder '))
self.assertIn('--voice $Voice', invocation)
@unittest.skipUnless(POWERSHELL, "PowerShell is needed for generator plan tests")
class Tests(unittest.TestCase):
def plan(self, *arguments):
return subprocess.run(
[POWERSHELL, "-NoProfile", "-NonInteractive", "-File",
str(ROOT / "scripts/generate_gps_voice.ps1"),
*arguments, "-WhatIf", "-Verbose"],
cwd=ROOT, capture_output=True, text=True, timeout=30,
)
def test_selected_defaults_and_original_profile(self):
result = self.plan()
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn(SELECTED_FILTER, result.stdout)
self.assertIn("Microsoft Zira Desktop; rate: -1", result.stdout)
self.assertIn(str(ROOT / "src/helpers/ui/GpsVoiceData.h"), result.stdout)
result = self.plan(
"-Voice", "Microsoft Zira Desktop", "-Compress:$false", "-PeakLimit", "0.8",
"-OutputHeader", "out/gps-voice/original-zira.h",
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn(BASELINE_FILTER, result.stdout)
self.assertIn("Microsoft Zira Desktop; rate: -1", result.stdout)
self.assertNotIn("acompressor=", result.stdout)
def test_compressed_variant_is_planned_without_writes(self):
with tempfile.TemporaryDirectory() as temporary:
directory = Path(temporary) / "preview"
header = Path(temporary) / "headers/mark.h"
result = self.plan(
"-Voice", "Microsoft Mark", "-Rate", "0", "-Compress",
"-PeakLimit", "0.10", "-OutputDirectory", str(directory),
"-OutputHeader", str(header),
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("Microsoft Mark; rate: 0", result.stdout)
self.assertIn("acompressor=threshold=0.08:ratio=6", result.stdout)
self.assertIn("makeup=4:knee=4:detection=rms", result.stdout)
self.assertIn("aresample=8000,alimiter=limit=0.1:level=disabled", result.stdout)
self.assertIn(str(header), result.stdout)
self.assertFalse(directory.exists())
self.assertFalse(header.parent.exists())
def test_variants_require_an_explicit_header(self):
for arguments in (("-Compress:$false",), ("-Voice", "Microsoft Mark"),
("-Rate", "0"), ("-PeakLimit", "0.10")):
with self.subTest(arguments=arguments):
result = self.plan(*arguments)
self.assertNotEqual(result.returncode, 0)
self.assertIn("explicit -OutputHeader", result.stderr)
def test_invalid_header_extension_is_rejected(self):
result = self.plan("-OutputHeader", "out/gps-voice/test.wav")
self.assertNotEqual(result.returncode, 0)
self.assertIn("must name a .h file", result.stderr)
def test_file_directory_collisions_are_rejected(self):
with tempfile.TemporaryDirectory() as temporary:
path = Path(temporary)
file = path / "existing-file"
file.touch()
result = self.plan("-OutputDirectory", str(file))
self.assertNotEqual(result.returncode, 0)
self.assertIn("names an existing file", result.stderr)
directory = path / "existing-directory.h"
directory.mkdir()
result = self.plan("-OutputHeader", str(directory))
self.assertNotEqual(result.returncode, 0)
self.assertIn("names an existing directory", result.stderr)
def test_rate_and_peak_ranges_are_rejected(self):
for arguments in (("-Rate", "11"), ("-Rate", "-11"),
("-PeakLimit", "0.01"), ("-PeakLimit", "1.1")):
with self.subTest(arguments=arguments):
result = self.plan("-OutputHeader", "out/gps-voice/test.h", *arguments)
self.assertNotEqual(result.returncode, 0)
self.assertIn(arguments[0][1:], result.stderr)
if __name__ == "__main__":
unittest.main()