静默检测首先要能计算某段音频数据的音量大小,那么首先有两个个公式明确:
dB = 20 * log(P1/P2)
其中P1/P2可以看作一个整体的阈值;
当声音采样深度为16bit时,P1/P2 = 65535,即dB ≈ 96;
当不确定P1/P2具体值时,那么就有
dB = 20 * log(音频数据)
另外,音频数据大小也有一个公式可表示:
数据量(字节/秒) = 采样率(Hz) * 采样大小(bit) * 声道数 / 8
这里有一个JAVA表示的计算分贝方法:
/**
* 计算输入数据段的db值,按公式应该为20*Math.log10(当前振幅值/最大振幅值);
* 位深为16bit,则代表两个字节表示一个音量采集单位;
* 此处用平方和平均值进行计算;
*
* @param data 输入pcm音频数据
* @param bit 位深,8或16
* @return 当前分贝值
*/
private int calculateVolume(byte[] data, int bit) {
int[] newBuffer = null;
int len = data.length;
int index;
//排列
if (bit == 8) {
newBuffer = new int[len];
for (index = 0; index < len; ++index) {
newBuffer[index] = data[index];
}
} else if (bit == 16) {
newBuffer = new int[len / 2];
for (index = 0; index < len / 2; ++index) {
byte byteH= data[index * 2];
byte byteL = data[index * 2 + 1];
newBuffer[index] = bytesToShort(byteH, byteL);
}
}
//平方和求平均值
if (newBuffer != null && newBuffer.length != 0) {
float avg = 0.0F;
for (int i = 0; i < newBuffer.length; ++i) {
avg += (float) (newBuffer[i] * newBuffer[i]);
}
avg /= (float) newBuffer.length;
int db = (int) (10.0D * Math.log10(avg + 1));
return db;
} else {
return 0;
}
}
private static short bytesToShort(byte byteH, byte byteL) {
short temp = 0;
temp += (byteL & 0xFF);
temp += (byteH & 0xFF) << 8;
return temp;
}
上面这个方法有几点需要明确:
- 使用平方和求平均值来计算一段音频数据的分贝值,因为已经平方过,所以公式中的20可以写为20/2=10;如果直接用绝对值和求平均值,那么仍然用20
- 使用short值来表示16bit的数据,因为有符号位,那么最大分贝值应该为20*log(32767) ≈ 90
- 使用大端模式表示数据,即低地址存高位字节
检测静默的前提是设定一个阈值,如果小于这个阈值,则判定为静默。
具体代码见传送门