FocusLec también tiene una intención didáctica, de forma que sirva para ver cómo se puede plantear una aplicación de este tamaño.
Para resaltar la palabra que suena hace falta que el motor de voz avise de cuál está pronunciando. En iOS el sistema documenta ese aviso como el mecanismo previsto para hacer exactamente esto. En Android es opcional para el motor instalado: el método del framework está definido como vacío por defecto y la documentación aclara que solo se invoca si el motor suministra información temporal. No hay ninguna clave que permita consultarlo por adelantado.
TtsEngine.Cuando empezó el proyecto, el plugin de voz de la comunidad emitía el aviso de rango solo en Android. Meter una interfaz propia por delante dejaba la puerta abierta a cambiar de plugin, o a escribir uno, sin tocar nada más.
TtsEngine y sus implementaciones. La tercera, el simulador, permite probar el motor de sincronización sin ningún dispositivo.Cada bloque lleva un identificador estable: su ruta estructural más una huella de 32 bits, así demo/p4#113xk17. Una posición de lectura es el par (bloque, ordinal de palabra) y nunca un número global de palabra ni un desplazamiento en píxeles. La diferencia se ve al reabrir un fichero que ha cambiado: un índice global se desplaza entero con que alguien añada un párrafo al principio, mientras que el par aguanta mientras el bloque siga reconociéndose.
En el diagrama hay dos campos que parecen redundantes: textoMostrado y textoNormalizado. Lo que se pinta en pantalla y lo que se manda al motor de voz no son la misma cadena. Hay guiones blandos que desaparecen, espacios que se colapsan, caracteres de anchura cero que sobran y ligaduras tipográficas que ocupan un carácter y se pronuncian como dos. Los avisos del motor vienen medidos sobre la segunda. Los rectángulos que hay que iluminar están en la primera. El resaltado depende de mantener la correspondencia entre las dos, en unidades UTF-16.
Texto fijo en el código, sin importación ni ajustes. Una batería automática de 21 lecturas por plataforma (siete textos de prueba a tres velocidades) comprobó que el aviso de palabra llega en Android y en iOS. Comparar el texto recibido con el esperado daba fallos falsos; se pasó a comparar posiciones y la precisión mínima subió de 0,733 a 1.
Bloques con identificador estable, la pantalla de lectura y la correspondencia entre el texto que se pinta y el que se pronuncia.
FocusLec está pensada, sobre todo, para documentos EPUB. No obstante, también puede leer documentos en formato TXT, PDF o Word.
Con un EPUB de 103.925 palabras, pintar la página costaba 4.525 ms y creaba 207.868 elementos. Con la lista virtualizada son 10 ms y 728 elementos.
El texto se envía al motor en trozos de frases completas, bajo el tope de 4000 caracteres de Android. Una sonda decide en cada arranque si el aparato puede marcar por palabra o solo por frase. Cuando un aviso no cuadra con el texto, la posición se recoloca buscando la palabra cerca.
Leer, pausa, seguir, navegación por frase y velocidad. Ninguna plataforma cambia la velocidad de una locución ya empezada: hay que detenerla y volver a encolar desde la palabra en curso.
Tipografías, tamaños, espaciados y temas de contraste. Las preferencias y el punto de lectura de cada documento se guardan en el dispositivo. El documento no se guarda: ni Android ni iOS mantienen el permiso sobre un fichero elegido con el selector.
Contraste medido, un tema en blanco y negro, pruebas con los tamaños de texto máximos del sistema y recorridos con TalkBack y VoiceOver. Si hay un lector de pantalla en marcha, la aplicación avisa de que las dos voces comparten altavoz.
Un DOCX es un ZIP con XML dentro, igual que un EPUB. Se aprovecharon el descompresor y el analizador que ya había.
Las formas desdobladas como “los/las niños/niñas” se leían con la barra (“los barra las”) o encadenando las dos formas. Al oído, una frase corriente se vuelve difícil de seguir. Ahora se elige si se lee todo o solo una de las formas. El texto en pantalla no cambia.
Al bajar la velocidad, el motor estira cada letra y deja el hueco entre palabras en cero: 54 ms por letra a 1× y 86 a 0,2×. Medido en un iPad y en un Android, pedir 0,2× solo alarga la lectura entre un 70 % y el doble. Por debajo de 0,7× la voz ya no se estira y lo que crece son las pausas. En iOS la velocidad tuvo que ir dentro del marcado SSML: con SSML, el parámetro normal de velocidad se ignora, como dice la documentación de Apple y confirmó el iPad.
La aplicación lee documentos en español, inglés, francés, italiano, portugués (de Portugal o de Brasil) y alemán, y su interfaz, incluidas las ventanas de información, está en esos seis idiomas. Leer en otro idioma no es solo cambiar de voz: cada uno trae sus abreviaturas, sus comillas y sus signos. En francés se escribe un espacio fino antes de “?” y “:”, y la escritura inclusiva con punto medio se lee como una sola palabra. En alemán, “3.” es un ordinal y no un final de frase, y hay que reconocer las comillas „así“ y el signo de género de “Lehrer*innen”. Se probó en un iPad y en un Android que la voz avisa de todas las palabras en los cinco idiomas nuevos.
Un caso de uso describe lo que una persona hace con la aplicación para conseguir algo concreto. Es más específico que una épica: de cada uno salen las historias de usuario y las tareas que se estiman y se planifican en cada iteración. En un proyecto ágil sirven para acordar qué hay que construir antes de construirlo y para comprobar después que lo construido lo cumple. Estos son algunos de los de FocusLec.
Una persona abre un documento de estudio y lo sigue con la vista y el oído, con la tipografía, el espaciado y la velocidad que le resultan cómodos.
Una persona amplía mucho el texto, sube el contraste y deja que la marca la lleve por el renglón mientras escucha.
Una persona abre un texto en la lengua que estudia, baja la velocidad y sigue la pronunciación palabra por palabra.
Una persona ajusta tipografía, tamaño, interlineado, espaciado, contraste, velocidad y aspecto del resaltado. La aplicación lo recuerda para la próxima vez.
Una persona abre un fichero que no se puede procesar y recibe una explicación de por qué y de qué puede hacer, sin que la aplicación se cierre.
En Android el motor dice en qué instante del audio cae cada palabra, así que el recuadro se puede adelantar lo que se pida. En iOS y en el navegador el aviso llega cuando la palabra ya suena. Durante un tiempo, el ajuste de adelanto no hacía nada en esas plataformas. Se resolvió aprendiendo el ritmo de la voz sobre la marcha: cada aviso dice cuánto duró la palabra anterior y, por sus letras, cuánto durará la siguiente.
@capgo/capacitor-speech-synthesis 8.0.21 y de la interfaz propia TtsEngine.El código se gestiona con Git siguiendo Git Flow.