數(shù)字音頻基本概念
在實(shí)現(xiàn)功能之前凳谦,我們先來了解一下數(shù)字音頻的有關(guān)屬性:
采樣頻率(Sample Rate):每秒采集聲音的數(shù)量尸执,它用赫茲(Hz)來表示眠屎。(采樣率越高越靠近原聲音的波形)
采樣精度(Bit Depth):指記錄聲音的動(dòng)態(tài)范圍,它以位(Bit)為單位岖常。(聲音的幅度差)
聲音通道(Channel):聲道數(shù)葫督。比如左聲道右聲道。
采樣量化后的音頻最終是一串?dāng)?shù)字,聲音的大小(幅度)會體現(xiàn)在這個(gè)每個(gè)數(shù)字?jǐn)?shù)值大小上偎快;而聲音的高低(頻率)和聲音的音色(Timbre)都和時(shí)間維度有關(guān)洽胶,會體現(xiàn)在數(shù)字之間的差異上。
音頻的編碼與解碼
自然界中的聲音非常復(fù)雜丐怯,波形極其復(fù)雜,通常我們采用的是脈沖代碼調(diào)制編碼梗搅,即PCM編碼效览。PCM通過抽樣、量化哆键、編碼三個(gè)步驟將連續(xù)變化的模擬信號轉(zhuǎn)換為數(shù)字編碼瘦锹。本篇文章介紹的混音就是對PCM數(shù)據(jù)做處理。
相對自然界的信號,任何數(shù)字音頻編碼方案都是有損的锭沟,因?yàn)闊o法完全還原。在計(jì)算機(jī)應(yīng)用中辫红,能夠達(dá)到最高保真水平的就是PCM編碼祝辣,平時(shí)常見的WAV文件就是在PCM數(shù)據(jù)前加上一個(gè)44字節(jié)的RIFF頭部組成的。
音頻信號在時(shí)域和頻域上具有相關(guān)性蝙斜,也即存在數(shù)據(jù)冗余,音頻編碼的實(shí)質(zhì)是減少音頻中的冗余娩鹉。
那么稚伍,解碼的目的就是讓編碼后的數(shù)據(jù)恢復(fù)成PCM源數(shù)據(jù)。
AAC,Mp3 --> Decoder --> Audio PCM Data
常見的音頻編碼格式有以下這些:
public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg";
public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
public static final String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
public static final String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
public static final String MIMETYPE_AUDIO_OPUS = "audio/opus";
public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
public static final String MIMETYPE_AUDIO_RAW = "audio/raw";
public static final String MIMETYPE_AUDIO_FLAC = "audio/flac";
public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
音頻的混音
音頻混音的原理: 量化的語音信號的疊加等價(jià)于空氣中聲波的疊加锈嫩。
反應(yīng)到音頻數(shù)據(jù)上艳汽,也就是把同一個(gè)聲道的數(shù)值進(jìn)行簡單的相加等舔,但是這樣同時(shí)會產(chǎn)生一個(gè)問題,那就是相加的結(jié)果可能會溢出慌植,當(dāng)然為了解決這個(gè)問題已經(jīng)有很多方案了,在這里我們采用簡單的平均算法丈钙。
下面的演示程序適用于音頻文件采樣率交汤、通道數(shù)、采樣精度一樣的情況:
/**
* 混合音頻星岗,使用平均算法
*
* @param mixedBytes 輸出混合后的數(shù)據(jù)到該byte數(shù)組
* @param shorts1 需要混合的short數(shù)組1
* @param shorts2 需要混合的short數(shù)組2
*/
private void mixRawAudioBytes(byte[] mixedBytes, short[] shorts1, short[] shorts2) {
for (int i = 0; i < shorts2.length; i++) {
shorts1[i] = (short) ((shorts2[i] + shorts1[i]) / 2);
}
for (int i = 0; i < shorts1.length; i++) {
mixedBytes[i * 2] = (byte) (shorts1[i] & 0x00FF);
mixedBytes[i * 2 + 1] = (byte) ((shorts1[i] & 0xFF00) >> 8);
}
}