语音文件 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系统,支持选择语音库,播放 ...
随机推荐
- java——多线程并发库
JDK5中增加了Doug Lea的并发库,这一引进给Java线程的管理和使用提供了强大的便利性. java.util.current包中提供了对线程优化.管理的各项操作,使得线程的使用变得的心应手.该 ...
- R中数据的输入和数据的标注
数据的导入 默认情况下数据导入时,字符型变量将转化为因子.若不希望转化,可设置 stringsAsFactors=FALSE 从带分隔符的文本文件中导入数据 read.table() file --& ...
- 2-删除IPC$的方式
一.使用命令临时删除IPC$的方式 1.查看IPC$是否启用 命令:net share 2.删除IPC$功能 命令:net share ipc$ /delete 注:使用命令删除后,重启服务器后,IP ...
- setTimeout设置为0 为啥不能立马执行
setTimeout(function(){}, timer) 是指延时执行.第一个参数是回调函数,第二个参数是指延时多久执行回调函数. setTimeout(function(){console.l ...
- BZOJ 2458: [BeiJing2011]最小三角形 (分治)
分治就是了. 类似于分治找最近/远点对. CODE #include <bits/stdc++.h> using namespace std; const double eps = 1e- ...
- 5、docker容器数据卷: -v添加共享传递容器数据卷
1.是什么 1.docker理念 先来看看Docker的理念:* 将运用与运行的环境打包形成容器运行 ,运行可以伴随着容器,但是我们对数据的要求希望是持久化的* 容器之间希望有可能共享数据 2.保 ...
- 【Android-开发环境】 eclipse开发环境搭建
1.下载安装JDK jdk下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.htm ...
- 【ArcMap】
1.加载图层(1)内容列表中右键添加数据(2)目录列表中拖拽(3)导航中的添加数据 2.编辑要素(1)选中编辑器点击开始编辑(2)在编辑要素中选中要编辑的要素 选择构造工具 执行编辑操作(3)停止编辑 ...
- More development resources
社区 名称 官网 google https://www.google.com/ github https://github.com/ StackOverflow https://stackoverfl ...
- Java项目出现的问题02----学习
1 框架配置无.java 在框架配置中当需要写类名是,注意是没有后面.java的 2 类中找不到main方法请将main方法定义为public static void main. 否则 JavaFX ...