android中AudioRecord使用

來源:互聯網
上載者:User
一 什麼是音訊採樣率和採樣大小  
自然界中的聲音非常複雜,波形極其複雜,通常我們採用的是脈衝代碼調製編碼。即PCM編碼。PCM通過抽樣、量化、編碼三個步驟將連續變化的類比訊號轉換為數字編碼。

抽樣:在音頻採集中叫做採樣率。
由於聲音其實是一種能量波,因此也有頻率和振幅的特徵,頻率對應於時間軸線,振幅對應於電平軸線。波是無限光滑的,弦線可以看成由無數點組成,由於儲存空間是相對有限的,數字編碼過程中,必須對弦線的點進行採樣。採樣的過程就是抽取某點的頻率值,很顯然,在一秒中內抽取的點越多,擷取得頻率資訊更豐富,為了複原波形,一次震動中,必須有2個點的採樣,人耳能夠感覺到的最高頻率為20kHz,因此要滿足人耳的聽覺要求,則需要至少每秒進行40k次採樣,用40kHz表達,這個40kHz就是採樣率。我們常見的CD,採樣率為44.1kHz。
量化:我們這裡的採樣大小就是量化的過程,將該頻率的能量值並量化,用於表示訊號強度。量化電平數為 2的整數次冪,我們常見的CD位16bit的採樣大小,即2的16次方。
編碼:
根據採樣率和採樣大小可以得知,相對自然界的訊號,音頻編碼最多隻能做到無限接近,至少目前的技術只能這樣了,相對自然界的訊號,任何數字音頻編碼方案都是有損的,因為無法完全還原。在電腦應用中,能夠達到最高保真水平的就是PCM編碼,被廣泛用於素材儲存及音樂欣賞,CD、DVD以及我們常見的WAV檔案中均有應用。因此,PCM約定俗成了無損編碼,因為PCM代表了數字音頻中最佳的保真水準,並不意味著PCM就能夠確保訊號絕對保真,PCM也只能做到最大程度的無限接近。我們而習慣性的把MP3列入有損音頻編碼範疇,是相對PCM編碼的。強調編碼的相對性的有損和無損,是為了告訴大家,要做到真正的無損是困難的,就像用數字去表達圓周率,不管精度多高,也只是無限接近,而不是真正等於圓周率的值

為什麼要使用音頻壓縮技術

要算一個PCM音頻流的碼率是一件很輕鬆的事情,採樣率值×採樣大小值×聲道數bps。一個採樣率為44.1KHz,採樣大小為16bit,雙聲道的PCM編碼的WAV檔案,它的資料速率則為 44.1K×16×2 =1411.2 Kbps。我們常說128K的MP3,對應的WAV的參數,就是這個1411.2 Kbps,這個參數也被稱為資料頻寬,它和ADSL中的頻寬是一個概念。將碼率除以8,就可以得到這個WAV的資料速率,即176.4KB/s。這表示儲存一秒鐘採樣率為44.1KHz,採樣大小為16bit,雙聲道的PCM編碼的音頻訊號,需要176.4KB的空間,1分鐘則約為10.34M,這對大部分使用者是不可接受的,尤其是喜歡在電腦上聽音樂的朋友,要降低磁碟佔用,只有2種方法,降低採樣指標或者壓縮。降低指標是不可取的,因此專家們研發了各種壓縮方案。由於用途和針對的目標市場不一樣,各種音頻壓縮編碼所達到的音質和壓縮比都不一樣,在後面的文章中我們都會一一提到。有一點是可以肯定的,他們都壓縮過。

頻率與採樣率的關係

採樣率表示了每秒對原始訊號採樣的次數,我們常見到的音頻檔案採樣率多為44.1KHz,這意味著什麼呢?假設我們有2段正弦波訊號,分別為20Hz和20KHz,長度均為一秒鐘,以對應我們能聽到的最低頻和最高頻,分別對這兩段訊號進行 40KHz的採樣,我們可以得到一個什麼樣的結果呢?結果是:20Hz的訊號每次震動被採樣了40K/20=2000次,而20K的訊號每次震動只有2次採樣。顯然,在相同的採樣率下,記錄低頻的資訊遠比高頻的詳細。這也是為什麼有些音響發燒友指責CD有數位聲不夠真實的原因,CD的44.1KHz採樣也無法保證高頻訊號被較好記錄。要較好的記錄高頻訊號,看來需要更高的採樣率,於是有些朋友在捕捉CD音軌的時候使用48KHz的採樣率,這是不可取的!這其實對音質沒有任何好處,對抓軌軟體來說,保持和CD提供的44.1KHz一樣的採樣率才是最佳音質的保證之一,而不是去提高它。較高的採樣率只有相對類比訊號的時候才有用,如果被採樣的訊號是數位,請不要去嘗試提高採樣率。

流特徵

隨著網路的發展,人們對線上收聽音樂提出了要求,因此也要求音頻檔案能夠一邊讀一邊播放,而不需要把這個檔案全部讀出後然後回放,這樣就可以做到不用下載就可以實現收聽了。也可以做到一邊編碼一邊播放,正是這種特徵,可以實現線上的直播,架設自己的數位廣播電台成為了現實。     二 android中AudioRecord採集音訊參數說明

在android中採集音訊api是android.media.AudioRecord類

其中構造器的幾個參數就是標準的聲音採集參數

以下是參數的含義解釋

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

Since: API Level 3

Class constructor.

Parameters

audioSource

the recording source. See MediaRecorder.AudioSource for recording source definitions.

音頻源:指的是從哪裡採集音頻。這裡我們當然是從麥克風採集音頻,所以此參數的值為MIC

sampleRateInHz

the sample rate expressed in Hertz. Examples of rates are (but not limited to) 44100, 22050 and 11025.

採樣率:音訊採樣頻率,每秒鐘能夠採樣的次數,採樣率越高,音質越高。給出的執行個體是44100、22050、11025但不限於這幾個參數。例如要採集低品質的音頻就可以使用4000、8000等低採樣率。

channelConfig

describes the configuration of the audio channels. See
CHANNEL_IN_MONO and
CHANNEL_IN_STEREO

聲道設定:android支援雙聲道立體聲和單聲道。MONO單聲道,STEREO立體聲

audioFormat

the format in which the audio data is represented. See
ENCODING_PCM_16BIT and
ENCODING_PCM_8BIT

編碼制式和採樣大小:採集來的資料當然使用PCM編碼(脈衝代碼調製編碼,即PCM編碼。PCM通過抽樣、量化、編碼三個步驟將連續變化的類比訊號轉換為數字編碼。)
android支援的採樣大小16bit
或者8bit。當然採樣大小越大,那麼資訊量越多,音質也越高,現在主流的採樣大小都是16bit,在低品質的語音傳輸的時候8bit
足夠了。

bufferSizeInBytes

the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. See
getMinBufferSize(int, int, int) to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will
result in an initialization failure.

採集資料需要的緩衝區的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

採集到的資料儲存在一個byteBuffer中,可以使用流將其讀出。亦可儲存成為檔案的形式

 

三 Android 使用AudioRecord錄音相關和音頻檔案的封裝

在Android中錄音可以用MediaRecord錄音,操作比較簡單。但是不夠專業,就是不能對音頻進行處理。如果要進行音訊即時的處理或者音訊一些封裝

就可以用AudioRecord來進行錄音了。

這裡給出一段代碼。實現了AudioRecord的錄音和WAV格式音訊封裝。

用AudioTrack和AudioTrack類可以進行邊錄邊播,可以參考:http://blog.sina.com.cn/s/blog_6309e1ed0100j1rw.html

我們這裡的代碼沒有播放。但是有封裝和詳解,如下:

 

 

package com.ppmeet;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import android.app.Activity;import android.graphics.PixelFormat;import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.view.Window;import android.view.WindowManager;import android.widget.Button;/** * class name:TestAudioRecord<BR> * class description:用AudioRecord來進行錄音<BR> * PS: <BR> *  * @version 1.00 2011/09/21 * @author CODYY)peijiangping */public class TestAudioRecord extends Activity {// 音頻擷取源private int audioSource = MediaRecorder.AudioSource.MIC;// 設定音頻採樣率,44100是目前的標準,但是某些裝置仍然支援22050,16000,11025private static int sampleRateInHz = 44100;// 設定音訊錄製的聲道CHANNEL_IN_STEREO為雙聲道,CHANNEL_CONFIGURATION_MONO為單聲道private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;// 音頻資料格式:PCM 16位每個樣本。保證裝置支援。PCM 8位每個樣本。不一定能得到裝置支援。private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;// 緩衝區位元組大小private int bufferSizeInBytes = 0;private Button Start;private Button Stop;private AudioRecord audioRecord;private boolean isRecord = false;// 設定正在錄製的狀態//AudioName裸音頻資料檔案private static final String AudioName = "/sdcard/love.raw";//NewAudioName可播放的音頻檔案private static final String NewAudioName = "/sdcard/new.wav";public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().setFormat(PixelFormat.TRANSLUCENT);// 讓介面橫屏requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉介面標題getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);// 重新設定介面大小setContentView(R.layout.main);init();}private void init() {Start = (Button) this.findViewById(R.id.start);Stop = (Button) this.findViewById(R.id.stop);Start.setOnClickListener(new TestAudioListener());Stop.setOnClickListener(new TestAudioListener());creatAudioRecord();}private void creatAudioRecord() {// 獲得緩衝區位元組大小bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig, audioFormat);// 建立AudioRecord對象audioRecord = new AudioRecord(audioSource, sampleRateInHz,channelConfig, audioFormat, bufferSizeInBytes);}class TestAudioListener implements OnClickListener {@Overridepublic void onClick(View v) {if (v == Start) {startRecord();}if (v == Stop) {stopRecord();}}}private void startRecord() {audioRecord.startRecording();// 讓錄製狀態為trueisRecord = true;// 開啟音頻檔案寫入線程new Thread(new AudioRecordThread()).start();}private void stopRecord() {close();}private void close() {if (audioRecord != null) {System.out.println("stopRecord");isRecord = false;//停止檔案寫入audioRecord.stop();audioRecord.release();//釋放資源audioRecord = null;}}class AudioRecordThread implements Runnable {@Overridepublic void run() {writeDateTOFile();//往檔案中寫入裸資料copyWaveFile(AudioName, NewAudioName);//給裸資料加上標頭檔}}/** * 這裡將資料寫入檔案,但是並不能播放,因為AudioRecord獲得的音頻是原始的裸音頻, * 如果需要播放就必須加入一些格式或者編碼的頭資訊。但是這樣的好處就是你可以對音訊 裸資料進行處理,比如你要做一個愛說話的TOM * 貓在這裡就進行音訊處理,然後重新封裝 所以說這樣得到的音頻比較容易做一些音訊處理。 */private void writeDateTOFile() {// new一個byte數組用來存一些位元組資料,大小為緩衝區大小byte[] audiodata = new byte[bufferSizeInBytes];FileOutputStream fos = null;int readsize = 0;try {File file = new File(AudioName);if (file.exists()) {file.delete();}fos = new FileOutputStream(file);// 建立一個可存取位元組的檔案} catch (Exception e) {e.printStackTrace();}while (isRecord == true) {readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {try {fos.write(audiodata);} catch (IOException e) {e.printStackTrace();}}}try {fos.close();// 關閉寫入流} catch (IOException e) {e.printStackTrace();}}// 這裡得到可播放的音頻檔案private void copyWaveFile(String inFilename, String outFilename) {FileInputStream in = null;FileOutputStream out = null;long totalAudioLen = 0;long totalDataLen = totalAudioLen + 36;long longSampleRate = sampleRateInHz;int channels = 2;long byteRate = 16 * sampleRateInHz * channels / 8;byte[] data = new byte[bufferSizeInBytes];try {in = new FileInputStream(inFilename);out = new FileOutputStream(outFilename);totalAudioLen = in.getChannel().size();totalDataLen = totalAudioLen + 36;WriteWaveFileHeader(out, totalAudioLen, totalDataLen,longSampleRate, channels, byteRate);while (in.read(data) != -1) {out.write(data);}in.close();out.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/** * 這裡提供一個頭資訊。插入這些資訊就可以得到可以播放的檔案。 * 為我為啥插入這44個位元組,這個還真沒深入研究,不過你隨便開啟一個wav * 音訊檔案,可以發現前面的標頭檔可以說基本一樣哦。每種格式的檔案都有 * 自己特有的標頭檔。 */private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,long totalDataLen, long longSampleRate, int channels, long byteRate)throws IOException {byte[] header = new byte[44];header[0] = 'R'; // RIFF/WAVE headerheader[1] = 'I';header[2] = 'F';header[3] = 'F';header[4] = (byte) (totalDataLen & 0xff);header[5] = (byte) ((totalDataLen >> 8) & 0xff);header[6] = (byte) ((totalDataLen >> 16) & 0xff);header[7] = (byte) ((totalDataLen >> 24) & 0xff);header[8] = 'W';header[9] = 'A';header[10] = 'V';header[11] = 'E';header[12] = 'f'; // 'fmt ' chunkheader[13] = 'm';header[14] = 't';header[15] = ' ';header[16] = 16; // 4 bytes: size of 'fmt ' chunkheader[17] = 0;header[18] = 0;header[19] = 0;header[20] = 1; // format = 1header[21] = 0;header[22] = (byte) channels;header[23] = 0;header[24] = (byte) (longSampleRate & 0xff);header[25] = (byte) ((longSampleRate >> 8) & 0xff);header[26] = (byte) ((longSampleRate >> 16) & 0xff);header[27] = (byte) ((longSampleRate >> 24) & 0xff);header[28] = (byte) (byteRate & 0xff);header[29] = (byte) ((byteRate >> 8) & 0xff);header[30] = (byte) ((byteRate >> 16) & 0xff);header[31] = (byte) ((byteRate >> 24) & 0xff);header[32] = (byte) (2 * 16 / 8); // block alignheader[33] = 0;header[34] = 16; // bits per sampleheader[35] = 0;header[36] = 'd';header[37] = 'a';header[38] = 't';header[39] = 'a';header[40] = (byte) (totalAudioLen & 0xff);header[41] = (byte) ((totalAudioLen >> 8) & 0xff);header[42] = (byte) ((totalAudioLen >> 16) & 0xff);header[43] = (byte) ((totalAudioLen >> 24) & 0xff);out.write(header, 0, 44);}@Overrideprotected void onDestroy() {close();super.onDestroy();}}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.