2025年10月16日 星期四

朗誦控制程式

朗誦控制程式


曾慶潭 Ching-Tang Tseng
ilikeforth@gmail.com
Hamilton, New Zealand
16 October 2025


這是一篇以語音輸出為題,展示如何將一個很基本的語音輸出功能,發展成能讓系統僅只需操作 READ 指令,就能唸出整篇文章並進行控制之程式的設計方法。

1. 程式特性

這種應用範例,就如同電腦繪圖,看起來功能非凡,但通常都與電腦作業系統的基本性能高度相關,因此,發展出來的程式有時效性,而且只能配合硬體既有的能力來設計,程式移往另外一套電腦或系統,就不能使用。

此類程式也因此而不可能規劃出標準指令,最終發展出來的應用程式,都得因時、因地制宜,僅安排特別指令,或只有幾個簡單規則指令。

語音輸出本身,是一項很大的課題,我們不可能從最基本的硬體操控來設計程式,現行作業系統的設計觀念,提供了發展者可以叫用程式來使用的基本運用方法, Win32Forth 系統因此亦跟著建立起叫用作業系統現成程式的功能,前人詳細讀完作業系統叫用程式的說明資料後,才設計出相關的叫用程式,我們的程式才能夠跟著使用。

語音輸出的基本功能已經存在於 Win32Forth V6.14 版本的系統中。換句話說,語音輸出的功能要求,已經不勞我們傷神。但原始程式提供的功能,只能操作系統,讓它一句一句的講人話。我們的目標,則是憑此功能,設計出能夠一次就唸出整篇文章的程式來。

『原始功能』與『我們的目標』間的差異,從 FORTH 系統的傳統觀念來看,主要就是被唸的文字,應該放置在那裡?有所不同而已。因此,我們打算設計的程式,就得設計出文字處理功能。另外,它牽扯到檔案操作、字串處理、與一些簡單的語音輸出固定規則。

想設計出這個應用程式之前,必須先行了解已有程式的性能。由於沒有任可可以參考的書面文件,所有性能都要靠操作電腦、實測、記錄後,才能完成,要耗不少時間。詳細的測試過程,作者將其寫成一篇網文,張貼在作者的個人網頁上,供大家參考,是 2010-8-2 貼出的『因子分解法』。(補註 : 該文已從本網頁撤除)

該文只作經驗記錄,沒有刊出程式,本文才刊出實際可用程式,為了節省本書篇幅,僅節錄該文部份相關敘述於此,以便讓讀者明白,在程式中為何出現一些將待講文字進行特殊處理的修改設計?然後才交給電腦程式執行語音輸出。

『因子分解法』文內,是這樣寫的:

這半個月,正式開始了語音輸出的程式設計,經過長期的積極準備,心中早已有了如何進行這件工作的具體腹案,因此,進展順利,截至昨天為止,『唸文章』的功能幾乎全部實現了,唸的是英文,想唸出中文,以後再說。

我每天在住家附近散步時,都會經過一條名叫 Rothesay 的街道,我實在是不知道街名的正確發音為何?街的名稱只是一個名字,字典上查不到,因此,長期迷惑於這條街名的唸法。我們散步時,也曾經有外來訪客,拿著地址字條問過我們,這條街在那裡?我告訴他方向時,曾試著想聽對方如何唸這條街名,但經我一問,他反而猶豫不敢發音了,只笑一笑回答說:『第一次來,也不知道該如何唸』。換句話說,我以一個中國人的身份問問題,所有天生講英文的朋友,都可能失去回答此一問題的信心,英文名字確實是可以隨著不同地方的人而唸成不同發音的,我們現在居住的都市 Hamilton 的唸法,英式發音就與美式發音不同。台灣宜蘭五結有一個『利澤簡』,會講台語的同胞,也不見得能用台語直接講對這個地名,不信?您現在就試試看,然後打電話到利澤簡派出所或消防隊,驗證一下發音。

現在,我找到一個充滿信心、敢於直接回答,永遠都可以請教的對象了,它就是我設計出來的軟體。即時性控制(Real time control)是 FORTH 的專長,自從大系統不能直接執行P@、P! 來進行硬體實質控制之後,我們對 FORTH 的感覺,可以說是心都涼了半截,此次設計電腦語音輸出時,卻可以排除這種遺憾。目前我所辦到的功能是:執行 READ filename ,可以得到名為 filename 的文字檔案,並自動唸完整篇文章,執行期間始終呈現即時性響應的感覺。

作者戲稱這種程式設計的方法,是一種『吸功大法』,性質確實如此。因為實際的語音輸出功能,我們根本不需要設計,是別種 C 式程式語言,先行設計好的動態連結程式,幫了大忙。而 Win32Forth 系統,只設計了吸功大法所需要的指令,將別人辛苦練成的功夫,全面吸取來用,完成了語音輸出的所有功能,『因子分解法』中,是這樣寫的:

現代 FORTH 系統內的功能,還真像金庸的小說:『天龍八部』裡面,那位來自大理國的段譽,身懷北冥神功的絕技,具有化功大法,有武功的人一旦被他沾上,立刻吸來自用。您若精研 Win32Forth 裡面的特異功能,發現它可以呼叫 C 式語言設計出來之 .dll 程式庫內所有 API 功能程式時,可以了解它簡直就是這種吸功大法,此法還不可逆,暫時是別的程式語言難以辦到的,要不然別的程式語言,只好將整個 FORTH 系統全請去用。

我這次進行的語音輸出程式設計,正在全面使用此一吸功大法,是借力使力進行程式設計。練得這項吸功大法,確實耗費不少時間,我完整的練成過用 C 設計程式,然後由 FORTH 『吸用』的詳實步驟,確實像北冥神功,而且這種功夫練會一次就夠了,以後都是別人設計程式,我只需借力使力叫來使用,這種功夫好用得很。

關於利用 FORTH 直接測試語音輸出性能的部份,『因子分解法』中,是這樣寫的:

我在利用 SAPI(Sound Application Program Interface) 程式設計語音輸出時,首先要做的事情就是因子分解,『講人話,唸文章,配合視障操作而反應』就將整個打算設計的系統一分為三了,接下來繼續像樹狀分支一般的再將問題分解。講人話是別人的作品,我不用傷腦筋,我只需善用吸功大法,搞清楚吸來使用時該有的規矩就夠了。

即時性控制功能的妙用,就是能讓使用者即時的獲得執行結果,只要花一點點的時間,您就能體會這一套軟體講人話的效果到底如何了?憑良心講,如果不是利用 FORTH 具有直接操作,能立即得到結果的特性,我根本就不想設計這種系統,換成不用 FORTH 來進行這種發展,情況可以想像,絕對是笨透了。直接操作時,我將測試因子分成數個,先大略分成講中文與講英文,再細分成亂講、講單字、講連體字、講符號、與以上皆有的混講,還得把整個鍵盤全面試透,產生出來的效果完全不同,就算有說明書描述這些細節,都絕對不如我用手直接操作,用耳直接聽取來得乾脆,這豈不就是視障者的程式設計方式?有超出原本預料之處,立刻留下記錄,後續發展需要知道這些特性。

試完之後,發現光是講單字,配上少數幾個不同符號,音調的高低就可不同,因此,讓電腦講中文的五音就也可行了。我將希望測試出來的效果,再度因子分解成一份固定的表格,經過兩天的摸索,就把表格填妥了,這就是 FORTH 。我絕不相信現行世界上其他的任何程式語言,能這樣子完成測試, Python 不知道會不會講話? Java 呢? Matlab 呢?我的嬰兒期啟明 FORTH ,開機點兩點後就會講人話,還是不用花錢買的東西。

接著,我規劃出要系統講整句話的測試,先以直接鍵入(Type-in)的方式來測,隨後就又發現,句中、句尾使用不同標準符號時,又出現了不同效果,必須繼續因子分解,列出所有可能的符號與句子組合,然後,操作 FORTH 唸出句子,發現電腦裡面的這個美國人確實聰明,唸得真像英文,該問則問,該嘆就嘆,該輕必輕,但中文講得不太好,有點生硬,還需要更多時間來揣摩。

為了集中精力完成『唸文章』的要求,我停止了講中文的測試與發展,以免干擾接下來更為複雜一些的程式設計。我再度將發展項目因子分解,先將唸文章的方式分解成兩個,一是全面翻譯本文成可唸文,然後直接唸全篇文章,另一方式是逐句翻譯,逐句講。前者的程式較容易設計,可是系統耗用大量的記憶體,講出之話,段落不太分明,是其缺點。後者的程式要考慮之處較多,解決所遭遇的問題時,必須自己動腦筋想辦法,很有挑戰性,但系統耗用記憶體較少,將來與別的功能程式,存在同一 FORTH 系統中時,影響較小,而且,最重要的是,要電腦以這種方式講話時,才比較像真人在講話,段落分明,正確的設計應該要採用後者。另外,測試程式時,發現了無法追蹤下去的不合理問題,如果每次講完話後,不強行將講話區域的記憶體內容清理乾淨,前面留下來的東西,會自動縮黏到新話語的尾部,繼續發音講話,沒有 FORTH 的性能,想得知此事,難啊!

程式設計完成到這個階段時,前述的兩個指令就已經設計出來了,基本上,在 FORTH 系統內自行打轉,都沒有問題,我指的是:文章用 FORTH 系統的編輯程式自己準備,然後全面唸出來,變得輕而易舉。我休息了幾天,建了幾篇『伊索寓言』(The Fables of Aesop)中的短文來欣賞,剛開始聽講時不太習慣,必須調整講話速度,系統以設定負數值來調慢速度,我需要用 -3 的設定才能完全聽得清楚,聽過幾篇後,就完全能用正常速度聽講了。

我自學英文的過程中,一直強迫自己聽英文時不要看文字,才能加速適應不同人講的英文,對這套系統而言,情況相同。我為視障朋友發展系統,系統設計出來後,我當然必須假想自己就是一名視障者,根本無書可看,完全要用聽力,要把狀況想像成,我現在比視障者更可憐,連點字都摸不出來時該怎麼辦?讀者您讀到這裡時,您實在該慶幸自己還有這麼健全的視力來看我的文章,但也不要忽略我們還有許多視障同胞,需要我們的幫助。

唸文章的軟體工程到此並未結束,我想唸的文章,不能只是使用 FORTH 系統自行建立的檔案文章才能唸,必須接受所有可能呈現在這個系統裡面的各種檔案格式才行。這項要求是件新的挑戰,一般程式語言更難處理,因為不同編輯軟體,編寫出來的純文字檔案全都不同,我又得進行因子分解了。

平日,我除了搞 FORTH 與打網文外,只上網看新聞與搜索資料,我不是聖人,偶爾欣賞一下清涼的美女照片也是難免的,經常抓資料儲存的方式,都用微軟的編輯軟體 Word ,現在正在打網文,用的也是 Word 系統,至於其他的編輯軟體,沒有使用經驗,也不想勉強去接觸。因此,這次的因子分解,就將問題分解成四個,一是用 FORTH 編輯程式,就是那片綠葉子 WinEd 建的文字檔,二是用記事本建的文字檔,三是用文件檔案編輯程式(WordPad)建的文字檔,四是用文書編輯軟體(Word)建的文字檔。

以前,讀別人寫的英文電腦書籍時,讀到過強調這些編輯程式編出的文字檔案,內容會有所不同的特別聲明,自己卻不曾仔細的看個明白,到底其中有甚麼不同?現在,為了程式設計需要,不得不碰了,趁機讀個仔細,然後從中尋找規則,最後才能設計出適用於各種編輯軟體,所編寫出來之文字檔案的程式。

能看透別人的規格,是件痛快的事情, FORTH 才能輕而易舉的辦到,因為系統中早就有現成的指令可用,我已用了 30 年,但現在才拿來看所有的文字檔,看完了立刻發展程式解決問題,也把原來發展成功的唸文章程式,改寫成更具有彈性的設計,可以輕鬆插入新面臨的不同格式文字檔閱讀要求之指令,如此一來,程式就可以適用於所有可能出現的狀況了。

讀過了四種不同的文字檔結構內容,還都分別為它們設計完適應性的程式,現在已經不怕再有新規格文字檔案出現了,因為頭腦已經被磨練過幾次,知道如何適應新問題,換句話說,將來應該沒有我的啟明 FORTH 系統讀不成的文字檔案,這些文字檔案暫時還須要根據圖示後人工識別檔案的格式,將來,我希望能做到全由程式自己識別,這一部份的發展就可以全部告一段落了。

比較上述四種文字檔案的規格後,發現由 WordPad 建成的文字檔比由 Word 建成的文字檔還難處理,遭遇困難時,我仍是採用因子分解法,將問題因子化成一個一個的問題,然後逐個解決,這半個月,我不停的採用這種解決問題的方式進行程式設計,效果非凡,程式設計得非常順利。

我自己也急於想享受設計出來的成果,好像已經有許久沒見到純用 FORTH 控制東西的成果了,現在又重拾這種愉快,還是講人話的東西,我很喜歡。我知道這樣的設計,可以幫助台灣健康的同胞學習英文。

仔細追究這套方法,能用到的語音輸出指令,總共只有三個,首要的第一個,是一個前引指令 VOICE ,它的用法,如同必須與後續指令形成片語,後續有限的幾個語音輸出控制指令,才得以被執行。第二個是設定講話速度的指令,名為 SETRATE ,執行前賦予數值,就能改變講話速度,給負值就變慢,給正值就變快,執行讓速度變慢的操作範例如下:

-3 VOICE SETRATE

我們打算設計的程式,不需要動用到設定講話速度的 SETRATE 指令。讀者只須知其功能,而在需要調整講話速度時,直接操作使用。

結果,最後僅剩第三個唯一的指令,是我們想要設計程式時,可以使用的指令了。指令的名稱是 SPEAK ,在原始源程式檔案 EX_SAPI.F 中,所記錄的範例用法為:

0 0 u" Hello World!" drop voice speak

一個 FORTH 程式老手,可以僅憑對上述指令執行時,指令間參數傳遞狀況的分析,了解自己可以如何運用這些指令。上列程式對大家可能造成的困擾,來自於由原設計人狄湯瑪(Thomas Dixon)自行添加的 u” ………” 指令,在系統中可以透過直接操作 SEE u” 來看清它的詳細設計內容,它還是一個立即執行性的指令。

事實上,經過仔細追究後,想利用 SPEAK 指令的方式,沒有那麼複雜, SPEAK 指令僅只需要先行提供一個安放字串處的起始記憶體位址就夠了。原作者純粹只是為了讓 SPEAK 能夠直接接受就地處理出來的字串,才會那樣設計 u” 指令。

分析結果告訴我們,想要操控 SPEAK 指令,下命令的方式可以簡化成:

0 0 address voice speak

其中的 address 代表待講之話的字串所安放的起始位址,而上述指令執行完畢之後,堆疊上會留下一個代表執行順利成功或失敗的旗號值。

僅僅就是這麼一丁點的分析,就足夠讓我們進行自己打算設計之程式的規劃了。想讓系統自動的唸出整篇檔案文章,就得設計檔案讀取程式。讀到的文章要放在那裡?得自行規劃。

檔案內存在了會妨礙 SPEAK 指令執行或影響效果的符號,得設計程式先行將其處理掉。考慮到人機界面問題,試成程式之後,就改良內容,讓它顯得友善。這些要求,全由純粹傳統的 FORTH 程式設計方式來完成,非常簡單,因為, FORTH 就擅長於搞自動控制,而上述這些要求,就是最典型的自動控制問題,只不過控制對象是字串與語音輸出而已。

2. 唸檔案文章的程式


 

\ Text to speach 2010-7-23 by Ching-Tang Tseng

needs FCOM.F

\ SAPI 5.0 typelibrary
5 0 typelib {C866CA3A-32F7-11D2-9602-00C04F8EE628}

ISpVoice ComIFace voice

\ Create voice instance
voice ISpVoice 1 0 SpVoice CoCreateInstance drop

0 VALUE FILEID            \ file identification
0 VALUE FPT1              \ file pointer 1
0 VALUE SPT               \ scanning pointer
0 VALUE CPT               \ coding pointer
0 VALUE BPT               \ beginning pointer
0 VALUE EPT               \ endding pointer

: FBUF1  ( -- n )         \ file buffer 1
  HERE 2000 + ;

: READING-BUF    ( -- n )          \ reading buffer
  FBUF1 FPT1 + 10 + ;              \ keep 10 bytes away from file buffer

: ASSIGN-FILE-NAME    ( -- adr slen )
  BL WORD COUNT ;

\ using example: GET-FILE FISHERMAN.TXT

: GET-FILE
  FBUF1 4096 0 FILL 
  ASSIGN-FILE-NAME  R/W      OPEN-FILE
  IF CR ABORT" OPEN-FILE error?"  THEN 
  >R  R@ TO FILEID 
  CR ." fileid is: " R@ .
          FBUF1 4096 R@      READ-FILE
  IF CR ABORT" READ-FILE error?"  THEN
     DUP TO FPT1
     CR . ." Bytes is reading!"
                     R>     CLOSE-FILE
  IF CR ABORT" CLOSE-FILE error?" THEN
;

: CODING  ( n -- )
    CPT C! 1 +TO CPT
  0 CPT C! 1 +TO CPT ;

: CHANGE-CODE    ( n -- n )                  \ improve the voice
  DUP
  CASE
    ASCII ( OF  DROP BL ENDOF                \ ( --> BL
    ASCII ) OF  DROP BL ENDOF                \ ) --> BL
    ASCII . OF  DROP ASCII , CODING 0 ENDOF  \ . --> , 0
  ENDCASE
;

: RANGING ( -- )
  FBUF1 TO BPT
\ for Word text file:     FBUF1 2560 + TO BPT
\
\ may be used here by other kinds of text file.
\
  FBUF1 FPT1 + TO EPT
  BEGIN
       EPT C@
       32 <
  WHILE
       -1 +TO EPT
  REPEAT
;

: PRINT-TEXT-FILE  ( -- )
  CR CR
  BPT DUP EPT SWAP - TYPE ;

: TEXT-TO-SPEACH  ( -- n )
  0 0 READING-BUF VOICE SPEAK ;

: SPEAK-A-SENTENCE  ( -- )
  READING-BUF TO CPT
          BPT TO SPT
       BEGIN
           SPT C@  1 +TO SPT
           DUP DUP 32 <
           IF
              DROP
           ELSE
              CHANGE-CODE
              CODING
           THEN
           ASCII . =
           IF
               TEXT-TO-SPEACH
               IF   QUIT
               ELSE READING-BUF 1000 0 FILL
               THEN
               READING-BUF TO CPT
           THEN
        SPT EPT >=
        UNTIL
;

: READ  ( -- )
  GET-FILE
  RANGING
  PRINT-TEXT-FILE
  1000 MS
  SPEAK-A-SENTENCE
  TEXT-TO-SPEACH
  DROP ;

\ -1 VOICE SETRATE DROP
\ READ CCT.F
\ READ FISHERMAN.TXT

: SPEAKING  DUP >R FBUF1 SWAP MOVE R> TO FPT1
 RANGING PRINT-TEXT-FILE SPEAK-A-SENTENCE TEXT-TO-SPEACH DROP ;

\ : TEST s" I am speaking. " SPEAKING ;

: SAY 0 0 [COMPILE] U" DROP VOICE SPEAK DROP ; IMMEDIATE

\ SAY This is a test.



3. 程式說明

程式內指令使用的名稱,事實上已經包含了簡要功能的說明意義,可用的 READ、SPEAKING、SAY 新增設計指令的後面,也提供了最簡單的使用範例,作者並不希望太過詳細解釋指令的內容,規劃程式的觀念則值得詳細說明。

簡單說明指令功能如下: READ 可用來直接讀出一篇檔案文章。 SPEAKING 可用於程式執行後進行語音輸出。 SAY 指令則可用來直接試驗語音輸出。另有一個可以很方便的讀取任何檔案,以便觀察檔案內容的萬用指令 GET-FILE ,發展其它程式時,可以用到,這個程式首先就得靠它完成檔案內容的分析工作。

在 FORTH 的學習過程中,這個程式所使用到的指令,因涉及字串處理,大約只能算是第二級的困難度而已,所以也不難看懂。

們想要系統自動讀出來的文章,是放在一個檔案之內,因此,程式的起始處,就先行規劃出兩個記憶體緩衝區,第一個用來放置從檔案讀進來的整篇文章,第二個用來放置每次從文章中抽取出來的一段完整句子。為什麼要這樣規劃?在我的網文『因子分解法』中,詳細敘述了係經過仔細研究後,得到的結論。

在 FORTH 系統中,使用者每逢必須規劃自己的緩衝區問題時,設計上的習慣,都是就從系統字典浮動的尾端,往上選一個區域來規劃,這樣,緩衝區就可以有一個彈性的起始位址。 PAD 為什麼被用來作為字串處理緩衝區的起始位址,道理也在這裡,它是一個可以隨著系統增長而水漲船高、自由浮動、見官就大三級似的緩衝區規劃方法。

這個程式中讀進檔案的緩衝區,在字典上方加上 2K 的記憶體量,比 PAD 高很多,可以確保系統運轉時,不會干涉到字串處理程式可能必須用到的 PAD 緩衝區。由於可以同時開啟的檔案不必僅限一個,所以此區的起始位址就名為 FBUF1 。

待讀語句所需要的緩衝區,就規劃在讀進檔案緩衝區的上方,名為 READING-BUF 。檔案被讀進系統後,長度是固定的,因此,這個緩衝區的起始位址,使用時雖然也是浮動的,但在檔案被成功讀入之後,就會自動被確定下來。

緩衝區內的資料,要被逐次的處理,處理時就需要夠用的指標來指到處理位置。根據設計上的需要,程式中規劃了五個指標:

0 VALUE FPT1 \ file pointer 1
0 VALUE SPT \ scanning pointer
0 VALUE CPT \ coding pointer
0 VALUE BPT \ beginning pointer
0 VALUE EPT \ endding pointer

一號檔案指標 FBUF1 固定的表示一號檔案讀進系統的長度,掃瞄指標 SPT 則在程式執行過程中,會在讀入檔案緩衝區內游走,表示資料被處理到了那一點?編碼指標 CPT 則在待講語句緩衝區內游走,代表待講語句已經被處理到了那一點?起點指標 BPT 與終點指標 EPT ,指到讀入檔案的特別起迄點,因為某些文字編輯系統所編寫出來的檔案,前後都夾雜了相關於文件的格式碼,這兩個指標用來去除不該被唸出來的資料。

所規劃的緩衝區與需要用到的指標,可以使用一張明確的記憶圖譜來表示,使用者就更容易明白設計這種程式的方法,記憶圖譜如下圖所示:

規劃緩衝區及指標之記憶圖譜

上述說明,就足以說明程式的規劃內容了。接下來,我們為這個程式設計了檔案讀取的完整程式,它可以作為所有程式的讀取之用,包括非文字式的檔案,所以也是個萬用程式。這個程式自身的發展過程中,也用這個 GET-FILE 指令的功能,分析確認各種文字檔案的內容,以便繼續設計程式。

在固定的作業系統中,檔案傳輸協定是固定的規定,本文不詳細解釋。

在分析文字檔案內容的過程中,作者發現某些文字資料區域內的符號,也會影響文字的語音輸出,因此,設計了 CODING 與 CHANGE-CODE 兩個指令,來換掉那些符號,整篇文章的讀出效果,就能比較令人滿意。

RANGING 指令,是用來去除讀入檔案前後無關之格式碼時使用的,為適用於各種不同的文件編輯系統,這個指令可以隨狀況而進行千變萬化的修正設計,任何一家商售文件編輯系統處理出來的文件檔案,都可以透過這個指令來進行待講出之前的預處理。由於它要處理的對象,種類可能非常多,此處不詳列適應於各種情況的設計內容,僅表徵性的列出兩種,一是針對 FORTH 系統自身可以編寫產生的 .F 式文字檔,另一種是一般編輯系統如 NotePad 能編寫產生的 .TXT 式文字檔,程式說明中,附贈一個可以處理掉 WORD 文件起頭格式碼的說明敘述。

剩下的四個指令:

PRINT-TEXT-FILE、TEXT-TO-SPEECH、SPEAK-A-SENTENCE、READ

功能就都各如其名,不必解釋。

依例,我們載入程式後,執行 READ 指令,唸一篇範例短文,螢幕上會先行印出整篇文章,等待一秒過後,自動讀完。效果顯示如下:


ok
READ FISHERMAN.TXT 
fileid is: 288 
666 Bytes is reading!

The Fisherman.
A fisherman had been fishing all day without catching anything.
As evening fell he found a very small fish on the end of his line.
"Please spare me," squeaked the little fish. 
"Please I am too small to make you a good meal for I am not fully grown yet, Why don't you throw me back into the river. 
Then, when I am bigger and worth eating you can come back and catch me again."
"No, no," said the man, who was very hungry. 
"I am going to hold on to you now that I have caught you.
If you once get back into the water you will take very good care not to come near me again and I shall have no supper now or later."
Hold on to what you have ok


我們也可以透過操作 GET-FILE 指令,來仔細分析別種編輯系統編寫儲存的文件檔案內容。下列為 WordPad 編寫出來的範例文件檔案內容,只要知道這樣的內容,我們就能相應的設計程式,修改出可以交給 SPEAK 指令進行語音輸出的文章。以下是作者臨時利用 WordPad ,隨便編寫一些文字,儲存成檔案後,直接操作這個程式,再執行系統中現成的傾印(DUMP)指令,在螢幕上顯示出來的檔案內容。


 
GET-FILE wordpad.txt 
fileid is: 288 
468 Bytes is reading! ok
fbuf1 500 dump 
  44A948 | 7B 5C 72 74 66 31 5C 61  6E 73 69 5C 61 6E 73 69 |{\rtf1\ansi\ansi|
  44A958 | 63 70 67 39 35 30 5C 64  65 66 66 30 5C 64 65 66 |cpg950\deff0\def|
  44A968 | 6C 61 6E 67 31 30 33 33  5C 64 65 66 6C 61 6E 67 |lang1033\deflang|
  44A978 | 66 65 31 30 32 38 7B 5C  66 6F 6E 74 74 62 6C 7B |fe1028{\fonttbl{|
  44A988 | 5C 66 30 5C 66 6D 6F 64  65 72 6E 5C 66 70 72 71 |\f0\fmodern\fprq|
  44A998 | 36 5C 66 63 68 61 72 73  65 74 31 33 36 20 5C 27 |6\fcharset136 \'|
  44A9A8 | 62 37 5C 27 37 33 5C 27  62 32 5C 27 64 33 5C 27 |b7\'73\'b2\'d3\'|
  44A9B8 | 61 39 5C 27 66 61 5C 27  63 35 5C 27 65 39 3B 7D |a9\'fa\'c5\'e9;}|
  44A9C8 | 7D 0D 0A 7B 5C 2A 5C 67  65 6E 65 72 61 74 6F 72 |}..{\*\generator|
  44A9D8 | 20 4D 73 66 74 65 64 69  74 20 35 2E 34 31 2E 31 | Msftedit 5.41.1|
  44A9E8 | 35 2E 31 35 30 37 3B 7D  5C 76 69 65 77 6B 69 6E |5.1507;}\viewkin|
  44A9F8 | 64 34 5C 75 63 31 5C 70  61 72 64 5C 6C 61 6E 67 |d4\uc1\pard\lang|
  44AA08 | 31 30 32 38 5C 66 30 5C  66 73 32 30 20 54 68 69 |1028\f0\fs20 Thi|
  44AA18 | 73 20 61 20 74 65 73 74  20 66 69 6C 65 20 66 6F |s a test file fo|
  44AA28 | 72 20 74 65 78 74 20 74  6F 20 76 6F 69 63 65 20 |r text to voice |
  44AA38 | 73 70 65 61 63 68 20 74  65 73 74 69 6E 67 2E 5C |speach testing.\|
  44AA48 | 70 61 72 0D 0A 54 68 69  73 20 66 69 6C 65 20 69 |par..This file i|
  44AA58 | 73 20 70 72 65 70 61 72  65 64 20 62 79 20 57 6F |s prepared by Wo|
  44AA68 | 72 64 50 61 64 20 73 79  73 74 65 6D 20 61 6E 64 |rdPad system and|
  44AA78 | 20 68 61 73 20 62 65 65  6E 20 73 61 76 65 64 20 | has been saved |
  44AA88 | 69 6E 74 6F 20 74 68 65  20 73 61 6D 65 20 64 69 |into the same di|
  44AA98 | 72 65 63 74 6F 72 79 20  77 69 74 68 20 46 6F 72 |rectory with For|
  44AAA8 | 74 68 20 73 79 73 74 65  6D 2E 5C 70 61 72 0D 0A |th system.\par..|
  44AAB8 | 49 20 61 6D 20 67 6F 69  6E 67 20 74 6F 20 74 65 |I am going to te|
  44AAC8 | 73 74 20 69 73 20 74 68  65 72 65 20 61 6E 79 20 |st is there any |
  44AAD8 | 70 72 6F 62 6C 65 6D 20  69 74 20 77 69 6C 6C 20 |problem it will |
  44AAE8 | 68 61 70 70 65 6E 20 77  68 65 6E 20 66 69 6C 65 |happen when file|
  44AAF8 | 20 69 73 20 72 65 61 64  69 6E 67 20 62 79 20 74 | is reading by t|
  44AB08 | 68 65 20 73 79 73 74 65  6D 2E 5C 70 61 72 0D 0A |he system.\par..|
  44AB18 | 7D 0D 0A 20 00 00 00 00  00 00 00 00 00 00 00 00 |}.. ............|
  44AB28 | 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |................|
  44AB38 | 00 00 00 00                                      |....| ok


其它格式的檔案,可以依樣獲得結果,為節省篇幅,不再舉例。

4. 討論

自動唸出檔案文章的程式,不涉及數學計算,所以,如果還堅持硬要使用 ABC FORTH 系統中的 BASIC 格式,來完成程式設計,就會是一件毫無意義的事情。使用純粹的 FORTH 傳統設計方式。

一個在學的學生,數學與英文的學習課業,佔有很重的份量,而且也是比較難學的課業,好的學習工具則能協助學生,解決一些學習上可能遭遇到的問題。程式語言就是一種工具,這本書舉用的數學範例程式,足以顯現系統能夠協助學生,解決數學問題的能力了。而這篇文章,則能顯現系統能夠協助學生解決學習英文時『說』方面的問題。也許語音輸出的品質仍有強烈的機械式音感,但是,這只是一個初次實現目標的範例程式,向這個方向踏出去的第一步,意義深遠。此前的流行程式語言或套裝軟體,罕見具有全面性混合功能的性能, FORTH 在各方面的發展,一向都是輕而易舉的就能辦到,電腦開機後,啟動 FORTH 系統,所有功能就已經存在其間的程式語言,目前幾乎是找不到的東西。

當使用者啟動 FORTH 系統之後,使用者就可以在程式中自由使用指令來設計會講話的程式,現在,作者設計的 ABC FORTH 系統已經辦到了。搞 C 式程式語言的人,您的系統隨便的就能提供這些性能嗎? Python 行嗎?賣得那麼貴的 MatLab、Mathematica 數學套裝軟體行嗎?都不行,對不對?大家好好的向 FORTH 學習吧,趕快跟進,本書作者輕而易舉的就辦到了。

作者長期僑居於紐西蘭,曾在大學裡見過海外來的法國學生,在需要參加研究成果發表會前,先行寫好一長篇英文講稿,編寫成檔案儲存起來,然後透過專門的語音輸出系統,唸出整個檔案內的講稿文章,以便進行聽覺修正。那位學生使用的是功能專一性的軟體系統,現在,我們的 FORTH 系統,則可以提供同樣的功能,提供給全中國的同胞免費使用,正面意義重大!

能唸得出英文,不是甚麼大不了的事情,但是,讀者之中,可能沒有人像作者一樣,妥善的運用過這一套語音輸出的功能,深入研究過其它相關的問題。它能按照英文字母式的漢語拼音規則發音,或者其它國家的語言,所以也能發出品質不太優良的中文語音輸出,還能唸出字典上也無法標示的英文字唸法。

我們在執行複雜的程式,執行完畢後,決策的輸出,如果強調非用語音不可,這個程式已經顯示, FORTH 程式語言已經具有現成的功能了。

大學英語系的學生,或喜歡研究英文詩的學者,強調唸出英文詩的效果,要隨心所欲時,這個程式也辦得到。英文詩的唸法注重輕、重音,與中文詩或拉丁文詩的注重長、短音有所不同,這個程式也都辦得到。這一章的範例程式,只是精簡初步的應用範例,深入發展,還能提供多方面的應用功能,例如:就依本章程式,繼續發展,要求系統按指定規則,自動或重覆唸文章中特定句子的功能,也很容易辦到。

這些後續的應用舉例,不在本篇文章的設計範圍之內,我們並沒有設計相關的程式來展示。

這個範例程式發展的初衷,係起因於想為視障朋友免費貢獻一點心力,協助他們使用電腦,但還未曾實際的應用於任何場合,以便接受考驗後設計出最佳性能。不過,只要使用人提得出具體要求,對作者而言,應該都是很容易就能解決的問題。這是一件很有意義的工作,能夠為人,也可能為己,人人都會老,聽覺據說是最後才會消失的感覺,有此程式可用,能為老者唸文章。

沒有留言: