更新:此答案已在调查后进行了编辑。最初我从内存中建议 SupportedAudioFormats 可能只是来自(可能配置错误的)注册表数据;调查表明,对我来说,在 Windows 7 上,情况确实如此,并且在 Windows 8 上得到了备份。
SupportedAudioFormats 的问题
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