|
2 S/ q- L5 Q- _& @6 O! u
华 中 师 范 大 学 卢 小 海(flier@126.com)
# n; e/ @8 O' ?* i r/ ~ 各位朋友,请加入本站邮件列表,你将得到本站最新更新及动态。
1 i* q# R/ D! g( I7 k7 ]! E5 N' Z7 D, m* l; I/ R: n- @5 a
---- 金 山 词 霸2000 的 英 文 全 文 朗 读 功 能 相 信 一 定 给 尝 试 过 的 用 户 留 下 了 很 深 刻 的 印 象, 而 作 为 一 个 程 序 设 计 者, 你 一 定 也 想 在 自 己 的 程 序 中 加 入 类 似 的 功 能 吧, 因 为 那 将 让 自 己 的 程 序 增 色 不 少。 1 i8 p4 }* d% N$ x8 g1 F
----其 实 这 并 不 是 一 件 困 难 的 事, 因 为 金 山 词 霸 实 际 上 也 只 是 直 接 使 用 了MS 的TTS(Text -to -Speech) 技 术 而 已, 通 过 对MS Speech API 的 编 程, 我 们 完 全 可 以 实 现 比 其 更 强 大 的 功 能。 下 面, 让 我 们 在Delphi 环 境 下 实 际 尝 试 一 下。
2 ^* R+ |1 q8 a8 v----首 先 从 金 山 词 霸 的 光 盘 上\ciba 目 录 下 运 行 并 安 装mstts.exe(MS TTS engine) 和spchapi.exe(MS Speech API)。
0 N, I+ z$ U: Z0 T) `----再 在Delphi 里 新 建 一 个Application。 . D' r% U6 i% t% b3 T# G
----然 后 从Delphi 的 菜 单Project/Import Type Library... 中 选 击Add..., 浏 览 到Windows 目 录 下 的Speech 子 目 录 里, 打 开vtxtauto.tlb, 可 以 看 到 下 面Class names 中 会 出 现 我 们 需 要 的 接 口 的 包 装 类 的 名 字TVTxtAuto, 注 意 对 话 框 底 部 的Generate Component Wrapper 需 要 被 选 中, 点 击Create Unit 就 可 以 打 开 一 个 名 为VTxtAuto_TLB 的Unit。
! y. s' L; ?* m' j----至 此, 我 们 就 可 以 开 始 实 际 编 程 了。 + ~: g+ f; B4 h5 X, @7 J
----首 先 在Form 的OnCreate 中 对 需 要 使 用 接 口 初 始 化 并 进 行 注 册:
`7 `" N( \/ A* s* r, I ...
0 b: i& Z3 D4 v; E. Y6 Q% } procedure TfrmMain.FormCreate(Sender: TObject);) i- n3 P: N2 M; i: t! E" @& y
begin
* H( t# {5 f1 v2 v0 _8 I& M FISpeech := CoVTxtAuto_.Create;# W; N7 C4 r1 F- K% S" N& S
FISpeech.Register(‘Demo Site', ‘Demo App');
. k" r* _! b/ M: o. l5 I7 d end;2 I' W5 v' ~$ v/ N
...
- C; o. Q% x9 W M3 O! ^----由 于Delphi 对 接 口 进 行 了 良 好 的 包 装, 因 此 只 需 直 接 建 立 包 装 类, 其 他 后 台 的 操 作 如 接 口 的 查 询、 释 放 等 交 给Delphi 在 后 台 自 动 完 成。 ( A5 M4 O4 V5 [8 p7 v% m% V3 C2 n
----注 意 这 里 的Register 操 作 是 必 不 可 少 的, 因 为 可 能 有 多 个 程 序 不 同 设 置 使 用TTS 引 擎。
9 x5 B) N/ ^4 H7 ]' `' N4 @3 {- S----然 后 在MainForm 上 放 一 个TMemo 和 若 干 个 TButton, 并 在 其OnClick 中 加 入 对 应 的 代 码。
' o$ o# t! ~/ P8 m- _9 mForm 定 义 如 下:
' Y, n5 G9 n. U4 S7 l object frmMain: TfrmMain7 d7 b) O# f: m" G9 s6 X
Left = 296
/ w$ ^# j6 u9 L1 `0 a$ C Top = 187
: e* O" `6 o4 }1 D5 c/ k, E0 C BorderStyle = bsDialog7 o/ l7 V' C* \1 m; \
Caption = ‘ 英 文 全 文 朗 读 演 示'
0 B8 \, {+ N4 G! N* H# @% s! a ClientHeight = 185
[( F, K2 m) a2 M ClientWidth = 456
9 _0 q) k0 e3 G+ P- n2 J. ` Color = clBtnFace. U& f8 L1 `9 {7 g
Font.Charset = GB2312_CHARSET# E2 I E7 z2 o
Font.Color = clWindowText* L( I' ^& _2 b. o D
Font.Height = -12
6 D F! a- B7 t6 W1 ]2 l$ P Font.Name = ‘ 宋 体'+ \) F, d9 l) l4 _7 F
Font.Style = []% n# P& y# L2 n: w2 G+ \
OldCreateOrder = False
. Y5 o, Q4 j* E Position = poDesktopCenter- T. w1 L/ K" F0 E( P8 ]4 u* z. X2 \4 ?
OnCreate = FormCreate9 I& n% o) s y. y1 ]# D7 f: {
PixelsPerInch = 96
\9 \# ?5 B$ j+ d# v2 l TextHeight = 122 _# t2 `' ~. s2 |4 F7 o9 s# t
object memText: TMemo/ {6 c# h* T4 O! `8 C
Left = 8, Q: W& H8 }# H4 x) m( {5 p0 Q n
Top = 8
2 W, h$ Q; \9 b+ M' a1 t3 p( ^ Width = 361; Z3 A/ Z* X$ k$ N
Height = 169
1 D+ j- F4 `, f* o7 b) M ScrollBars = ssVertical
" l3 s& f. Z' x# ] TabOrder = 09 {' T/ u7 V6 O- z
end4 ]/ X2 K' g/ I, I8 ]
object btnRead: TButton+ F2 Z* {. c3 p6 J& E& S
Left = 376" J0 D( o2 u. u6 k4 `7 j
Top = 8
$ Z# p: L8 t- S) E( | Width = 756 m: m/ Y) k; R E
Height = 255 ?, L; B1 ^. @# v5 y' n0 ]
Caption = ‘ 朗 读( &R)'+ d R' G' e l/ R& G5 L' {6 x1 q
TabOrder = 1( \+ D8 @: r' L8 \
OnClick = btnReadClick6 A! ]* f! J5 w
end
u( Z F# R* Y( ~1 q/ }. G. k object btnPause: TButton" n: o' J; @7 g( g7 ]8 K
Left = 376, _8 G, N7 [- G u8 e% U8 H
Top = 40
/ C8 n( J. T7 f$ R Width = 75$ i, t- q& T; w/ m ]
Height = 25
2 J% ~( J: o+ Y% _5 \- n, ` Caption = ‘ 暂 停( &P)'
, t7 g2 e/ k# M( C Enabled = False1 e) l& a6 n3 e' U2 b3 |' o
TabOrder = 2' r) f( ~0 e9 m' G; Y
OnClick = btnPauseClick* C% `& S6 o0 T" J) w9 C+ E5 N! g
end
" L/ U/ B, s* ]( L" {- b object btnStop: TButton
4 O) r+ R/ a" a$ N Left = 376
$ w1 @1 H: x7 o0 i. G Top = 728 F+ o+ _! i1 |, E& c7 {
Width = 75: X' e9 }/ F( U( J$ t3 F
Height = 25
1 u* ~1 E1 T$ Y+ H4 _- g; o: \0 r Caption = ‘ 停 止( &S)'
2 K# C6 Y, Q1 r& O {7 @ Enabled = False" z6 b# \) N- j0 p
TabOrder = 3* r5 E, b+ t: l0 U
OnClick = btnStopClick
1 p, J& d) v; q$ G end' c& r7 {8 D/ f3 @9 K# q# O, v
object btnForward: TButton
9 {: C: g9 [# p, v9 { Left = 376* U' p2 w5 C( H" u/ G7 p
Top = 120! _+ Y% V$ X, g, V7 T3 Q* i+ O' C
Width = 75
" n+ Y8 A- @# V3 `- n( A Height = 25- D- F6 p4 E) x: o* i! N
Caption = ‘ 下 一 句( &N)'
' O8 ?% H5 B" t2 t8 H9 A/ V Enabled = False0 }' \5 |' u5 H) u* m
TabOrder = 4
0 w" p5 S4 l6 b OnClick = btnForwardClick
3 t0 C) h4 I1 ~) V end" X1 I6 K6 z* i( C: E
object btnRewind: TButton
5 t0 A, Y. I1 l3 n. e) n. w* ^ Left = 3767 U; u3 k8 a0 P! |8 k
Top = 1521 q3 p0 E' a$ s; X
Width = 75
0 \2 [5 ?6 J5 ~" r7 x# |* Z Height = 25
2 }% j- F& C- H Caption = ‘ 上 一 句( &W)'; d; K7 j6 u2 O
Enabled = False$ ^# d9 V# C* T1 \: O/ s
TabOrder = 5
; l+ G+ z+ D% G0 q) S OnClick = btnRewindClick
6 N# [2 F+ r8 F end5 p% W: |0 J; i$ T( a
end # N3 f! q* `! T
----关 键 代 码 段 如 下:
2 } Q! H+ |9 M( `/ Q---- 1. 朗 读 与 停 止
B) Y- M4 e* H+ o# Y ...
! l2 ^: J6 g: bprocedure TfrmMain.btnReadClick(Sender: TObject);
; n5 Y; K/ w* t7 k- T; h begin
7 X3 F. X6 y3 ?% v: } FISpeech.Speak(memText.Lines.Text, vtxtst_
& h0 n/ N' A$ w7 [, O. T9 K2 _5 k) dREADING);. B8 l" Q2 h3 |
btnPause.Enabled := True;2 }' a3 S7 f- V6 i& y/ B+ p6 q/ C
btnStop.Enabled := True;
) n& u8 C& S( t0 o P7 n5 @ end;4 X5 G& ^' v# V5 {
8 Q1 l+ h) f/ c' x$ H
procedure TfrmMain.btnStopClick(Sender: TObject);
% j2 Q, ~; C) t: `9 d/ g begin
$ f4 a$ _4 {- S7 x2 E FISpeech.StopSpeaking;
, r7 w) X0 D' I& q; X btnPause.Enabled := False;
9 @3 c" ?4 }# u+ F5 M: h) \ btnStop.Enabled := False;
7 [! f; r9 [! j7 z5 R% p9 z9 _ btnPause.Caption := ‘ 暂 停( &P)';7 V* w% p3 g4 P, i
end;0 o+ | t2 t, S _8 w
...
: b+ C9 Y9 `6 i3 J- p7 O% _----Speak 成 员 函 数 的 第 一 个 参 数 向TTS 引 擎 传 递 需 要 朗 读 的 文 字, 第 二 个 参 数 由 指 定 朗 读 时 使 用 的 语 气 和 优 先 级 的 两 个 符 号 合 并 而 成。
- x. k$ X4 I: K+ y8 p: Q$ s% O4 e1 d- ]/ G/ }
---- 2. 暂 停 与 恢 复
7 J- A% P3 b' _4 X9 n5 F8 H' C ...
4 F& [6 T% A* m8 @( nprocedure TfrmMain.btnPauseClick(Sender: TObject);. C& F. r3 ?3 q' l' R" J
begin% @% i# @% a$ y
with FISpeech do5 [( E' h* e' H
if IsSpeaking then$ R1 n3 b! r- n0 g0 C! j
begin
4 R# y/ G5 m0 M2 q' R1 } {1 H4 X& n8 e# ? AudioPause;
) s5 a% l6 @- e I5 @ btnPause.Caption := ‘ 恢 复( &R)';1 A+ y' S+ c: S# p. h( g3 p
end( M' P4 [7 f5 ], x/ @& j. @. P' p
else7 s3 J) ` o% T# f
begin% |* ?" d8 c3 h# B, _' m
AudioResume;; w$ [. j) u( F1 r2 F
btnPause.Caption := ‘ 暂 停( &P)';* l) [1 @2 a% u
end;
# w8 h4 t! Q! ~: R& Z, ?: Zend;
6 P' J; \% \* W...
- B' B% E& L g/ W8 ?- N----这 里 通 过IsSpeaking 属 性 可 以 取 得 当 前 状 态, 然 后 通 过AudioPause 和AudioResume 暂 停 和 恢 复 朗 读。
$ e8 x |% ^/ s----另 外 用 成 员 函 数AudioFastForward 和AudioRewind 可 以 向 前 和 后 跳 过 一 句 朗 读, 通 过 读 写Speed 属 性 还 可 以 取 得 或 设 置 朗 读 的 语 速, 单 位 是 字/ 分, 缺 省 值 为170。 & b- b$ k/ Y- V- X3 ^! b6 H# Q' C
----注 意Speed 和Enabled 属 性 缺 省 设 置 是 只 写 的, 但 实 际 上IVTxtAuto 提 供 了Get_Speed 和Get_Enabled 函 数, 所 以 我 们 只 要 把VTxtAuto_TLB 单 元 中 的 声 明 修 改 一 下, 如: & z& ~" P9 \+ T' `+ Z3 \ j
...$ q9 \ y+ `5 l+ C" |8 a
IVTxtAuto = interface(IDispatch)7 V! ]0 J9 M4 _- K
...& G" r9 q$ N. H1 e' T
property Speed: Integer read Get_Speed write Set_Speed;
0 l$ ^- [7 T# X3 w/ F' ]2 @ property Enabled: Integer read Get_Enabled write Set_Enabled;- [/ E( e5 ]. w+ E
...
" W1 q/ b" x' b7 J( L0 Iend;
- g0 k2 y$ P; _) i: G' G9 A ... / A9 n" R" O; o. d- d" S* ?1 s
----即 可 正 常 使 用Speed 和Enabled 属 性 了。 ' Z v m) j' b- k/ j3 X4 {
----至 此, 一 个 简 单 的 英 文 全 文 朗 读 器 就 完 成 了, 有 兴 趣 的 朋 友 可 以 为 其 加 入 监 视 剪 贴 板, 热 键 激 活 等 功 能。 1 L% n7 z6 z% a& N" ^% q M# b
----本 文 程 序 在Win NT/98 + Delphi 4/5 环 境 下 调 试 通 过。
- p6 e0 O4 w( J3 A! U. } + i% E+ r0 X( {' V
|