Èñïîëüçîâàíèå MS Speech API 5.1 â ïðîãðàììàõ íà FreeBASIC

Äàòà ïóáëèêàöèè:2007
Ïîäåëèòüñÿ â Twitter Ïîäåëèòüñÿ â F******k Ïîäåëèòüñÿ â VKontakte Ïîäåëèòüñÿ â Telegram Ïîäåëèòüñÿ â Mastodon

Ïðåäâàðèòåëüíûå çàìå÷àíèÿ

Êàê è â ñëó÷àå ñ Microsoft Speech API 4.0 ( ñì. ñîîòâåòñòâóþùóþ ñòàòüþ), äëÿ âçàèìîäåéñòâèÿ ñ êîìïîíåíòàìè Microsoft Speech API 5.1 (MS SAPI 5.1) ìû âîñïîëüçóåìñÿ ôóíêöèÿìè áèáëèîòåêè DispHelper.

Êðîìå óæå èçâåñòíûõ íàì ôóíêöèé dhCallMethod, dhGetValue è dhPutValue, äëÿ ðàáîòû ñ êîëëåêöèÿìè îáúåêòîâ, âîçâðàùàåìûõ íåêîòîðûìè ìåòîäàìè êîìïîíåíòîâ SAPI 5.1, íàì ïîòðåáóþòñÿ ôóíêöèÿ dhPutRef è íàáîð ìàêðîñîâ FOR_EACH. Ýòè ìàêðîñû îáúÿâëåíû â ôàéëå disphelper.bi. Ìàêðîñû FOR_EACH îòëè÷àþòñÿ äðóã îò äðóãà êîëè÷åñòâîì àðãóìåíòîâ, ÷òî ñîîòâåòñòâóþùèì îáðàçîì îòðàæàåòñÿ â èìåíè ìàêðîñà: FOR_EACH0, FOR_EACH1, FOR_EACH2,.. FOR_EACH9. Âñå ðàçíîâèäíîñòè ýòîãî ìàêðîñà ïîçâîëÿþò âûçâàòü ìåòîä, âîçâðàùàþùèé êîëëåêöèþ îáúåêòîâ, à çàòåì âûïîëíèòü îïðåäåëåííûå äåéñòâèÿ ñ êàæäûì èç îáúåêòîâ êîëëåêöèè (íàïðèìåð, âûçâàòü ìåòîä, ïîëó÷èòü èëè ïðèñâîèòü çíà÷åíèå ñâîéñòâó îáúåêòà).

 âåðñèè 0.15b êîìïèëÿòîðà FreeBASIC â ôàéëå disphelper.bi ìàêðîñ FOR_EACH ñîäåðæèò îøèáêó, èç-çà êîòîðîé íåëüçÿ áûëî óñïåøíî ñêîìïèëèðîâàòü ïðîãðàììó. Äëÿ òîãî ÷òîáû îáîéòè ýòó îøèáêó, â íà÷àëî èñõîäíîãî êîäà, ãäå èñïîëüçóåòñÿ ìàêðîñ FOR_EACH) ïîñëå ñòðîêè

#include "disphelper/disphelper.bi"
ñëåäóåò ïîìåñòèòü òàêîé ôðàãìåíò:
#ifdef FOR_EACH0
#undef FOR_EACH0
#define FOR_EACH0(objName, pDisp, szMember) _
	scope 																						:_
		dim as IEnumVARIANT ptr xx_pEnum_xx = NULL    											:_
		DISPATCH_OBJ(objName)                													:_
		if (SUCCEEDED(dhEnumBegin(@xx_pEnum_xx, pDisp, szMember))) then 						:_
			do while(dhEnumNextObject(xx_pEnum_xx, @objName) = NOERROR)
#endif

Ñóòü îøèáêè â òîì, ÷òî âìåñòî êëþ÷åâîãî ñëîâà Scope èñïîëüçîâàíî "escope", à ïðèâåäåííûé ôðàãìåíò èñïðàâëÿåò ýòó ñèòóàöèþ. Àíàëîãè÷íàÿ îøèáêà ïðèñóòñòâóåò âî âñåõ ðåàëèçàöèÿõ ìàêðîñà FOR_EACH.

 âåðñèè 0.16b êîìïèëÿòîðà FreeBASIC ýòà îøèáêà óñòðàíåíà. Îäíàêî òå, êòî ðåøèë ïåðåéòè îò âåðñèè 0.15b ê âåðñèè 0.16b, äîëæíû îáðàòèòü âíèìàíèå íà òî, ÷òî â íîâîé âåðñèè ïî-èíîìó îáðàáàòûâàåòñÿ óíàðíûé îïåðàòîð NOT. Íàïðèìåð, ïðåäïîëîæèì, ÷òî ôóíêöèÿ MyFunc() âîçâðàùàåò ëîãè÷åñêîå çíà÷åíèå TRUE èëè FALSE. Äëÿ êîìïèëÿòîðà âåðñèè 0.15b êîððåêòíûì áûëî òàêîå âûðàæåíèå:

IF NOT MyFunc() THEN
	MessageBox (NULL, "Ôóíêöèÿ âåðíóëà FALSE.", "Îò÷åò", 0)
ELSE
	MessageBox (NULL, "Ôóíêöèÿ âåðíóëà TRUE.", "Îò÷åò", 0)
END IF

 ïðèëîæåíèè, ñîáðàííîì ïðè ïîìîùè êîìïèëÿòîðà âåðñèè 0.16b, âûøåóêàçàííàÿ êîíñòðóêöèÿ áóäåò ðàáîòàòü ñ îøèáêîé. Äëÿ ïðàâèëüíîé ðàáîòû ýòîãî êîäà íåîáõîäèìî íåïîñðåäñòâåííî ñðàâíèâàòü ðåçóëüòàò ðàáîòû ôóíêöèè MyFunc() ñ êîíñòàíòàìè TRUE èëè FALSE. Íàïðèìåð:

IF FALSE = MyFunc() THEN
	MessageBox (NULL, "Ôóíêöèÿ âåðíóëà FALSE.", "Îò÷åò", 0)
ELSE
	MessageBox (NULL, "Ôóíêöèÿ âåðíóëà TRUE.", "Îò÷åò", 0)
END IF

Ðàáîòà ñ îáúåêòîì SpVoice

Íàèáîëåå ïîëíóþ èíôîðìàöèþ î ìåòîäàõ è ñâîéñòâàõ îáúåêòîâ OLE àâòîìàòèçàöèè, âõîäÿùèõ â ñîñòàâ MS SAPI 5.1, ìîæíî íàéòè â äîêóìåíòàöèè, ïðèëàãàåìîé ê MS SAPI SDK 5.1 (ðàçäåë Automation). Òàì æå ïðèâîäÿòñÿ ðàçëè÷íûå ïðèìåðû èñõîäíîãî êîäà äëÿ ñðåäû Visual Basic. Ïàêåò MS Speech SDK, à òàêæå äîïîëíèòåëüíûå ãîëîñà ìîæíî çàãðóçèòü ñî ñòðàíèöû ïîðòàëà Microsoft (ñì. ðàçäåë â êîíöå ñòàòüè).

Îñíîâíûì îáúåêòîì, ðåàëèçóþùèì ñèíòåç ðå÷è ïî òåêñòó, ÿâëÿåòñÿ SpVoice. Ñòðîãî ãîâîðÿ, ïðè èñïîëüçîâàíèè ôóíêöèé DispHelper íå èìååò çíà÷åíèÿ íàçâàíèå îáúåêòà, ïîòîìó ÷òî â êîäå ïðîãðàììû âñå îáúåêòû ÿâëÿþòñÿ óêàçàòåëÿìè íà èíòåðôåéñ IDispatch. Îäíàêî äëÿ óäîáñòâà ìû îñòàâèì çà îáúåêòàìè òå èìåíà, êîòîðûå íàçíà÷åíû èì â äîêóìåíòàöèè ê MS SAPI 5.1. Ïðè èñïîëüçîâàíèè ôóíêöèé DispHelper íåîáõîäèìî çíàòü íàçâàíèÿ ìåòîäîâ (methods) è ñâîéñòâ (properties) èíòåðåñóþùåãî íàñ îáúåêòà. Âîò ïåðå÷åíü ìåòîäîâ è ñâîéñòâ îáúåêòà SpVoice, êîòîðûå áóäóò èñïîëüçîâàíû â íèæåñëåäóþùèõ ïðèìåðàõ:

  • .Speak (Text As String, [Flags As SpeechVoiceSpeakFlags) AS LONG -- ìåòîä, êîòîðûé â çàâèñèìîñòè îò çíà÷åíèÿ ñâîåãî âòîðîãî ïàðàìåòðà, ïîçâîëÿåò îçâó÷èòü ñòðîêó òåêñòà â ñèíõðîííîì èëè àñèíõðîííîì ðåæèìå. Âòîðîé ïàðàìåòð ýòîãî ìåòîäà ïðåäñòàâëÿåò ñîáîé íàáîð ôëàãîâ, îïðåäåëÿþùèõ îïöèè îçâó÷èâàíèÿ. Ïî óìîë÷àíèþ âòîðîé ïàðàìåòð ìîæíî íå óêàçûâàòü, òîãäà â ñèíõðîííîì ðåæèìå áóäåò îçâó÷åíà ñòðîêà òåêñòà, ïåðåäàííàÿ â êà÷åñòâå ïåðâîãî ïàðàìåòðà, ïðè ýòîì çíàêè ïðåïèíàíèÿ ÷èòàòüñÿ íå áóäóò è XML òåãè ðå÷åâîé ðàçìåòêè îáðàáàòûâàòüñÿ òîæå íå áóäóò. Ìåòîä âîçâðàùàåò íîìåð ðå÷åâîãî ïîòîêà.
  • .GetVoices -- ìåòîä, ïîçâîëÿþùèé â ñîîòâåòñòâèè ñ çàäàííûìè êðèòåðèÿìè ñîñòàâèòü êîëëåêöèþ îáúåêòîâ, ñîîòâåòñòâóþùèõ óñòàíîâëåííûì â ñèñòåìå ãîëîñàì â ñòàíäàðòå MS SAPI 5.1. Ïðè âûçîâå ýòîãî ìåòîäà áåç ïàðàìåòðîâ âîçâðàùàåòñÿ êîëëåêöèÿ âñåõ èìåþùèõñÿ â ñèñòåìå ãîëîñîâ.
  • .GetAudioOutputs -- ìåòîä, ïîçâîëÿþùèé â ñîîòâåòñòâèè ñ óêàçàííûìè êðèòåðèÿìè ñîñòàâèòü êîëëåêöèþ îáúåêòîâ, ñîîòâåòñòâóþùèõ èìåþùèìñÿ â ñèñòåìå çâóêîâîñïðîèçâîäÿùèì óñòðîéñòâàì. Ïðè âûçîâå ýòîãî ìåòîäà áåç ïàðàìåòðîâ âîçâðàùàåòñÿ êîëëåêöèÿ âñåõ èìåþùèõñÿ óñòðîéñòâ.
  • .Voice -- ñâîéñòâî, êîòîðîå õðàíèò îáúåêò SpObjectToken, ñîîòâåòñòâóþùé àêòèâíîìó ãîëîñó, òî åñòü òîìó ãîëîñó èç êîëëåêöèè óñòàíîâëåííûõ ãîëîñîâ, êîòîðûì áóäåò îçâó÷åí òåêñò.
  • .AudioOutput -- ñâîéñòâî, êîòîðîå õðàíèò îáúåêò SpObjectToken, ñîîòâåòñòâóþùé òåêóùåìó çâóêîâîñïðîèçâîäÿùåìó óñòðîéñòâó.
  • .Rate AS LONG -- ñâîéñòâî, êîòîðîå õðàíèò çíà÷åíèå òåìïà ðå÷è ( îò -10 äî 10). Ýòî ñâîéñòâî ïîçâîëÿåò ñîõðàíèòü çíà÷åíèå, âûõîäÿùåå çà óêàçàííûå ïðåäåëû, íî, êàê ïðàâèëî, íà òåìï ðå÷è çàïðåäåëüíûå çíà÷åíèÿ íå âëèÿþò.
  • .Volume AS LONG -- ñâîéñòâî, õðàíÿùåå çíà÷åíèå ãðîìêîñòè ðå÷è (îò 0 äî 100). Ýòî ñâîéñòâî íå ïîçâîëÿåò ñîõðàíèòü çíà÷åíèÿ, âûõîäÿùèå çà ïðåäåëû óêàçàííîãî äèàïàçîíà.  ñëó÷àå ïðèñâàèâàíèÿ íåêîððåêòíîãî çíà÷åíèÿ âîçíèêàåò îøèáêà.

Ñëåäóåò îáðàòèòü âíèìàíèå íà òî, ÷òî ìåòîä .GetVoices îáúåêòà SpVoice ïîëó÷àåò íåîáõîäèìóþ èíôîðìàöèþ îá óñòàíîâëåííûõ ãîëîñàõ ("äâèæêàõ" èç ñèñòåìíîãî ðååñòðà (âåòêà "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens"). Îäíàêî ðååñòð íå âñåãäà ñîäåðæèò êîððåêòíóþ èíôîðìàöèþ. Íàïðèìåð, â íåì ìîãóò îêàçàòüñÿ "áèòûå" âåòêè, îñòàâëåííûå ðàíåå óñòàíîâëåííûìè SAPI5-ñèíòåçàòîðàìè è íå óäàëåííûå èìè ïðè äåèíñòàëëÿöèè. Åñëè âûáðàòü òàêîé "áèòûé" ãîëîñ â êà÷åñòâå àêòèâíîãî, òî âîçíèêíåò îøèáêà (â òîì ÷èñëå è â Ïàíåëè óïðàâëåíèÿ -> Ðå÷ü).

Èòàê, òåïåðü óæå ìîæíî ïðèñòóïàòü ê íàïèñàíèþ êîäà. Ìû ñîáèðàåìñÿ èñïîëüçîâàòü ãîëîñàMS SAPI 5.1 äëÿ ñèíòåçà ðå÷è â íàøåì ïðèëîæåíèè íà FreeBASIC. Äëÿ ýòîãî íåîáõîäèìî âûïîëíèòü íåñêîëüêî ïîñëåäîâàòåëüíûõ äåéñòâèé. Ïåðâûì äåëîì, ïðè ïîìîùè ôóíêöèè DHCreateObject ìû çàãðóçèì â ïàìÿòü îáúåêò SpVoice, çàðåãèñòðèðîâàííûé â ñèñòåìå êàê "Sapi.SpVoice":

DIM object IDispatch ptr
IF FAILED(dhCreateObject ("Sapi.SpVoice", NULL, @Object)) THEN
	'... îáðàáîòêà îøèáêè
END IF
	' ... íîðìàëüíàÿ ðàáîòà

Çàòåì ïðè ïîìîùè ìåòîäà .GetVoices ìîæíî ïîëó÷èòü êîëëåêöèþ èìåþùèõñÿ ãîëîñîâ è, ïåðåáðàâ èõ ïðè ïîìîùè ìàêðîñà FOR_EACH0, çàïîëíèòü íàçâàíèÿìè ýòèõ ãîëîñîâ, íàïðèìåð, âûïàäàþùèé ñïèñîê. Ýòî äàñò ïîëüçîâàòåëþ âîçìîæíîñòü ñàìîñòîÿòåëüíî âûáðàòü íóæíûé ãîëîñ èç ñïèñêà.

DIM szDescription AS WSTRING PTR
FOR_EACH0(spVoice, Object, ".GetVoices")
	' Ïîëó÷àåì ñòðîêó îïèñàíèÿ î÷åðåäíîãî ãîëîñà
		dhGetValue("%S", @szDescription, spVoice, ".GetDescription")
	' Ïîìåùàåì ñòðîêó ñ îïèñàíèåì ãîëîñà â êîìáèíèðîâàííûé ñïèñîê
		SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
NEXT_(spvoice)

dhFreeString(szDescription)

Ñëåäóþùèé ôðàãìåíò êîäà ïîêàçûâàåò, êàê óñòàíîâèòü âûáðàííûé ãîëîñ â êà÷åñòâå àêòèâíîãî (ñâîéñòâî .Voice îáúåêòà SpVoice). Çäåñü ïåðåìåííàÿ Index ñîäåðæèò íîìåð âûáðàííîãî ãîëîñà:

	DHGetValue ("%o", @spVoices, object,  ".GetVoices")
	DHGetValue ("%o", @spVoice, spVoices, ".Item(%u)", Index)
	dhPutRef(Object, ".Voice = %o", spVoice)

Ìåòîä .GetVoices îáúåêòà SpVoice ìîæåò â êà÷åñòâå àðãóìåíòà ïðèíèìàòü ñòðîêó, ñîäåðæàùóþ ïàðàìåòðû îòáîðà ãîëîñîâ èç îáùåãî ñïèñêà. Íàïðèìåð, äëÿ òîãî ÷òîáû îòîáðàòü òîëüêî òå ãîëîñà, êîòîðûå ïðåäíàçíà÷åíû äëÿ ñèíòåçà ðóññêîé ðå÷è, íóæíî ïåðåäàòü ñòðîêó "Language=419". Ðàçóìååòñÿ, â ýòîì ñëó÷àå íóæíî èñïîëüçîâàòü ìàêðîñ FOR_EACH1:

DIM szDescription AS WSTRING PTR
FOR_EACH1(spVoice, Object, ".GetVoices(%s)", "Language=419")
	dhGetValue("%S", @szDescription, spVoice, ".GetDescription")
	SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
NEXT_(spvoice)
dhFreeString(szDescription)

Ñîîòâåòñòâóþùèå èçìåíåíèÿ íóæíî âíåñòè è âî ôðàãìåíò êîäà, â êîòîðîì óñòàíàâëèâàåòñÿ àêòèâíûé ãîëîñ:

	DHGetValue ("%o", @spVoices, object,  ".GetVoices(%s)", "Language=419")
	DHGetValue ("%o", @spVoice, spVoices, ".Item(%u)", Index)
	dhPutRef(Object, ".Voice = %o", spVoice)

Àíàëîãè÷íûì îáðàçîì ìû ìîæåì ïðåäîñòàâèòü ïîëüçîâàòåëþ âîçìîæíîñòü âûáðàòü çâóêîâîå óñòðîéñòâî, ÷åðåç êîòîðîå áóäåò çâó÷àòü ñèíòåçèðîâàííàÿ ðå÷ü. Ýòî áûâàåò íåîáõîäèìî, êîãäà òðåáóåòñÿ ðàçäåëèòü çâóêîâîé è ðå÷åâîé ïîòîêè ìåæäó äâóìÿ è áîëåå çâóêîâûìè êàðòàìè èëè, íàïðèìåð, ìåæäó çâóêîâîé êàðòîé è ãîëîñîâûì ìîäåìîì. Ïðèìåð òàêîãî ðåøåíèÿ ïðèâåäåí â èñõîäíûõ êîäàõ äåìîíñòðàöèîííîé ïðîãðàììû.

Ïîñëåäíèé øàã -- ýòî íåïîñðåäñòâåííûé ñèíòåç ðå÷è. Äëÿ ýòîãî äîñòàòî÷íî âûçâàòü ìåòîä .Speak, ïåðåäàâ â êà÷åñòâå àðãóìåíòà ñòðîêó òåêñòà, êîòîðûé íóæíî îçâó÷èòü.

dhCallMethod(Object, ".Speak(%S)", Phrase)

Ïðèìåð èñõîäíîãî êîäà

 êà÷åñòâå ïðèìåðà íèæå ïðèâåäåí èñõîäíûé êîä ïðèëîæåíèÿ Windows, êîòîðîå îòîáðàæàåò íà ýêðàíå äèàëîãîâîå îêíî ñî ñïèñêîì óñòàíîâëåííûõ â ñèñòåìå ãîëîñîâ MS SAPI 5.1 è ñïèñêîì äîñòóïíûõ çâóêîâûõ óñòðîéñòâ. Êðîìå òîãî, â äèàëîãå ïðèñóòñòâóåò òåêñòîâîå ïîëå, â êîòîðîì ïîëüçîâàòåëü ìîæåò íàáðàòü òåêñò. Ïðè íàæàòèè êëàâèøè Enter èëè ïðè ùåë÷êå ïî êíîïêå "Speak" òåêñò èç ïîëÿ ðåäàêòèðîâàíèÿ áóäåò îçâó÷åí âûáðàííûì ãîëîñîì.

Èñõîäíûé êîä ïðèëîæåíèÿ âêëþ÷àåò ñëåäóþùèå ôàéëû:

  1. speech.bas -- îñíîâíîå ïðèëîæåíèå, ôîðìèðóþùåå äèàëîãîâîå îêíî è ðåàëèçóþùåå ôóíêöèþ îáðàáîòêè ñîîáùåíèé.
  2. speech.rc -- ôàéë îïèñàíèÿ ðåñóðñîâ.
  3. resource.bi -- çàãîëîâî÷íûé ôàéë ñ îïðåäåëåíèåì èäåíòèôèêàòîðîâ ðåñóðñîâ.
  4. sapi5.bas -- íàáîð ôóíêöèé-"îáåðòîê" äëÿ âçàèìîäåéñòâèÿ ñ êîìïîíåíòàìè MS SAPI 5.1.
  5. sapi5.bi -- çàãîëîâî÷íûé ôàéë ñ îáúÿâëåíèÿìè ôóíêöèé è ïðîöåäóð èç sapi5.bas.

Ôàéë speech.bas

' speech.bas - Îñíîâíîé ôàéë ïðèëîæåíèÿ, äåìîíñòðèðóþùåãî èñïîëüçîâàíèå 
' MS SAPI 5.1 â ïðîãðàììàõ íà FreeBASIC.
' Êîìïèëèðîâàòü:  fbc.exe" -s gui speech.rc speech.bas sapi5.bas

option explicit 
#define UNICODE
#include once "windows.bi" 
#include "disphelper/disphelper.bi"
#include "sapi5.bi"
#include "resource.bi"

DECLARE FUNCTION DlgProc (byval hwnd as HWND, byval umsg as UINT, byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
                          
DIM SHARED as IDispatch ptr tts = NULL

dhInitialize( TRUE )
dhToggleExceptions( TRUE )
DialogBoxParam( GetModuleHandle( NULL), cptr(LPCSTR, IDD_DLG1), NULL, @DlgProc, NULL ) 
SAFE_RELEASE( tts)
dhUninitialize( TRUE )
END
' Program end 

                                 
FUNCTION DlgProc (byval hwnd as HWND, byval umsg as UINT, byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
    DIM as long id, event
    
    SELECT CASE uMsg
    CASE WM_INITDIALOG
    IF TRUE <> SAPI5_Initialize(tts) THEN
    	EndDialog( hwnd, 0 ) 
	Return TRUE
    END IF

    ' Çàïîëíÿåì ñïèñîê ãîëîñîâ
    SAPI5_GetVoices(tts, GetDlgItem(hWnd, IDC_VOICES_LIST))
    SAPI5_SelectVoice (tts, 0)
    SAPI5_SetSpeed (tts, 5)
    SAPI5_SetVolume(tts, 100)
    
    ' Çàïîëíÿåì ñïèñîê àóäèîóñòðîéñòâ
    SAPI5_GetAudioOutputs(tts, GetDlgItem(hWnd, IDC_AUDIOOUTPUTS_LIST))
    SAPI5_SelectAudioOutput(tts, 0)

    CASE WM_CLOSE
    EndDialog( hwnd, 0 ) 

    CASE WM_COMMAND
    id    = loword( wParam )
    event = hiword( wParam )
    
    SELECT CASE id
	CASE IDOK 
	scope
	DIM szBuf as WSTRING * 1024
	GetDlgItemText(hWnd, IDC_TEXT_TO_SPEAK, szBuf, 1024)

	SAPI5_Speak (tts, @szBuf)
	END Scope

	CASE IDCANCEL
	EndDialog( hwnd, 0 )

	CASE IDC_VOICES_LIST:
	IF CBN_SELCHANGE = event  THEN
	    SAPI5_SelectVoice (tts, SendDlgItemMessage (hWnd, Id, CB_GETCURSEL, 0, 0))
	END IF

	CASE IDC_AUDIOOUTPUTS_LIST:
	IF CBN_SELCHANGE = event THEN
	    SAPI5_SelectAudioOutput(tts, SendDlgItemMessage (hWnd, Id, CB_GETCURSEL, 0, 0))
	End If

	END SELECT
        
    CASE ELSE
    return FALSE
    
    END SELECT
return TRUE
END FUNCTION

Ôàéë speech.rc

#include "resource.bi"

IDD_DLG1 DIALOGEX 0,0,200,90
CAPTION "SAPI 5: Text-to-speech Example" 
FONT 8,"MS Sans Serif" 
STYLE 0x10CC0000 
EXSTYLE 0x00000080 
BEGIN
LTEXT "Voice:", IDC_STATIC, 5, 5, 40, 9
COMBOBOX IDC_VOICES_LIST, 50, 5, 145, 10, WS_TABSTOP| CBS_DROPDOWNLIST | WS_VSCROLL  
LTEXT "Output:", IDC_STATIC, 5, 5+11, 40, 9
COMBOBOX IDC_AUDIOOUTPUTS_LIST	, 50, 5+11, 145, 10, WS_TABSTOP| CBS_DROPDOWNLIST | WS_VSCROLL  
LTEXT "Text to speak:", IDC_STATIC, 5, 5+22, 100,  10
EDITTEXT IDC_TEXT_TO_SPEAK, 5, 5+33, 190, 10

 DEFPUSHBUTTON  "Speak", IDOK, 120, 5+55, 35, 10 
PUSHBUTTON   "Close", IDCANCEL, 120+37, 5+55, 35, 10 
END

Ôàéë resource.bi


#define IDD_DLG1 1000 
#define IDC_BTN1 1002
#define IDC_STATIC -1
#define IDC_BTNSPEAK 1001

#define IDC_VOICES_LIST	2001
#define IDC_AUDIOOUTPUTS_LIST	2002
#define IDC_TEXT_TO_SPEAK	2003
#endif

Ôàéë sapi5.bas


option explicit 

#define UNICODE
#include once "windows.bi" 
#include "disphelper/disphelper.bi"

FUNCTION SAPI5_Initialize (byRef Object as IDispatch PTR) as BOOL
DIM as String ProgId = "Sapi.SpVoice"
DIM hr as HRESULT
    IF FAILED(dhCreateObject (ProgId, NULL, @Object)) THEN return FALSE
    return TRUE
END FUNCTION

SUB SAPI5_GetVoices (byRef object as IDispatch ptr,byval hCtrl as HWND)
DIM szDescription as WString ptr
    SendMessage (hCtrl, CB_RESETCONTENT, 0, 0)
    FOR_EACH0(spVoice, Object, ".GetVoices")
	dhGetValue("%S", @szDescription, spVoice, ".GetDescription")
	SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
    NEXT_(spvoice)
    SendMessage (hCtrl, CB_SETCURSEL,  0, 0)
    dhFreeString(szDescription)
END SUB

SUB SAPI5_SelectVoice (byRef Object as IDispatch ptr , byVal Index as Integer)
DIM spVoices, spVoice as IDispatch ptr

    DHGetValue ("%o", @spVoices, object,  ".GetVoices")
    DHGetValue ("%o", @spVoice, spVoices, ".Item(%u)", Index)
    dhPutRef(Object, ".Voice = %o", spVoice)
END SUB

SUB SAPI5_GetAudioOutputs(byRef object as IDispatch ptr,byval hCtrl as HWND)
DIM szDescription as WString ptr

    SendMessage (hCtrl, CB_RESETCONTENT, 0, 0)
    FOR_EACH0(spAudioOutput, Object, ".GetAudioOutputs")
	dhGetValue("%S", @szDescription, spAudioOutput, ".GetDescription")
	SendMessage (hCtrl, CB_ADDSTRING, 0, szDescription)
    NEXT_(spAudioOutput)
    SendMessage (hCtrl, CB_SETCURSEL,  0, 0)
    dhFreeString(szDescription)
END SUB

SUB SAPI5_SelectAudioOutput(byRef Object as IDispatch ptr , byVal Index as Integer)
DIM spAudioOutputs, spAudioOutput as IDispatch ptr
    DHGetValue ("%o", @spAudioOutputs, object,  ".GetAudioOutputs")
    DHGetValue ("%o", @spAudioOutput, spAudioOutputs, ".Item(%u)", Index)
    dhPutRef(Object, ".AudioOutput= %o", spAudioOutput)
END SUB

SUB SAPI5_SetSpeed (byRef Object as IDispatch ptr , byVal Speed as Integer)
    dhPutValue(Object, ".Rate=%d", Speed) 
END SUB

SUB SAPI5_SetVolume(byRef Object as IDispatch ptr , byVal Volume as Integer)
    IF Volume > 100 THEN VOLUME = 100
    IF Volume < 0 THEN Volume=0 
    dhPutValue(Object, ".Volume=%u", Volume) 
END SUB

SUB SAPI5_Speak (byRef Object as IDispatch ptr , byVal Phrase as WString PTR)
    dhCallMethod(Object, ".Speak(%S)", Phrase)
END SUB

Ôàéë sapi5.bi

#ifndef _SAPI5_BI
#define _SAPI5_BI
DECLARE FUNCTION SAPI5_Initialize (byRef Object as IDispatch PTR) as BOOL
DECLARE SUB SAPI5_GetVoices (byRef Object as IDispatch ptr, byval hCtrl as HWND)
DECLARE SUB  SAPI5_SelectVoice (byRef Object as IDispatch ptr, byVal Index as Integer)
DECLARE SUB SAPI5_GetAudioOutputs(byRef Object as IDispatch ptr, byval hCtrl as HWND)
DECLARE SUB  SAPI5_SelectAudioOutput(byRef Object as IDispatch ptr, byVal Index as Integer)
DECLARE SUB SAPI5_SetSpeed(byRef Object as IDispatch ptr , byVal Speed as Integer)
DECLARE SUB SAPI5_SetVolume(byRef Object as IDispatch ptr , byVal Volume as Integer)
DECLARE SUB SAPI5_Speak (byRef Object as IDispatch ptr , byVal Phraseas  as WString PTR)
#endif


Ðàñïðîñòðàíåíèå ìàòåðèàëîâ ñàéòà îçíà÷àåò, ÷òî ðàñïðîñòðàíèòåëü ïðèíÿë óñëîâèÿ ëèöåíçèîííîãî ñîãëàøåíèÿ.
Èäåÿ è ðåàëèçàöèÿ: © Âëàäèìèð Äîâûäåíêîâ è Àíàòîëèé Êàìûíèí,  2004-2026