#!/usr/bin/env bash # Voz de JARVIS con Piper: castellano de España, no latinoamericano. # # jarvis-piper.sh # # Kokoro, que es lo que trae Newelle, no tiene ni una voz de España: sus dos # masculinas en español (em_alex, em_santa) suenan latinas. Piper si las tiene, # es libre y corre local. Se invoca desde el handler custom_command, que ya # ejecuta en el host. # # El descenso de tono se hace aqui y no en la cadena de la app porque alli se # usa asetrate, que necesita saber la frecuencia de muestreo: esta calculada # para los 24 kHz de Kokoro y Piper saca 22050, asi que aplicaria una bajada # distinta de la pedida. Aqui se usa rubberband, que trabaja en semitonos y le # da igual la frecuencia. Existe en el ffmpeg del sistema pero no en el del # flatpak, y este script ya corre fuera. # # Ajustes por entorno: # JARVIS_PIPER_VOZ es_ES-sharvard-medium (defecto) | es_ES-davefx-medium # | es_ES-carlfm-x_low # JARVIS_PIPER_TONO 0.90 (defecto). 1.0 no toca el tono; por debajo de # 0.85 empieza a sonar artificial. set -uo pipefail # La raiz se deduce de donde esta este fichero, no del $HOME de nadie: asi el # arbol se puede mover o clonar en otra maquina y sigue funcionando sin editar # rutas. `cd -P` resuelve enlaces simbolicos, que el lanzador de escritorio # puede invocarlo por uno. RAIZ=$(cd -P "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd) BASE=$RAIZ/voz VOZ=${JARVIS_PIPER_VOZ:-es_ES-sharvard-medium} TONO=${JARVIS_PIPER_TONO:-0.90} SALIDA=${1:-} TEXTO=${2:-} [ -n "$SALIDA" ] || { echo "falta el fichero de salida" >&2; exit 1; } [ -n "$TEXTO" ] || { echo "sin texto que decir" >&2; exit 1; } MODELO=$BASE/modelos/$VOZ.onnx [ -f "$MODELO" ] || { echo "no esta el modelo $MODELO" >&2; exit 1; } CRUDO=$(mktemp --suffix=.wav) trap 'rm -f "$CRUDO"' EXIT printf '%s' "$TEXTO" | "$BASE/piper/piper" \ --model "$MODELO" --output_file "$CRUDO" 2>/dev/null [ -s "$CRUDO" ] || { echo "piper no genero audio" >&2; exit 1; } if [ "$TONO" = "1.0" ] || ! command -v ffmpeg >/dev/null; then cp "$CRUDO" "$SALIDA" else ffmpeg -hide_banner -loglevel error -i "$CRUDO" \ -af "rubberband=pitch=$TONO" -y "$SALIDA" 2>/dev/null \ || cp "$CRUDO" "$SALIDA" fi