精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
最近完成了语音识别项目,在整理学习文档时,找到了本文,可以当做C#算法学习的例子,也可以帮助C#写语音识别客户端,里面提到的一些思路可以借签,所以分享给大家,注意原文来自codeproject,最终权利归属codeproejct,这里我加了一些理解和注释,帮大家更好掌握。如果想深入学习这个例子里的代码,锐英源软件有开源服务,欢迎联系。
ShakyVoice(最初代号为 BatteryDrainer Pro)是一款用于 Pocket PC 的简单语音压力分析工具。它仅测量暴露压力的众多语音参数之一,然而,这正是大多数廉价电话交谈测谎仪所做的。我只添加了一个时间线跟踪功能,可以及时查看值,程序没有说明什么是真什么是假 - 这种处理你必须自己做一些谎言和真相的样本文件。我认为这使程序比那些不知道真相听起来如何的愚蠢玩具更准确和有用。
*此程序需要安装 MS .NET compact Framework。
该应用程序直接测量语音压力。您可以通过比较真值文件和您记录的谎言文件中的压力差异来衡量谎言。形式上是这样的:
LieMeasure = |TruthFileStressReading - LieFileStressReading|
注:上面是最简单的数学运用,-是减,||是取绝对值,初学者要知道循环符号,除符号,平方符号,开方符号,log对数,指数,矩阵类符号。有时候看算法代码,必须掌握数学符号,麻烦也要记。注解结束。
该程序不显示LieMeasure,因为您总是必须向它提供两个文件(真相和谎言)。如果您已经对扬声器的正常参数有所了解,则可以查看单个文件,以便查看是否存在差异。
你首先记录一个真相文件和一个谎言文件。该程序仅支持 8khz PCM 单声道文件,因此您应该转到开始 -> 程序 -> 设置 -> 输入并将录音格式设置为8, 000 Hz,16 Bit, Mono (16 KB/s),并确保您没有选择某些 GSM 或 Microsoft 格式,该应用程序仅适用于未压缩的 PCM WAVE 文件。否则 - 它将显示错误消息或错误数据(取决于您做错了什么)。现在,为了记录真值文件,请转到记录 -> 记录真值并以正常方式使用控件。然后你可以通过Records -> Record lie 记录谎言文件. 任何记录的文件都存储在内存中,可以在下一个会话中调用。之后-您可以通过记录单独分析文件->分析真相/谎言. 分析后,文件参数显示在时间线上。您应该记录简短的记录,不超过 30 秒,因为分析速度非常慢(并且会很快耗尽电池)。
注:这是开源学习例子的典型情况,只是让学习,不是产品化。
这是实用性和精度如此基本的原因之一。红线是压力 - 更高的值意味着更大的压力。白线是信号的总功率,黄色是震颤功率(实际上是功率的平方根,出于速度考虑)。该程序计算相对于总语音信号功率的震颤功率 - 这是衡量压力的好方法。您通常应该查看最大值(在图表的顶部),了解最大值是多少(红色)——这是您分析的一个很好的起点。时间以毫秒为单位(在时间栏上)。
通常,将这些情况视为压力:
为了区分说话和沉默,你应该在白线上跟踪,不要太低。低白线表示当前段可能为空(静默)。应力估计是基于大约 1/2 秒的卡盘与一些硬编码因子重叠的。
注:普通编程人员要掌握算法的输入和输出,这里的线就是输出。
人们在说谎时会感到压力。谎言越大,压力越大。当他们知道有机会被抓住或知道他们在重要的事情上撒谎时,他们会感到更加紧张。压力很容易被发现。这是与正常参数的任何偏差——比如心律、视网膜反应、眨眼频率(这个确实有效)、血压、体温、脑电图和声音。其他的比较主观,我根本不提。在本文中,我将重点关注表示压力的语音参数。这是一个非常广泛的话题——检测重音的方法有很多,其中一些非常复杂。我已经实现了最简单的一个 - 一个“差”的微震检测器。它的工作原理是这样的——它用频率为 8-12 Hz 的正弦波估计语音的调制。换句话说,它检查语音能量是否以 1/14 - 1/8 秒的间隔跳跃。我们如何做到这一点?- 许多方式 - 然而,看起来最常见的一种是语音数据帧的频谱分析。频谱分析通常通过使用快速傅里叶变换 (FFT) 算法获取语音数据的傅里叶变换图像来完成。实现这个算法并不容易——我是从 频谱分析通常通过使用快速傅里叶变换 (FFT) 算法获取语音数据的傅里叶变换图像来完成。实现这个算法并不容易——我是从 频谱分析通常通过使用快速傅里叶变换 (FFT) 算法获取语音数据的傅里叶变换图像来完成。实现这个算法并不容易——我是从斯蒂芬·伯恩西。我只需要将一些函数从 C 移植到 C#(将其保留在一个unsafe部分中)。如果某个 DSP 专家正在阅读本文,他/她已经在笑,因为这不是测量我们正在寻求的调制的正确方法。是的,但在实践中,如果我们得到 6-15 Hz 频段的能量,我们几乎可以得到这个正确的调制能量。当然,这不是很精确,我想它仍然有用,因为有些人实际上正在卖掉这样的设备。
最重要的部分是分析代码。它首先获取一组大小数据,FrameSize然后执行 FFT,计算总能量和震颤能量,并设置应力估计。关于我如何读取/记录波形文件以及如何显示数据有很多细节,我无法真正评论所有内容。这都是工作的问题,没有什么太光明的。
while(notdone)
{
this.LieFile.inStream.Position=store_pos;
int read=this.LieFile.inStream.Read(tmp,0,FrameSize*2);
if(read!=FrameSize*2)
{
notdone=false;
for(int q=read;q<FrameSize*2;q++) tmp[q]=0;
}
unsafe
{
fixed(byte *pdata=tmp)
{
byte *assignable=pdata;
for(int q=0;q<2*FrameSize;q+=2)
{
short tword=(short)((((int)assignable[1])<<8)|assignable[0]);
fdata[q]=((float)tword)/((float)(0xffff>>1));
fdata[q+1]=0;
assignable+=2;
}
}
fixed(float * fftme=fdata)
{
smbFft(fftme,4096,-1);
}
float total=0;float tremor=0;
for(int q=0;q<FrameSize;q++)
{
fdata[q]=(float)Math.Sqrt(Math.Pow(fdata[2*q],2)+
Math.Pow(fdata[2*q+1],2));//注:这里出现了数学符号
total+=fdata[q];
}
total/=FrameSize;
for(int q=7;q<=15;q++)
{
tremor+=fdata[q];
}
tremor/=6;
Data[1,0].Add(tremor);
Data[1,1].Add(total);
Data[1,2].Add(tremor/total);//注:这里是结果
}
store_pos+=OverlapFactor;
progressBar1.Value=
(int)(100F*(float)store_pos/(float)this.LieFile.inStream.Length);
}
我会提到一些更先进的技术。更准确的压力指标是扬声器的振动音高(或基频)。你有没有注意到(在说谎时)你的声音变得又细又高。嗯,那是因为你的音高越来越高——我所说的算法对音高变化的敏感度可能比你的耳朵和大脑高 100 倍。这将大大提高准确性。
另一种选择是测量呼吸间隔和语速——这个也非常准确。
所有这三种方法都可以在几乎没有硬件/性能要求的 Pocket PC 设备上实现。