基础知识

度量声音强度。大家最熟悉的单位就是分贝(decibel,缩写为dB)。这是一个无纲量的相对单位。计算公式例如以下:

分子是測量值的声压,分母是參考值的声压(20微帕。人类所能听到的最小声压)。

因此日常中说道声音强度是多少多少分贝时。都是默认了一个非常小的參考值的。

而Android设备传感器能够提供的物理量是场的幅值(amplitude),经常使用下列公式计算分贝值:

从SDK中读取了某段音频数据的振幅后,取最大振幅或平均振幅(能够用平方和平均,或绝对值的和平均)。代入上述公式的A1。

如今问题是,作为參考值的振幅A0取多少呢?

博主查阅非常多帖子、博文,这里是最一团浆糊的地方。

有的博文取600,是基于它视噪音的振幅为600的如果。此时算出来的是相对背景噪音的分贝值。要是用户不正确麦克风发出声音,算出的基本都是0分贝。而用户实际使用场景下的背景噪音大小千差万别。咱要是也照葫芦画瓢就不正确了。尤其是对于那些制作绝对分贝计的需求,应找出20微帕声压值相应的振幅(或者也能够拿一个标准分贝计做校准參考)。

博主比較懒,把A0定为1,即Android设备麦克风所能”听“到的最小声音振幅。

这样拿到測量值振幅直接代入第二个公式的A1中,就可以算出分贝值了。

Android API

使用麦克风须要在AndroidManifest.xml里申请对应权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

可以获得音源数据的类有两个:android.media.MediaRecorder和android.media.AudioRecord

MediaRecorder:

这个类的对象初始化比較麻烦。由于它是被设计用来录制一段完整的音频并写入文件系统中的。可是初始化之后获得振幅却比較方便,我们直接用它的无參方法getMaxAmplitude就可以获得一小段时间内音源数据中的最大振幅。

只是取最大值的可能弊端是会受到极端数据的影响。使得后来计算的分贝值波动比較大。只是这种方法是非常多录音应用计算音量等级所採用的办法。

该方法返回的是0到32767范围的16位整型。原理可能是对一段值域为-32768到32767的音源数据取当中绝对值最大的值并返回。这个值与单位为帕斯卡的声压值是有线性函数关系的。另外须要注意的是第一次调用这种方法取得的值是0,代入公式中算出的分贝值是负无穷大。故须要在代码中对这样的情况做推断。能够算出。因为getMaxAmplitude返回的数值最大是32767,因此算出的最大分贝值是90.3。

也就是说。博主令參考振幅值为1。计算出的分贝值正常值域为0 dB 到90.3 dB

代码片:

package com.example.atest;

import java.io.File;
import java.io.IOException; import android.media.MediaRecorder;
import android.os.Handler;
import android.util.Log; /**
* amr音频处理
*/
public class MediaRecorderDemo {
private final String TAG = "MediaRecord";
private MediaRecorder mMediaRecorder;
public static final int MAX_LENGTH = 1000 * 60 * 10;// 最大录音时长1000*60*10;
private String filePath; public MediaRecorderDemo(){
this.filePath = "/dev/null";
} public MediaRecorderDemo(File file) {
this.filePath = file.getAbsolutePath();
} private long startTime;
private long endTime; /**
* 開始录音 使用amr格式
*
* 录音文件
* @return
*/
public void startRecord() {
// 開始录音
/* ①Initial:实例化MediaRecorder对象 */
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
try {
/* ②setAudioSource/setVedioSource */
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风
/* ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的採样 */
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
/*
* ②设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式
* 。H263视频/ARM音频编码)、MPEG-4、RAW_AMR(仅仅支持音频且音频编码要求为AMR_NB)
*/
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); /* ③准备 */
mMediaRecorder.setOutputFile(filePath);
mMediaRecorder.setMaxDuration(MAX_LENGTH);
mMediaRecorder.prepare();
/* ④開始 */
mMediaRecorder.start();
// AudioRecord audioRecord.
/* 获取開始时间* */
startTime = System.currentTimeMillis();
updateMicStatus();
Log.i("ACTION_START", "startTime" + startTime);
} catch (IllegalStateException e) {
Log.i(TAG,
"call startAmr(File mRecAudioFile) failed!"
+ e.getMessage());
} catch (IOException e) {
Log.i(TAG,
"call startAmr(File mRecAudioFile) failed!"
+ e.getMessage());
}
} /**
* 停止录音
*
*/
public long stopRecord() {
if (mMediaRecorder == null)
return 0L;
endTime = System.currentTimeMillis();
Log.i("ACTION_END", "endTime" + endTime);
mMediaRecorder.stop();
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
Log.i("ACTION_LENGTH", "Time" + (endTime - startTime));
return endTime - startTime;
} private final Handler mHandler = new Handler();
private Runnable mUpdateMicStatusTimer = new Runnable() {
public void run() {
updateMicStatus();
}
}; /**
* 更新话筒状态
*
*/
private int BASE = 1;
private int SPACE = 100;// 间隔取样时间 private void updateMicStatus() {
if (mMediaRecorder != null) {
double ratio = (double)mMediaRecorder.getMaxAmplitude() /BASE;
double db = 0;// 分贝
if (ratio > 1)
db = 20 * Math.log10(ratio);
Log.d(TAG,"分贝值:"+db);
mHandler.postDelayed(mUpdateMicStatusTimer, SPACE);
}
}
}

AudioRecord:

这个类能够获得详细的音源数据值。将一段音源数据用read(byte[] audioData, int offsetInBytes, int sizeInBytes)方法从缓冲区读取到我们传入的字节数组audioData后,便能够对其进行操作。如求平方和或绝对值的平均值。这样能够避免个别极端值的影响。使计算的结果更加稳定。求得平均值之后。假设是平方和则代入常数系数为10的公式中。假设是绝对值的则代入常数系数为20的公式中,算出分贝值。

代码片

package com.example.atest;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log; public class AudioRecordDemo { private static final String TAG = "AudioRecord";
static final int SAMPLE_RATE_IN_HZ = 8000;
static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ,
AudioFormat.CHANNEL_IN_DEFAULT, AudioFormat.ENCODING_PCM_16BIT);
AudioRecord mAudioRecord;
boolean isGetVoiceRun;
Object mLock; public AudioRecordDemo() {
mLock = new Object();
} public void getNoiseLevel() {
if (isGetVoiceRun) {
Log.e(TAG, "还在录着呢");
return;
}
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE_IN_HZ, AudioFormat.CHANNEL_IN_DEFAULT,
AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE);
if (mAudioRecord == null) {
Log.e("sound", "mAudioRecord初始化失败");
}
isGetVoiceRun = true; new Thread(new Runnable() {
@Override
public void run() {
mAudioRecord.startRecording();
short[] buffer = new short[BUFFER_SIZE];
while (isGetVoiceRun) {
//r是实际读取的数据长度,一般而言r会小于buffersize
int r = mAudioRecord.read(buffer, 0, BUFFER_SIZE);
long v = 0;
// 将 buffer 内容取出。进行平方和运算
for (int i = 0; i < buffer.length; i++) {
v += buffer[i] * buffer[i];
}
// 平方和除以数据总长度,得到音量大小。
double mean = v / (double) r;
double volume = 10 * Math.log10(mean);
Log.d(TAG, "分贝值:" + volume);
// 大概一秒十次
synchronized (mLock) {
try {
mLock.wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}).start();
}
}

代码的调用Activity

package com.example.atest;

import android.app.Activity;
import android.os.Bundle; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new AudioRecordDemo().getNoiseLevel();
} }

測试结果

源代码下载地址:http://download.csdn.net/detail/pcaxb/9028495

Android 获取麦克风的音量(分贝)的更多相关文章

  1. android小工具-系统音量管理器

    简介:调节系统音量的小工具,能够快捷的调节系统铃声,媒体音乐.闹钟和通话声音.你可能会想,手机自带的音量键还不够快捷吗?还得写个程序?首先,用音量键调音只能调节一种声音,像闹钟这种声音不能直接调.其次 ...

  2. Android获取内置sdcard跟外置sdcard路径

    Android获取内置sdcard跟外置sdcard路径.(测试过两个手机,亲测可用) 1.先得到外置sdcard路径,这个接口是系统提供的标准接口. 2.得到上一级文件夹目录 3.得到该目录的所有文 ...

  3. Android获取系统时间方法的总结

    Android获取系统时间方法的方法有很多种,常用的有Calendar.Date.currentTimeMills等方法. (1)Calendar Calendar获取系统时间首先要用Calendar ...

  4. Android获取屏幕宽和高

    android获取屏幕的高度和宽度用到WindowManager这个类,两种方法:   1.WindowManager wm = (WindowManager) getContext()        ...

  5. android 获取文件夹、文件的大小 以B、KB、MB、GB 为单位

    android 获取文件夹.文件的大小 以B.KB.MB.GB 为单位   public class FileSizeUtil { public static final int SIZETYPE_B ...

  6. Android获取APK包名的几种方法

    Android获取APK包名的几种方法:1.adb shell pm list package -f | findstr 关键字 #只能获取到包名,主Activity名无法获取到 2.使用aapt-- ...

  7. Flex显示麦克风当前音量

    Flex动态显示麦克风当前音量 效果: 代码: <?xml version="1.0" encoding="utf-8"?> <s:Appli ...

  8. I.MX6 android 获取framebuffer信息

    /******************************************************************************** * I.MX6 android 获取 ...

  9. android 获取IMEI号

    android 获取 imei号码 核心代码: Imei = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId( ...

随机推荐

  1. [剑指offer] 8+9. 跳台阶+变态跳台阶 (递归 时间复杂度)

    跳台阶是斐波那契数列的一个典型应用,其思路如下: # -*- coding:utf-8 -*- class Solution: def __init__(self): self.value=[0]*5 ...

  2. C# 上位机的USB设备拔插检测

    我们做USB通信时,通信成功后,往往要检测USB设备的拔插状态,这里就USB拔插进行一下说明. 参考:https://www.imooc.com/article/17438 先说明一下,我这里只是用C ...

  3. 一行代码解决IE兼容性问题

    在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE给出了解决方案Google也给出了解决方案百度也应用了这种方案去解决IE的兼容问题 百度源代码如下 <!Doctype html> ...

  4. js数字转换为float,取N个小数

    javascript中的变量都是弱类型,所有的变量都声明为var,在类型转换过程中就没有java那么方便,它是通过 parseInt(变量).parseFloat(变量)等方法来进行类型转换的.注意: ...

  5. javascript-js常用插件集合

    area.js 中国地区分级的js代码  Scripts/crypto.js  CryptoJS (crypto.js) 为 JavaScript 提供了各种各样的加密算法               ...

  6. jquery访问ashx文件示例

    转自原文jquery访问ashx文件示例 .ashx 文件用于写web handler的..ashx文件与.aspx文件类似,可以通过它来调用HttpHandler类,它免去了普通.aspx页面的控件 ...

  7. 日志工具全面理解及配置应用---以Log4j例子

    一.日志系统基本常识 1.日志系统作用:将日志信息输出到控制台和文本文件,以追踪代码运行信息. 2.日志系统操作的是什么?日志系统打印信息,也是调用日志系统的log.Info(),log.Warn() ...

  8. java语言MySQL批处理

    本质来讲就是使用Statement和PreStatement的addBatch()方法 代码 import java.sql.*; public class GetConnection{ public ...

  9. java之 ------ DAO设计模式的【具体解释】及常见设计模式的【应用】

    DAO Data Access Object(数据訪问接口) 一.场景和问题 在Java程序中.常常须要把数据持久化,也须要获取持久化的数据.可是在进行数据持久化的过程中面临诸多问题(如:数据源 不同 ...

  10. Struts2学习(四)利用ajax异步上传

    上一篇说到怎样在struts2中进行上传下载.我们使用了struts的标签通过表单提交的方式,但大家知道表单提交会造成页面总体的刷新,这样的方式很不友好,那我们今天就来说说怎样结合ajax方式进行异步 ...