我的应用程序中有下一个“问题”,我写应用程序,有人会写文本,SAPI TTS将其翻译成语音,接下来我将使用输出WAV。 我需要的是关于音素的信息(输出中的WAV是一些音素,声音说多长时间等等)。 好吧,我使用了SpVoice.Phoneme(),我为phonemes添加了处理程序。好的,现在我可以获得持续时间等。但是在SpVoice.Phoneme()中是属性StreamPosition但我不知道这意味着什么..
来自MSDN的:
StreamPosition
音素开始的输出流中的字符位置。
我不明白它们是否意味着输出WAV中的“字节”位置(在WHICH字节是音素)..或输出WAV的毫秒时间。或者是什么意思??
例如,对于文字:
这很高。这很低。这很快。这很慢。
我得到了StreamPositions值:
位置:0
您的位置:120
您的位置:2562
....
您的位置:143798
您的位置:147874
位置:151950
输出WAV文件有5.377098秒,最后一个音素“ow”大约在4.734s中被告知。 输出WAV文件有237 568bytes ..因此属性StreamPosition“147874”的值可能不是开始音素的字节。 “定时”相同(以ms为单位,因为WAV有5.3s但151950ms是151,950s ......所以这是关闭的......)。
那么什么是StreamPosition?(什么意思是StreamPosition中的值?)
我真的需要抓住音素开始时的确切时间。我用DateTime.Now.Ticks / 10000试了一下。当用户点击按钮开始翻译TTS我保存这个日期时间值,当一些处理程序捕获一些音素时,我再次捕获该值。然后我将使用currTime-startTime获取值。但这种“方法”并不那么精确。总有一些分歧。有SpVoice.Phoneme()一些“方法”或什么来获得关于音素开始的时间的确切信息? 如果没有,是否有更好的方法可以在ms中获得更准确的时间?
为我的英语而且非常感谢所有答案和建议..
答案 0 :(得分:1)
所以我会回答..
属性 StreamPosition 在输出流中可能是“咬人”位置(可能是WAV)。
如果您想知道输出流中的毫秒位置,您需要编写如下内容:
(INT)StreamPosition /(双)wavFileFormat_samplesPerSec /((双)wavFileFormat_BitsPerSample / 8)
所以你需要找到有关outputStream的信息,比如bitsPerSample,SamplesPerSec,你将获得毫秒的时间。
答案 1 :(得分:0)
1)我不确定如何将输出保存到wav文件,但文件大小 237 568bytes比正常大(,如果采样率为16khz ),作为5.377098秒wav文件的文件大小
是5.377098 * 16000 * 2 = 172067字节+标题(44字节)
所以,我认为你的wav文件也包含了phoneme事件。
2)TTS需要时间来生成输出,所以你不能以这种方式计时,我建议你:
2.1)记录你可能已经在1
中完成的音素事件You can also refer to Windows SDK
C:\ Program Files \ Microsoft SDKs \ Windows \ v7.1 \ Samples \ winui \ speech \ ttsapplication
if (SUCCEEDED(hr))
{
// OriginalFmt.WaveFormatExPtr()->nSamplesPerSec;
hr = SPBindToFile( m_szWFileName, SPFM_CREATE_ALWAYS, &cpWavStream, &OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr(),SPFEI_ALL_TTS_EVENTS);
}
if( SUCCEEDED( hr ) )
{
// Set the voice's output to the wav file instead of the speakers
hr = m_cpVoice->SetOutput(cpWavStream, TRUE);
}
2.2)其他事件的时间,例如流启动< =我对确切名称不太确定。
Windows SDK中的:
while (m_cpVoice->GetEvents(1, &event, &ul) == S_OK)
{
if (event.eEventId == SPEI_VISEME)
{
printf("v: %i\'",event.lParam); // viseme
printf("t: %i\'",event.wParam); // duration of viseme
}
else if (event.eEventId == SPEI_END_INPUT_STREAM)
{
} else if (event.eEventId == SPEI_START_INPUT_STREAM)
{
}
}
但代码不在C#
中