Android pcm轉(zhuǎn)wav格式方法
程序中的錄音文件之前直接保存的是 .pcm格式,一直也相安無事,用的挺好。最近有一個webview中需要加載錄音文件,出現(xiàn)了不兼容的問題,所以需要把 .pcm格式文件轉(zhuǎn)換為 .wav格式。
PCM
PCM(Pulse Code Modulation----脈碼調(diào)制錄音)。所謂PCM錄音就是將聲音等模擬信號變成符號化的脈沖列,再予以記錄。PCM信號是由[1]、[0]等符號構(gòu)成的數(shù)字信號,而未經(jīng)過任何編碼和壓縮處理。與模擬信號比,它不易受傳送系統(tǒng)的雜波及失真的影響。動態(tài)范圍寬,可得到音質(zhì)相當(dāng)好的效果。簡單的說,pcm就是沒有壓縮的音頻格式。
wav
wav全稱是WAVE,.wav是其擴(kuò)展名,它是一種無損的音頻文件格式,WAV符合 RIFF(Resource Interchange File Format)規(guī)范。所有的WAV都有一個文件頭,這個文件頭是音頻流的編碼參數(shù)。WAV對音頻流的編碼沒有硬性規(guī)定,除了PCM之外,還有幾乎所有支持ACM規(guī)范的編碼都可以為WAV的音頻流進(jìn)行編碼。
pcm和wav關(guān)系 pcm是無損wav文件中音頻數(shù)據(jù)的一種編碼方式,pcm加上wav文件頭就可以轉(zhuǎn)為wav格式,但wav還可以用其它方式編碼。
PcmToWavUtil
package com.hgb.mytest;
import android.media.AudioFormat;
import android.media.AudioRecord;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by HaoGuibao
* Date 2016/8/26.
* Description :pcm格式的音頻轉(zhuǎn)換為wav格式的工具類
*/
public class PcmToWavUtil {
private int mBufferSize; //緩存的音頻大小
private int mSampleRate = 8000;// 8000|16000
private int mChannel = AudioFormat.CHANNEL_IN_STEREO; //立體聲
private int mEncoding = AudioFormat.ENCODING_PCM_16BIT;
public PcmToWavUtil() {
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, mEncoding);
}
/**
* @param sampleRate sample rate、采樣率
* @param channel channel、聲道
* @param encoding Audio data format、音頻格式
*/
public PcmToWavUtil(int sampleRate, int channel, int encoding) {
this.mSampleRate = sampleRate;
this.mChannel = channel;
this.mEncoding = encoding;
this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, mEncoding);
}
/**
* pcm文件轉(zhuǎn)wav文件
*
* @param inFilename 源文件路徑
* @param outFilename 目標(biāo)文件路徑
*/
public void pcmToWav(String inFilename, String outFilename) {
FileInputStream in;
FileOutputStream out;
long totalAudioLen;
long totalDataLen;
long longSampleRate = mSampleRate;
int channels = 2;
long byteRate = 16 * mSampleRate * channels / 8;
byte[] data = new byte[mBufferSize];
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 (IOException e) {
e.printStackTrace();
}
}
/**
* 加入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 header
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);
header[8] = 'W'; //WAVE
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
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;
header[20] = 1; // format = 1
header[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 align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
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);
out.write(header, 0, 44);
}
}
Demo 把手機(jī)內(nèi)存卡上 /sdcard/yxck/treamentRecord/ 的123.pcm轉(zhuǎn)換為123.wav文件。
public class MainActivity extends AppCompatActivity {
/**
* pcm格式轉(zhuǎn)wav格式工具類
*/
private PcmToWavUtil pcmToWavUtil = new PcmToWavUtil();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String path = "/sdcard/yxck/treamentRecord/123.pcm";
//按原路徑把音頻文件后綴改一下;
final String outpath = path.replace(".pcm", ".wav");
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pcmToWavUtil.pcmToWav(path, outpath);
}
});
}
}
pcm轉(zhuǎn)換wav格式成功

相關(guān)文章
在Android應(yīng)用中實現(xiàn)離線數(shù)據(jù)同步的步驟詳解
在構(gòu)建 Android 應(yīng)用時,離線數(shù)據(jù)同步是一個不可或缺的環(huán)節(jié),無論是網(wǎng)絡(luò)狀況不佳,還是用戶處于飛行模式,離線數(shù)據(jù)同步都能讓用戶在無網(wǎng)絡(luò)的情況下繼續(xù)使用應(yīng)用,本文將詳細(xì)介紹如何在 Android 應(yīng)用中實現(xiàn)離線數(shù)據(jù)同步,需要的朋友可以參考下2024-08-08
BroadcastReceiver靜態(tài)注冊案例詳解
這篇文章主要為大家詳細(xì)介紹了BroadcastReceiver靜態(tài)注冊案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
Android?Activity通用懸浮可拖拽View封裝的思路詳解
這篇文章主要介紹了Android?Activity通用懸浮可拖拽View封裝,實現(xiàn)思路是通過封裝通用的基礎(chǔ)懸浮View,繼承通用View,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
Android自定義View實現(xiàn)價格區(qū)間選擇控件
這篇文章主要為大家詳細(xì)介紹了Android如何利用自定義View實現(xiàn)價格區(qū)間選擇控件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-11-11
android中可以通過兩種方式調(diào)用接口發(fā)送短信
調(diào)用系統(tǒng)短信接口直接發(fā)送短信;調(diào)起系統(tǒng)發(fā)短信功能,本文將給出兩種方式的實現(xiàn)代碼,感興趣的朋友可以了解下,或許對你有所幫助2013-02-02
Android RecycleView和線型布局制作聊天布局
大家好,本篇文章主要講的是Android RecycleView和線型布局制作聊天布局,感興趣的同學(xué)趕緊來看一看吧,對你有幫助的話記得收藏一下2022-01-01
Android 設(shè)置主題實現(xiàn)點擊波紋效果的示例
本篇文章主要介紹了Android 設(shè)置主題實現(xiàn)點擊波紋效果的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
android實現(xiàn)簡單進(jìn)度條ProgressBar效果
這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)簡單進(jìn)度條ProgressBar效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07

