From b3990ae6b9dca04cb5693cc2ef81307afba90e30 Mon Sep 17 00:00:00 2001 From: john Date: Thu, 11 Sep 2025 10:56:08 +0200 Subject: [PATCH] say --- say.zsh | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100755 say.zsh diff --git a/say.zsh b/say.zsh new file mode 100755 index 0000000..1fb5e35 --- /dev/null +++ b/say.zsh @@ -0,0 +1,78 @@ +#!/bin/env zsh + +voices_dir=/usr/share/piper-voices +voice="$voices_dir/en/en_US/ryan/high/en_US-ryan-high.onnx" + +parse_voice() { + emulate -L zsh + local query="$1" chosen + [[ -n "$query" ]] || { echo "voice query required" >&2; exit 2; } + + chosen=$( + jq -r --arg root "$voices_dir" ' + to_entries + | .[].value.files + | keys[] + | select(endswith(".onnx")) + | if startswith("/") then . else "\($root)/\(.)" end + ' "$voices_dir/voices.json" \ + | fzf --filter="$query" \ + | head -n1 + ) + + [[ -n "$chosen" ]] || { echo "no matching voice for: $query" >&2; exit 4; } + voice="$chosen" +} + + +list_voices() { + jq -r 'keys[]' $voices_dir/voices.json +} + +print_help() { + echo "Usage: say [options] " + echo "Options:" + echo " -h, --help Show this help message and exit" + echo " -v, --voice Set voice" + echo " -l, --list List available voices and exit" +} + +do_say() { + echo "$voice" >&2 + emulate -L zsh + { [[ $# -eq 0 ]] && cat || echo "$@"; } \ + | piper-tts --model "$voice" --output_raw 2>/dev/null \ + | aplay -r 22050 -f S16_LE -t raw - 2>/dev/null + +} + +opts=$(getopt -o hv:l --long help,voice:,list -n "$0" -- "$@") || exit 5 +eval set -- "$opts" + +while true; do + case "$1" in + -h|--help) + print_help + exit 0 + ;; + -v|--voice) + parse_voice "$2" + shift 2 + ;; + -l|--list) + list_voices + exit 0 + ;; + --) + shift + break + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +do_say "$@" +