基础知识

度量声音强度。大家最熟悉的单位就是分贝(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. NOIP2018提高组省一冲奖班模测训练(三)

    NOIP2018提高组省一冲奖班模测训练(三) 自己按照noip的方式考,只在最后一两分钟交了一次 第一题过了,对拍拍到尾. 第二题不会.考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还 ...

  2. 自备LocalDateTime工具类

    package cn.zytao.taosir.common.utils; import java.time.Instant; import java.time.LocalDate; import j ...

  3. 【codeforces 799D】Field expansion

    [题目链接]:http://codeforces.com/contest/799/problem/D [题意] 给你长方形的两条边h,w; 你每次可以从n个数字中选出一个数字x; 然后把h或w乘上x; ...

  4. Xshell 安装 Xftp

    一.下载 Xftp 链接:https://pan.baidu.com/s/1dGeL2gD 密码:as9x 二.安装 Xftp 无脑下一步 三.点击 Xshell 上的新建文件传输 四.弹出 xftp ...

  5. 使用jmap和MAT分析JVM堆内存

    http://blog.csdn.net/alli0968/article/details/52460008

  6. XML 解析---dom解析和sax解析

    眼下XML解析的方法主要用两种: 1.dom解析:(Document Object Model.即文档对象模型)是W3C组织推荐的解析XML的一种方式. 使用dom解析XML文档,该解析器会先把XML ...

  7. Navgationcontroller 的pop

    1.NavgationController pop 回来不进入viewdisload,利用原来载入的视图 不是啊,他pop回来的时候不进viewdidload 直接进去viewwillApper这种方 ...

  8. Spring中@Transactional事务回滚(含实例具体解说,附源代码)

    一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用. 以下举个栗子:比方一个部门里面有非常多成员,这两者分别保存在部门表和成员表里面,在 ...

  9. ORA-01261: Parameter db_recovery_file_dest destination string cannot be translat

    查看了Oracle的初始化文件. $cat /oracle/oms/102_64/dbs/initSID.ora 如:db_recovery_file_dest='/oracle/oms/flash_ ...

  10. Another app is currently holding the yum lock; waiting for it to exit…

    yum被锁定无法使用,错误信息截图如下:解决方法:rm -rf /var/run/yum.pid 来强行解除锁定,然后你的yum就可以运行了