PBToolboxAI v4 ← Site

speechout — n_pbt_speechout #

← Referência dos componentes · Índice do guia

Leitura em voz alta: a aplicação lê um texto frase a frase e diz-lhe onde vai. Sem serviço de terceiros, sem chave de API — a síntese é a do posto de trabalho.

▶ Ver ao vivo — Aplicação de demonstração, mosaico Speech out: a pré-visualização, o código que a produz e esta página, lado a lado.


Em resumo #

Objeto não visualn_pbt_speechout
Serve paraFazer ouvir um texto: acessibilidade, mãos ocupadas, um aviso que ninguém olha
PrincípioDá o texto; o componente corta-o em frases e diz-lhe qual está a ler
DependênciaA síntese de voz do posto — sem serviço de terceiros, sem chave de API

Início 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.")

Não visual: a ligação dos eventos #

Uma voz não tem nada para mostrar. O componente não desenha portanto nada: nenhuma barra de leitura para arranjar espaço, nenhum lugar tirado àquilo que serve.

E para isso não tem de ligar nada: um objeto não visual não tem janela, logo não há campainha, mas o componente recolhe os seus eventos no ciclo do PowerBuilder enquanto a voz está aberta e dispara-os no objeto. Só escreve os tratadores ue_* (sem recetor, sem 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 a leitura no SEU texto #

ue_sentence transporta o índice e o texto da frase que está a ser lida. É daí que vem o realce — no seu mle_, na sua datawindow ou no seu statictext: você sabe onde está o seu texto, nós nunca.

O caminho inverso também existe: of_speak_from() retoma numa frase precisa, o que se liga ao clique num parágrafo. Os números vêm de ue_sentence, logo apontam sempre para o que foi realmente lido.

O corte é o do componente, não o seu: of_sentence_count() devolve a contagem dele. Não volte a contar do seu lado, as duas divergiriam.


O que o posto sabe realmente dizer #

of_languages() devolve os idiomas que este posto sabe efetivamente pronunciar, sem duplicados. É a pergunta que um utilizador faz: não «que vozes existem», mas «o meu idioma está lá».

of_voices() desce um degrau e nomeia as próprias vozes. Ambas as listas vêm da máquina, não de nós: nunca escreva um nome fixo no código.

O reconhecimento de voz não tem equivalente, e não é um esquecimento: o reconhecimento não traz qualquer lista dos idiomas que aceita.

Sem qualquer componente da sua parte, gnv_utils.of_speech_languages(as_tags[]) dá a mesma lista — a DLL consulta uma voz oculta e depois descarta-a: é o que uma janela pergunta antes de a voz existir, que idioma propor, em qual ler. A chamada é síncrona e pode demorar alguns segundos da primeira vez (o ponteiro mostra a espera; a resposta é guardada cinco segundos): a lista de vozes chega tarde, e a chamada espera por ela. E gnv_utils.of_speech_voices(as_names[], as_langs[]) dá as vozes em si com o seu idioma, para propor «Hortense» ou «Julie» em vez de uma etiqueta; gnv_utils.of_locale_name(as_tag) dá a uma etiqueta o seu nome legível — «francês (França)» 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]

Propriedades #

PropriedadeTipoPredefiniçãoFunção
is_langstringen-USIdioma lido, em BCP-47 (constantes LANG_*). Decide que voz é escolhida — enquanto is_voice estiver vazia, pois um nome de voz fixa a sua própria língua. Sem voz para essa língua o posto lê com a que tem, e ue_voice_fallback nomeia as duas — também uma REGIÃO ausente (pede-se fr-CA, lê uma voz fr-FR). Viva: alterada durante uma leitura, vale a partir da frase seguinte
is_textstring""O texto a ler. O componente corta-o em frases; etiquetas dizem COMO ler um pedaço: [pause=500], [spell]…[/spell], [say-as=digits]…[/say-as], [mark=nome], [rate=150]…[/rate] (ver abaixo)
is_voicestring""Nome da voz, tirado de of_voices(). Vazio = a primeira que fala is_lang. Viva, como is_lang
ii_rateinteger100Velocidade, em POR CENTO da normal (10 a 400). Alterada durante a leitura, aplica-se à frase seguinte
ii_pitchinteger100Altura da voz, em POR CENTO da altura normal (0 a 200). Alterado durante a leitura, aplica-se à frase seguinte
ii_volumeinteger100Volume em percentagem (0 mudo a 100), a escala do leitor de vídeo. Alterado durante a leitura, aplica-se à frase seguinte
il_timeout_mslong300000Duração máxima de uma leitura SÍNCRONA: cinco minutos. Depois, of_speak_sync devolve -4 e a leitura é cortada (is_last_error diz porquê). 0 ou menos: sem limite (24 horas no máximo)
is_last_errorstring""Porque o último of_speak_sync devolveu -4: voz não criada, falha do motor, tempo esgotado, outro of_speak_sync já à espera; também porque of_pick_voice não pôde ler a lista de vozes
ipo_ownerpowerobjectnullO objeto visual para o qual esta voz trabalha: a licença verifica-se na sua classe. Definido depois de a voz abrir, é transmitido na chamada seguinte. Necessário apenas na aplicação de demonstração; uma chave de desenvolvimento ou de execução desbloqueia a voz sem ele. Não desbloqueada, a voz está em modo demo — 4 frases e 400 caracteres por leitura (fila incluída), depois é dita a menção demo

Métodos #

MétodoFunção
of_open ( )Cria a voz. Facultativo — of_speak fá-lo — mas chamá-lo ao abrir a janela paga o custo uma vez, longe da primeira frase. Devolve um número positivo quando a voz existe, -2 se não pôde ser criada (is_last_error diz porquê)
of_is_open ( )Verdadeiro assim que a voz existe
of_speak ( string as_text )Define o texto e lê-o, desde a primeira frase. Sem argumento, relê is_text. Devolve 0 uma vez enviado, -2 se a voz não pôde ser criada
of_speak_from ( long al_index )Retoma a leitura numa frase precisa. Devolve 0 uma vez enviado, -5 para além da última frase (nada é lido, e uma leitura em curso continua), -2 se a voz não pôde ser criada, -4 se a página não respondeu
of_pause ( )Suspende a leitura onde está — incluindo uma leitura que ainda espera a lista de vozes: só começará com of_resume. Devolve 0 (nada a suspender numa voz nunca aberta, que não é criada para isso), -4 se a página não respondeu
of_resume ( )Retoma onde of_pause parou. Devolve 0, -4 se a página não respondeu
of_stop ( )Para a leitura; of_speak recomeça pela primeira frase
of_is_speaking ( )Verdadeiro desde of_speak até ao fim da leitura — a espera da lista de vozes e uma leitura em pausa incluídas. Perguntado ao componente, nunca uma cópia desatualizada
of_is_paused ( )Verdadeiro enquanto a leitura está em pausa (of_pause), até of_resume ou of_stop
of_sentence_count ( )Devolve quantas frases o componente faz de is_text tal como está nesse momento, antes de qualquer leitura; durante uma leitura, as do texto lido
of_count ( ) → longQuantas frases o componente fez do texto — o mesmo número que of_sentence_count devolve. A biblioteca faz esta pergunta sob um único nome em todo o lado
of_voices ( ref string as_names[] )Preenche o vetor com as vozes instaladas neste posto e devolve quantas são
of_languages ( ref string as_tags[] )Preenche o vetor com os idiomas que este posto sabe pronunciar, sem duplicados, e devolve quantos são
of_voice_used ( )A voz que o componente entregará realmente ao motor — nem sempre a que is_lang pede: um posto carrega as vozes que alguém lá instalou e nenhuma outra. Vazio = o componente não impõe nenhuma, e o motor toma a sua, a da língua do sistema. Nomeá-la seria adivinhar. ue_voice_fallback di-lo ao ler; isto lê-se antes, com is_lang e is_voice tal como estão nesse momento
of_speak_sync ( { string as_text } )Lê e ESPERA o fim: a linha seguinte corre após a última frase, a janela continua a pintar-se. Devolve 0 no fim, -4 em caso de falha, de tempo esgotado ou se outro of_speak_sync já está à espera (chamado a partir de um evento que ele levantou) — is_last_error diz porquê
of_enqueue ( string as_text )Põe um texto em FILA: lido de imediato se a voz está livre, após a leitura em curso caso contrário, sem nunca a cortar. Devolve 0, -2 se a voz não pôde ser criada
of_clear_queue ( )Esquece os textos em espera, sem cortar o que se lê. Devolve 0 (uma voz nunca aberta não tem fila, e não é criada para isso), -4 se a página não respondeu
of_queue_count ( )Devolve o número de textos ainda em espera (o que se lê não conta)
of_add_replacement ( string as_from, string as_to )Uma regra de pronúncia: cada palavra INTEIRA as_from é lida as_to (PB → PowerBuilder). Aplicada antes das etiquetas, guardada pelo objeto. Devolve 0, -5 se as_from estiver vazio
of_clear_replacements ( )Esvazia o dicionário. Devolve 0
of_replacement_count ( )Devolve o número de regras do dicionário
of_add_abbreviation ( string as_text )Uma ABREVIATURA sua: o ponto que a segue não termina a frase — Art. 5 continua a ser uma frase. O ponto final pode ser omitido, as maiúsculas contam. Uma lista integrada já cobre as habituais das seis línguas desta documentação (Mr., Dr., e.g., M., Mme., z.B., Sig., p.ej.…). Devolve 0 uma vez adicionada, -5 se as_text estiver vazio ou contiver um espaço
of_clear_abbreviations ( )Esquece as abreviaturas adicionadas com of_add_abbreviation — a lista integrada fica. Devolve sempre 0
of_pick_voice ( string as_lang, string as_gender )Escolhe uma voz INSTALADA para um idioma e, se existir, um género (GENDER_FEMALE, GENDER_MALE, GENDER_ANY): idioma exato, depois a sua família. Põe-na em is_voice e devolve-a; vazio se nenhuma voz fala esse idioma. Um as_lang vazio significa is_lang. Se a lista de vozes estiver ilegível, is_voice fica como estava e is_last_error diz porquê
of_duration ( )Devolve a duração ESTIMADA da leitura, em milissegundos (palavras por minuto ao ritmo pedido, pausas incluídas): para uma barra de progresso, não para um cronómetro. O ritmo APRENDE a voz: cada frase lida até ao fim mede o real, guardado por voz neste posto
of_position ( )Devolve a posição estimada da leitura, em milissegundos, afinada pelas palavras que o motor reporta; 0 quando nada se lê
of_progress ( )Devolve o progresso estimado, de 0 a 100
of_spoken_text ( )As frases TAL COMO a voz as recebe, uma por linha (dicionário aplicado, etiquetas resolvidas): o texto a mostrar para seguir palavra a palavra
of_process_events ( )Esvazia os eventos pendentes e levanta-os neste objeto. O pump interno do componente chama-o por si enquanto a voz está aberta — nunca o chama
of_close ( )Liberta a voz, parando antes o que estivesse a dizer: uma leitura em curso termina com o seu ue_stopped, levantado antes do retorno. Destruir o objeto também fecha a voz, mas não levanta NENHUM evento: os controlos da janela podem já estar destruídos
of_reset ( )Repõe todas as propriedades no valor inicial

Eventos #

EventoDisparado quando
ue_started (string as_lang)A voz começa realmente a falar; as_lang é a língua que lê — a da voz, fr-FR para um fr-CA ausente do computador (ver ue_voice_fallback). Uma pausa posta antes (of_speak e depois of_pause no mesmo script) retém-no até of_resume
ue_stopped ( )A última frase terminou, ou a leitura foi cortada — of_stop, um novo of_speak, of_close: toda a leitura começada termina com um ue_stopped
ue_paused ( )A leitura está suspensa
ue_resumed ( )A leitura recomeça
ue_sentence (long al_index, string as_text)Para cada frase, com o seu lugar e o seu texto: é assim que se segue a leitura noutro ponto da janela. Uma frase com mais de 250 caracteres é cortada (numa vírgula, senão num espaço), e um pedaço [rate] é uma frase própria: cada parte tem o seu número
ue_error (string as_message)O posto não tem motor nem voz alguma, a voz falha, ou ocorre um erro de script na sua página. Uma voz simplesmente AUSENTE não é um erro: é ue_voice_fallback. Também quando o motor abandona uma frase sem dizer nada («engine did not answer»): uma leitura nunca fica «em curso» para sempre
ue_voices_ready (long al_count)O motor preencheu a sua lista de vozes — chega tarde; of_voices, of_languages, of_voice_used e of_pick_voice esperam por ela sozinhos (2,5 s no máximo), este evento só diz QUANDO chegou; al_count diz quantas o posto tem
ue_word (long al_index, long al_start, long al_length)A PALAVRA em curso na frase al_index: Mid(frase, al_start, al_length). Sempre levantado: pelas palavras que a voz reporta, e ESTIMADO pelo relógio quando não reporta nenhuma
ue_queue_done ( )O último texto da fila (of_enqueue) está lido
ue_voice_fallback (string as_wanted, string as_used)A voz ou o idioma pedido não está neste posto — a sua REGIÃO incluída (pede-se fr-CA, lê fr-FR); as_used nomeia a que lê em seu lugar. Uma informação, não um erro: a leitura continua
ue_mark (string as_name)A voz atinge um [mark=nome] do texto; as_name é esse nome. Levantado no início da frase (uma marca antes da sua primeira palavra), quando a palavra que segue a marca é atingida, ou no fim da frase: uma marca nunca se perde

Pronúncia: pausas, soletração, dicionário #

O WebView2 não tem SSML. O texto traz por isso cinco etiquetas próprias, resolvidas antes do corte em frases, e um dicionário de palavras inteiras aplicado antes delas. Uma etiqueta desconhecida é lida tal como está.

EtiquetaEfeito
[pause=500]Um silêncio de 500 ms (10 s no máximo). A pausa termina a frase em curso. No FIM do texto: um silêncio após a última frase (para espaçar dois anúncios da fila)
[spell]ABC12[/spell]Cada carácter dito um a um: «A, B, C, 1, 2». Nunca termina a frase (os seus pontos são caracteres: um endereço, uma versão) e separa-se de uma palavra que toque
[say-as=digits]4152[/say-as]Os dígitos um a um, não «quatro mil cento e cinquenta e dois»
[say-as=characters]…[/say-as]Como [spell]
[mark=row2]Uma marca: ue_mark("row2") é levantado quando a voz lá chega — para realçar uma linha da sua janela no momento certo
[rate=50]1 250 USD[/rate]Esse pedaço a 50 % de ii_rate (10 a 400) — para ler um montante mais devagar. É uma frase própria
// 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].")

Uma abreviatura não termina a frase: Mr. Smith, Dr., e.g., M. Dupont, z.B. ficam na frase que as traz (lista integrada para as seis línguas desta documentação; etc. só termina a frase antes de uma maiúscula). As suas acrescentam-se com of_add_abbreviation. Uma frase com mais de 250 caracteres — uma nota colada sem ponto — é cortada numa vírgula, senão num espaço: um motor abandona em silêncio os enunciados demasiado longos.

// 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].")

Fila, leitura síncrona, progresso #


Exemplos #

Ler uma notificação #

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

Realçar a frase em 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)

Escolher a voz e a velocidade #

// 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 sem cortar: a fila #

// 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

Realçar a palavra em 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)

Uma voz por idioma e género, depois ler esperando o fim #

// 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

Boas práticas #


← Referência dos componentes · Índice do guia