【问题标题】:What is right way for "timing" phoneme in SAPI TTS (c#)?? (SpVoice.Phoneme()->streamPosition)SAPI TTS(c#)中“计时”音素的正确方法是什么? (SpVoice.Phoneme()->streamPosition)
【发布时间】:2012-01-29 01:54:03
【问题描述】:

我的应用程序中有下一个“问题”,我编写应用程序,有人会在其中编写文本,SAPI TTS 将其翻译成语音,接下来我将使用输出 WAV。 我需要的是有关音素的信息(在输出 WAV 中是一些音素,语音说多长时间等).. 好的,我使用了 SpVoice.Phoneme() 并添加了音素处理程序。好的,现在我可以得到持续时间等..但是在 SpVoice.Phoneme() 中是属性 StreamPosition 但我不知道这意味着什么..

来自 MSDN:

流位置
输出流中音素开始的字符位置。

我不明白它们是指输出 WAV 中的“字节”位置(音素在哪个字节上)..还是输出 WAV 中的毫秒时间..还是什么意思??

例如,对于文本:

这很高。这是低的。这很快。这很慢。

我得到了 StreamPositions 值:

位置:0
当前位置:120
当前位置:2562
....
当前位置:143798
当前位置:147874
当前位置:151950

输出的 WAV 文件有 5.377098 秒,最后一个音素“ow”大约在 4.734 秒内被告知。 输出的 WAV 文件有 237 568 字节。所以属性 StreamPosition "147874" 的值可能不是开始音素的字节。 “计时”也是如此(以毫秒为单位,因为 WAV 有 5.3 秒,但 151950 毫秒是 151,950 秒..所以这是关闭的..)。

那么什么是 StreamPosition?(StreamPosition 中的值是什么意思?)

我真的需要准确地捕捉音素开始的时间。我用 DateTime.Now.Ticks/10000 试过了。当用户单击开始翻译 TTS 的按钮时,我会保存此日期时间值,当某些处理程序捕获某些音素时,我会再次捕获该值。然后我将使用 currTime-startTime 获得值。但这种“方法”并不那么准确。总有一些分歧。有 SpVoice.Phoneme() 一些“方法”或其他东西来获取有关音素开始时间的确切信息吗? 如果没有,有没有更好的方法来获得更精确的毫秒时间?

感谢我的英语,非常感谢所有答案和建议..

【问题讨论】:

  • 我会尝试,但我不确定这是否对我有帮助..在 PC 上运行的进程仍然会有一些分歧,等等..但也许这会像滴答声一样好 :) ..
  • 所以 datetime.now.ticks 和秒表之间的差异在 1-4 毫秒之间(我在这两行之间有一些操作..所以这将是因为那里的那些命令..)
  • 您正在突破分辨率的极限。我相信你能得到的最接近的是在 15 毫秒内。看看这个link。我相信我误解了你。但我还是会留下这个评论
  • 谢谢你的链接,我会再读一遍,因为有些东西我不明白..但是..我现在能说什么..我怎么看,计时器或秒表对我来说是不好的解决方案问题(获取有关音素开始的信息)..但是当 SAPI TTS、Phoneme() 不实现“计时”时我还能做什么(它只实现持续时间)..uaaaaaa ..谢谢您的回答 mr.Hall :)

标签: c# timing sapi text-to-speech


【解决方案1】:

好的,我会回答自己。我的学士教授给我发了一些他写的 C++ 代码。我前两天读了它,现在我知道我有多愚蠢了。

所以我会回答..

属性 StreamPosition 确实是输出流中的“咬”位置(可能是 WAV)。

如果您想知道输出流中的毫秒位置,您需要编写如下内容:

(int)StreamPosition/(double)wavFileFormat_samplesPerSec/((double)wavFileFormat_BitsPerSample/8)

因此您需要找到有关 outputStream 的信息,例如 bitsPerSample、SamplesPerSec,您将获得毫秒计时。

【讨论】:

    【解决方案2】:

    1) 我不确定你如何将输出保存到 wav 文件,但文件大小 237 568bytes 比正常大(如果采样率为 16khz),作为 5.377098 秒 wav 文件的文件大小

    是 5.377098*16000*2 = 172067 字节 + 标头(44 字节)

    所以,我认为您的 wav 文件也包含音素事件。

    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# 中

    【讨论】:

    • 谢谢回答,我不确定,你对 2.1 的意思是什么)记录音素事件,因为你可能已经在 1 中完成了。如果这有助于我搜索一些关于 C++ 的建议。有一些 SPEI_ “某事”事件和 SPEVENT 以及属性 ullAudioStreamOffset,这正是我所需要的。但是这个事件是在 C++ 中,但是当我进入对象浏览器时,我正在寻找我在 C# 中没有 SPEVENT。这可能是问题所在。如果我应该得到 ullAudioStreamOffset,我将以毫秒为单位计算位置。如果你能描述一下你对 2.1 的意思,我会试试。谢谢!
    猜你喜欢
    • 2011-11-06
    • 2012-02-10
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-05
    • 2010-09-10
    相关资源
    最近更新 更多