PBToolboxAI v4 ← Site

speechout — n_pbt_speechout #

← Referencia de componentes · Índice de la guía

Lectura en voz alta: la aplicación lee un texto frase por frase y le dice por dónde va. Sin servicio de terceros, sin clave de API — la síntesis es la del equipo.

▶ Verlo en vivo — Aplicación de demostración, mosaico Speech out: la vista previa, el código que la produce y esta página, lado a lado.


En resumen #

Objeto no visualn_pbt_speechout
Sirve paraHacer oír un texto: accesibilidad, manos ocupadas, un aviso que nadie mira
PrincipioUsted da el texto; el componente lo corta en frases y le dice cuál está leyendo
DependenciaLa síntesis de voz del equipo — sin servicio de terceros, sin clave de API

Inicio rápido #

// once, when the window opens
inv_voice.of_open()

// then, wherever you need it
inv_voice.is_lang = inv_voice.LANG_FR_FR
inv_voice.of_speak(/*text*/ "Bonjour. Votre commande est expediee.")

No visual: el cableado de los eventos #

Una voz no tiene nada que mostrar. El componente no dibuja por tanto nada: ninguna barra de reproducción que colocar, ningún espacio quitado a lo que sirve.

Y para ello no tiene que cablear nada: un objeto no visual no tiene ventana, así que no hay timbre, pero el componente recoge sus propios eventos en el bucle de PowerBuilder mientras la voz está abierta y los lanza en el objeto. Solo escribe los manejadores ue_* (sin receptor, sin temporizador).

// Just speak -- the ue_* events arrive on their own :
inv_voice.of_speak(/*text*/ "Good morning. Your order has shipped.")

// the ue_sentence / ue_word / ue_stopped events arrive on their own

Seguir la lectura en SU texto #

ue_sentence lleva el índice y el texto de la frase que se está leyendo. De ahí sale el resaltado — en su mle_, su datawindow o su statictext: usted sabe dónde está su texto, nosotros nunca.

El camino inverso también existe: of_speak_from() retoma en una frase concreta, lo que se conecta al clic sobre un párrafo. Los números vienen de ue_sentence, así que siempre señalan lo que realmente se leyó.

El corte es el del componente, no el suyo: of_sentence_count() devuelve su propia cuenta. No vuelva a contar por su lado, las dos derivarían.


Lo que el equipo sabe decir de verdad #

of_languages() devuelve los idiomas que este equipo sabe pronunciar de verdad, sin duplicados. Es la pregunta que se hace un usuario: no «qué voces existen», sino «está mi idioma».

of_voices() baja un escalón y nombra las voces mismas. Ambas listas vienen de la máquina, no de nosotros: nunca codifique un nombre fijo.

El reconocimiento de voz no tiene equivalente, y no es un olvido: el reconocimiento no lleva ninguna lista de los idiomas que acepta.

Sin ningún componente por su parte, gnv_utils.of_speech_languages(as_tags[]) da la misma lista — la DLL consulta una voz oculta y luego la descarta: es lo que una ventana pregunta antes de que la voz exista, qué idioma ofrecer, en cuál leer. La llamada es síncrona y puede tardar unos segundos la primera vez (el puntero muestra la espera; la respuesta se guarda cinco segundos): la lista de voces llega tarde, y la llamada la espera. Y gnv_utils.of_speech_voices(as_names[], as_langs[]) da las voces mismas con su idioma, para ofrecer «Hortense» o «Julie» en lugar de una etiqueta; gnv_utils.of_locale_name(as_tag) da a una etiqueta su nombre legible — «francés (Francia)» para fr-FR.

// Local variables
string ls_tags[]

// Read in the first language this workstation can speak
if inv_voice.of_languages(/*tags*/ ls_tags) > 0 then inv_voice.is_lang = ls_tags[1]

Propiedades #

PropiedadTipoPredeterminadoFunción
is_langstringen-USIdioma leído, en BCP-47 (constantes LANG_*). Decide qué voz se elige — mientras is_voice esté vacía, ya que un nombre de voz fija su propio idioma. Sin voz para ese idioma el equipo lee con la que tiene, y ue_voice_fallback nombra ambas — también una REGIÓN ausente (se pide fr-CA, lee una voz fr-FR). Viva: cambiada durante una lectura, vale desde la frase siguiente
is_textstring""El texto a leer. El componente lo corta en frases; unas etiquetas dicen CÓMO leer un trozo: [pause=500], [spell]…[/spell], [say-as=digits]…[/say-as], [mark=nombre], [rate=150]…[/rate] (ver más abajo)
is_voicestring""Nombre de la voz, tomado de of_voices(). Vacío = la primera que habla is_lang. Viva, como is_lang
ii_rateinteger100Velocidad, en POR CIENTO de la normal (10 a 400). Cambiada durante la lectura, se aplica a la frase siguiente
ii_pitchinteger100Tono de la voz, en POR CIENTO del tono normal (0 a 200). Cambiado durante la lectura, se aplica a la frase siguiente
ii_volumeinteger100Volumen en porcentaje (0 mudo a 100), la escala del reproductor de vídeo. Cambiado durante la lectura, se aplica a la frase siguiente
il_timeout_mslong300000Duración máxima de una lectura SÍNCRONA: cinco minutos. Después, of_speak_sync devuelve -4 y la lectura se corta (is_last_error dice por qué). 0 o menos: sin límite (24 horas como máximo)
is_last_errorstring""Por qué el último of_speak_sync devolvió -4: voz no creada, fallo del motor, tiempo agotado, otro of_speak_sync ya en espera; también por qué of_pick_voice no pudo leer la lista de voces
ipo_ownerpowerobjectnullEl objeto visual para el que trabaja esta voz: la licencia se comprueba en su clase. Asignado después de abrir la voz, se transmite en la llamada siguiente. Necesario solo en la aplicación de demostración; una clave de desarrollo o de ejecución desbloquea la voz sin él. Sin desbloquear, la voz está en modo demo — 4 frases y 400 caracteres por lectura (cola incluida), luego se dice la mención demo

Métodos #

MétodoFunción
of_open ( )Crea la voz. Opcional — of_speak lo hace — pero llamarlo al abrir la ventana paga el coste una vez, lejos de la primera frase. Devuelve un número positivo cuando la voz existe, -2 si no pudo crearse (is_last_error dice por qué)
of_is_open ( )Verdadero una vez creada la voz
of_speak ( string as_text )Pone el texto y lo lee, desde la primera frase. Sin argumento, relee is_text. Devuelve 0 una vez enviado, -2 si la voz no pudo crearse
of_speak_from ( long al_index )Retoma la lectura en una frase concreta. Devuelve 0 una vez enviado, -5 más allá de la última frase (no se lee nada, y una lectura en curso continúa), -2 si la voz no pudo crearse, -4 si la página no respondió
of_pause ( )Suspende la lectura donde está — incluida una lectura que aún espera la lista de voces: solo empezará con of_resume. Devuelve 0 (nada que suspender en una voz nunca abierta, que no se crea para eso), -4 si la página no respondió
of_resume ( )Retoma donde of_pause se detuvo. Devuelve 0, -4 si la página no respondió
of_stop ( )Detiene la lectura; of_speak vuelve a empezar por la primera frase
of_is_speaking ( )Verdadero desde of_speak hasta el final de la lectura — la espera de la lista de voces y una lectura en pausa incluidas. Preguntado al componente, nunca una copia caducada
of_is_paused ( )Verdadero mientras la lectura está en pausa (of_pause), hasta of_resume u of_stop
of_sentence_count ( )Devuelve cuántas frases hace el componente de is_text tal como está ahora, antes de cualquier lectura; durante una lectura, las del texto que se lee
of_count ( ) → longCuántas frases ha hecho el componente del texto — el mismo número que devuelve of_sentence_count. La biblioteca hace esta pregunta bajo un solo nombre en todas partes
of_voices ( ref string as_names[] )Rellena la matriz con las voces instaladas en este equipo y devuelve cuántas hay
of_languages ( ref string as_tags[] )Rellena la matriz con los idiomas que este equipo sabe pronunciar, sin duplicados, y devuelve cuántos hay
of_voice_used ( )La voz que el componente entregará realmente al motor — no siempre la que pide is_lang: un equipo lleva las voces que alguien instaló y ninguna otra. Vacío = el componente no impone ninguna, y el motor toma la suya, la del idioma del sistema. Nombrarla sería adivinar. ue_voice_fallback lo dice al leer; esto se lee antes, con is_lang e is_voice tal como están en ese momento
of_speak_sync ( { string as_text } )Lee y ESPERA el final: la línea siguiente corre tras la última frase, la ventana sigue pintándose. Devuelve 0 al final, -4 en caso de fallo, de tiempo agotado o si otro of_speak_sync ya está esperando (llamado desde un evento que él levantó) — is_last_error dice por qué
of_enqueue ( string as_text )Pone un texto en COLA: leído enseguida si la voz está libre, tras la lectura en curso si no, sin cortarla nunca. Devuelve 0, -2 si la voz no pudo crearse
of_clear_queue ( )Olvida los textos en espera, sin cortar el que se lee. Devuelve 0 (una voz nunca abierta no tiene cola, y no se crea para eso), -4 si la página no respondió
of_queue_count ( )Devuelve el número de textos aún en espera (el que se lee no cuenta)
of_add_replacement ( string as_from, string as_to )Una regla de pronunciación: cada palabra ENTERA as_from se lee as_to (PB → PowerBuilder). Aplicada antes de las etiquetas, guardada por el objeto. Devuelve 0, -5 si as_from está vacío
of_clear_replacements ( )Vacía el diccionario. Devuelve 0
of_replacement_count ( )Devuelve el número de reglas del diccionario
of_add_abbreviation ( string as_text )Una ABREVIATURA propia: el punto que la sigue no termina la frase — Art. 5 sigue siendo una frase. El punto final puede omitirse, las mayúsculas cuentan. Una lista integrada ya cubre las habituales de los seis idiomas de esta documentación (Mr., Dr., e.g., M., Mme., z.B., Sig., p.ej.…). Devuelve 0 una vez añadida, -5 si as_text está vacío o contiene un espacio
of_clear_abbreviations ( )Olvida las abreviaturas añadidas con of_add_abbreviation — la lista integrada se queda. Devuelve siempre 0
of_pick_voice ( string as_lang, string as_gender )Elige una voz INSTALADA para un idioma y, si existe, un género (GENDER_FEMALE, GENDER_MALE, GENDER_ANY): idioma exacto, luego su familia. La pone en is_voice y la devuelve; vacío si ninguna voz habla ese idioma. Un as_lang vacío significa is_lang. Si la lista de voces no se puede leer, is_voice queda como estaba e is_last_error dice por qué
of_duration ( )Devuelve la duración ESTIMADA de la lectura, en milisegundos (palabras por minuto a la velocidad pedida, pausas incluidas): para una barra de progreso, no para un cronómetro. El ritmo APRENDE la voz: cada frase leída hasta el final mide el real, recordado por voz en este equipo
of_position ( )Devuelve la posición estimada de la lectura, en milisegundos, afinada por las palabras que el motor reporta; 0 cuando nada se lee
of_progress ( )Devuelve el progreso estimado, de 0 a 100
of_spoken_text ( )Las frases TAL COMO la voz las recibe, una por línea (diccionario aplicado, etiquetas resueltas): el texto a mostrar para seguir palabra a palabra
of_process_events ( )Vacía los eventos pendientes y los lanza sobre este objeto. El pump interno del componente lo llama por usted mientras la voz está abierta — usted nunca lo llama
of_close ( )Libera la voz, deteniendo antes lo que estuviera diciendo: una lectura en curso termina con su ue_stopped, levantado antes del retorno. Destruir el objeto también cierra la voz, pero no levanta NINGÚN evento: los controles de la ventana pueden estar ya destruidos
of_reset ( )Devuelve todas las propiedades a su valor original

Eventos #

EventoSe dispara cuando
ue_started (string as_lang)La voz empieza de verdad a hablar; as_lang es el idioma que lee — el de la voz, fr-FR para un fr-CA ausente del equipo (vea ue_voice_fallback). Una pausa puesta antes (of_speak y luego of_pause en el mismo script) lo retiene hasta of_resume
ue_stopped ( )La última frase ha terminado, o la lectura se ha cortado — of_stop, un nuevo of_speak, of_close: toda lectura empezada termina con un ue_stopped
ue_paused ( )La lectura está suspendida
ue_resumed ( )La lectura se reanuda
ue_sentence (long al_index, string as_text)Para cada frase, con su rango y su texto: así se sigue la lectura en otra parte de la ventana. Una frase de más de 250 caracteres se corta (en una coma, si no en un espacio), y un trozo [rate] es una frase propia: cada parte tiene su número
ue_error (string as_message)El equipo no tiene motor ni voz alguna, la voz falla, o se produce un error de script en su página. Una voz simplemente AUSENTE no es un error: es ue_voice_fallback. También cuando el motor abandona una frase sin decir nada («engine did not answer»): una lectura nunca queda «en curso» para siempre
ue_voices_ready (long al_count)El motor ha llenado su lista de voces — llega tarde; of_voices, of_languages, of_voice_used y of_pick_voice la esperan por sí mismos (2,5 s como máximo), este evento solo dice CUÁNDO llegó; al_count dice cuántas tiene el equipo
ue_word (long al_index, long al_start, long al_length)La PALABRA en curso en la frase al_index: Mid(frase, al_start, al_length). Siempre levantado: según las palabras que la voz reporta, y ESTIMADO por el reloj cuando no reporta ninguna
ue_queue_done ( )El último texto de la cola (of_enqueue) está leído
ue_voice_fallback (string as_wanted, string as_used)La voz o el idioma pedido no está en este equipo — su REGIÓN incluida (se pide fr-CA, lee fr-FR); as_used nombra la que lee en su lugar. Una información, no un error: la lectura continúa
ue_mark (string as_name)La voz alcanza un [mark=nombre] del texto; as_name es ese nombre. Se levanta al empezar la frase (una marca antes de su primera palabra), al alcanzar la palabra que sigue a la marca, o al final de la frase: una marca nunca se pierde

Pronunciación: pausas, deletreo, diccionario #

WebView2 no tiene SSML. El texto lleva por tanto cinco etiquetas propias, resueltas antes del corte en frases, y un diccionario de palabras enteras aplicado antes. Una etiqueta desconocida se lee tal cual.

EtiquetaEfecto
[pause=500]Un silencio de 500 ms (10 s como máximo). La pausa termina la frase en curso. Al FINAL del texto: un silencio tras la última frase (para espaciar dos anuncios de la cola)
[spell]ABC12[/spell]Cada carácter dicho uno por uno: «A, B, C, 1, 2». Nunca termina la frase (sus puntos son caracteres: una dirección, una versión) y se separa de una palabra que toque
[say-as=digits]4152[/say-as]Los dígitos uno por uno, no «cuatro mil ciento cincuenta y dos»
[say-as=characters]…[/say-as]Como [spell]
[mark=row2]Una marca: ue_mark("row2") se levanta cuando la voz llega ahí — para resaltar una fila de su ventana en el momento justo
[rate=50]1 250 USD[/rate]Ese trozo al 50 % de ii_rate (10 a 400) — para leer un importe más despacio. Es una frase propia
// The dictionary : whole words, in the order added, case-sensitive
inv_voice.of_add_replacement(/*from*/ "PB", /*to*/ "PowerBuilder")
inv_voice.of_add_replacement(/*from*/ "Mme", /*to*/ "Madame")
inv_voice.of_add_replacement(/*from*/ "4152", /*to*/ "[say-as=digits]4152[/say-as]")   // a rule may add a tag

// Then speak : the dictionary and the tags are applied first
inv_voice.of_speak(/*text*/ "Mme Durand, PB order 4152 [pause=600] code [spell]PBT[/spell].")

Una abreviatura no termina la frase: Mr. Smith, Dr., e.g., M. Dupont, z.B. se quedan en la frase que las lleva (lista integrada para los seis idiomas de esta documentación; etc. solo termina la frase ante una mayúscula). Las suyas se añaden con of_add_abbreviation. Una frase de más de 250 caracteres — una nota pegada sin punto — se corta en una coma, si no en un espacio: un motor abandona en silencio los enunciados demasiado largos.

// Your own abbreviation : "Art. 5" stays in one sentence
inv_voice.of_add_abbreviation(/*text*/ "Art")

// A mark raises ue_mark("total") when the voice gets there ; the amount is read slower
inv_voice.of_speak(/*text*/ "See Art. 5 of the contract. [mark=total]The total is [rate=70]1 250 dollars[/rate].")

Cola, lectura síncrona, progreso #


Ejemplos #

Leer una notificación #

// Read the notification aloud, without waiting for the end
inv_voice.of_speak(/*text*/ "Order 4152 has been shipped. It arrives on Thursday.")

Resaltar la frase en curso #

// in ue_sentence, on the nonvisual object
st_read.text = as_text

// and a click on a paragraph resumes from it
inv_voice.of_speak_from(/*index*/ 2)

Elegir la voz y la velocidad #

// Local variables
string ls_voices[]

// The first installed voice, a quarter slower, then speak
if inv_voice.of_voices(/*names*/ ls_voices) > 0 then inv_voice.is_voice = ls_voices[1]
inv_voice.ii_rate = 75
inv_voice.of_speak()

Anunciar sin cortar: la cola #

// Each event of the application is queued : all of them are heard, in order
inv_voice.of_enqueue(/*text*/ "Order 4152 has been shipped.")
inv_voice.of_enqueue(/*text*/ "Order 4153 is ready.")

// ue_queue_done fires after the last one

Resaltar la palabra en curso #

// in ue_sentence : keep the sentence
is_sentence = as_text

// in ue_word : the word is Mid(is_sentence, al_start, al_length)
st_read.text = Left(is_sentence, al_start - 1) + "[" + Mid(is_sentence, al_start, al_length) + "]" + Mid(is_sentence, al_start + al_length)

Una voz por idioma y género, luego leer esperando el final #

// A French female voice, then speak and wait for the end before asking
inv_voice.of_pick_voice(/*lang*/ n_pbt_speechout.LANG_FR_FR, /*gender*/ n_pbt_speechout.GENDER_FEMALE)
if inv_voice.of_speak_sync(/*text*/ "Please confirm the order.") = 0 then
	li_answer = MessageBox("Order", "Confirm ?", Question!, YesNo!)
end if

Buenas prácticas #


← Referencia de componentes · Índice de la guía