#!/usr/bin/env python3 """ Chrome Google TTS WAV renderer. Purpose: Converts the same local ChromeOS Google TTS assets used by rovers into server-side WAV files that can be handed to another playback transport. Scope: This script only renders one utterance to a file; device playback and camera delivery stay owned by Node services. """ import argparse import ctypes import os import struct import sys import wave ASSET_ROOT = "/opt/roverd/googletts" LIB_PATH = os.path.join(ASSET_ROOT, "libchrometts.so") VOICE_DIR = os.path.join(ASSET_ROOT, "en-us-x-multi-r30") PIPELINE = "pipeline.pb" SAMPLE_RATE = 24000 MAX_TEXT_CHARS = 512 VOICES = { "sfg": "female", "iob": "female", "iog": "female", "iol": "male", "iom": "male", "tpc": "female", "tpd": "male", "tpf": "female", } DEFAULT_VOICE = "tpf" DEFAULT_PITCH = 1.0 DEFAULT_SPEED = 1.0 MIN_PITCH = 0.5 MAX_PITCH = 2.0 MIN_SPEED = 0.5 MAX_SPEED = 2.0 def varint(value): out = bytearray() while value >= 0x80: out.append((value & 0x7F) | 0x80) value >>= 7 out.append(value) return bytes(out) def field_bytes(number, payload): return varint((number << 3) | 2) + varint(len(payload)) + payload def field_float(number, value): return varint((number << 3) | 5) + struct.pack(" maximum: return maximum return value def float_to_s16le(samples): pcm = bytearray() for sample in samples: clipped = max(-1.0, min(1.0, float(sample))) pcm.extend(struct.pack(" 0: count = int(frames_written.value) if count > 0: wav.writeframes(float_to_s16le(self.buffer[:count])) def shutdown(self): self.lib.GoogleTtsShutdown() def main(): parser = argparse.ArgumentParser(description="Render Chrome Google TTS to a WAV file.") parser.add_argument("--text", required=True) parser.add_argument("--voice", default=DEFAULT_VOICE) parser.add_argument("--pitch", type=float, default=DEFAULT_PITCH) parser.add_argument("--speed", type=float, default=DEFAULT_SPEED) parser.add_argument("--output", required=True) args = parser.parse_args() tts = ChromeTTS() try: tts.render_wav(args.text, args.output, args.voice, args.pitch, args.speed) finally: tts.shutdown() return 0 if __name__ == "__main__": try: raise SystemExit(main()) except Exception as exc: sys.stderr.write(f"chromegtts-wav failed: {exc}\n") raise SystemExit(1)