更新:此答案已在调查后进行了编辑。最初,我从内存中建议 SupportedAudioFormats 可能只是来自(可能配置错误的)注册表数据;调查表明,对我来说,在 Windows 7 上,情况确实如此,并且在 Windows 8 上得到了备份。
支持的音频格式问题
System.Speech
包装了古老的 COM 语音 API (SAPI),一些声音是 32 位和 64 位的,或者可能配置错误(在 64 位机器的注册表上,HKLM/Software/Microsoft/Speech/Voices
与HKLM/Software/Wow6432Node/Microsoft/Speech/Voices
.
我已经将 ILSpy 指向了System.Speech
它的VoiceInfo
类,并且我非常确信 SupportedAudioFormats 完全来自注册表数据,因此SupportedAudioFormats
如果您的 TTS 引擎没有为您的应用程序的平台目标正确注册( x86、Any 或 64 位),或者如果供应商根本没有在注册表中提供此信息。
语音可能仍支持不同的、额外的或更少的格式,因为这取决于语音引擎(代码)而不是注册表(数据)。所以它可以在黑暗中拍摄。在这方面,标准 Windows 声音通常比第三方声音更一致,但它们仍然不一定有用地提供SupportedAudioFormats
.
很难找到这些信息
我发现仍然可以获得当前语音的当前格式——但这确实依赖于反射来访问 System.Speech SAPI 包装器的内部。
因此,这是非常脆弱的代码!而且我不建议在生产中使用。
注意:以下代码确实需要您调用 Speak() 一次进行设置;在没有 Speak() 的情况下,需要更多的调用来强制设置。但是,我可以打电话Speak("")
什么都不说,而且效果很好。
执行:
[StructLayout(LayoutKind.Sequential)]
struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
WAVEFORMATEX GetCurrentWaveFormat(SpeechSynthesizer synthesizer)
{
var voiceSynthesis = synthesizer.GetType()
.GetProperty("VoiceSynthesizer", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(synthesizer, null);
var ttsVoice = voiceSynthesis.GetType()
.GetMethod("CurrentVoice", BindingFlags.Instance | BindingFlags.NonPublic)
.Invoke(voiceSynthesis, new object[] { false });
var waveFormat = (byte[])ttsVoice.GetType()
.GetField("_waveFormat", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(ttsVoice);
var pin = GCHandle.Alloc(waveFormat, GCHandleType.Pinned);
var format = (WAVEFORMATEX)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(WAVEFORMATEX));
pin.Free();
return format;
}
用法:
SpeechSynthesizer s = new SpeechSynthesizer();
s.Speak("Hello");
var format = GetCurrentWaveFormat(s);
Debug.WriteLine($"{s.Voice.SupportedAudioFormats.Count} formats are claimed as supported.");
Debug.WriteLine($"Actual format: {format.nChannels} channel {format.nSamplesPerSec} Hz {format.wBitsPerSample} audio");
为了测试它,我在 下重命名了 Microsoft Anna 的AudioFormats
注册表项HKLM/Software/Wow6432Node/Microsoft/Speech/Voices/Tokens/MS-Anna-1033-20-Dsk/Attributes
,导致SpeechSynthesizer.Voice.SupportedAudioFormats
查询时没有元素。以下是这种情况下的输出:
0 formats are claimed as supported.
Actual format: 1 channel 16000 Hz 16 audio