通过Android录音进行简单音频分析
Android录音有MediaRecorder和AudioRecord两种方式,前者使用方便,可以直接生成录音文件,但是录音格式为aac和amr等等,都经过压缩处理,不方便进行音频分析。
而用AudioRecord可以得到PCM编码的原音频数据,可以用FFT对数据进行处理,简单分析声音的频率。
1.AndroidRecord录音
private static final String FILE_NAME = "MainMicRecord";
private static final int SAMPLE_RATE = 44100;//Hz,采样频率
private static final double FREQUENCY = 500; //Hz,标准频率(这里分析的是500Hz)
private static final double RESOLUTION = 10; //Hz,误差
private static final long RECORD_TIME = 2000;
private File mSampleFile;
private int bufferSize=0;
private AudioRecord mAudioRecord; private void startRecord() {
try {
mSampleFile = new File(getFilesDir()+"/"+FILE_NAME);
if(mSampleFile.exists()){
if(!mSampleFile.delete()){
return;
}
}
if(!mSampleFile.createNewFile()){
return;
}
} catch(IOException e) {
return;
}
//为了方便,这里只录制单声道
//如果是双声道,得到的数据是一左一右,注意数据的保存和处理
bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize);
mAudioRecord.startRecording();
new Thread(new AudioRecordThread()).start();
} private class AudioRecordThread implements Runnable{
@Override
public void run() {
//将录音数据写入文件
short[] audiodata = new short[bufferSize/2];
DataOutputStream fos = null;
try {
fos = new DataOutputStream( new FileOutputStream(mSampleFile));
int readSize;
while (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){
readSize = mAudioRecord.read(audiodata,0,audiodata.length);
if(AudioRecord.ERROR_INVALID_OPERATION != readSize){
for(int i = 0;i<readSize;i++){
fos.writeShort(audiodata[i]);
fos.flush();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
} //在这里release
mAudioRecord.release();
mAudioRecord = null;
}
}
}; //在这里stop的时候先不要release
private void stopRecording() {
mAudioRecord.stop();
} //对录音文件进行分析
private void frequencyAnalyse(){
if(mSampleFile == null){return;
}
try {
DataInputStream inputStream = new DataInputStream(new FileInputStream(mSampleFile));
//16bit采样,因此用short[]
//如果是8bit采样,这里直接用byte[]
//从文件中读出一段数据,这里长度是SAMPLE_RATE,也就是1s采样的数据
short[] buffer=new short[SAMPLE_RATE];
for(int i = 0;i<buffer.length;i++){
buffer[i] = inputStream.readShort();
}
short[] data = new short[FFT.FFT_N]; //为了数据稳定,在这里FFT分析只取最后的FFT_N个数据
System.arraycopy(buffer, buffer.length - FFT.FFT_N,
data, 0, FFT.FFT_N); //FFT分析得到频率
double frequence = FFT.GetFrequency(data);
if(Math.abs(frequence - FREQUENCY)<RESOLUTION){
//测试通过
}else{
//测试失败
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.FFT实现
参考:http://introcs.cs.princeton.edu/java/97data/FFT.java.html
(1)复数类
public class Complex { public double real, imag; public Complex(double real,double im){
this.real = real;
this.imag = im;
} public Complex(){
this(0,0);
} public Complex(Complex c){
this(c.real,c.imag);
} @Override
public String toString() {
return "("+this.real+"+"+this.imag +"i)";
} //加法
public final Complex add(Complex c){
return new Complex(this.real+c.real,this.imag +c.imag);
} //减法
public final Complex minus(Complex c){
return new Complex(this.real-c.real,this.imag -c.imag);
} //求模值
public final double getMod(){
return Math.sqrt(this.real * this.real+this.imag * this.imag);
} //乘法
public final Complex multiply(Complex c){
return new Complex(
this.real*c.real - this.imag *c.imag,
this.real*c.imag + this.imag *c.real);
}
}
(2)FFT求最大频率
public class FFT {
public static final int FFT_N = 4096;
public static final int SAMPLE_RATE = 44100; //HZ //快速傅里叶变换
public static Complex[] getFFT(Complex[] data){
int N = data.length;
if(N==1){
return new Complex[]{data[0]};
}
if(N%2 != 0){
throw new RuntimeException("N is not a power of 2");
} //fft of even/odd terms
Complex[] even = new Complex[N/2];
Complex[] odd = new Complex[N/2];
for(int k = 0;k<N/2;k++){
even[k] = data[2*k];
odd[k] = data[2*k+1];
}
Complex[] q= getFFT(even);
Complex[] r = getFFT(odd); Complex[] y = new Complex[N];
for (int k = 0;k<N/2;k++){
double kth = -2*k*Math.PI/N;
Complex wk = new Complex(Math.cos(kth), Math.sin(kth));
y[k] = q[k].add(wk.multiply(r[k]));
y[k+N/2] = q[k].minus(wk.multiply(r[k]));
} return y;
} //================================================================
public static double GetFrequency(short[] data){
Log.i("FFT","GetFrequency");
if(data.length<FFT_N){
throw new RuntimeException("Data length lower than "+FFT_N);
}
Complex[] f = new Complex[FFT_N];
for(int i=0;i<FFT_N;i++){
f[i] = new Complex(data[i],0); //实部为正弦波FFT_N点采样,赋值为1
//虚部为0
} f = getFFT(f); //进行快速福利叶变换
// String str = "";
// for(int i = 0;i<FFT_N;i++){
// str+=f[i].toString()+" ";
// }
// Log.i("FFT","fft: "+str);
double[] s = new double[FFT_N/2];
// str = "";
for(int i=0;i<FFT_N/2;i++){
s[i] = f[i].getMod();
// str += ""+s[i]+" ";
}
// Log.i("FFT","s: "+str); int fmax=0;
for(int i=1;i<FFT_N/2;i++){ //利用FFT的对称性,只取前一半进行处理
if(s[i]>s[fmax])
fmax=i; //计算最大频率的序号值
}
// Log.i("FFT","max index:"+fmax+" fft:"+f[fmax]+" s:"+s[fmax]);
double fre = fmax*(double)SAMPLE_RATE / FFT_N;
Log.i("FFT","fre:"+fre);
return fre;
}
}
通过Android录音进行简单音频分析的更多相关文章
- Android.mk文件简单分析
Android.mk文件简单分析 一个Android.mk文件用来向编译系统描写叙述须要编译的源码.详细来说:该文件是GNUMakefile的一小部分.会被编译系统解析一次或多次. 能够在每个Andr ...
- Android智能手机上的音频浅析
手机可以说是现在人日常生活中最离不开的电子设备了.它自诞生以来,从模拟的发展到数字的,从1G发展到目前的4G以及不久将来的5G,从最初的只有唯一的功能(打电话)发展到目前的全功能,从功能机(featu ...
- Android 录音和播放
今天工作上需要做一个一边录音一边播放的功能,大致原因是有一个外部设备输入音频到我们机器,然后我们机器需要马上把音频播放出来.所以了解了一些有关录音和播放的知识.接到这个任务的第一反应就是看看Andro ...
- Android智能手机上的音频浅析【转】
本文转载自:https://blog.csdn.net/david_tym/article/details/80903385 手机可以说是现在人日常生活中最离不开的电子设备了.它自诞生以来,从模拟的发 ...
- (转)Android 系统 root 破解原理分析
现在Android系统的root破解基本上成为大家的必备技能!网上也有很多中一键破解的软件,使root破解越来越容易.但是你思考过root破解的 原理吗?root破解的本质是什么呢?难道是利用了Lin ...
- [Android]Android系统启动流程源码分析
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5013863.html Android系统启动流程源码分析 首先 ...
- 【Android】【录音】Android录音--AudioRecord、MediaRecorder
[Android][录音]Android录音--AudioRecord.MediaRecorder Android提供了两个API用于实现录音功能:android.media.AudioRecord. ...
- Android智能手机中各种音频场景下的audio data path
上一篇文章(Android智能手机上的音频浅析)说本篇将详细讲解Android智能手机中各种音频场景下的音频数据流向,现在我们就开始.智能手机中音频的主要场景有音频播放.音频录制.语音通信等.不同场景 ...
- audacity 做音频分析之--初相识
软件介绍: Audacity是一个跨平台的声音编辑软件,用于录音和编辑音频,是自由.开放源代码的软件.可在Mac OS X.Microsoft Windows.GNU/Linux和其它操作系统上运作. ...
随机推荐
- MFC 文件对话框
文件对话框的分类 文件对话框分为打开文件对话框和保存文件对话框,相信大家在Windows系统中经常见到这两种文件对话框.例如,很多编辑软件像记事本等都有"打开"选项,选择" ...
- Appium运行时,error: Logcat capture failed: spawn ENOENT的解决办法
目前发现有以下两种可能: 一:查看环境变量是否配置成功. ANDROIDSDK D:\my_2_softwares\JAVA\adt-bundle-windows-x86-20140702\sdkPA ...
- bootstrap学习总结-02 网格布局
1 网格布局 Bootstrap 提供了一套响应式.移动设备优先的流式栅格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列. <!DOCTYPE html> ...
- [转发]Dumps of system information with Apple computers
In this article, I gathered up all the dumps, who found. If you see something new table will be upda ...
- Cross-Site Scripting(XSS)简介
最近才开始研究HTML以及安全问题.如果有什么说得不对的地方,望请指出. 在网络应用安全中,XSS可能是最常见,范围最大,所包含攻击方法最多,同时也是最难以理解的一种攻击.在OWASP所列出的十大网络 ...
- nginx访问日志获取访问前10的url
在ELK里面获取top10的url在日志量非常大的情况下是非常消耗内存的,所以写了一个脚本用来快速获取. 配置文件 log.conf [log] log_file = /data/logs/nginx ...
- jquery 解析数据库中的json日期为正常的格式
//在action从后台数据库中请求获得日期以后,得到的是json格式的数据,因此要解析才能显示在前台1.在jsp页面写的代码如下:<html> <script> Date.p ...
- pyqt2_官网教程
https://pythonspot.com/en/pyqt4/ Articles You can find a collection of PyQT articles below. Applicat ...
- C#中使用DateTimePicker控件显示修改日期时间
1.只显示日期 默认就是 2.只显示时间 修改属性 Format 设为Time ShowUpDown设为true 3.同时显示日期时间 Format设为Custom CustomF ...
- JAVA 的普通加法运算
利用Scanner类,其中数字输入的函数,利用while循环结构来得到输入的实数,当输入的是字母时,结束循环 源代码: package ccc;import java.util.*;public cl ...