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 Objekt | n_pbt_speechout |
| Wofür | Einen Text hörbar machen: Barrierefreiheit, belegte Hände, eine Meldung, die niemand ansieht |
| Prinzip | Sie übergeben den Text; die Komponente zerlegt ihn in Sätze und sagt Ihnen, welchen sie liest |
| Abhängigkeit | Die 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 #
| Eigenschaft | Typ | Standard | Rolle |
|---|---|---|---|
is_lang | string | en-US | Vorgelesene 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_text | string | "" | 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_voice | string | "" | Stimmname aus of_voices(). Leer = die erste, die is_lang spricht. Live, wie is_lang |
ii_rate | integer | 100 | Tempo in PROZENT des normalen Tempos (10 bis 400). Mitten im Lesen geändert, gilt es ab dem nächsten Satz |
ii_pitch | integer | 100 | Tonhö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_volume | integer | 100 | Lautstä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_ms | long | 300000 | Lä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_error | string | "" | 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_owner | powerobject | null | Das 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 #
| Methode | Rolle |
|---|---|
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 ( ) → long | Wie 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 #
| Ereignis | Ausgelö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.
| Tag | Wirkung |
|---|---|
[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 #
of_speakunterbricht,of_enqueuewartet. Eine Anwendung, die Ereignisse ansagt (Alarm, Ergebnis, Benachrichtigung), stellt in die Warteschlange: zwei kurz aufeinander folgende Ansagen werden beide gehört, undue_queue_donesagt, wann die letzte gelesen ist.of_clear_queuevergisst das Wartende, ohne zu unterbrechen;of_stoptut beides.of_speak_synckehrt am Ende zurück. Das Skript wartet auf den letzten Satz (das Fenster zeichnet weiter), begrenzt durchil_timeout_ms, das das Lesen ABBRICHT, sobald es erreicht ist — für „lies das, dann stelle die Frage“.of_duration,of_position,of_progresssind Schätzungen: die Engine sagt nichts zur Dauer, sie zählen Wörter beim gewünschten Tempo, verfeinert durch die von der Engine gemeldeten Wörter. Genug für einen Fortschrittsbalken aus einem Timer, nicht für eine Stoppuhr.of_pick_voice(Sprache, Geschlecht)wählt eine installierte Stimme nach Sprache, dann Geschlecht, und setzt sie inis_voice. Das Geschlecht kommt vom Vornamen, den Windows jeder Stimme gibt; eine Stimme mit unbekanntem Vornamen antwortet aufGENDER_ANY.- Kein Audio-Export. Die Synthese von WebView2 liefert keinen Stream: das Vorlesen kann nicht in eine Datei geschrieben werden. Das ist keine fehlende Einstellung, das ist die Engine.
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 #
- Ein Satz nach dem anderen: Die Komponente übergibt der Engine einen einzigen Satz und verkettet. Das erlaubt einen sauberen Stopp zwischen zwei Sätzen und verhindert Chromiums stilles Aufgeben jenseits von etwa fünfzehn Sekunden.
- Heben Sie den gelesenen Satz in Ihrem Text hervor, aus
ue_sentence— das ist die halbe Miete beim Vorlesen. - Rufen Sie
of_languages()auf, statt zu vermuten: Eine bei Ihnen installierte Sprache muss es beim Kunden nicht sein. - Rufen Sie
of_speaknicht in Serie über eine Ergebnismenge auf: Jeder Aufruf schneidet den vorigen ab, und der Benutzer hört nur Anfänge. Dafür gibt esof_enqueue.