语音文件 pcm 静默(静音)判断
转载:http://www.voidcn.com/relative/p-fwdkigvh-bro.html
pcm 文件存储的是 原始的声音波型二进制流,没有文件头。
(1)首先要确认 pcm文件的每个采样数据 采样位数,一般为8bit或16bit。
(2)然后确定是双声道还是单声道,双声道是两个声道的数据交互排列,需要单独提取出每个声道的数据。
(3)然后确定有没有符号位,如采样点位16bit有符号位的的范围为-32768~32767
(4)确定当前操作系统的内存方式是大端,还是小端存储。具体看http://blog.csdn.net/u013378306/article/details/78904238
(5)根据以上四条对pcm文件进行解析,转化为10进制文件
注意:对于1-3可以在windows使用cooledit 工具设置参数播放pcm文件来确定具体参数,也可以使用以下java代码进行测试:
本例子的语音为: 静默1秒,然后说 “你好”,然后静默两秒。pcm文件下载路径:http://download.csdn.net/download/u013378306/10175068
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream; import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine; public class test { /**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub File file = new File("3.pcm");
System.out.println(file.length());
int offset = 0;
int bufferSize = Integer.valueOf(String.valueOf(file.length())) ;
byte[] audioData = new byte[bufferSize];
InputStream in = new FileInputStream(file);
in.read(audioData); float sampleRate = 20000;
int sampleSizeInBits = 16;
int channels = 1;
boolean signed = true;
boolean bigEndian = false;
// sampleRate - 每秒的样本数
// sampleSizeInBits - 每个样本中的位数
// channels - 声道数(单声道 1 个,立体声 2 个)
// signed - 指示数据是有符号的,还是无符号的
// bigEndian -是否为大端存储, 指示是否以 big-endian 字节顺序存储单个样本中的数据(false 意味着
// little-endian)。
AudioFormat af = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, af, bufferSize);
SourceDataLine sdl = (SourceDataLine) AudioSystem.getLine(info);
sdl.open(af);
sdl.start();
for(int i=0;i<audioData.length;i++)
audioData[i]*=1;
while (offset < audioData.length) {
offset += sdl.write(audioData, offset, bufferSize);
}
} }
如果测试通过确定了参数就可以对pcm文件进行解析,如下java代码对每个采样数据为16bits,单声道的pcm,在操作系统内存为小端存储下解析为10进制文件。
package test; import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.math.BigInteger; public class ffff { /**
* 采样位为16bits,小端存储,单声道解析为10进制文件
* @param args
*/
public static void main(String[] args) {
try {
File file = new File("3.pcm");
System.out.println(file.length());
System.out.println(file.length());
int bufferSize = Integer.valueOf(String.valueOf(file.length()));
byte[] buffers = new byte[bufferSize];
InputStream in = new FileInputStream(file);
in.read(buffers);
String rs = "";
for (int i = 0; i < buffers.length; i++) {
byte[] bs = new byte[2];
bs[0]=buffers[i+1];//小端存储,
bs[1]=buffers[i];
int s = Integer.valueOf(binary(bs, 10));
i = i + 1;
rs += " " + s; }
writeFile(rs);
in.close(); } catch (Exception e) {
e.printStackTrace(); }
} public static void writeFile(String s) {
try { FileWriter fw = new FileWriter("hello3.txt"); fw.write(s, 0, s.length());
fw.flush();
fw.close(); } catch (Exception e) {
e.printStackTrace();
} } public static String binary(byte[] bytes, int radix) {
return new BigInteger(bytes).toString(radix);// 这里的1代表正数
}
}
执行完可以查看hello.txt ,可以看到一开始振幅很小,如下,基本不超过100:
-15 -12 -18 -24 -17 -8 -8 -17 -22 -14 -5 -18 -47 -67 -60 -41 -28 -28 -23 -12 -6 -9 -13 -8 0 6 21 49 68 48 -2 -43 -47 -32 -22 -10 22 56
但说你好的时候,振幅变得很大:
-2507 -2585 -2600 -2596 -2620 -2670 -2703 -2674 -2581 -2468 -2378 -2305 -2200 -2018 -1774 -1523 -1307 -1127 -962 -806 -652 -505 -384 -313 -281 -241 -163
然后静默两秒,振幅又变的很小:
5 3 0 -4 -5 -6 -6 -7 -7 -8 -9 -8 -10 -10 -11 -10 -11 -11 -11 -11 -11 -11 -10 -9 -7 -6 -3 -2 -2 -3 -3 -3 -1 2 4 4
具体波形图可以使用python代码显示:
import numpy as np
import pylab as pl
import math
import codecs
file=codecs.open("hello3.txt","r") //原文代码file=codecs.open("hello3.txt","rb"),b是binary,以二进制方式读取,是错误的。
lines=" "
for line in file.readlines():
lines=lines+line
ys=lines.split(" ")
yss=[]
ays=list()
axs=list()
i=0
max1=pow(2,16)-1
for y in ys:
if y.strip()=="":
continue
yss.append(y) for index in range(len(yss)): y1=yss[index] i+=1;
y=int(y1) ays.append(y)
axs.append(i)
#print i
file.close()
pl.plot(axs, ays,"ro")# use pylab to plot x and y
pl.show()# show the plot on the screen
得到波形图

这里音频振幅与audacity中呈现的结果吻合,只是这里把振幅放大以便用肉眼去观察。

2019-11-20 更新:
经过实践发展,可以使用时间单位来检测该时间内的数据是否检测振幅。
(数学不太好,随便用一个字符代替说明一下)
设时间单位为t,音频采样率为S,如果连续的时间单位t时间内振幅很小(也可以计算分贝数),可以认为是静音(没有声音录入) 。
待检验数据长度L=S*t,则检测目标是长度为L的数组,如果这个时间类振幅(分贝)数据小于阈值(threshold),则认为近似静音。
例:采样率16000,2秒以外则认为没有声音输入。即 2*16000长度的数组内,所有数组低于一个阈值。
stackoverflow答案:
参考:https://stackoverflow.com/questions/5800649/detect-silence-when-recording
How can I detect silence when recording operation is started in Java?
Calculate the dB or RMS value for a group of sound frames and decide at what level it is considered to be 'silence'.
What is PCM data?
Data that is in Pulse-code modulation format.
How can I calculate PCM data in Java?
I do not understand that question. But guessing it has something to do with the speech-recognition tag, I have some bad news.
This might theoretically be done using the Java Speech API. But there are apparently no 'speech to text' implementations available for the API (only 'text to speech').
I have to calculate rms for speech-recognition project. But I do not know how can I calculate in Java.
For a single channel that is represented by signal sizes in a double ranging from -1 to 1, you might use this method.
/** Computes the RMS volume of a group of signal sizes ranging from -1 to 1. */
public double volumeRMS(double[] raw) {
double sum = 0d;
if (raw.length==0) {
return sum;
} else {
for (int ii=0; ii<raw.length; ii++) {
sum += raw[ii];
}
}
double average = sum/raw.length; double sumMeanSquare = 0d;
for (int ii=0; ii<raw.length; ii++) {
sumMeanSquare += Math.pow(raw[ii]-average,2d);
}
double averageMeanSquare = sumMeanSquare/raw.length;
double rootMeanSquare = Math.sqrt(averageMeanSquare); return rootMeanSquare;
}
There is a byte buffer to save input values from the line, and what I should have to do with this buffer?
If using the volumeRMS(double[]) method, convert the byte values to an array of double values ranging from -1 to 1. ;)
笔者的思路是计算音频分贝值,可以参考通过pcm音频数据计算分贝
以下代码转载自:https://blog.csdn.net/balijinyi/article/details/80284520
很多场合我们需要动态显示实时声音分贝,下面列举三种计算分贝的算法。(以双声道为例,也就是一个short类型,最大能量值为32767)
1:计算分贝 音频数据与大小
首先我们分别累加每个采样点的数值,除以采样个数,得到声音平均能量值。
然后再将其做100与32767之间的等比量化。得到1-100的量化值。
通常情况下,人声分布在较低的能量范围,这样就会使量化后的数据大致分布在1-20的较小区间,不能够很敏感的感知变化。
所以我们将其做了5倍的放大,当然计算后大于100的值,我们将其赋值100.
//参数为数据,采样个数
//返回值为分贝
#define VOLUMEMAX 32767
int SimpleCalculate_DB(short* pcmData, int sample)
{
signed short ret = ;
if (sample > ){
int sum = ;
signed short* pos = (signed short *)pcmData;
for (int i = ; i < sample; i++){
sum += abs(*pos);
pos++;
}
ret = sum * 500.0 / (sample * VOLUMEMAX);
if (ret >= ){
ret = ;
}
}
return ret;
}
2:计算均方根(RMS) 即能量值
static const float kMaxSquaredLevel = * ;
constexpr float kMinLevel = .f; void Process(const int16_t* data, size_t length)
{
float sum_square_ = ;
size_t sample_count_ = ;
for (size_t i = ; i < length; ++i) {
sum_square_ += data[i] * data[i];
}
sample_count_ += length;.
float rms = sum_square_ / (sample_count_ * kMaxSquaredLevel);
//20log_10(x^0.5) = 10log_10(x)
rms = * log10(rms);
if (rms < -kMinLevel)
rms = -kMinLevel;
rms = -rms;
return static_cast<int>(rms + 0.5);
}
3:获取音频数据最大的振幅(即绝对值最大)(0-32767),除以1000,得到(0-32)。从数组中获取相应索引所对应的分贝值。(提取自webrtc)
const int8_t permutation[] =
{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}; int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length)
{
size_t i = ;
int absolute = , maximum = ;
for (i = ; i < length; i++) {
absolute = abs((int)vector[i]);
if (absolute > maximum) {
maximum = absolute;
}
}
if (maximum > ) {
maximum = ;
}
return (int16_t)maximum;
} void ComputeLevel(const int16_t* data, size_t length)
{
int16_t _absMax = ;
int16_t _count = ;
int8_t _currentLevel = ;
int16_t absValue();
absValue = WebRtcSpl_MaxAbsValueW16(data,length);
if (absValue > _absMax)
_absMax = absValue;
if (_count++ == ) {
_count = ;
int32_t position = _absMax/;
if ((position == ) && (_absMax > )){
position = ;
}
_currentLevel = permutation[position];
_absMax >>= ;
}
}
语音文件 pcm 静默(静音)判断的更多相关文章
- js 上传文件后缀名的判断 var flag=false;应用
js 上传文件后缀名的判断 var flag=false;应用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional// ...
- web前端对上传的文件进行类型大小判断的js自定义函数
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- C# wav语音文件合并
开发完成语音播报产品,由于客户所使用的播放产品种类繁多,在使用HDMI接口播放音频时,由于采用的声卡不同,个别机器会出现播报声音过小,或者不播报的情况.所以采用将语音文件合并播放的方式,来解决此问题. ...
- Yaml 文件中Condition If- else 判断的问题
在做项目的CI/ CD 时,难免会用到 Travis.CI 和 AppVeyor 以及 CodeCov 来判断测试的覆盖率,今天突然遇到了一个问题,就是我需要在每次做测试的时候判断是否存在一个环境变量 ...
- UNIX环境编程学习笔记(6)——文件I/O之判断文件类型
lienhua342014-09-01 1 文件类型 我们平时最常接触的文件类型有普通文件(regular file)和目录(di-rectory file),但是 UNIX 系统提供了多种文件类型: ...
- python 兼容中文路径 + 目标文件是否是图像格式判断
1. 中文路径兼容python程序如果路径中包含中文字符,不加处理会有类似报错:'ascii' codec can't decode byte 0xxx in position xx:ordinal ...
- asp.net使用SpeechSynthesizer类生成语音文件部署到iis遇到的几个坑
首先需要引入命名空间System.Speech.Synthesis,代码如下: using (var speechSyn = new SpeechSynthesizer()) { speechSyn. ...
- 文件夹操作之判断是否存在(Directory)
Directory类用于操作文件夹,用于创建.移动和枚举目录和子目录的静态方法.DirectoryInfo类用于典型操作,如复制,移动,重命名,创建和删除目录.他们都可用于获取和设置相关属性或有关创建 ...
- Delphi文字转语音TTS【支持选择语音库,播放,暂停,开始,停止,生成语音文件,设置音量,设置语速】
作者QQ:(648437169) 点击下载➨文字转语音TTS [Delphi 文字转语音TTS]调用系统自带的TTS组件,支持XP,vista,win7,win8,win10系统,支持选择语音库,播放 ...
随机推荐
- VLC 可能的 XML parser error 解决
由于 VLC 设置不当 (通常是动了 skin 选项……),再次加载时 VLC 不能正常启动,并报如下错误: [00007f7dd003b670] xml xml reader error: XML ...
- 认识Caffe与Caffe2
认识Caffe与Caffe2 目录: 一.Caffe的作者-贾扬清 二.Caffe简介--Caffe.Caffe2.Caffe2Go 三.认识Caffe 四.认识Caffe2 五.认识Caffe2Go ...
- 前端知识体系:JavaScript基础-原型和原型链-理解原型设计模式以及 JavaScript中的原型规则
理解原型设计模式以及 JavaScript中的原型规则(原文地址) 1.原型对象:我们创建的每一个函数(JavaScript中函数也是一个对象)都有一个原型属性 prototype,原型属性实质上是一 ...
- barcode模块: plus.barcode.scan 进行扫描图片出现无法识别二维码,打印的错误信息是code:8,message:''
原因之一:图片的像素太大了,无法识别. 解决方法: 压缩一下图片. 这里的 data 我放了一个 像素为 4040 × 4040 的 图片. 进行识别的时候会报, (无法识别的图片,都是返回这些值) ...
- modbus-crc16——c语言
为确保消息数据的完整性,除了验证消息CRC之外,建议实现检查串行端口(UART)成帧错误的代码.如果接收消息中的CRC与接收设备计算的CRC不匹配,则应忽略该消息.下面的C语言代码片段显示了如何使用逐 ...
- CodeForces 839D - Winter is here | Codeforces Round #428 (Div. 2)
赛后听 Forever97 讲的思路,强的一匹- - /* CodeForces 839D - Winter is here [ 数论,容斥 ] | Codeforces Round #428 (Di ...
- 【Wince-禁止重复启动程序】Wince 不重复启动程序
创建类Mutex.cs: using System; using System.Linq; using System.Collections.Generic; using System.Text; u ...
- Elasticsearch7.1中文文档-第一章-入门
安装openjdk wget --no-cookies --no-check-certificate --header "Cookie: oraclelicense=accept-secur ...
- springbootdruidmybatismysql多数据源事务管理
springboot+druid+mybatis+mysql+多数据源事务管理 分布式事务在java中的解决方案就是JTA(即Java Transaction API):springboot官方提供了 ...
- hdu 2510
Tiling_easy version Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...