PBToolboxAI v4 ← Site

speechout — n_pbt_speechout #

← Komponentenreferenz · Inhalt des Handbuchs

Vorlesen: Die Anwendung liest einen Text Satz für Satz und sagt Ihnen, wo sie steht. Kein Drittanbieterdienst, kein API-Schlüssel — die Sprachsynthese ist die des Arbeitsplatzes.

▶ Live ansehen — Demoanwendung, Kachel Speech out: die Vorschau, der zugehörige Code und diese Seite nebeneinander.


Kurzüberblick #

Nichtvisuelles Objektn_pbt_speechout
WofürEinen Text hörbar machen: Barrierefreiheit, belegte Hände, eine Meldung, die niemand ansieht
PrinzipSie übergeben den Text; die Komponente zerlegt ihn in Sätze und sagt Ihnen, welchen sie liest
AbhängigkeitDie Sprachsynthese des Arbeitsplatzes — kein Drittanbieterdienst, kein API-Schlüssel

Schnellstart #

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

Nichtvisuell: die Verdrahtung der Ereignisse #

Eine Stimme hat nichts zu zeigen. Die Komponente zeichnet daher nichts: keine Abspielleiste, für die Platz zu finden wäre, kein Raum, der dem weggenommen wird, dem sie dient.

Und Sie müssen dafür nichts verdrahten: Ein nichtvisuelles Objekt hat kein Fenster, also keine Glocke, aber die Komponente holt ihre Ereignisse selbst auf der PowerBuilder-Schleife, solange die Stimme offen ist, und löst sie am Objekt aus. Sie schreiben nur die ue_*-Handler (kein Empfänger, kein Timer).

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

Dem Vorlesen in IHREM Text folgen #

ue_sentence trägt den Index und den Text des gerade gelesenen Satzes. Daher stammt die Hervorhebung — in Ihrem mle_, Ihrer datawindow oder Ihrem statictext: Sie wissen, wo Ihr Text steht, wir nie.

Auch der Rückweg existiert: of_speak_from() setzt bei einem bestimmten Satz an, was man auf den Klick auf einen Absatz legt. Die Nummern stammen aus ue_sentence und bezeichnen daher stets das tatsächlich Gelesene.

Die Zerlegung ist die der Komponente, nicht Ihre: of_sentence_count() liefert ihre eigene Zählung. Zählen Sie nicht selbst nach, beides würde auseinanderlaufen.


Was der Arbeitsplatz wirklich sprechen kann #

of_languages() liefert die Sprachen, die dieser Arbeitsplatz tatsächlich aussprechen kann, ohne Dubletten. Das ist die Frage eines Benutzers: nicht „welche Stimmen gibt es“, sondern „ist meine Sprache dabei“.

of_voices() geht eine Stufe tiefer und benennt die Stimmen selbst. Beide Listen stammen von der Maschine, nicht von uns: kodieren Sie nie einen Namen fest.

Die Spracherkennung hat kein Gegenstück, und das ist kein Versehen: Die Erkennung führt keine Liste der von ihr akzeptierten Sprachen.

Ganz ohne eigene Komponente liefert gnv_utils.of_speech_languages(as_tags[]) dieselbe Liste — die DLL befragt eine verborgene Stimme und verwirft sie wieder: das fragt ein Dialog, bevor die Stimme existiert, welche Sprache anbieten, in welcher lesen. Der Aufruf ist synchron und kann beim ersten Mal einige Sekunden dauern (der Mauszeiger zeigt das Warten; die Antwort wird fünf Sekunden behalten): die Stimmenliste kommt spät, und der Aufruf wartet darauf. Und gnv_utils.of_speech_voices(as_names[], as_langs[]) liefert die Stimmen selbst mit ihrer Sprache, um „Hortense“ oder „Julie“ statt einer Marke anzubieten; gnv_utils.of_locale_name(as_tag) gibt einer Sprachmarke ihren lesbaren Namen — „Französisch (Frankreich)“ für 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]

Eigenschaften #

EigenschaftTypStandardRolle
is_langstringen-USVorgelesene Sprache in BCP-47 (LANG_*-Konstanten). Entscheidet, welche Stimme gewählt wird — solange is_voice leer ist, denn ein Stimmname legt seine eigene Sprache fest. Ohne Stimme für diese Sprache liest der Rechner mit der vorhandenen, und ue_voice_fallback nennt beide — auch eine fehlende REGION (fr-CA verlangt, eine fr-FR-Stimme liest). Live: während des Lesens geändert, gilt sie ab dem nächsten Satz
is_textstring""Der zu lesende Text. Die Komponente zerlegt ihn in Sätze; Tags sagen, WIE ein Stück gelesen wird: [pause=500], [spell]…[/spell], [say-as=digits]…[/say-as], [mark=name], [rate=150]…[/rate] (siehe unten)
is_voicestring""Stimmname aus of_voices(). Leer = die erste, die is_lang spricht. Live, wie is_lang
ii_rateinteger100Tempo in PROZENT des normalen Tempos (10 bis 400). Mitten im Lesen geändert, gilt es ab dem nächsten Satz
ii_pitchinteger100Tonhöhe der Stimme in PROZENT der normalen Höhe (0 bis 200). Mitten im Lesen geändert, gilt es ab dem nächsten Satz
ii_volumeinteger100Lautstärke in Prozent (0 stumm bis 100), die Skala des Videoplayers. Mitten im Lesen geändert, gilt es ab dem nächsten Satz
il_timeout_mslong300000Längste Dauer einer SYNCHRONEN Wiedergabe: fünf Minuten. Danach gibt of_speak_sync -4 zurück und die Wiedergabe wird abgebrochen (is_last_error sagt warum). 0 oder weniger: keine Grenze (höchstens 24 Stunden)
is_last_errorstring""Warum das letzte of_speak_sync -4 lieferte: Stimme nicht erzeugt, Engine-Fehler, Zeitüberschreitung, ein anderes of_speak_sync wartet schon; auch warum of_pick_voice die Stimmenliste nicht lesen konnte
ipo_ownerpowerobjectnullDas visuelle Objekt, für das diese Stimme arbeitet: die Lizenz wird an seiner Klasse geprüft. Nach dem Öffnen der Stimme gesetzt, wird es beim nächsten Aufruf übergeben. Nur in der Demoanwendung nötig; ein Entwicklungs- oder Laufzeitschlüssel schaltet die Stimme ohne es frei. Nicht freigeschaltet läuft die Stimme im Demomodus — 4 Sätze und 400 Zeichen pro Lesung (Warteschlange inbegriffen), dann wird der Demo-Hinweis gesprochen

Methoden #

MethodeRolle
of_open ( )Erzeugt die Stimme. Optional — of_speak tut es — aber beim Öffnen des Fensters aufgerufen, fällt der Aufwand einmal an, fern des ersten Satzes. Liefert eine positive Zahl, sobald die Stimme existiert, -2, wenn sie nicht erzeugt werden konnte (is_last_error nennt den Grund)
of_is_open ( )Wahr, sobald die Stimme existiert
of_speak ( string as_text )Setzt den Text und liest ihn ab dem ersten Satz. Ohne Argument wird is_text erneut gelesen. Liefert 0 nach dem Senden, -2, wenn die Stimme nicht erzeugt werden konnte
of_speak_from ( long al_index )Setzt das Lesen bei einem bestimmten Satz fort. Liefert 0 nach dem Senden, -5 nach dem letzten Satz (nichts wird gelesen, ein laufendes Lesen geht weiter), -2, wenn die Stimme nicht erzeugt werden konnte, -4, wenn die Seite nicht antwortete
of_pause ( )Hält das Lesen an der aktuellen Stelle an — auch ein Lesen, das noch auf die Stimmenliste wartet: es beginnt erst mit of_resume. Liefert 0 (nichts anzuhalten bei einer nie geöffneten Stimme, die dafür nicht erzeugt wird), -4, wenn die Seite nicht antwortete
of_resume ( )Setzt dort fort, wo of_pause aufgehört hat. Liefert 0, -4, wenn die Seite nicht antwortete
of_stop ( )Beendet das Lesen; of_speak beginnt wieder beim ersten Satz
of_is_speaking ( )Wahr ab of_speak bis zum Ende des Lesens — das Warten auf die Stimmenliste und ein pausiertes Lesen eingeschlossen. Bei der Komponente erfragt, nie eine veraltete Kopie
of_is_paused ( )Wahr, solange das Lesen pausiert ist (of_pause), bis of_resume oder of_stop
of_sentence_count ( )Liefert, wie viele Sätze die Komponente aus is_text in seinem jetzigen Zustand macht, vor jedem Lesen; während eines Lesens die Zahl des gelesenen Textes
of_count ( ) → longWie viele Sätze die Komponente aus dem Text gemacht hat — dieselbe Zahl, die of_sentence_count liefert. Die Bibliothek stellt diese Frage überall unter einem Namen
of_voices ( ref string as_names[] )Füllt das Array mit den auf diesem Arbeitsplatz installierten Stimmen und liefert deren Anzahl
of_languages ( ref string as_tags[] )Füllt das Array mit den Sprachen, die dieser Arbeitsplatz aussprechen kann, ohne Dubletten, und liefert deren Anzahl
of_voice_used ( )Die Stimme, die die Komponente dem Motor tatsächlich übergibt — nicht immer die von is_lang verlangte: Ein Arbeitsplatz trägt die Stimmen, die jemand installiert hat, und keine anderen. Leer = die Komponente gibt keine vor, und der Motor nimmt seine eigene, die der Systemsprache. Diese zu benennen wäre geraten. ue_voice_fallback sagt es beim Lesen; dies liest es vorher, mit is_lang und is_voice so, wie sie gerade sind
of_speak_sync ( { string as_text } )Liest und WARTET auf das Ende: die nächste Zeile läuft nach dem letzten Satz, das Fenster zeichnet weiter. Gibt 0 zurück am Ende, -4 bei Fehler, Zeitüberschreitung oder wenn schon ein anderes of_speak_sync wartet (aus einem von ihm ausgelösten Event aufgerufen) — is_last_error sagt warum
of_enqueue ( string as_text )Stellt einen Text in die WARTESCHLANGE: sofort gelesen, wenn die Stimme frei ist, sonst nach dem laufenden Lesen, ohne es je zu unterbrechen. Gibt 0 zurück, -2 wenn die Stimme nicht erzeugt werden konnte
of_clear_queue ( )Vergisst die wartenden Texte, ohne den gelesenen zu unterbrechen. Liefert 0 (eine nie geöffnete Stimme hat keine Warteschlange und wird dafür nicht erzeugt), -4, wenn die Seite nicht antwortete
of_queue_count ( )Gibt die Zahl der noch wartenden Texte zurück (der gelesene zählt nicht)
of_add_replacement ( string as_from, string as_to )Eine Ausspracheregel: jedes GANZE Wort as_from wird als as_to gelesen (PB → PowerBuilder). Vor den Tags angewandt, vom Objekt behalten. Gibt 0 zurück, -5 wenn as_from leer ist
of_clear_replacements ( )Leert das Wörterbuch. Gibt 0 zurück
of_replacement_count ( )Gibt die Zahl der Regeln im Wörterbuch zurück
of_add_abbreviation ( string as_text )Eine eigene ABKÜRZUNG: der Punkt danach beendet den Satz nicht — Art. 5 bleibt ein Satz. Der Schlusspunkt darf fehlen, die Groß-/Kleinschreibung zählt. Eine eingebaute Liste deckt schon die üblichen der sechs Sprachen dieser Dokumentation ab (Mr., Dr., e.g., M., Mme., z.B., Sig., p.ej.…). Liefert 0 nach dem Hinzufügen, -5, wenn as_text leer ist oder ein Leerzeichen enthält
of_clear_abbreviations ( )Vergisst die mit of_add_abbreviation hinzugefügten Abkürzungen — die eingebaute Liste bleibt. Liefert immer 0
of_pick_voice ( string as_lang, string as_gender )Wählt eine INSTALLIERTE Stimme für eine Sprache und, falls vorhanden, ein Geschlecht (GENDER_FEMALE, GENDER_MALE, GENDER_ANY): genaue Sprache, dann ihre Familie. Setzt sie in is_voice und gibt sie zurück; leer, wenn keine Stimme diese Sprache spricht. Ein leeres as_lang bedeutet is_lang. Ist die Stimmenliste nicht lesbar, bleibt is_voice unverändert und is_last_error sagt warum
of_duration ( )Gibt die GESCHÄTZTE Dauer des Vorlesens in Millisekunden zurück (Wörter pro Minute beim gewünschten Tempo, Pausen inklusive): für einen Fortschrittsbalken, nicht für eine Stoppuhr. Das Tempo LERNT die Stimme: jeder zu Ende gelesene Satz misst das echte, je Stimme auf diesem Rechner gemerkt
of_position ( )Gibt die geschätzte Position des Vorlesens in Millisekunden zurück, verfeinert durch die von der Engine gemeldeten Wörter; 0 wenn nichts gelesen wird
of_progress ( )Gibt den geschätzten Fortschritt zurück, 0 bis 100
of_spoken_text ( )Die Sätze, WIE die Stimme sie erhält, einer pro Zeile (Wörterbuch angewandt, Tags aufgelöst): der Text, der anzuzeigen ist, um Wort für Wort zu folgen
of_process_events ( )Leert die anstehenden Ereignisse und löst sie auf diesem Objekt aus. Der interne Pump der Komponente ruft sie für Sie auf, solange die Stimme offen ist — Sie rufen sie nie auf
of_close ( )Gibt die Stimme frei und stoppt zuvor, was sie gerade sagte: ein laufendes Lesen endet mit seinem ue_stopped, ausgelöst vor der Rückkehr. Das Zerstören des Objekts schließt die Stimme ebenfalls, löst aber KEIN Ereignis aus: die Steuerelemente des Fensters können schon zerstört sein
of_reset ( )Setzt alle Eigenschaften auf ihren Ausgangswert zurück

Ereignisse #

EreignisAusgelöst wenn
ue_started (string as_lang)Die Stimme beginnt wirklich zu sprechen; as_lang ist die Sprache, die sie liest — die der Stimme, fr-FR für ein auf dem Rechner fehlendes fr-CA (siehe ue_voice_fallback). Eine vorher gesetzte Pause (of_speak, dann of_pause im selben Skript) hält es bis of_resume zurück
ue_stopped ( )Der letzte Satz ist fertig, oder das Lesen wurde abgebrochen — of_stop, ein neues of_speak, of_close: jedes begonnene Lesen endet mit einem ue_stopped
ue_paused ( )Das Lesen ist angehalten
ue_resumed ( )Das Lesen läuft weiter
ue_sentence (long al_index, string as_text)Für jeden Satz, mit Rang und Text: so folgt man dem Lesen anderswo im Fenster. Ein Satz mit mehr als 250 Zeichen wird geteilt (an einem Komma, sonst an einem Leerzeichen), und ein [rate]-Stück ist ein eigener Satz: jeder Teil hat seine Nummer
ue_error (string as_message)Der Arbeitsplatz hat keine Engine oder keine Stimme, die Stimme versagt, oder in ihrer Seite tritt ein Skriptfehler auf. Eine bloß FEHLENDE Stimme ist kein Fehler: das ist ue_voice_fallback. Auch wenn die Engine einen Satz wortlos fallen lässt („engine did not answer“): ein Lesen bleibt nie für immer „laufend“
ue_voices_ready (long al_count)Die Engine hat ihre Stimmenliste gefüllt — sie kommt spät; of_voices, of_languages, of_voice_used und of_pick_voice warten von selbst darauf (höchstens 2,5 s), dieses Event sagt nur, WANN sie kam; al_count nennt, wie viele der Arbeitsplatz hat
ue_word (long al_index, long al_start, long al_length)Das gerade gesprochene WORT im Satz al_index: Mid(satz, al_start, al_length). Immer ausgelöst: nach den Wörtern, die die Stimme meldet, und nach der Uhr GESCHÄTZT, wenn sie keine meldet
ue_queue_done ( )Der letzte Text der Warteschlange (of_enqueue) ist gelesen
ue_voice_fallback (string as_wanted, string as_used)Die gewünschte Stimme oder Sprache ist nicht auf diesem Arbeitsplatz — ihre REGION eingeschlossen (fr-CA verlangt, fr-FR liest); as_used nennt die, die stattdessen liest. Eine Information, kein Fehler: das Vorlesen geht weiter
ue_mark (string as_name)Die Stimme erreicht ein [mark=name] des Textes; as_name ist dieser Name. Ausgelöst beim Satzbeginn (eine Marke vor dem ersten Wort), wenn das Wort nach der Marke erreicht ist, oder am Satzende: eine Marke geht nie verloren

Aussprache: Pausen, Buchstabieren, Wörterbuch #

WebView2 hat kein SSML. Der Text trägt daher fünf eigene Tags, die vor der Satztrennung aufgelöst werden, und ein Wörterbuch ganzer Wörter, das davor angewandt wird. Ein unbekanntes Tag wird gelesen, wie es dasteht.

TagWirkung
[pause=500]Eine Stille von 500 ms (höchstens 10 s). Die Pause beendet den laufenden Satz. Am TEXTENDE: eine Stille nach dem letzten Satz (um zwei Ansagen der Warteschlange zu trennen)
[spell]ABC12[/spell]Jedes Zeichen einzeln gesprochen: „A, B, C, 1, 2“. Beendet nie den Satz (seine Punkte sind Zeichen: eine Adresse, eine Version) und wird von einem angrenzenden Wort getrennt
[say-as=digits]4152[/say-as]Die Ziffern einzeln, nicht „viertausendeinhundertzweiundfünfzig“
[say-as=characters]…[/say-as]Wie [spell]
[mark=row2]Eine Marke: ue_mark("row2") wird ausgelöst, wenn die Stimme dort ankommt — um eine Zeile Ihres Fensters im richtigen Moment hervorzuheben
[rate=50]1 250 USD[/rate]Dieses Stück mit 50 % von ii_rate (10 bis 400) — um einen Betrag langsamer zu lesen. Es ist ein eigener Satz
// 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].")

Eine Abkürzung beendet den Satz nicht: Mr. Smith, Dr., e.g., M. Dupont, z.B. bleiben im Satz, der sie trägt (eingebaute Liste für die sechs Sprachen dieser Dokumentation; etc. beendet den Satz nur vor einem Großbuchstaben). Eigene fügt man mit of_add_abbreviation hinzu. Ein Satz mit mehr als 250 Zeichen — ein ohne Punkt eingefügtes Memo — wird an einem Komma geteilt, sonst an einem Leerzeichen: eine Engine gibt zu lange Äußerungen stillschweigend auf.

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

Warteschlange, synchrones Vorlesen, Fortschritt #


Beispiele #

Eine Benachrichtigung vorlesen #

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

Den aktuellen Satz hervorheben #

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

Stimme und Tempo wählen #

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

Ansagen ohne Unterbrechen: die Warteschlange #

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

Das aktuelle Wort hervorheben #

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

Eine Stimme nach Sprache und Geschlecht, dann Vorlesen bis zum Ende #

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

Bewährte Praxis #


← Komponentenreferenz · Inhalt des Handbuchs