PCM静默检测

静默检测首先要能计算某段音频数据的音量大小,那么首先有两个个公式明确:

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;
	}

上面这个方法有几点需要明确:

  1. 使用平方和求平均值来计算一段音频数据的分贝值,因为已经平方过,所以公式中的20可以写为20/2=10;如果直接用绝对值和求平均值,那么仍然用20
  2. 使用short值来表示16bit的数据,因为有符号位,那么最大分贝值应该为20*log(32767) ≈ 90
  3. 使用大端模式表示数据,即低地址存高位字节

检测静默的前提是设定一个阈值,如果小于这个阈值,则判定为静默。
具体代码见传送门

猜你喜欢

转载自blog.csdn.net/ifmylove2011/article/details/107956353
今日推荐