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("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("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 bis zu zwei Sekunden dauern: 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.
string ls_tags[]
if inv_voice.of_languages(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 |
is_text | string | "" | Der zu lesende Text. Die Komponente zerlegt ihn in Sätze; drei Tags sagen, WIE ein Stück gelesen wird: [pause=500], [spell]…[/spell], [say-as=digits]…[/say-as] (siehe unten) |
is_voice | string | "" | Stimmname aus of_voices(). Leer = die erste, die is_lang spricht |
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) |
ii_volume | integer | 100 | Lautstärke in Prozent (0 stumm bis 100), die Skala des Videoplayers |
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) |
is_last_error | string | "" | Warum das letzte of_speak_sync -4 lieferte: Stimme nicht erzeugt, Engine-Fehler, Zeitüberschreitung |
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, 0 oder weniger, wenn sie nicht erzeugt werden konnte |
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, -1, 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, -1, wenn die Stimme nicht erzeugt werden konnte |
of_pause ( ) | Hält das Lesen an der aktuellen Stelle an. Liefert 0 nach dem Senden, -1, wenn die Stimme nicht erzeugt werden konnte |
of_resume ( ) | Setzt dort fort, wo of_pause aufgehört hat. Liefert 0 nach dem Senden, -1, wenn die Stimme nicht erzeugt werden konnte |
of_stop ( ) | Beendet das Lesen; of_speak beginnt wieder beim ersten Satz |
of_is_speaking ( ) | Wahr, solange ein Satz gelesen wird — ein pausiertes Lesen zählt noch. Bei der Komponente erfragt, nie eine veraltete Kopie |
of_sentence_count ( ) | Liefert, wie viele Sätze die Komponente aus dem Text gemacht hat |
of_count ( ) → integer | 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_error sagt dasselbe beim Lesen; dies liest es vorher |
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 oder Zeitüberschreitung (is_last_error) |
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, -1 wenn die Stimme nicht erzeugt werden konnte |
of_clear_queue ( ) | Vergisst die wartenden Texte, ohne den gelesenen zu unterbrechen. Gibt 0 zurück, -1 wenn die Stimme nicht erzeugt werden konnte |
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_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 |
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. Der Destruktor ruft es auf |
of_reset ( ) | Setzt alle Eigenschaften auf ihren Ausgangswert zurück |
Ereignisse #
| Ereignis | Ausgelöst wenn |
|---|---|
ue_started (string as_lang) | Das Lesen beginnt; as_lang erinnert an die Sprache |
ue_stopped ( ) | Der letzte Satz ist fertig, oder of_stop wurde aufgerufen |
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 |
ue_error (string as_message) | Der Arbeitsplatz hat keine Engine oder keine Stimme, oder die Stimme versagt. Eine bloß FEHLENDE Stimme ist kein Fehler: das ist ue_voice_fallback |
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). Wenn die Engine Wörter meldet (die meisten Windows-Stimmen) |
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; as_used nennt die, die stattdessen liest. Eine Information, kein Fehler: das Vorlesen geht weiter |
Aussprache: Pausen, Buchstabieren, Wörterbuch #
WebView2 hat kein SSML. Der Text trägt daher drei 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 |
[spell]ABC12[/spell] | Jedes Zeichen einzeln gesprochen: „A, B, C, 1, 2“ |
[say-as=digits]4152[/say-as] | Die Ziffern einzeln, nicht „viertausendeinhundertzweiundfünfzig“ |
[say-as=characters]…[/say-as] | Wie [spell] |
// The dictionary : whole words, in the order added, case-sensitive
inv_voice.of_add_replacement("PB", "PowerBuilder")
inv_voice.of_add_replacement("Mme", "Madame")
inv_voice.of_add_replacement("4152", "[say-as=digits]4152[/say-as]") // a rule may add a tag
inv_voice.of_speak("Mme Durand, PB order 4152 [pause=600] code [spell]PBT[/spell].")
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— 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 #
inv_voice.of_speak("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(2)
Stimme und Tempo wählen #
string ls_voices[]
if inv_voice.of_voices(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("Order 4152 has been shipped.")
inv_voice.of_enqueue("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 #
inv_voice.of_pick_voice(n_pbt_speechout.LANG_FR_FR, n_pbt_speechout.GENDER_FEMALE)
if inv_voice.of_speak_sync("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.