语音文件 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.util.NoSuchElementException
问题引入 Java商店作业不同函数里需要获取用户输入,用Scanner的时候,出现了异常java.util.NoSuchElementException 作业中代码模式如下,func1和func2中都 ...
- JavaScript教程——this 关键字
简单说,this就是属性或方法“当前”所在的对象. 原文地址:https://wangdoc.com/javascript/oop/this.html
- BZOJ3157 国王奇遇记——神奇的推式子
先膜一发Miskcoo,大佬的博客上多项式相关的非常全 原题戳我 题目大意 求 \[\sum\limits_{i=1}^{n}i^mm^i\] 题解 设一个函数\(f(i)=\sum\limits_{ ...
- SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚
通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...
- hivesql中的concat函数,concat_ws函数,concat_group函数之间的区别
一.CONCAT()函数CONCAT()函数用于将多个字符串连接成一个字符串.使用数据表Info作为示例,其中SELECT id,name FROM info LIMIT 1;的返回结果为 +---- ...
- Bootstrap-轮播图-No.6
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- 洛谷P1020 导弹拦截【单调栈】
题目:https://www.luogu.org/problemnew/show/P1020 题意: 给定一些导弹的高度. 一个导弹系统只能拦截高度不增的一系列导弹,问如果只有一个系统最多能拦截多少导 ...
- 如何使用Hasu USB to USB Controller Converter刷写tmk固件交换Caps和Ctrl
相关链接 购买Hasu USB to USB Controller Converter:https://www.1upkeyboards.com/shop/controllers/usb-to-usb ...
- spring-boot-configuration-processor 是干啥用的
spring默认使用yml中的配置,但有时候要用传统的xml或properties配置,就需要使用spring-boot-configuration-processor了 引入pom依赖 <de ...
- laravel Passport - Dingo/Api v2.0+Passport 实现 api 认证
第一部分: 安装passport 使⽤ Composer 依赖包管理器安装 Passport : composer require laravel/passport 接下来,将 Passport 的服 ...