试用PowerShell调用SAPI实现文字转语音

TTS(Text-To-Speech)这类技术,由于大概十年前受了一些熏陶,哪怕到现在都很在意。现在终于想玩一玩,暂且从Windows自带的SAPI 5入手吧。

环境

操作系统Win10 21H1,PowerShell版本为7.1(这其实意味着System.Speech.Synthesis.SpeechSynthesizer不能用,因为这个是.NET Framework专属的)。日文系统,不过另外安装了中国語(簡体字、中国)的音声認識。

参考资料

  1. VBSでOneCoreの音声を使用する:尽管使用的是VBScript,不过调用SAPI.SpVoice这点倒是很符合需求。
  2. C# Speech.Synthesis 在WIN10如何读出kangkang等其他语音:有关Kangkang这个语音的问题。官方一直都弄错了,只好我们自己手改。
  3. XML TTS Tutorial SAPI 5.4:这个是SAPI的XML,是微软自己的仕样,并非共通的。
  4. Chinese Phonemes (SAPI 5.4)<pron>标签sym属性里可以用这些来表达语音。另外,<speak>标签中<phoneme>标签在alphabet属性为sapi时的ph属性里尽管看似也可以这么用,但实际上很多情况下语音干脆是错的,是错的啊!所以建议避免。

正文

准备工作

查阅了一些资料,发现语音有SpeechSpeech_OneCore之分(参见参考资料1),个人希望利用后者。不过吧,这里我想用Kangkang语音,所以参照参考资料2,先用pwsh处理一下:

Test-Path -LiteralPath HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_zhCN_KangkangM
# -> True
Get-ChildItem -File C:\Windows\Speech_OneCore\Engines\TTS\zh-CN -Filter *M2052Kangkang*
# -> 没有特别变动的话,应该能列出Kangkang的相关文件。当然知道它在就行了
# -> 不写filter的话,可以看看还有什么别的可以用,据说Hongyu就不错,但有点麻烦,这里就不细谈了
Get-ItemPropertyValue -LiteralPath HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_zhCN_KangkangM -Name VoicePath
# -> 如果没有自己改动的话,我记得这里应该是Yaoyao:
# -> C:\WINDOWS\Speech_OneCore\Engines\TTS\zh-CN\M2052Yaoyao
# 那当然不对了,那么之后就把它改对咯
# === 以下请在管理员权限下操作 ===
Set-ItemProperty -LiteralPath HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_zhCN_KangkangM -Name VoicePath C:\Windows\Speech_OneCore\Engines\TTS\zh-CN\M2052Kangkang
# === 以上请在管理员权限下操作 ===

如此就可以使用Kangkang语音了。

简单使用

按照参考资料1去做就好,要注意的是我们是对COM对象操作。唉,至少先能出声:

$sp = New-Object -ComObject SAPI.SpVoice
$cat = New-Object -ComObject SAPI.SpObjectTokenCategory
# 想用Speech_OneCore所以指定一下:
$cat.SetId('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices', $false)
# 看一下现在能用什么
$cat.EnumerateTokens()
#-> 列出了当前可用的语音。注意一下KangkangM是哪一个,这边是索引8
# 那么把KangkangM指定上:
$sp.Voice = $sp.Voice = $cat.EnumerateTokens()[8]
# 喋れるかな~?
[void] $sp.Speak('是不是前世欠下你的债,性生活快乐就要李凯')
# 喋ってた!

以上是很基础的用法。

其实经常我们希望细化操作,比如直接读出拼音之类。那么且往下看。

进阶使用

承上。

先展示能正常用的情况:

# 有首音击的歌叫 What color...
# 请注意,现在使用的xml标签是<sapi>
[void] $sp.Speak(@'
<sapi>
  <pron sym="sha 2 se 3"/>
</sapi>
'@, 8) # “啥色”,www

这样可以反映出一些官话方言跟普通话的声调差别。嘛,这边用胶辽官话和东北官话的情况比较多。

不建议用声调模拟方言的调值,如此一来至少语义很成问题。

很想要的一点是,儿化音啊,儿化音。实在弄不出来,但真的很想要。

(TBD)

音频文件输出

(TBD)

COM对象释放

感觉如何?用完了别忘了把COM对象释放掉:

[void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sp)
[void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($cat)

后记

那么利用这个或许可以做解说视频?试试看咯w

InSb

InSb

只是跟工作和生活相关的记录