PCM簡介
PCM(Pulse Code Modulation),脈衝編碼調製。人耳聽到的是模擬信號,PCM是把聲音從模擬信號轉化爲數字信號的技術。原理是用一個固定的頻率對模擬信號進行採樣,採樣後的信號在波形上看就像一串連續的幅值不一的脈衝(脈搏似的短暫起伏的電衝擊),把這些脈衝的幅值按一定精度進行量化,這些量化後的數值被連續的輸出、傳輸、處理或記錄到存儲介質中,所有這些組成了數字音頻的產生過程(抽樣、量化、編碼三個過程)。要將這種信號轉爲 PCM 格式的方法,是使用三個參數來表示聲音,它們是聲道數、採樣位數和採樣頻率。
採樣頻率
即取樣頻率,指每秒鐘取得聲音樣本的次數,是設備一秒鐘內對模擬信號的採樣次數。採樣頻率越高,聲音的質量也就越好,聲音的還原也就越真實,但同一時候它佔的資源比較多。因爲人耳的分辨率非常有限,太高的頻率並不能分辨出來。
在16位聲卡中有22KHz、44KHz等幾級,當中,8Khz的電話採樣率就可以達到人的對話程度,22KHz相當於普通FM廣播的音質,44KHz已相當於CD,MP3音質了,48KHz相當於miniDV、數字電視、DVD、電影和專業音頻。
採樣位數
即採樣值或取樣值(就是將採樣樣本幅度量化)。它是用來衡量聲音波動變化的一個參數。也能夠說是聲卡的分辨率。它的數值越大,分辨率也就越高。所發出聲音的能力越強。採樣位數比如8bit(現在少見)、16bit(常用)和24bit,指的是描述數字信號所使用的位數。
聲道數
聲音在錄製或播放時在不同空間位置採集或回放的相互獨立的音頻信號。有單聲道和立體聲之分,單聲道的聲音僅僅能使用一個喇叭發聲(有的也處理成兩個喇叭輸出同一個聲道的聲音)。立體聲的PCM 能夠使兩個喇叭都發聲(一般左右聲道有分工) ,更能感受到空間效果。單聲道採樣數據爲8位的短整數(short);雙聲道採樣數據爲16位的整數,(int),高八位(左聲道)和低八位(右聲道)分別代表兩個聲道。
[時長]s * [採樣率]Hz * [採樣位數]bit * [聲道數] / 8 = [文件大小]byte
某音頻信號是採樣率爲8kHz、聲道數2、位寬爲16bit,時長爲1s,則音頻數據的大小爲:
1 * 8000 * 16 *2 = 256000 bit / 8 = 32000 byte / 1024 = 31.25 KB
wav文件頭
/**
* 獲取WAV頭獲取文件
* @param totalAudioLen 整個音頻PCM數據大小
* @param sampleRate 採樣率,例如16000Hz
* @param channels 聲道數 單聲道:1或雙聲道:2
* @param bitNum 採樣位數,8或16
*/
private byte[] getWaveFileHeader(long totalAudioLen,int sampleRate, int channels, int bitNum) {
Log.d(TAG, "getWaveFileHeader filesize = " + String.valueOf(totalAudioLen));
//採樣字節byte率
long byteRate = sampleRate * channels * bitNum / 8;
//整個數據大小
//總大小,由於不包括RIFF和WAVE,所以是44 - 8 = 36,在加上PCM文件大小
long totalDataLen = totalAudioLen + 36;
byte[] header = new byte[44];
header[0] = 'R'; // RIFF
header[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);
//WAVE
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
//FMT Chunk
header[12] = 'f'; // 'fmt '
header[13] = 'm';
header[14] = 't';
header[15] = ' ';//過渡字節
//數據大小
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
//編碼方式 10H爲PCM編碼格式
header[20] = 1; // format = 1
header[21] = 0;
//通道數
header[22] = (byte) channels;
header[23] = 0;
//採樣率,每個通道的播放速度
header[24] = (byte) (sampleRate & 0xff);
header[25] = (byte) ((sampleRate >> 8) & 0xff);
header[26] = (byte) ((sampleRate >> 16) & 0xff);
header[27] = (byte) ((sampleRate >> 24) & 0xff);
//音頻數據傳送速率,採樣率*通道數*採樣深度/8
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) (channels * bitNum / 8);
header[33] = 0;
//每個樣本的數據位數
header[34] = (byte) bitNum;
header[35] = 0;
//Data chunk
header[36] = 'd';//data
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);
return header;
}
RIFF全稱爲資源互換文件格式(Resources Interchange File Format),是Windows下大部分多媒體文件遵循的一種文件結構。RIFF文件所包含的數據類型由該文件的擴展名來標識,能以RIFF格式存儲的數據有:
- 音頻視頻交錯格式數據 .AVI
- 波形格式數據 .WAV
- 位圖數據格式 .RDI
- MIDI格式數據 .RMI
- 調色板格式 .PAL
- 多媒體電影 .RMN
- 動畫光標 .ANI
- 其他的RIFF文件 .BND