如何更改 SAPI.SPVoice 使用的语音

hug*_*0ul 6 windows powershell sapi windows-10

我希望能够为我的文本转语音输出选择替代语音。
\n我正在使用 ComObject SAPI.SPVoice,但我发现我无法更改实际使用的语音。
\n(顺便说一句 - 我正在使用 SAPI.SPVoice,因为它适用于 Windows 10 上的 PowerShell Core 和 PowerShell Desktop)

\n\n
${PromptTTS} = New-Object -ComObject SAPI.SPVoice\n
Run Code Online (Sandbox Code Playgroud)\n\n
\xe2\x9d\xaf $PromptTTS | gm\n
Run Code Online (Sandbox Code Playgroud)\n\n
   TypeName: System.__ComObject#{269316d8-57bd-11d2-9eee-00c04f797396}\n\nName                                   MemberType   Definition\n----                                   ----------   ----------\nDisplayUI                              Method       void DisplayUI (int hWndParent, string Title, string TypeOfUI, Variant ExtraData)\nGetAudioOutputs                        Method       ISpeechObjectTokens GetAudioOutputs (string RequiredAttributes, string OptionalAttributes)\nGetVoices                              Method       ISpeechObjectTokens GetVoices (string RequiredAttributes, string OptionalAttributes)\nIsUISupported                          Method       bool IsUISupported (string TypeOfUI, Variant ExtraData)\nPause                                  Method       void Pause ()\nResume                                 Method       void Resume ()\nSkip                                   Method       int Skip (string Type, int NumItems)\nSpeak                                  Method       int Speak (string Text, SpeechVoiceSpeakFlags Flags)\nSpeakCompleteEvent                     Method       int SpeakCompleteEvent ()\nSpeakStream                            Method       int SpeakStream (ISpeechBaseStream Stream, SpeechVoiceSpeakFlags Flags)\nWaitUntilDone                          Method       bool WaitUntilDone (int msTimeout)\nAlertBoundary                          Property     SpeechVoiceEvents AlertBoundary () {get} {set}\nAllowAudioOutputFormatChangesOnNextSet Property     bool AllowAudioOutputFormatChangesOnNextSet () {get} {set}\nAudioOutput                            Property     ISpeechObjectToken AudioOutput () {get} {set by ref}\nAudioOutputStream                      Property     ISpeechBaseStream AudioOutputStream () {get} {set by ref}\nEventInterests                         Property     SpeechVoiceEvents EventInterests () {get} {set}\nPriority                               Property     SpeechVoicePriority Priority () {get} {set}\nRate                                   Property     int Rate () {get} {set}\nStatus                                 Property     ISpeechVoiceStatus Status () {get}\nSynchronousSpeakTimeout                Property     int SynchronousSpeakTimeout () {get} {set}\nVoice                                  Property     ISpeechObjectToken Voice () {get} {set by ref}\nVolume                                 Property     int Volume () {get} {set}\nqueryMSDNClassInfo                     ScriptMethod System.Object queryMSDNClassInfo();\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的研究表明我应该能够:

\n\n
\xe2\x9d\xaf $PromptTTS.Voice = ${PromptTTS}.GetVoices().Item(0) ; $PromptTTS.Speak("Hello voice 0")\n\xe2\x9d\xaf $PromptTTS.Voice = ${PromptTTS}.GetVoices().Item(1) ; $PromptTTS.Speak("Hello voice 1")\n\xe2\x9d\xaf $PromptTTS.Voice = ${PromptTTS}.GetVoices().Item(2) ; $PromptTTS.Speak("Hello voice 2")\n
Run Code Online (Sandbox Code Playgroud)\n\n

等等。

\n\n

然而,虽然命令执行没有错误,但使用的声音 /heard 并没有改变。

\n

mkl*_*nt0 5

不幸的是,从 v7.1.0-preview.2 开始,分配 to .Voice更改说话的声音在 PowerShell Core中不起作用- 它仅在 Windows PowerShell 中起作用 PowerShell版本高达 v5.1)。

.NET Core 的 COM 支持是有限的,虽然 PowerShell(Core)在一定程度上弥补了这一点,但有些东西仍然不起作用。

实际上,在 PowerShell (Core) 6+ 中,以下分配会被悄悄忽略:

# !! IGNORED in PowerShell [Core] 6+ - the default voice (David)
# !! is NOT changed (to Hedda).
$PromptTTS.Voice = $PromptTTS.GetVoices().Item(1)
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我不知道有什么解决方法(至少仅使用 PowerShell 代码)。


技术背景

检查.Voice财产的$PromptTTS | Get-Member Voice收益:

# !! IGNORED in PowerShell [Core] 6+ - the default voice (David)
# !! is NOT changed (to Hedda).
$PromptTTS.Voice = $PromptTTS.GetVoices().Item(1)
Run Code Online (Sandbox Code Playgroud)

怀疑是该set by ref部分的问题,可能与以下问题有关,引用自此GitHub问题

.NET Core 中不支持( PowerShell Core 中的ComBinder调用是存根方法)。ComInterop.ComBinder.TryBindSetMember