Android 获取麦克风的音量(分贝)
基础知识
度量声音强度。大家最熟悉的单位就是分贝(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();
} }
測试结果
Android 获取麦克风的音量(分贝)的更多相关文章
- android小工具-系统音量管理器
简介:调节系统音量的小工具,能够快捷的调节系统铃声,媒体音乐.闹钟和通话声音.你可能会想,手机自带的音量键还不够快捷吗?还得写个程序?首先,用音量键调音只能调节一种声音,像闹钟这种声音不能直接调.其次 ...
- Android获取内置sdcard跟外置sdcard路径
Android获取内置sdcard跟外置sdcard路径.(测试过两个手机,亲测可用) 1.先得到外置sdcard路径,这个接口是系统提供的标准接口. 2.得到上一级文件夹目录 3.得到该目录的所有文 ...
- Android获取系统时间方法的总结
Android获取系统时间方法的方法有很多种,常用的有Calendar.Date.currentTimeMills等方法. (1)Calendar Calendar获取系统时间首先要用Calendar ...
- Android获取屏幕宽和高
android获取屏幕的高度和宽度用到WindowManager这个类,两种方法: 1.WindowManager wm = (WindowManager) getContext() ...
- android 获取文件夹、文件的大小 以B、KB、MB、GB 为单位
android 获取文件夹.文件的大小 以B.KB.MB.GB 为单位 public class FileSizeUtil { public static final int SIZETYPE_B ...
- Android获取APK包名的几种方法
Android获取APK包名的几种方法:1.adb shell pm list package -f | findstr 关键字 #只能获取到包名,主Activity名无法获取到 2.使用aapt-- ...
- Flex显示麦克风当前音量
Flex动态显示麦克风当前音量 效果: 代码: <?xml version="1.0" encoding="utf-8"?> <s:Appli ...
- I.MX6 android 获取framebuffer信息
/******************************************************************************** * I.MX6 android 获取 ...
- android 获取IMEI号
android 获取 imei号码 核心代码: Imei = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId( ...
随机推荐
- "随笔"列表 - 按时间先后顺序排列
这是一个测试 linux采用scp命令拷贝文件到本地,拷贝本地文件到远程服务器 美化博客园 virtual box虚拟机在linux下设置共享文件夹 纯净版linux (debian)挂载Virtua ...
- C# .net IDE Rider入门
话说史上最强IDE Visual Studio 所向披靡数十载尚无敌手,现在Intellij带着统一IDE界的目标来挑战VS的霸主地位.了解Rider后发现,哎哟亮点多多,还不错哦! Rider是一款 ...
- 浅谈密码加SALT原理
我们知道,如果直接对密码进行散列,那么黑客可以对通过获得这个密码散列值,然后通过查散列值字典(例如MD5密码破解网站),得到某用户的密码. 加Salt可以一定程度上解决这一问题.所谓加Salt方法, ...
- MyBatis初始化
1. 准备工作 为了看清楚MyBatis的整个初始化过程,先创建一个简单的Java项目,目录结构如下图所示: 1.1 Product 产品实体类 public class Product { priv ...
- 上机题目(0基础)-计算两个正整数的最大公约数和最小公倍数(Java)
题目例如以下:
- debian mysql 定时自己主动备份的脚本
#!/bin/sh LOG=/var/log/mysql-backup.log # mysql db info USER_ROOT=XXXXXX USER_PWD=XXXXXXX # mysql da ...
- div在父集高度未知的情况下垂直居中的方法
父集高度未知,子集高度已知: 可以使用弹性盒来解决: justify-content属性定义了项目在主轴上的对齐方式. align-items属性定义项目在交叉轴上如何对齐.
- elementUI 易错点
1.element table里面添加单选时,如果存在下拉框的筛选功能,那么每次下拉框筛选条件变化时 都得清空之前选中的信息,如果不数据更新后如果更新后的数据跟之前选中的相同 则会无法选中
- jquery的clone()引发的问题,下拉框点击没有反应
此段代码是对某块元素的移位:上移.下移.对比修改前后的两段代码: 修改前: //点击移位 function move(obj,posi){ var al=$(obj).parent('li').par ...
- Dos.ORM使用教程
Dos.C#.Net使用 Dos.ORM(原Hxj.Data)于2009年发布,并发布实体生成工具.在开发过程参考了多个ORM框架,特别是NBear,MySoft.EF.Dapper等.吸取了他们的一 ...