Ahm*_*mad 11 c# audio sapi speechsynthesizer
在C#的文本到语音应用程序中,我使用SpeechSynthesizer类,它有一个名为的事件SpeakProgress,每个语音都被触发.但是对于某些声音,参数e.AudioPosition不与输出音频流同步,并且输出波形文件的播放速度比此位置显示的速度快(请参阅此相关问题).
无论如何,我试图找到有关比特率和与所选语音相关的其他信息的确切信息.正如我所经历的那样,如果我可以使用此信息初始化wave文件,则将解决同步问题.但是,如果我找不到这样的信息SupportedAudioFormat,我知道找不到其他方法.例如,"Microsoft David Desktop"语音不提供支持的格式VoiceInfo,但它似乎支持PCM 16000 hz,16位格式.
如何找到SpeechSynthesizer所选语音的音频格式
var formats = CurVoice.VoiceInfo.SupportedAudioFormats;
if (formats.Count > 0)
{
var format = formats[0];
reader.SetOutputToWaveFile(CurAudioFile, format);
}
else
{
var format = // How can I find it, if the audio hasn't provided it?
reader.SetOutputToWaveFile(CurAudioFile, format );
}
Run Code Online (Sandbox Code Playgroud)
更新:此答案已在调查后进行了编辑。最初,我凭记忆建议 SupportedAudioFormats 可能只是来自(可能配置错误)注册表数据;调查表明,对我来说,在 Windows 7 上,情况确实如此,并且在 Windows 8 上也有备份。
System.Speech封装了古老的 COM 语音 API (SAPI),某些语音是 32 位与 64 位,或者可能配置错误(在 64 位计算机的注册表上,HKLM/Software/Microsoft/Speech/Voices与HKLM/Software/Wow6432Node/Microsoft/Speech/Voices.
我已经指出了 ILSpySystem.Speech及其类,并且我非常确信 SupportedAudioFormats 仅来自注册表数据,因此,如果您的 TTS 引擎没有为应用程序的平台目标正确注册,则VoiceInfo在枚举时可能会得到零结果( SupportedAudioFormatsx86、任何或 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;
}
Run Code Online (Sandbox Code Playgroud)
用法:
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");
Run Code Online (Sandbox Code Playgroud)
为了测试它,我将 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
672 次 |
| 最近记录: |