Home Programmeren met de Fluency API

Tutorial

In deze tutorial bouwen we stap voor stap een eenvoudige Delphi-applicatie, die tekst kan voorlezen uit een tekstvenster. De gebruiker kan een stem kiezen uit een lijst, en het tempo instellen.

We gaan er van uit dat je enigszins bekend bent met Delphi, en de Pascal-syntaxis. Als je zelf een andere programmeertaal gebruikt, dan kun je de code-fragmenten wellicht globaal volgen.


Gebruikersinterface

Maak een formulier dat er ongeveer uitziet als de afbeelding hieronder.


Demo-programma

Het formulier heeft de volgende elementen:

naam type omschrijving
Memo TMemo Een tekstvenster waar de gebruiker tekst kan invoeren. Zet de eigenschap HideSelection van dit Memo op FALSE.
Voices TComboBox Een lijst waaruit de gebruiker een stem kan kiezen. Zet de eigenschap Style op DropDownList.
Start TButton Een knop om het voorlezen te starten.
Stop TButton Een knop om het voorlezen te stoppen.
Tempo TTrackbar Een slider om het spreektempo in te stellen. De slider heeft de volgende eigenschappen: Frequency = 10, Min = -10, Position = 0 en Max = 10.

Fluency TTS toevoegen

Voeg FluencyAPI.pas toe aan de uses-regel.

Voeg alvast twee variabelen toe aan het formulier: Voice en Channel. Deze zullen we verderop gebruiken.

Roep fluencyInitialize aan in de Create-event van het formulier, en fluencyClose in de Close-event.

Je hebt nu een applicatie die Fluency TTS laadt bij het opstarten, en weer vrijgeeft bij het afsluiten. Draai je applicatie om te controleren of dit geen foutmeldingen geeft.


De lijst met stemmen vullen

Gebruik de functies fluencyGetVoiceCount en fluencyGetVoiceName om de ComboBox te vullen met de lijst van beschikbare stemmen. Je doet dit door de Create-event uit te breiden als hieronder.

Gebruik de functie fluencyGetPreferredVoiceName om in deze lijst de favoriete stem van de gebruiker alvast te selecteren. Voeg de volgende regels toe aan de code van de Create-event.

Test of dit allemaal werkt.


Voice en Channel initialiseren

We hebben al twee variabelen Voice en Channel (zie hierboven), nu gaan we deze initialiseren met de functies fluencyCreateVoice en fluencyCreateChannel. Breid de Create-event als volgt uit.

Merk op dat we 0 invullen voor de sampling rate. We kiezen daarmee de standaard sampling rate van 22 KHz. Ook kiezen we voor een mono-kanaal.


De tekst laten voorlezen

We hebben nu genoeg voorbereidingen getroffen om eens wat spraak te laten horen. Voeg een OnClick-event toe aan de Start-knop, en gebruik de functies fluencySetInputText en fluencySpeak om de spraak te starten.

Merk op dat we nog geen callback hebben toegevoegd (het tweede argument van fluencySpeak is nil). Dit komt later.

Wel voegen we meteen de functie fluencyStopSpeaking toe aan de OnClick-event van de Stop-knop.

Experimenteer wat met de applicatie zoals hij nu is. Het zal je opvallen dat de tekst steeds met dezelfde stem, en in hetzelfde tempo wordt voorgelezen. Ook zou het mooier zijn als in het tekstvenster een cursor zou meelopen met de spraak. Deze verfijningen gaan we hieronder aanbrengen.


Van stem wisselen

De gebruiker kan nu wel een stem kiezen, maar om het effect daarvan te horen moeten we code toevoegen aan de OnChange-event van de Voices-lijst.

Daartoe gebruiken we (opnieuw) de functie fluencyCreateVoice, en de functie fluencySetVoice.

Dit werkt op zich goed, je kunt zelfs tijdens het spreken van stem wisselen!

Maar er is wel een probleem. Omdat we een eerder gekozen stem niet vrijgeven, hebben we na verloop van tijd alle stemmen in het geheugen geladen (Fluency TTS is gelukkig wel zo slim om een stem niet twee keer te laden). Dit zal niet zo snel tot problemen leiden, maar aangezien elke stem ongeveer 1,5 MB aan geheugenruimte vraagt, is het wel een beetje zonde. En bovendien, het is niet zoals het hoort!

Daarom breiden we de bovenstaande code als volgt uit met de functie fluencyDeleteVoice.

Vraag: Waarom geeft de code hieronder een protectiefout als je tijdens het spreken een andere stem kiest?



Het spreektempo aanpassen

We gaan nu werk maken van het spreektempo. Eerst breiden we de code van de Create-event nogmaals uit met een regel die de functie fluencyGetPreferredTempo aanroept om de slider te initialiseren.

Vervolgens voegen we de functie fluencySetTempo toe aan de OnChange-event van de Tempo-slider.



Synchronisatie

Tot slot gaan we een callback-functie toevoegen, die ervoor zorgt dat tijdens het spreken elk woord ge-highlight wordt. We noemen de callback-functie FLUENCYSYNC.

Behalve dat we het woord highlighten in reactie op SYNC_PROGRESS, zetten we ook tijdens het spreken het tekstvenster op ReadOnly. Dit doen we om te voorkomen dat de gebruiker van de applicatie de tekst wijzigt terwijl we aan het highlighten zijn.

Om de callback te activeren passen we de code bij de Start-knop als volgt aan.

En daarmee is onze applicatie compleet. De volledige broncode kun je downloaden van de pagina met voorbeeldapplicaties.


Mogelijke uitbreidingen

De applicatie mag dan af zijn, er valt natuurlijk genoeg te verbeteren. Als je wat meer wilt oefenen om de Fluency API goed in de vingers te krijgen, dan zijn hier wat ideeën:

  • Behalve een Tempo-slider zou de gebruiker wellicht ook controle willen hebben over het volume of de stereobalans. Voeg hiervoor twee sliders toe. Vergeet niet om bij de functie fluencyCreateChannel om een stereo-kanaal te vragen!
  • Voeg de mogelijkheid toe om de spraak in een audio-bestand op te slaan. Hiervoor gebruik je de functie fluencySpeakToFile. Hou er rekening mee dat deze functie niet tegelijk met fluencySpeak gebruikt mag worden, ook niet per ongeluk!
  • We zijn nogal nonchalant omgegaan met het feit dat de functie fluencyInitialize als resultaat een boolean oplevert, die aangeeft of de initialisatie al dan niet gelukt is. Is dat niet het geval, dan kun je geen enkele API-functie gebruiken. Ook andere functies zouden kunnen falen. Bijvoorbeeld: fluencyCreateVoice zou een nil pointer terug kunnen geven. Wat moet je allemaal doen om deze applicatie bullet proof te maken?