我正在编写一个使用SpeechSynthesizer根据请求生成wave文件的东西,但是我遇到了噼里啪啦的噪音问题。奇怪的是直接输出到声卡就好了。
这个简短的PowerShell脚本演示了这个问题,虽然我用C#编写程序。
Add-Type -AssemblyName System.Speech
$speech = New-Object System.Speech.Synthesis.SpeechSynthesizer
$speech.Speak('Guybrush Threepwood, mighty pirate!')
$speech.SetOutputToWaveFile("${PSScriptRoot}\foo.wav")
$speech.Speak('Guybrush Threepwood, mighty pirate!')
这应该做什么,输出到扬声器,然后在脚本旁边保存与“foo.wav”相同的声音。
它的作用是输出到扬声器,然后将一个噼里啪啦的老唱机声音版本保存为波形文件。我已经在三台不同的机器上对它进行了测试,虽然默认情况下它们选择了不同的声音(所有微软都提供默认声音),但它们听起来像是垃圾在波形文件中下楼梯。
为什么?
编辑:我在Windows 10 Pro上进行测试,最新的更新在任务栏上添加了恼人的“人物”按钮。
编辑3:It's even more noticeable with a female voice
编辑4:The same voice as above, saved to file with TextAloud 3 - no cracking, no vertical spikes.
我发现很难相信这是一个PoSH问题。它不是PoSH在序列化到磁盘上进行编码。它正在使用的API /类。
'MSDN.Microsoft.com/恩-US/library/system.speech.synthesis.speech synthesizer(V=vs.110).aspx
根据MSDN,没有控制编码,比特率等的选项。
.wav从未成为HQ的东西。所以,我想知道你是否通过转换器将.wav作为.mp3或mp4,如果这样可以纠正你的质量问题。但这也意味着将转换器放在用户系统上。
其次,自Win8以来,默认播放器甚至没有正确播放.wav。当然,您仍然可以将.wav的默认播放设置为Windows Media Player或通过VLC调用该文件,但它仍然是.wav文件。然而,这也意味着,您必须在每个目标系统上设置媒体播放器分配。
这是SpeechSynthesizer API的一个问题,它简单地提供了质量差,噼里啪啦的音频,如上面的示例所示。解决方案是执行TextAloud所做的操作,即直接使用SpeechLib COM对象。
这是通过向“Microsoft语音对象库(5.4)”添加COM引用来完成的。这是我最终得到的代码片段,它产生与TextAloud相同质量的音频片段:
public new static byte[] GetSound(Order o)
{
const SpeechVoiceSpeakFlags speechFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync;
var synth = new SpVoice();
var wave = new SpMemoryStream();
var voices = synth.GetVoices();
try
{
// synth setup
synth.Volume = Math.Max(1, Math.Min(100, o.Volume ?? 100));
synth.Rate = Math.Max(-10, Math.Min(10, o.Rate ?? 0));
foreach (SpObjectToken voice in voices)
{
if (voice.GetAttribute("Name") == o.Voice.Name)
{
synth.Voice = voice;
}
}
wave.Format.Type = SpeechAudioFormatType.SAFT22kHz16BitMono;
synth.AudioOutputStream = wave;
synth.Speak(o.Text, speechFlags);
synth.WaitUntilDone(Timeout.Infinite);
var waveFormat = new WaveFormat(22050, 16, 1);
using (var ms = new MemoryStream((byte[])wave.GetData()))
using (var reader = new RawSourceWaveStream(ms, waveFormat))
using (var outStream = new MemoryStream())
using (var writer = new WaveFileWriter(outStream, waveFormat))
{
reader.CopyTo(writer);
return o.Mp3 ? ConvertToMp3(outStream) : outStream.GetBuffer();
}
}
finally
{
Marshal.ReleaseComObject(voices);
Marshal.ReleaseComObject(wave);
Marshal.ReleaseComObject(synth);
}
}
这是将wav文件转换为mp3的代码。它使用来自nuget的NAudio.Lame。
internal static byte[] ConvertToMp3(Stream wave)
{
wave.Position = 0;
using (var mp3 = new MemoryStream())
using (var reader = new WaveFileReader(wave))
using (var writer = new LameMP3FileWriter(mp3, reader.WaveFormat, 128))
{
reader.CopyTo(writer);
mp3.Position = 0;
return mp3.ToArray();
}
}