簡體   English   中英

將.pcm 文件轉換為.wav 文件

[英]Convert .pcm file to .wav file

我需要在我的 Android 應用程序中將.pcm 文件轉換為.wav 文件。 PCM 錄音是原始數字音頻樣本。 以前,一個 PCM 音頻文件是以 16000 的采樣頻率錄制的,在單聲道模式下(channelConfigurationRecord = AudioFormat.CHANNEL_IN_MONO),一個樣本中的 16 位(audioEncoding = AudioFormat.ENCODING_PCM_16BIT)。 要將 PCM 轉換為 WAV,我需要先編寫一個 header,然后添加我所有的 PCM 數據。 我花了很多時間在這上面,我嘗試了很多變種,但沒有任何效果。 我不知道我做錯了什么......幫幫我!

public class Convert {
    File filePcm;
    File fileWav;

    char chunkId[]={'R','I','F','F'};
    byte chunkSize[];
    char format[]={'W','A','V','E'};
    char subchunk1Id[]={'f','m','t',' '};
    byte subchunk1Size[]={0b0,0b0,0b0,16};
    byte audioFormat[]={0,1};
    byte numChannels[]={0,1};
    byte sampleRate[]={0b0,0b0,0b111110,(byte)0b10000000};
    byte byteRate[]={0b0,0b0,0b1111101,0b0};
    byte blockAlign[]={0,2};
    byte bitsPerSample[]={0,16};
    char subchunk2Id[]={'d','a','t','a'};
    byte subchunk2Size[];

    public Convert (File filePcm){
        this.filePcm = filePcm;
    }
    public void convertWavFile(){
        try {
            fileWav = new File("");
            fileWav.createNewFile();
            writeHeader();
            writePcmData();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void writeHeader() throws IOException {
        long chunkSiz=36+filePcm.length();
        chunkSize = new byte[]{ (byte) (chunkSiz & 0xff),
                (byte) ((chunkSiz >> 8) & 0xff),
                (byte) ((chunkSiz >> 16) & 0xff),
                (byte) ((chunkSiz >> 24) & 0xff)};
        long subchunk2Siz=filePcm.length();
        subchunk2Size = new byte[]{ (byte) (subchunk2Siz & 0xff),
                (byte) ((subchunk2Siz >> 8) & 0xff),
                (byte) ((subchunk2Siz >> 16) & 0xff),
                (byte) ((subchunk2Siz >> 24) & 0xff)};

        FileOutputStream d = new FileOutputStream(fileWav);
        for (char c:chunkId) d.write(c);
        for (byte c:chunkSize) d.write(c);
        for (char c:format) d.write(c);
        for (char c:subchunk1Id) d.write(c);
        for (byte c:subchunk1Size)d.write (c);
        for (byte c:audioFormat)d.write (c);
        for (byte c:numChannels)d.write (c);
        for (byte c:sampleRate) d.write(c);
        for (byte c:byteRate) d.write(c);
        for (byte c:blockAlign)d.write (c);
        for (byte c:bitsPerSample)d.write (c);
        for (char c:subchunk2Id) d.write(c);
        for (byte c:subchunk2Size) d.write(c);
    }

    private void writePcmData() throws IOException {
        FileInputStream fileInputStream = new FileInputStream(filePcm);
        FileOutputStream fileOutputStream = new FileOutputStream(fileWav);
        int i;
        while((i=fileInputStream.read())!=-1){
            fileOutputStream.write(i);
        }
    }
}

輸入數據是未經處理的 pcm 樣本,在創建並寫入此 shell 后,該文件無法被任何播放器識別

首先添加 FFMPEG 庫,該庫可以輕松轉換、合並、混合視頻和音頻。

構建.gradle(應用程序)

 implementation 'com.writingminds:FFmpegAndroid:0.3.2'

活動

    File yourPcmFile = new File("YOUR_PCM_FILE_ABSOLUTE_PATH");
    File yourWawOutput = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/output.wav");
    String command = "-f s16le -ar 44.1k -ac 2 -i "+yourPcmFile.getAbsolutePath()+ yourWawOutput.getAbsolutePath();
    FFmpeg ffmpeg = FFmpeg.getInstance(context);
    try {
        ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
            @Override
            public void onStart() {
            }

            @Override
            public void onFailure() {
            }

            @Override
            public void onSuccess() {
            }

            @Override
            public void onFinish() {
            }
        });
    } catch (Exception e) {
        Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
    }

    try {
        ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
            @Override
            public void onStart() {
                dialog.show();
            }

            @Override
            public void onProgress(String message) {

            }

            @Override
            public void onFailure(String message) {
                Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }

            @Override
            public void onSuccess(String message) {
                Toast.makeText(context, "Build has been successful", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }

            @Override
            public void onFinish() {

            }
        });
    } catch (Exception e) {
        Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
    } finally {
        if (ffmpeg.isFFmpegCommandRunning()) {
            ffmpeg.killRunningProcesses();

顯現

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

更多信息

-f s16le -ar 44.1k -ac 2 -i "+yourPcmFile.getAbsolutePath()+ yourWawOutput.getAbsolutePath()
-f s16le >>> signed 16-bit little endian samples
-ar 44.1k >>> sample rate 44.1kHz
-ac 2 >>> 2 channels (stereo)
-i yourPcmFile.getAbsolutePath() >>> input file
yourWawOutput.getAbsolutePath() >>> output file

該文件是在 FileOutputStream object 實例化時創建的。 如果文件已存在,則將其覆蓋。

您正在創建文件兩次。

一次在 writeHeader() function 和一次 writePCM() function 中。

當您寫入 PCM 數據時,您正在覆蓋您寫入的 header 數據,並且您最終會得到另一個 PCM 文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM