'*************************************************************************** ' __________ __ ___. ' Open \______ \ ____ ____ | | _\_ |__ _______ ___ ' Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / ' Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < ' Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ ' \/ \/ \/ \/ \/ ' $Id$ ' ' Copyright (C) 2007 Steve Bavin, Jens Arnold, Mesar Hameed ' ' All files in this archive are subject to the GNU General Public License. ' See the file COPYING in the source tree root for full license agreement. ' ' This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ' KIND, either express or implied. ' '*************************************************************************** Option Explicit Const SSFMCreateForWrite = 3 ' Audio formats for SAPI5 filestream object Const SPSF_8kHz16BitMono = 6 Const SPSF_11kHz16BitMono = 10 Const SPSF_12kHz16BitMono = 14 Const SPSF_16kHz16BitMono = 18 Const SPSF_22kHz16BitMono = 22 Const SPSF_24kHz16BitMono = 26 Const SPSF_32kHz16BitMono = 30 Const SPSF_44kHz16BitMono = 34 Const SPSF_48kHz16BitMono = 38 Dim oShell, oArgs, oEnv Dim bVerbose, bSAPI4, bList Dim sLanguage, sVoice, sSpeed, sVendor Dim oSpVoice, oSpFS ' SAPI5 voice and filestream Dim oTTS, nMode ' SAPI4 TTS object, mode selector Dim oVoice ' for traversing the list of voices Dim nLangID, sSelectString Dim aLine, aData ' used in command reading On Error Resume Next Set oShell = CreateObject("WScript.Shell") Set oEnv = oShell.Environment("Process") bVerbose = (oEnv("V") <> "") Set oArgs = WScript.Arguments.Named bSAPI4 = oArgs.Exists("sapi4") bList = oArgs.Exists("listvoices") sLanguage = oArgs.Item("language") sVoice = oArgs.Item("voice") sSpeed = oArgs.Item("speed") If bSAPI4 Then ' Create SAPI4 ActiveVoice object Set oTTS = WScript.CreateObject("ActiveVoice.ActiveVoice", "TTS_") If Err.Number <> 0 Then Err.Clear Set oTTS = WScript.CreateObject("ActiveVoice.ActiveVoice.1", "TTS_") If Err.Number <> 0 Then WScript.StdErr.WriteLine "Error - could not get ActiveVoice" _ & " object. SAPI 4 not installed?" WScript.Quit 1 End If End If oTTS.Initialized = 1 If bList Then ' Just list available voices for the selected language For Each nLangID in LangIDs(sLanguage) For nMode = 1 To oTTS.CountEngines If oTTS.LanguageID(nMode) = nLangID Then WScript.StdErr.Write oTTS.ModeName(nMode) & "," End If Next Next WScript.StdErr.WriteLine WScript.Quit 0 End If ' Select matching voice For Each nLangID in LangIDs(sLanguage) sSelectString = "LanguageID=" & nLangID If sVoice <> "" Then sSelectString = sSelectString & ";Speaker=" & sVoice _ & ";ModeName=" & sVoice End If nMode = oTTS.Find(sSelectString) If oTTS.LanguageID(nMode) = nLangID And (sVoice = "" Or _ oTTS.Speaker(nMode) = sVoice Or oTTS.ModeName(nMode) = sVoice) Then If bVerbose Then WScript.StdErr.WriteLine "Using " & sSelectString Exit For Else sSelectString = "" End If Next If sSelectString = "" Then WScript.StdErr.WriteLine "Error - found no matching voice for " _ & sLanguage & ", " & sVoice WScript.Quit 1 End If oTTS.Select nMode ' Speed selection If sSpeed <> "" Then oTTS.Speed = sSpeed ' Get vendor infomration sVendor = oTTS.MfgName(nMode) Else ' SAPI5 ' Create SAPI5 object Set oSpVoice = CreateObject("SAPI.SpVoice") If Err.Number <> 0 Then WScript.StdErr.WriteLine "Error - could not get SpVoice object." _ & " SAPI 5 not installed?" WScript.Quit 1 End If If bList Then ' Just list available voices for the selected language For Each nLangID in LangIDs(sLanguage) sSelectString = "Language=" & Hex(nLangID) For Each oVoice in oSpVoice.GetVoices(sSelectString) WScript.StdErr.Write oVoice.GetAttribute("Name") & "," Next Next WScript.StdErr.WriteLine WScript.Quit 0 End If ' Select matching voice For Each nLangID in LangIDs(sLanguage) sSelectString = "Language=" & Hex(nLangID) If sVoice <> "" Then sSelectString = sSelectString & ";Name=" & sVoice End If Set oSpVoice.Voice = oSpVoice.GetVoices(sSelectString).Item(0) If Err.Number = 0 Then If bVerbose Then WScript.StdErr.WriteLine "Using " & sSelectString Exit For Else sSelectString = "" Err.Clear End If Next If sSelectString = "" Then WScript.StdErr.WriteLine "Error - found no matching voice for " _ & sLanguage & ", " & sVoice WScript.Quit 1 End If ' Speed selection If sSpeed <> "" Then oSpVoice.Rate = sSpeed ' Get vendor information, protect from missing attribute sVendor = oSpVoice.Voice.GetAttribute("Vendor") If Err.Number <> 0 Then Err.Clear sVendor = "(unknown)" End If ' Filestream object for output Set oSpFS = CreateObject("SAPI.SpFileStream") oSpFS.Format.Type = AudioFormat(sVendor) End If Do aLine = Split(WScript.StdIn.ReadLine, vbTab, 2) If Err.Number <> 0 Then WScript.StdErr.WriteLine "Error " & Err.Number & ": " & Err.Description WScript.Quit 1 End If Select Case aLine(0) ' command Case "QUERY" Select Case aLine(1) Case "VENDOR" WScript.StdOut.WriteLine sVendor End Select Case "SPEAK" aData = Split(aLine(1), vbTab, 2) aData(1) = UTF8decode(aData(1)) If bVerbose Then WScript.StdErr.WriteLine "Saying " & aData(1) _ & " in " & aData(0) If bSAPI4 Then oTTS.FileName = aData(0) oTTS.Speak aData(1) While oTTS.Speaking WScript.Sleep 1 Wend oTTS.FileName = "" Else oSpFS.Open aData(0), SSFMCreateForWrite, false Set oSpVoice.AudioOutputStream = oSpFS oSpVoice.Speak aData(1) oSpFS.Close End If Case "EXEC" If bVerbose Then WScript.StdErr.WriteLine "> " & aLine(1) oShell.Run aLine(1), 0, true If Err.Number <> 0 Then If Not bVerbose Then WScript.StdErr.Write "> " & aLine(1) & ": " End If If Err.Number = &H80070002 Then ' Actually file not found WScript.StdErr.WriteLine "command not found" Else WScript.StdErr.WriteLine "error " & Err.Number & ":" _ & Err.Description End If WScript.Quit 2 End If Case "SYNC" If bVerbose Then WScript.StdErr.WriteLine "Syncing" WScript.StdOut.WriteLine aLine(1) ' Just echo what was passed Case "QUIT" If bVerbose Then WScript.StdErr.WriteLine "Quitting" WScript.Quit 0 End Select Loop ' Subroutines ' ----------- ' Decode an UTF-8 string into a standard windows unicode string (UTF-16) Function UTF8decode(ByRef sText) Dim i, c, nCode, nTail, nTextLen UTF8decode = "" nTail = 0 nTextLen = Len(sText) i = 1 While i <= nTextLen c = Asc(Mid(sText, i, 1)) i = i + 1 If c <= &h7F Or c >= &hC2 Then ' Start of new character If c < &h80 Then ' U-00000000 - U-0000007F, 1 byte nCode = c ElseIf c < &hE0 Then ' U-00000080 - U-000007FF, 2 bytes nTail = 1 nCode = c And &h1F ElseIf c < &hF0 Then ' U-00000800 - U-0000FFFF, 3 bytes nTail = 2 nCode = c And &h0F ElseIf c < &hF5 Then ' U-00010000 - U-001FFFFF, 4 bytes nTail = 3 nCode = c And 7 Else ' Invalid size nCode = &hFFFD End If While nTail > 0 And i <= nTextLen nTail = nTail - 1 c = Asc(Mid(sText, i, 1)) i = i + 1 If (c And &hC0) = &h80 Then ' Valid continuation char nCode = nCode * &h40 + (c And &h3F) Else ' Invalid continuation char nCode = &hFFFD i = i - 1 nTail = 0 End If Wend Else nCode = &hFFFD End If If nCode >= &h10000 Then ' Character outside BMP - use surrogate pair nCode = nCode - &h10000 c = &hD800 + ((nCode \ &h400) And &h3FF) ' high surrogate UTF8decode = UTF8decode & ChrW(c) nCode = &hDC00 + (nCode And &h3FF) ' low surrogate End If UTF8decode = UTF8decode & ChrW(nCode) Wend End Function ' SAPI5 output format selection based on engine Function AudioFormat(ByRef sVendor) Select Case sVendor Case "Microsoft" AudioFormat = SPSF_22kHz16BitMono Case "AT&T Labs" AudioFormat = SPSF_32kHz16BitMono Case "Loquendo" AudioFormat = SPSF_16kHz16BitMono Case "ScanSoft, Inc" AudioFormat = SPSF_22kHz16BitMono Case "Voiceware" AudioFormat = SPSF_16kHz16BitMono Case Else AudioFormat = SPSF_22kHz16BitMono WScript.StdOut.WriteLine "Warning - unknown vendor """ & sVendor _ & """ - using default wave format" End Select End Function ' Language mapping rockbox->windows Function LangIDs(ByRef sLanguage) Dim aIDs Select Case sLanguage Case "afrikaans" LangIDs = Array(&h436) Case "bulgarian" LangIDs = Array(&h402) Case "catala" LangIDs = Array(&h403) Case "chinese-simp" LangIDs = Array(&h804) ' PRC Case "chinese-trad" LangIDs = Array(&h404) ' Taiwan. Perhaps also Hong Kong, Singapore, Macau? Case "czech" LangIDs = Array(&h405) Case "dansk" LangIDs = Array(&h406) Case "deutsch" LangIDs = Array(&h407, &hc07, &h1007, &h1407) ' Standard, Austrian, Luxembourg, Liechtenstein (Swiss -> wallisertitsch) Case "eesti" LangIDs = Array(&h425) Case "english" LangIDs = Array( &h809, &h409, &hc09, &h1009, &h1409, &h1809, _ &h1c09, &h2009, &h2409, &h2809, &h2c09, &h3009, _ &h3409) ' British, American, Australian, Canadian, New Zealand, Ireland, ' South Africa, Jamaika, Caribbean, Belize, Trinidad, Zimbabwe, ' Philippines Case "espanol" LangIDs = Array( &h40a, &hc0a, &h80a, &h100a, &h140a, &h180a, _ &h1c0a, &h200a, &h240a, &h280a, &h2c0a, &h300a, _ &h340a, &h380a, &h3c0a, &h400a, &h440a, &h480a, _ &h4c0a, &h500a) ' trad. sort., mordern sort., Mexican, Guatemala, Costa Rica, ' Panama, Dominican Republic, Venezuela, Colombia, Peru, Argentina, ' Ecuador, Chile, Uruguay, Paraguay, Bolivia, El Salvador, ' Honduras, Nicaragua, Puerto Rico Case "esperanto" WScript.StdErr.WriteLine "Error: no esperanto support in Windows" WScript.Quit 1 Case "finnish" LangIDs = Array(&h40b) Case "francais" LangIDs = Array(&h40c, &h80c, &hc0c, &h100c, &h140c, &h180c) ' Standard, Belgian, Canadian, Swiss, Luxembourg, Monaco Case "galego" LangIDs = Array(&h456) Case "greek" LangIDs = Array(&h408) Case "hebrew" LangIDs = Array(&h40d) Case "hindi" LangIDs = Array(&h439) Case "islenska" LangIDs = Array(&h40f) Case "italiano" LangIDs = Array(&h410, &h810) ' Standard, Swiss Case "japanese" LangIDs = Array(&h411) Case "korean" LangIDs = Array(&h412) Case "magyar" LangIDs = Array(&h40e) Case "nederlands" LangIDs = Array(&h413, &h813) ' Standard, Belgian Case "norsk" LangIDs = Array(&h414) ' Bokmal Case "norsk-nynorsk" LangIDs = Array(&h814) Case "polski" LangIDs = Array(&h415) Case "portugues" LangIDs = Array(&h816) Case "portugues-brasileiro" LangIDs = Array(&h416) Case "romaneste" LangIDs = Array(&h418) Case "russian" LangIDs = Array(&h419) Case "slovenscina" LangIDs = Array(&h424) Case "srpski" LangIDs = Array(&hc1a) ' Cyrillic Case "svenska" LangIDs = Array(&h41d, &h81d) ' Standard, Finland Case "tagalog" LangIDs = Array(&h464) ' Filipino, might not be 100% correct Case "thai" LangIDs = Array(&h41e) Case "turkce" LangIDs = Array(&h41f) Case "wallisertitsch" LangIDs = Array(&h807) ' Swiss German End Select End Function