C# 无法创建多个TTS“;wav";在C中使用MS-SAPI 5.1的文件#
大家好 我正在从事一个项目,我将不得不创建使用TTS的WAV文件的名称 我将MS-SAPI 5.1 SDK安装在Windows Server 2003上,并使用C#编写TTS程序。除了默认的Microsoft Sam语音外,我还有服务器上安装的NeoSpeech TTS语音 我遇到的问题是,该程序生成的WAV文件不超过1个 更具体地说,如果我向程序发送4个名称,程序将创建4个WAV文件。但是,只有第一个名称被正确转换。文件大小大于1 kb,并且该文件也在media player中播放 其他3个文件已创建,但大小为1KB,不能在任何媒体播放器中使用 我对C#和MS-SAPI都是新手,但我相信我在创建代码方面做得不错。我花了好几天的时间想弄明白这一点,但现在我已经精疲力竭了 我们非常感谢您对这个问题的任何见解。谢谢你抽出时间 这是我的密码:C# 无法创建多个TTS“;wav";在C中使用MS-SAPI 5.1的文件#,c#,wav,text-to-speech,sapi,C#,Wav,Text To Speech,Sapi,大家好 我正在从事一个项目,我将不得不创建使用TTS的WAV文件的名称 我将MS-SAPI 5.1 SDK安装在Windows Server 2003上,并使用C#编写TTS程序。除了默认的Microsoft Sam语音外,我还有服务器上安装的NeoSpeech TTS语音 我遇到的问题是,该程序生成的WAV文件不超过1个 更具体地说,如果我向程序发送4个名称,程序将创建4个WAV文件。但是,只有第一个名称被正确转换。文件大小大于1 kb,并且该文件也在media player中播放 其他3个文
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using SpeechLib;
using System.Threading;
namespace TTS_Text_To_Wav
{
class Gender
{
public static String MALE = "Male";
public static String FEMALE = "Female";
}
class Languages
{
public static String ENGLISH = "409;9";
public static String SPANISH = "40a";
}
class Vendor
{
public static String VOICEWARE = "Voiceware";
public static String MICROSOFT = "Microsoft";
}
class SampleTTS
{
static void Main(string[] args)
{
SampleTTS processor = null;
try
{
processor = new SampleTTS();
// get unprocessed items
ArrayList unProcessedItems = new ArrayList();
unProcessedItems.Add("Kate");
unProcessedItems.Add("Sam");
unProcessedItems.Add("Paul");
unProcessedItems.Add("Violeta");
if (unProcessedItems != null)
{
foreach (string record in unProcessedItems)
{
// convert text to wav
processor.ConvertStringToSpeechWav(record, "c:/temp/" + record + ".wav", Vendor.VOICEWARE, Gender.MALE, Languages.ENGLISH);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
void ConvertStringToSpeechWav(String textToConvert, String pathToCreateWavFile, String vendor, String gender, String language)
{
SpVoice voice = null;
SpFileStream spFileStream = null;
try
{
spFileStream = new SpFileStream();
voice = new SpVoice();
spFileStream.Format.Type = SpeechAudioFormatType.SAFT8kHz16BitMono;
spFileStream.Open(pathToCreateWavFile, SpeechStreamFileMode.SSFMCreateForWrite, false);
voice.Voice = voice.GetVoices("Vendor=" + vendor + ";Gender=" + gender, "Language=" + language).Item(0);
voice.AudioOutputStream = spFileStream;
voice.Speak(textToConvert, SpeechVoiceSpeakFlags.SVSFlagsAsync | SpeechVoiceSpeakFlags.SVSFPurgeBeforeSpeak);
voice.WaitUntilDone(Timeout.Infinite);
}
catch (Exception e)
{
throw new Exception("Error occured in ConvertStringToSpeechWav()\n" + e.Message);
}
finally
{
if (spFileStream != null)
{
spFileStream.Close();
}
}
}
}
}
编辑:
我似乎注意到一些新的行为。该代码适用于系统上的Microsoft Voice。我似乎只有用新语言的声音才有这个问题
这是否意味着我的代码是正确的,声音有问题?首先,我得到了客户的声音,所以对此我无能为力。第二,这些是为制作准备的声音。我很确定他们都经过了很好的测试,否则我们会听到很多关于它的消息
我仍然倾向于相信我写的代码出了问题
还有其他建议吗?我在这里遇到了一个真正的问题,任何帮助都将不胜感激。我做TTS已经有一段时间了,但据我回忆,Speak方法是异步的,因此在第一次播放时,后续调用可能会被阻止
看起来您是通过使用“SpeechVoiceSpeakFlags.SVSFlagsAsync”标志来明确执行此操作的,因此请尝试先更改此标志。我遇到了类似的问题,但我使用的是来自不同供应商的声音(不是NeoSpeech),并且该问题仅在生成大约300个成功的wav文件后才出现 但症状是一样的:所有不能工作的wav文件的大小都小于1K 我注意到,将失败的行移到列表的顶部仍然会产生类似的结果:最初大约300行成功(即使其中一些行在上一次运行中失败)。因此,问题不在于生产线本身,而在于处理了多少 我找不到任何方法来“重置”语音系统,所以我试着每100行呼叫一次垃圾收集器。成功了 所以我建议你试试:
GC.Collect()代码>
在ConvertStringToSpeechWav函数的末尾。虽然我没有看到任何明显的导致TTS问题的原因,但是您可以使用一些最佳实践和代码简化
首先,不需要实例化包含Main()和SampleTTS的类来调用ConvertStringToSpeechWav():
示例TTS类可以重写如下:
class SampleTTS
{
static void Main(string[] args)
{
try
{
// get unprocessed items
List<String> unProcessedItems = new List<String>();
unProcessedItems.Add("Kate");
unProcessedItems.Add("Sam");
unProcessedItems.Add("Paul");
unProcessedItems.Add("Violeta");
foreach (string record in unProcessedItems)
{
// convert text to wav
ConvertStringToSpeechWav(record, "c:/temp/" + record + ".wav", Vendor.VOICEWARE, Gender.MALE, Languages.ENGLISH);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
让GC来清理。您是否尝试过像PauloPinto建议的那样调用GC.Collect(),只是为了看看它是否有效?您不必为了让某些东西工作而坚持严格的编码原则。我们的目标应该始终是干净、有原则地编写代码,但更重要的是让代码处于工作状态,然后根据需要进行重构
我希望这能有所帮助
干杯。谢谢你的评论,杜比。在查看MSDN:SpeechVoiceSpeakFlags.SVSFDefault后,我将代码更改为此。不幸的是,这也产生了同样的结果。不知何故,没有生成后续文件。这对GC来说不是一个好的做法。收集每一行“某些”行,我怀疑它是否真的解决了问题,如果它真的解决了问题,代码应该会有一些奇怪的地方。谢谢Paulo的评论。这次我想站在戴维德这边。我可以理解,在生产截止日期下,您会认为任何解决方案都是可以接受的,但这不是解决问题的正确方法。我将继续为这个问题寻找正确而优雅的解决方案,我建议您也这样做,即使GC.Collect()现在已经解决了您的问题@DavidePiras我已经在上面发布了我的代码,不知道您是否可以查看它,并让我知道我的代码是否有问题。谢谢你们两位,谢谢你们的时间@戴维德皮拉斯:我同意这不是“好的做法”,但我仍然会说一个工作计划比一个非工作计划好。调用GC解决了这个问题,这表明MS-SAPI SDK没有正确释放隐藏的资源。所以坏习惯可能来自内心深处@那么我的建议不起作用了吗?我明白你为什么不想在生产环境中使用它,但它可能会给你另一个错误的线索。我运行一台64位的笔记本电脑,声音是32位的,所以我唯一可以进行测试的地方就是实际的服务器。我和我的首席技术官谈过这件事,他甚至拒绝让我尝试:)(这是意料之中的)。我们现在使用AT&T语音,这与我上面的代码配合得很好。我现在有理由相信我从客户那里听到的声音是老旧的或有问题的。也许你也应该试试其他的声音。我不认为SAPI SDK存在缺陷。总是第三方供应商做得不好。谢谢你的评论。我使用java,所以我不太确定是否从StaticMain调用非静态方法。我同意你的观点,ArrayList->List
更好,因为它是类型安全的。我已经设置了空检查,因为理想情况下,数据将来自DB,但我必须调整代码以便发布。我没有尝试GC.Collect()。有机会的话我会试一试的。但是看到你
class SampleTTS
{
static void Main(string[] args)
{
try
{
// get unprocessed items
List<String> unProcessedItems = new List<String>();
unProcessedItems.Add("Kate");
unProcessedItems.Add("Sam");
unProcessedItems.Add("Paul");
unProcessedItems.Add("Violeta");
foreach (string record in unProcessedItems)
{
// convert text to wav
ConvertStringToSpeechWav(record, "c:/temp/" + record + ".wav", Vendor.VOICEWARE, Gender.MALE, Languages.ENGLISH);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
voice = new SpVoice();