#!/usr/bin/env bash # gen-stt-fixtures.sh — regenerate the golden STT audio fixtures. # # The fixtures in cmd/mavsttd/testdata/*.wav are SYNTHESISED, not recorded. # They come out of the same piper voices maven speaks with, so nothing of the # owner's voice is committed and every fixture is reproducible from this # script plus the voice model. They are also small: 16 kHz mono s16le, a # couple of seconds each. # # Usage: # scripts/gen-stt-fixtures.sh # # Voices are picked up from, in order, $PIPER_VOICE_RU / $PIPER_VOICE_EN, then # the repo's models/tts, then ~/esp-server/voices. The English voice is not # vendored; if it is missing the English fixture is skipped and the existing # one is left alone. set -euo pipefail root="$(cd "$(dirname "$0")/.." && pwd)" out="$root/cmd/mavsttd/testdata" piper="${PIPER_BIN:-$root/deps/piper/piper}" espeak="${PIPER_ESPEAK:-$root/deps/piper/espeak-ng-data}" pick_voice() { for c in "$@"; do [ -f "$c" ] && { echo "$c"; return 0; } done return 1 } ru="$(pick_voice "${PIPER_VOICE_RU:-}" "$root/models/tts/ru_RU-irina-medium.onnx" "$HOME/esp-server/voices/ru_RU-irina-medium.onnx")" || { echo "no russian piper voice found" >&2 exit 1 } en="$(pick_voice "${PIPER_VOICE_EN:-}" "$root/models/tts/en_US-lessac-medium.onnx" "$HOME/esp-server/voices/en_US-lessac-medium.onnx")" || en="" # synth # piper emits raw 22050 Hz s16le on stdout; ffmpeg resamples to the canonical # 16 kHz mono and writes a plain 44-byte-header WAV (-fflags bitexact keeps # ffmpeg's encoder LIST chunk out, so the bytes are stable across ffmpeg # builds and internal/audio.PCMFromWAV reads them without scanning). synth() { local voice="$1" dest="$2" text="$3" printf '%s' "$text" | LD_LIBRARY_PATH="$(dirname "$piper")" "$piper" \ --model "$voice" --config "$voice.json" \ --espeak_data "$espeak" --output_raw --quiet | ffmpeg -hide_banner -loglevel error -y \ -f s16le -ar 22050 -ac 1 -i - \ -af "adelay=200,apad=pad_dur=0.2" \ -ar 16000 -ac 1 -c:a pcm_s16le -fflags bitexact "$dest" echo "wrote $dest ($(stat -c%s "$dest") bytes)" } synth "$ru" "$out/ru_reminder.wav" "Напомни мне через час позвонить маме." synth "$ru" "$out/ru_fact.wav" "Отметь, что я выпил воды." synth "$ru" "$out/ru_query.wav" "Что у меня сегодня по календарю?" if [ -n "$en" ]; then # Keep the English line free of words piper spells out letter by letter — # "nginx" comes out of lessac as "engine X", which is a TTS artefact and # would make the fixture assert on the wrong thing. synth "$en" "$out/en_act.wav" "Restart the web server and check the disk space." else echo "no english piper voice found — skipping en_act.wav" >&2 fi echo "fixtures regenerated; expected transcripts live in $out/golden_v1.json"