Lectura de texto seleccionada a golpe de tecla: integrando motores de voz en AutoHotkey
Si usás AutoHotkey v2 en un entorno de 64 bits y querés integrar síntesis de voz tradicional por comandos rápidos, te enfrentás a una limitación de arquitectura: los procesos de 64 bits no pueden acceder directamente a componentes de 32 bits (como las voces SAPI5 clásicas).
Para solucionar esto sin depender de software pesado, obsoleto o intermediarios externos, podemos implementar un esquema modular basado en un script auxiliar de 32 bits y archivos temporales como búfer. Además, este enfoque permite ampliar el sistema para utilizar motores de voz locales más modernos (como Piper).
1. Estructura central y archivo main.ahk
Para mantener la prolijidad en scripts avanzados, la mejor práctica es utilizar un archivo centralizador que cargue los diferentes módulos funcionales mediante directivas #Include.
Ejemplo de tu main.ahk[cite: 5]:
#Requires AutoHotkey v2.0
#SingleInstance Force
SendMode "Input"
SetWorkingDir A_ScriptDir
SetKeyDelay 10, 10
; Disparo inmediato: ningún hotstring espera tecla terminadora
#Hotstring *
; SendEvent para hotstrings: evita que backspaces y texto nuevo se superpongan
#Hotstring SI
; Inclusión de módulos y scripts secundarios
#Include "frases.ahk"
#Include "hotkeys.ahk"
#Include "hablar_jorge.ahk"
#Include "piper.ahk"
2. El módulo de control: hablar_jorge.ahk
Este módulo maneja las pulsaciones de teclado[cite: 1]. Si seleccionás texto, lo captura; si no hay selección, evalúa el portapapeles[cite: 1]. Guarda el contenido en un archivo temporal para evitar problemas de caracteres en la consola y lanza el proceso auxiliar[cite: 1].
También incluye atajos para detener la locución al instante o repetir lo último leído[cite: 1].
; ==========================================
; Módulo: Hablar con Loquendo Jorge (SAPI5)
; ==========================================
global loquendoPID := 0
^!F6::
{
global loquendoPID
if (loquendoPID) {
try ProcessClose(loquendoPID)
loquendoPID := 0
}
clipSaved := ClipboardAll()
A_Clipboard := ""
Send "^c"
if !ClipWait(0.3) {
A_Clipboard := clipSaved
}
textoALeer := A_Clipboard
A_Clipboard := clipSaved
if (textoALeer != "" && Type(textoALeer) = "String") {
; Pausa inicial para evitar que el motor devore la primera sílaba
textoALeerModificado := " . " . textoALeer
tempFile := A_Temp . "\loquendo_buffer.txt"
if FileExist(tempFile)
FileDelete(tempFile)
FileAppend(textoALeerModificado, tempFile, "UTF-8")
ahk32 := A_ProgramFiles . "\AutoHotkey\v2\AutoHotkey32.exe"
if !FileExist(ahk32)
ahk32 := A_AppData . "\AutoHotkey\v2\AutoHotkey32.exe"
scriptAux := A_ScriptDir . "\hablar_jorge_aux.ahk"
if FileExist(ahk32) and FileExist(scriptAux) {
Run('"' . ahk32 . '" "' . scriptAux . '"', , "Hide", &loquendoPID)
}
}
}
; Ctrl+Alt+F9 → Detener reproducción de audio general
^!F9::
{
try ProcessClose("ffplay.exe")
global loquendoPID
if (loquendoPID) {
try ProcessClose(loquendoPID)
loquendoPID := 0
}
}
; Ctrl+Alt+Shift+F6 → Relee lo último almacenado en el búfer
^+!F6::
{
global loquendoPID
if !FileExist(A_Temp "\loquendo_buffer.txt")
return
if (loquendoPID) {
try ProcessClose(loquendoPID)
loquendoPID := 0
}
ahk32 := A_ProgramFiles . "\AutoHotkey\v2\AutoHotkey32.exe"
if !FileExist(ahk32)
ahk32 := A_AppData . "\AutoHotkey\v2\AutoHotkey32.exe"
scriptAux := A_ScriptDir . "\hablar_jorge_aux.ahk"
if FileExist(ahk32) and FileExist(scriptAux)
Run('"' . ahk32 . '" "' . scriptAux . '"', , "Hide", &loquendoPID)
}
3. El script auxiliar de 32 bits: hablar_jorge_aux.ahk
Al ejecutarse bajo el motor de 32 bits[cite: 4], este archivo interactúa sin trabas con SAPI5 para localizar la voz e interpretar el búfer de texto plano[cite: 4].
#Requires AutoHotkey v2.0 32-bit
#SingleInstance Ignore
tempFile := A_Temp . "\loquendo_buffer.txt"
if FileExist(tempFile) {
textoALeer := FileRead(tempFile, "UTF-8")
if (textoALeer != "") {
try {
v := ComObject("SAPI.SpVoice")
for x in v.GetVoices() {
if InStr(StrLower(x.GetDescription()), "jorge") {
v.Voice := x
break
}
}
v.Rate := 20
v.Speak(textoALeer, 0)
}
}
}
4. Instalación y configuración de Piper
Piper es un motor de síntesis de voz neuronal rápido y de ejecución 100% local. Para integrarlo con este sistema en Windows, seguí estos pasos:
- Creá una carpeta en el directorio raíz de tu disco (por ejemplo,
C:\piper). - Descargá la última versión ejecutable de Piper para Windows desde su repositorio oficial en GitHub y descomprimila dentro de
C:\piper(necesitarás el archivopiper.exe). - Descargá un modelo de voz compatible en formato ONNX y su archivo de configuración JSON correspondiente (por ejemplo, el modelo en español argentino
es_AR-daniela-high.onnx) y guardalos en la misma carpetaC:\piper. - Asegurate de contar con el reproductor
ffplay.exe(perteneciente a FFmpeg) ubicado también enC:\piper, ya que es el encargado de procesar y reproducir el flujo de audio crudo en tiempo real.
Una vez colocado todo en la ruta indicada, el módulo piper.ahk se encargará de coordinar la lectura mediante tuberías de consola:
#Requires AutoHotkey v2.0
; Ctrl + Alt + F10 → Lee texto con Piper
^!F10::
{
clipSaved := ClipboardAll()
A_Clipboard := ""
Send "^c"
if !ClipWait(0.3)
A_Clipboard := clipSaved
textToRead := A_Clipboard
A_Clipboard := clipSaved
clipSaved := ""
if Trim(textToRead) == ""
return
piperExe := "C:\piper\piper.exe"
modelPath := "C:\piper\es_AR-daniela-high.onnx"
ffplayExe := "C:\piper\ffplay.exe"
speedFactor := "0.8"
tempFile := A_Temp . "\piper_read_buffer.txt"
if FileExist(tempFile)
FileDelete(tempFile)
FileAppend(textToRead, tempFile, "UTF-8")
ProcessClose("ffplay.exe")
cmd := Format('"{1}" /c "{2} --model {3} --length-scale {4} --output_raw < {5} | {6} -f s16le -ar 22050 -ch_layout mono -nodisp -autoexit -"', A_ComSpec, piperExe, modelPath, speedFactor, tempFile, ffplayExe)
Run(cmd, "C:\piper", "Hide")
}
; Ctrl+Alt+Shift+F10 → Relee lo último con Piper
^+!F10::
{
archivo := A_Temp "\piper_read_buffer.txt"
if !FileExist(archivo)
return
try ProcessClose("ffplay.exe")
cmd := Format('"{1}" /c "C:\piper\piper.exe --model C:\piper\es_AR-daniela-high.onnx --length-scale 0.8 --output_raw < {2} | C:\piper\ffplay.exe -f s16le -ar 22050 -ch_layout mono -nodisp -autoexit -"', A_ComSpec, archivo)
Run(cmd, "C:\piper", "Hide")
}
5. Puesta en marcha automática con Windows
Para que tus macros estén operativas apenas enciendas la PC:
- Presioná Windows + R, escribí shell:startup y pulsá Enter.
- Hacé clic derecho en la carpeta de inicio y elegí Nuevo > Acceso directo.
- Seleccioná tu archivo main.ahk, guardalo con un nombre descriptivo y listo.