【问题标题】:Microsoft SpeechSynthesizer crackles when outputting to files and streamsMicrosoft SpeechSynthesizer 在输出到文件和流时发出噼啪声
【发布时间】:2017-12-23 08:48:18
【问题描述】:

我正在编写一个使用 SpeechSynthesizer 根据请求生成波形文件的东西,但是我遇到了噼啪声的问题。奇怪的是直接输出到声卡就好了。

这个简短的 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”。

它的作用是输出到扬声器,然后将一个噼啪作响的旧电唱机声音版本保存为波形文件。我在三台不同的机器上对此进行了测试,虽然它们默认选择不同的声音(所有 Microsoft 都提供了默认声音),但它们在波形文件中听起来都像是从楼梯上掉下来的垃圾。

为什么?

编辑:我正在 Windows 10 Pro 上对此进行测试,最新更新在任务栏上添加了烦人的“人物”按钮。

编辑 2:Here's a link to an example sound generated with the above script. Notice the crackling voice, that's not there when the script outputs directly to the speakers.

编辑 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.

【问题讨论】:

  • 无法复制。无论我是将结果保存在文件中还是立即播放语音,对我来说听起来都一样。
  • 我能麻烦你把你的wav文件上传到某个地方吗?我使用的那个网站非常简单,不需要注册。如果只是我的声卡或 wav 文件播放设置,那么您的 wav 文件应该与我的相同。或者,你听到我的 wav 噼啪作响了吗?
  • 我想我在instaud.io/1zsv分享了我的 foo.wav 文件
  • 谢谢!然而,这似乎和我的一样有裂纹。人们甚至可以在 instaud.io 制作的图表上看到它们,作为“海盗”一词中间的两条垂直线,以及其他几个地方,尽管不那么明显。我确信当脚本直接输出到扬声器时我没有听到这些。我什至现在尝试了第四台机器,我最近得到的一台小型笔记本电脑 - 结果相同。
  • 我在我的问题中添加了另一个声音文件,这次是女性声音。同样,裂纹也可以看到为垂直线,所以它不应该是播放设备。

标签: c# powershell audio text-to-speech


【解决方案1】:

我很难相信这是一个 PoSH 问题。 不是 PoSH 对序列化到磁盘进行编码。它是正在使用的 API/类。

'msdn.microsoft.com/en-us/library/system.speech.synthesis.speechsynthesizer(v=vs.110).aspx'

根据 MSDN,没有选项可以控制编码、比特率等。

.wav 从来都不是总部的东西。所以,我想知道您是否将 .wav 通过转换器转换为 .mp3 或 mp4,如果这样可以纠正您的质量问题。但这也意味着在用户系统上安装转换器。

其次,从 Win8 开始,默认播放器甚至无法正确播放 .wav 或根本无法播放。当然,您仍然可以将 .wav 的默认播放设置为 Windows Media Player 或通过 VLC 调用文件,但它仍然是 .wav 文件。然而,这也意味着,您必须在每个目标系统上设置媒体播放器分配。

【讨论】:

  • 这确实是一个 API 问题,因为它也发生在 C# 中。但是,关于波形文件的质量,你错了,当你使用 SetOutputToAudioStream method 时,API 确实有设置质量的选项。关于质量,wave 通常用于速度较慢的计算机,由于处理能力的限制,无法将 CD 音频直接编码为 mp3。它不会降低质量(尽管 mp3 会降低质量)。
  • 我搞砸了那个 SetOutputToAudioStream,它在我尝试的任何尝试中都没有任何区别。因此,我之前的回应。但是你和我在一起的时间似乎比我多,所以,我不得不相信你的话。但是,在实时使用或序列化时,我没有遇到 .mp3/mp4 格式的问题。
  • 它不能做太多,因为每个声音本身通常都是有限的。例如,来自Ivona 的声音通常为 22kHz,或更准确地说是 22050Hz,这意味着如果您以 44.1kHz 对其进行采样,您所做的就是将每个样本中的两个样本放入两倍大的文件中。不过,如果您讨厌自己的耳朵,您可以运行更少的样本。
【解决方案2】:

这是 SpeechSynthesizer API 的问题,它只是提供了质量差、噼啪作响的音频,如上面的示例所示。解决办法就是做TextAloud做的,直接使用SpeechLib COM对象。

这是通过添加对“Microsoft Speech Object Library (5.4)”的 COM 引用来完成的。这是我最终得到的代码的 sn-p,它会生成与 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);
    }
}

这是将波形文件转换为 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();
    }
}

【讨论】:

  • 您是如何添加对Microsoft Speech Object Library 的引用的?我需要在/reference 中为 csc 指定什么?
  • 在我的 Visual Studio .Net(不是核心,无法执行此 AFAIK)项目中,我右键单击了 References => Add Reference => COM => Microsoft Speech Object Library version 5.4
猜你喜欢
  • 2021-04-25
  • 2016-02-26
  • 1970-01-01
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多