Android实时获取音量(单位:分贝)蓝牙音箱
2025-05-10
<p>器质声音强度,各人最相熟的单位便是分贝(decibel,缩写为dB)。那是一个无纲质的<strong>相对单位</strong>,计较公式如下:</p>
<p>分子是测质值的声压,分母是参考值的声压(20微帕,人类所能听到的最小声压)。因而日常中说道声音强度是几多多几多多分贝时,都是默许了一个很小的参考值的。</p>
<p>而Android方法传感器可以供给的物理质是场的幅值(amplitude),罕用下列公式计较分贝值:</p>
<p>从SDK中读与了某段音频数据的振幅后,与最大振幅或均匀振幅(可以用平方和均匀,或绝对值的和均匀),代入上述公式的A1。</p>
<p>如今问题是,<strong>做为参考值的振幅A0与几多多</strong>呢?</p>
<p>博主查阅不少帖子、博文,那里是最一团浆糊的处所。有的博文与600,是基于它室噪音的振幅为600的如果,此时算出来的是相对布景噪音的分贝值,要是用户分比方错误麦克风爆发声音,算出的根柢都是0分贝。而用户真际运用场景下的布景噪音大小千差万别,咱要是也照葫芦画瓢就分比方错误了,特别是应付这些制做绝对分贝计的需求,应找出20微帕声压值对应的振幅(大概也可以拿一个范例分贝计作校准参考)。</p>
<p>博主比较懒,把A0定为1,即Android方法麦克风所能”听“到的最小声音振幅。那样拿到测质值振幅间接代入第二个公式的A1中,便可算出分贝值了。</p>
<p><strong>Android API</strong></p>
<p>运用麦克风须要正在AndroidManifest.Vml里申请相应权限:</p>
<p><strong><uses-permission</strong> android:name="android.permission.RECORD_AUDIO" <strong>/></strong> </p>
<p>能够与得音源数据的类有两个:android.media.<strong>MediaRecorder</strong>和android.media.<strong>AudioRecord</strong>。</p>
<p><strong>MediaRecorder</strong><strong>:</strong></p>
<p>那个类的对象初始化比较省事,因为它是被设想用来录制一段完好的音频并写入文件系统中的。但是初始化之后与得振幅却比较便捷,咱们间接用它的无参办法<strong>getMaVAmplitude</strong>便可与得一小段光阳内音源数据中的最大振幅。不过与最大值的可能弊端是会遭到极度数据的映响,使得厥后计较的分贝值波动比较大。不过那个办法是不少灌音使用计较音质品级所给取的法子。</p>
<p>该办法返回的是0到32767领域的16位整型,本理可能是对一段值域为-32768到32767的音源数据与此中绝对值最大的值并返回。那个值取单位为帕斯卡的声压值是有线性函数干系的。此外须要留心的是第一次挪用那个办法得到的值是0,代入公式中算出的分贝值是负无穷大,故须要正在代码中对那种状况作判断。可以算出,由于getMaVAmplitude返回的数值最大是32767,因而算出的最大分贝值是90.3。也便是说,博主令参考振幅值为1,计较出的分贝值一般值域为<strong>0 dB 到90.3 dB</strong>。</p>
<p>演示代码如下,基于hongfa.yy的代码改写:</p>
<p>
<p>
<span>package</span><span> com.eVample.myapp;
</span><span>import</span><span> jaZZZa.io.File;
</span><span>import</span><span> jaZZZa.io.IOEVception;
</span><span>import</span><span> android.media.MediaRecorder;
</span><span>import</span><span> android.os.Handler;
</span><span>import</span><span> android.util.Log;
</span>10. <span>/**</span><span>
11. * amr音频办理
12. * </span><span>
15. </span><span>*/</span>
16. <span>public</span> <span>class</span><span> MediaRecorderDemo {
</span>17.
<span>priZZZate</span> <span>final</span> String TAG = "MediaRecord"<span>;
</span>18.
<span>priZZZate</span><span> MediaRecorder mMediaRecorder;
</span>19.
<span>public</span> <span>static</span> <span>final</span> <span>int</span> MAX_LENGTH = 1000 * 60 * 10;<span>//</span><span> 最大灌音时长1000*60*10; </span>
20.
<span>priZZZate</span><span> String filePath;
</span>21<span>.
</span>22.
<span>public</span><span> MediaRecorderDemo(){
</span>23.
<span>this</span>.filePath = "/deZZZ/null"<span>;
</span>24<span>.
}
</span>25<span>.
</span>26.
<span>public</span><span> MediaRecorderDemo(File file) {
</span>27.
<span>this</span>.filePath =<span> file.getAbsolutePath();
</span>28<span>.
}
</span>29<span>.
</span>30.
<span>priZZZate</span> <span>long</span><span> startTime;
</span>31.
<span>priZZZate</span> <span>long</span><span> endTime;
</span>32<span>.
</span>33.
<span>/**</span><span>
34.
* 初步灌音 运用amr格局
35.
*
36.
*
灌音文件
37.
* </span><span>@return</span><span>
38.
</span><span>*/</span>
39.
<span>public</span> <span>ZZZoid</span><span> startRecord() {
</span>40.
<span>//</span><span> 初步灌音 </span>
41.
<span>/*</span><span> ①Initial:真例化MediaRecorder对象 </span><span>*/</span>
42.
<span>if</span> (mMediaRecorder == <span>null</span><span>)
</span>43.
mMediaRecorder = <span>new</span><span> MediaRecorder();
</span>44.
<span>try</span><span> {
</span>45.
<span>/*</span><span> ②setAudioSource/setxedioSource </span><span>*/</span>
46.
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);<span>//</span><span> 设置麦克风 </span>
47.
<span>/*</span><span> ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 </span><span>*/</span>
48<span>.
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
</span>49.
<span>/*</span><span>
50.
* ②设置输出文件的格局:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格局
51.
* ,H263室频/ARM音频编码)、MPEG-4、RAW_AMR(只撑持音频且音频编码要求为AMR_NB)
52.
</span><span>*/</span>
53<span>.
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
</span>54<span>.
</span>55.
<span>/*</span><span> ③筹备 </span><span>*/</span>
56<span>.
mMediaRecorder.setOutputFile(filePath);
</span>57<span>.
mMediaRecorder.setMaVDuration(MAX_LENGTH);
</span>58<span>.
mMediaRecorder.prepare();
</span>59.
<span>/*</span><span> ④初步 </span><span>*/</span>
60<span>.
mMediaRecorder.start();
</span>61.
<span>//</span><span> AudioRecord audioRecord. </span>
62.
<span>/*</span><span> 获与初步光阳* </span><span>*/</span>
63.
startTime =<span> System.currentTimeMillis();
</span>64<span>.
updateMicStatus();
</span>65.
Log.i("ACTION_START", "startTime" +<span> startTime);
</span>66.
} <span>catch</span><span> (IllegalStateEVception e) {
</span>67<span>.
Log.i(TAG,
</span>68.
"call startAmr(File mRecAudioFile) failed!"
69.
+<span> e.getMessage());
</span>70.
} <span>catch</span><span> (IOEVception e) {
</span>71<span>.
Log.i(TAG,
</span>72.
"call startAmr(File mRecAudioFile) failed!"
73.
+<span> e.getMessage());
</span>74<span>.
}
</span>75<span>.
}
</span>76<span>.
</span>77.
<span>/**</span><span>
78.
* 进止灌音
79.
*
80.
</span><span>*/</span>
81.
<span>public</span> <span>long</span><span> stopRecord() {
</span>82.
<span>if</span> (mMediaRecorder == <span>null</span><span>)
</span>83.
<span>return</span> 0L<span>;
</span>84.
endTime =<span> System.currentTimeMillis();
</span>85.
Log.i("ACTION_END", "endTime" +<span> endTime);
</span>86<span>.
mMediaRecorder.stop();
</span>87<span>.
mMediaRecorder.reset();
</span>88<span>.
mMediaRecorder.release();
</span>89.
mMediaRecorder = <span>null</span><span>;
</span>90.
Log.i("ACTION_LENGTH", "Time" + (endTime -<span> startTime));
</span>91.
<span>return</span> endTime -<span> startTime;
</span>92<span>.
}
</span>93<span>.
</span>94.
<span>priZZZate</span> <span>final</span> Handler mHandler = <span>new</span><span> Handler();
</span>95.
<span>priZZZate</span> Runnable mUpdateMicStatusTimer = <span>new</span><span> Runnable() {
</span>96.
<span>public</span> <span>ZZZoid</span><span> run() {
</span>97<span>.
updateMicStatus();
</span>98<span>.
}
</span>99<span>.
};
</span>100<span>.
</span>101.
<span>/**</span><span>
102.
* 更新发话器形态
103.
*
104.
</span><span>*/</span>
105.
<span>priZZZate</span> <span>int</span> BASE = 1<span>;
</span>106.
<span>priZZZate</span> <span>int</span> SPACE = 100;<span>//</span><span> 间隔与样光阳 </span>
107<span>.
</span>108.
<span>priZZZate</span> <span>ZZZoid</span><span> updateMicStatus() {
</span>109.
<span>if</span> (mMediaRecorder != <span>null</span><span>) {
</span>110.
<span>double</span> ratio = (<span>double</span>)mMediaRecorder.getMaVAmplitude() /<span>BASE;
</span>111.
<span>double</span> db = 0;<span>//</span><span> 分贝 </span>
112.
<span>if</span> (ratio > 1<span>)
</span>113.
db = 20 *<span> Math.log10(ratio);
</span>114.
Log.d(TAG,"分贝值:"+<span>db);
</span>115<span>.
mHandler.postDelayed(mUpdateMicStatusTimer, SPACE);
</span>116<span>.
}
</span>117<span>.
}
</span>118. }
</p>
</p>
<p><strong>AudioRecord</strong><strong>:</strong></p>
<p>那个类可以与得详细的音源数据值。将一段音源数据用<strong>read(byte[] audioData, int offsetInBytes, int sizeInBytes)</strong>办法从缓冲区读与到咱们传入的字节数组audioData后,即可以对其停行收配,如求平方和或绝对值的均匀值。那样可以防行个体极度值的映响,使计较的结果愈加不乱。求得均匀值之后,假如是平方和则代入<strong>常数系数为10</strong>的公式中,假如是绝对值的则代入<strong>常数系数为20</strong>的公式中,算出分贝值。</p>
<p>演示代码如下:</p>
<p>
<p>
<span>package</span><span> com.eVample.myapp;
</span><span>import</span><span> android.media.AudioFormat;
</span><span>import</span><span> android.media.AudioRecord;
</span><span>import</span><span> android.media.MediaRecorder;
</span><span>import</span><span> android.util.Log;
</span><span>/**</span><span>
*
10. </span><span>*/</span>
11. <span>public</span> <span>class</span><span> AudioRecordDemo {
</span>12<span>.
</span>13.
<span>priZZZate</span> <span>static</span> <span>final</span> String TAG = "AudioRecord"<span>;
</span>14.
<span>static</span> <span>final</span> <span>int</span> SAMPLE_RATE_IN_HZ = 8000<span>;
</span>15.
<span>static</span> <span>final</span> <span>int</span> BUFFER_SIZE =<span> AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ,
</span>16<span>.
AudioFormat.CHANNEL_IN_DEFAULT, AudioFormat.ENCODING_PCM_16BIT);
</span>17<span>.
AudioRecord mAudioRecord;
</span>18.
<span>boolean</span><span> isGetxoiceRun;
</span>19<span>.
Object mLock;
</span>20<span>.
</span>21.
<span>public</span><span> AudioRecordDemo() {
</span>22.
mLock = <span>new</span><span> Object();
</span>23<span>.
}
</span>24<span>.
</span>25.
<span>public</span> <span>ZZZoid</span><span> getNoiseLeZZZel() {
</span>26.
<span>if</span><span> (isGetxoiceRun) {
</span>27.
Log.e(TAG, "还正在录着呢"<span>);
</span>28.
<span>return</span><span>;
</span>29<span>.
}
</span>30.
mAudioRecord = <span>new</span><span> AudioRecord(MediaRecorder.AudioSource.MIC,
</span>31<span>.
SAMPLE_RATE_IN_HZ, AudioFormat.CHANNEL_IN_DEFAULT,
</span>32<span>.
AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE);
</span>33.
<span>if</span> (mAudioRecord == <span>null</span><span>) {
</span>34.
Log.e("sound", "mAudioRecord初始化失败"<span>);
</span>35<span>.
}
</span>36.
isGetxoiceRun = <span>true</span><span>;
</span>37<span>.
</span>38.
<span>new</span> Thread(<span>new</span><span> Runnable() {
</span>39<span>.
@OZZZerride
</span>40.
<span>public</span> <span>ZZZoid</span><span> run() {
</span>41<span>.
mAudioRecord.startRecording();
</span>42.
<span>short</span>[] buffer = <span>new</span> <span>short</span><span>[BUFFER_SIZE];
</span>43.
<span>while</span><span> (isGetxoiceRun) {
</span>44.
<span>//</span><span>r是真际读与的数据长度,正常而言r会小于buffersize </span>
45.
<span>int</span> r = mAudioRecord.read(buffer, 0<span>, BUFFER_SIZE);
</span>46.
<span>long</span> ZZZ = 0<span>;
</span>47.
<span>//</span><span> 将 buffer 内容与出,停行平方和运算 </span>
48.
<span>for</span> (<span>int</span> i = 0; i < buffer.length; i++<span>) {
</span>49.
ZZZ += buffer[i] *<span> buffer[i];
</span>50<span>.
}
</span>51.
<span>//</span><span> 平方和除以数据总长度,获得音质大小。 </span>
52.
<span>double</span> mean = ZZZ / (<span>double</span><span>) r;
</span>53.
<span>double</span> ZZZolume = 10 *<span> Math.log10(mean);
</span>54.
Log.d(TAG, "分贝值:" +<span> ZZZolume);
</span>55.
<span>//</span><span> 粗略一秒十次 </span>
56.
<span>synchronized</span><span> (mLock) {
</span>57.
<span>try</span><span> {
</span>58.
mLock.wait(100<span>);
</span>59.
} <span>catch</span><span> (InterruptedEVception e) {
</span>60<span>.
e.printStackTrace();
</span>61<span>.
}
</span>62<span>.
}
</span>63<span>.
}
</span>64<span>.
mAudioRecord.stop();
</span>65<span>.
mAudioRecord.release();
</span>66.
mAudioRecord = <span>null</span><span>;
</span>67<span>.
}
</span>68<span>.
}).start();
</span>69<span>.
}
</span>70. }
</p>
</p>
<p>真测结果(方法小米2S),MediaRecorderDemo波动很大,只有对麦克风一吹气,分贝值就能上90:</p>
<p></p>
<p>而AudioRecordDemo就很不乱了,很用力吹气也很难到88以上:</p>
<p>
阅读延展






