Android 擷取麥克風的音量(分貝)

來源:互聯網
上載者:User

標籤:dem   offset   family   while   影響   寫入   level   term   vedio   

基礎知識

度量聲音強度。大家最熟悉的單位就是分貝(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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new AudioRecordDemo().getNoiseLevel();}}

測試結果


原始碼:http://download.csdn.net/detail/pcaxb/9028495



Android 擷取麥克風的音量(分貝)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.