天天看點

Android AudioRecord錄制wav格式的音頻

Android AudioRecord錄制wav格式的音頻

package com.example.chezi008.recorderdemo;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Environment;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * 描述:
 * 作者:chezi008 on 2016/11/4 17:11
 * 郵箱:[email protected]
 */
public class AudioUtil {

    private static AudioUtil mInstance;
    private AudioRecord recorder;
    //錄音源
    private static int audioSource = MediaRecorder.AudioSource.MIC;
    //錄音的采樣頻率
    private static int audioRate = ;
    //錄音的聲道,單聲道
    private static int audioChannel = AudioFormat.CHANNEL_IN_MONO;
    //量化的深度
    private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    //緩存的大小
    private static int bufferSize = AudioRecord.getMinBufferSize(audioRate,audioChannel,audioFormat);
    //記錄播放狀态
    private boolean isRecording = false;
    //數字信号數組
    private byte [] noteArray;
    //PCM檔案
    private File pcmFile;
    //WAV檔案
    private File wavFile;
    //檔案輸出流
    private OutputStream os;
    //檔案根目錄
    private String basePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/yinfu/";
    //wav檔案目錄
    private String outFileName = basePath+"/yinfu.wav";
    //pcm檔案目錄
    private String inFileName = basePath+"/yinfu.pcm";

    private AudioUtil(){
        createFile();//建立檔案
        recorder = new AudioRecord(audioSource,audioRate,audioChannel,audioFormat,bufferSize);
    }

    public synchronized static AudioUtil getInstance(){
        if(mInstance == null){
            mInstance = new AudioUtil();
        }
        return mInstance;
    }

    //讀取錄音數字資料線程
    class WriteThread implements Runnable{
        public void run(){
            writeData();
        }
    }

    //開始錄音
    public void startRecord(){
        isRecording = true;
        recorder.startRecording();
    }

    //停止錄音
    public void stopRecord(){
        isRecording = false;
        recorder.stop();
    }

    //将資料寫入檔案夾,檔案的寫入沒有做優化
    public void writeData(){
        noteArray = new byte[bufferSize];
        //建立檔案輸出流
        try {
            os = new BufferedOutputStream(new FileOutputStream(pcmFile));
        }catch (IOException e){

        }
        while(isRecording == true){
            int recordSize = recorder.read(noteArray,,bufferSize);
            if(recordSize>){
                try{
                    os.write(noteArray);
                }catch(IOException e){

                }
            }
        }
        if (os != null) {
            try {
                os.close();
            }catch (IOException e){

            }
        }
    }

    // 這裡得到可播放的音頻檔案
    public void convertWaveFile() {
        FileInputStream in = null;
        FileOutputStream out = null;
        long totalAudioLen = ;
        long totalDataLen = totalAudioLen + ;
        long longSampleRate = AudioUtil.audioRate;
        int channels = ;
        long byteRate =  *AudioUtil.audioRate * channels / ;
        byte[] data = new byte[bufferSize];
        try {
            in = new FileInputStream(inFileName);
            out = new FileOutputStream(outFileName);
            totalAudioLen = in.getChannel().size();
            //由于不包括RIFF和WAV
            totalDataLen = totalAudioLen + ;
            WriteWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate);
            while (in.read(data) != -) {
                out.write(data);
            }
            in.close();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /* 任何一種檔案在頭部添加相應的頭檔案才能夠确定的表示這種檔案的格式,wave是RIFF檔案結構,每一部分為一個chunk,其中有RIFF WAVE chunk, FMT Chunk,Fact chunk,Data chunk,其中Fact chunk是可以選擇的, */
    private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate,
                                     int channels, long byteRate) throws IOException {
        byte[] header = new byte[];
        header[] = 'R'; // RIFF
        header[] = 'I';
        header[] = 'F';
        header[] = 'F';
        header[] = (byte) (totalDataLen & );//資料大小
        header[] = (byte) ((totalDataLen >> ) & );
        header[] = (byte) ((totalDataLen >> ) & );
        header[] = (byte) ((totalDataLen >> ) & );
        header[] = 'W';//WAVE
        header[] = 'A';
        header[] = 'V';
        header[] = 'E';
        //FMT Chunk
        header[] = 'f'; // 'fmt '
        header[] = 'm';
        header[] = 't';
        header[] = ' ';//過渡位元組
        //資料大小
        header[] = ; // 4 bytes: size of 'fmt ' chunk
        header[] = ;
        header[] = ;
        header[] = ;
        //編碼方式 10H為PCM編碼格式
        header[] = ; // format = 1
        header[] = ;
        //通道數
        header[] = (byte) channels;
        header[] = ;
        //采樣率,每個通道的播放速度
        header[] = (byte) (longSampleRate & );
        header[] = (byte) ((longSampleRate >> ) & );
        header[] = (byte) ((longSampleRate >> ) & );
        header[] = (byte) ((longSampleRate >> ) & );
        //音頻資料傳送速率,采樣率*通道數*采樣深度/8
        header[] = (byte) (byteRate & );
        header[] = (byte) ((byteRate >> ) & );
        header[] = (byte) ((byteRate >> ) & );
        header[] = (byte) ((byteRate >> ) & );
        // 确定系統一次要處理多少個這樣位元組的資料,确定緩沖區,通道數*采樣位數
        header[] = (byte) ( *  / );
        header[] = ;
        //每個樣本的資料位數
        header[] = ;
        header[] = ;
        //Data chunk
        header[] = 'd';//data
        header[] = 'a';
        header[] = 't';
        header[] = 'a';
        header[] = (byte) (totalAudioLen & );
        header[] = (byte) ((totalAudioLen >> ) & );
        header[] = (byte) ((totalAudioLen >> ) & );
        header[] = (byte) ((totalAudioLen >> ) & );
        out.write(header, , );
    }

    //建立檔案夾,首先建立目錄,然後建立對應的檔案
    public void createFile(){
        File baseFile = new File(basePath);
        if(!baseFile.exists())
            baseFile.mkdirs();
        pcmFile = new File(basePath+"/yinfu.pcm");
        wavFile = new File(basePath+"/yinfu.wav");
        if(pcmFile.exists()){
            pcmFile.delete();
        }
        if(wavFile.exists()){
            wavFile.delete();
        }
        try{
            pcmFile.createNewFile();
            wavFile.createNewFile();
        }catch(IOException e){

        }
    }

    //記錄資料
    public void recordData(){
        new Thread(new WriteThread()).start();
    }
}