`
包su
  • 浏览: 31105 次
  • 来自: 南京
社区版块
存档分类
最新评论

如何像talking tom那样,自动监听到外部声音,和,简单的变声_2

 
阅读更多

****************************************************前言

没错,这是第2篇,第1篇在这里如何像talking tom那样,自动监听到外部声音,和,简单的变声_1

 

那么,第2篇将会说些什么呢?

1.第1篇中的方法,可以使用,但是局限性很大:你使用了该方法,你能检测到device1的声音,但是,相同的代码被安装到了device2(不同的品牌,或者,不同的型号),你发现监听不了了,你需要修改阀值。当你发布一款应用的时候,你会幻想着老板将所有的设备都为你买一台,以能在这些机器上进行测试

 

****************************************************打破那个局限性

public int read (byte[] audioData, int offsetInBytes, int sizeInBytes)
android可以监听到扬声器的数据(最终数据会放入audioData中),接下来,你需要对这个audioData中的数据进行分析,以判定,这部分数据是否是“人”的声音

 

如何判定:
你要先从audioData中拿到一个个的sample
sample是什么:样本,也许,你还听说过samplerate这个词语,它代表的是 一段时间内样本被采集的次数,声音最终被播放成什么样子,跟sample有很大的关系
sample占用了多少个字节:这个,你需要学习一个wav文件的header,推荐你一个:https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
你会发现wav是个一个大杂缸,你会发现什么是PCM的wav

 

在得出了sample之后,我们将进行如下运算(假设,1个sample占用了2个字节)

int sample = 0;
float average;
for (int i = 0; i < audioDataLength; i += 2) {
	sample = Math.abs(audioData[i] | (audioData[i + 1] << 8));
	// 平均的sample
	average += 1.0f * sample / audioDataLength;
}

 

有必要再说一下,java中的byte/short/int等等,就是signed的,也就意味着,audioData[i] | (audioData[i + 1] << 8)这个值有可能是负数,所以,请你不要惊奇
而负数的存在,也是正常的,它代表了一个我们都不想去了解的专业概念
最终,你得到了一个值average,来代替一个数组audioData

 

如果直接拿average作为条件,来判定:刚监听到的声音数据是否是人声,也是可以的,但是,你会发现刚才我们提出的问题:局限性太大,即是:你的代码需要频繁的更改阀值,以确保在不同的device上面,能够监听到声音
如何打破这种局限性,使用一个你不想接触的概念:分贝
网上有很多,如何将pcm data转换为分贝的方法,下面说一下,我采用的这种(也意味着,你可以找到更准确的方法,也,欢迎回复我该方法):
float db = (float) Math.abs(10 * Math.log10(average * average / 32767 / 32767));
非常的简单,最终,你从average得到了一个分贝值。
你会发现整个过程:audioData -> average -> db

 

你可以拿分贝来作为判定条件,我的实验结果是:无论device的操作系统是2.x还是4.x,只要位于[20,40]区间内,你都可以认为,你监听到的是人声
也请你注意:[20,40]并不是完美的,我实验了将近10-台机器,涵盖了samsung,htc,huawei,均是正确的
但是我也找到了:对于huawei u8800+,区间为[50,60],所以,如果你找到了更准确的方法,欢迎回复我

华丽的连接线:

绑架一个wav

图片+音频->视频

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics