rockbox/tools/sapi_voice.vbs
Dominik Riebeling a1b780e670 Add support for Microsoft Speech Platform.
MSSP is accessible via vbs by simply changing the object to be used (both
SAPI5 and MSSP use the ISpVoice COM interface). Add command line parameter to
sapi_voice.vbs to switch the COM object used, and add the necessary
implementation of the SAPI class to Rockbox Utility.

Important: you will need to install the Speech Runtime separately and install
the version matching the bitsize of Rockbox Utility. I.e. you will need to
install the x86 version even on a x64 machine (unless you build a 64bit binary
of Rockbox Utility).

Change-Id: If760cd69c556c17a2ae539965d0941d16fdc10e1
2012-09-09 12:07:53 +02:00

402 lines
14 KiB
Text

'***************************************************************************
' __________ __ ___.
' 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
Const STDIN = 0
Const STDOUT = 1
Const STDERR = 2
Dim oShell, oArgs, oEnv
Dim oFSO, oStdIn, oStdOut
Dim bVerbose, bSAPI4, bList
Dim bMSSP
Dim sLanguage, sVoice, sSpeed, sName, 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 oFSO = CreateObject("Scripting.FileSystemObject")
Set oStdIn = oFSO.GetStandardStream(STDIN, true)
Set oStdOut = oFSO.GetStandardStream(STDOUT, true)
Set oShell = CreateObject("WScript.Shell")
Set oEnv = oShell.Environment("Process")
bVerbose = (oEnv("V") <> "")
Set oArgs = WScript.Arguments.Named
bSAPI4 = oArgs.Exists("sapi4")
bMSSP = oArgs.Exists("mssp")
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
sName = oTTS.ModeName(nMode)
If bVerbose Then
WScript.StdErr.WriteLine "Using " & sName & " for " & sSelectString
End If
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 information
sVendor = oTTS.MfgName(nMode)
Else ' SAPI5
' Create SAPI5 object
If bMSSP Then
Set oSpVoice = CreateObject("speech.SpVoice")
Else
Set oSpVoice = CreateObject("SAPI.SpVoice")
End If
If Err.Number <> 0 Then
WScript.StdErr.WriteLine "Error " & Err.Number _
& " - 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
sName = oSpVoice.Voice.GetAttribute("Name")
If bVerbose Then
WScript.StdErr.WriteLine "Using " & sName & " for " & sSelectString
End If
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)"
' Some L&H engines don't set the vendor attribute - check the name
If Len(sName) > 3 And Left(sName, 3) = "LH " Then
sVendor = "L&H"
End If
End If
' Filestream object for output
Set oSpFS = CreateObject("SAPI.SpFileStream")
oSpFS.Format.Type = AudioFormat(sVendor)
End If
Do
aLine = Split(oStdIn.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"
oStdOut.WriteLine sVendor
End Select
Case "SPEAK"
aData = Split(aLine(1), vbTab, 2)
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"
oStdOut.WriteLine aLine(1) ' Just echo what was passed
Case "QUIT"
If bVerbose Then WScript.StdErr.WriteLine "Quitting"
WScript.Quit 0
End Select
Loop
' Subroutines
' -----------
' 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.StdErr.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 "arabic"
LangIDs = Array( &h401, &h801, &hc01, &h1001, &h1401, &h1801, _
&h1c01, &h2001, &h2401, &h2801, &h2c01, &h3001, _
&h3401, &h3801, &h3c01, &h4001)
' Saudi Arabia, Iraq, Egypt, Libya, Algeria, Morocco, Tunisia,
' Oman, Yemen, Syria, Jordan, Lebanon, Kuwait, U.A.E., Bahrain,
' Qatar
Case "basque"
LangIDs = Array(&h42d)
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-us"
LangIDs = Array( &h409, &h809, &hc09, &h1009, &h1409, &h1809, _
&h1c09, &h2009, &h2409, &h2809, &h2c09, &h3009, _
&h3409)
' American, British, Australian, Canadian, New Zealand, Ireland,
' South Africa, Jamaika, Caribbean, Belize, Trinidad, Zimbabwe,
' Philippines
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, &hc0c, &h100c, &h140c, &h180c)
' Standard, Canadian, Swiss, Luxembourg, Monaco (Belgian -> walon)
Case "galego"
LangIDs = Array(&h456)
Case "greek"
LangIDs = Array(&h408)
Case "hebrew"
LangIDs = Array(&h40d)
Case "hindi"
LangIDs = Array(&h439)
Case "hrvatski"
LangIDs = Array(&h41a, &h101a) ' Croatia, Bosnia and Herzegovina
Case "islenska"
LangIDs = Array(&h40f)
Case "italiano"
LangIDs = Array(&h410, &h810) ' Standard, Swiss
Case "japanese"
LangIDs = Array(&h411)
Case "korean"
LangIDs = Array(&h412)
Case "latviesu"
LangIDs = Array(&h426)
Case "lietuviu"
LangIDs = Array(&h427)
Case "magyar"
LangIDs = Array(&h40e)
Case "nederlands"
LangIDs = Array(&h413, &h813) ' Standard, Belgian
Case "norsk-nynorsk"
LangIDs = Array(&h814)
Case "norsk"
LangIDs = Array(&h414) ' Bokmal
Case "polski"
LangIDs = Array(&h415)
Case "portugues-brasileiro"
LangIDs = Array(&h416)
Case "portugues"
LangIDs = Array(&h816)
Case "romaneste"
LangIDs = Array(&h418)
Case "russian"
LangIDs = Array(&h419)
Case "slovak"
LangIDs = Array(&h41B)
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 "ukrainian"
LangIDs = Array(&h422)
Case "wallisertitsch"
LangIDs = Array(&h807) ' Swiss German
Case "walon"
LangIDs = Array(&h80c) ' Belgian French
End Select
End Function