java pcm to wav

前端 未结 5 1673
别跟我提以往
别跟我提以往 2020-12-18 10:32

I have a pcm file, and I want to convert it to a wav file.

Is there any suitable api or code for this?

相关标签:
5条回答
  • 2020-12-18 10:44

    I know one called "OperateWav" that I used to develop a convertor(linux c/c++) in my first project during my first internship.I am not sure if this one exists per se and whether it supports java.Actually wav file is simply adding a wav format header on pcm raw data...

    0 讨论(0)
  • 2020-12-18 10:46

    it's My Code

    /**
     * Write PCM data as WAV file
     * @param os  Stream to save file to
     * @param pcmdata  8 bit PCMData
     * @param srate  Sample rate - 8000, 16000, etc.
     * @param channel Number of channels - Mono = 1, Stereo = 2, etc..
     * @param format Number of bits per sample (16 here)
     * @throws IOException
     */
    public void PCMtoFile(OutputStream os, short[] pcmdata, int srate, int channel, int format) throws IOException {
        byte[] header = new byte[44];
        byte[] data = get16BitPcm(pcmdata);
    
        long totalDataLen = data.length + 36;
        long bitrate = srate * channel * format;
    
        header[0] = 'R'; 
        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';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; 
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = (byte) format; 
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; 
        header[21] = 0;
        header[22] = (byte) channel; 
        header[23] = 0;
        header[24] = (byte) (srate & 0xff);
        header[25] = (byte) ((srate >> 8) & 0xff);
        header[26] = (byte) ((srate >> 16) & 0xff);
        header[27] = (byte) ((srate >> 24) & 0xff);
        header[28] = (byte) ((bitrate / 8) & 0xff);
        header[29] = (byte) (((bitrate / 8) >> 8) & 0xff);
        header[30] = (byte) (((bitrate / 8) >> 16) & 0xff);
        header[31] = (byte) (((bitrate / 8) >> 24) & 0xff);
        header[32] = (byte) ((channel * format) / 8); 
        header[33] = 0;
        header[34] = 16; 
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (data.length  & 0xff);
        header[41] = (byte) ((data.length >> 8) & 0xff);
        header[42] = (byte) ((data.length >> 16) & 0xff);
        header[43] = (byte) ((data.length >> 24) & 0xff);
    
        os.write(header, 0, 44);
        os.write(data);
        os.close();
    }
    

    EDIT: 2016-01-11

    public byte[] get16BitPcm(short[] data) {
        byte[] resultData = new byte[2 * data.length];
        int iter = 0;
        for (double sample : data) {
            short maxSample = (short)((sample * Short.MAX_VALUE));
            resultData[iter++] = (byte)(maxSample & 0x00ff);
            resultData[iter++] = (byte)((maxSample & 0xff00) >>> 8);
        }
        return resultData;
    }
    
    0 讨论(0)
  • 2020-12-18 10:59

    This should be quite simple to do because WAV = Metadata + PCM (in that order). This should work:

    private void rawToWave(final File rawFile, final File waveFile) throws IOException {
    
    byte[] rawData = new byte[(int) rawFile.length()];
    DataInputStream input = null;
    try {
        input = new DataInputStream(new FileInputStream(rawFile));
        input.read(rawData);
    } finally {
        if (input != null) {
            input.close();
        }
    }
    
    DataOutputStream output = null;
    try {
        output = new DataOutputStream(new FileOutputStream(waveFile));
        // WAVE header
        // see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
        writeString(output, "RIFF"); // chunk id
        writeInt(output, 36 + rawData.length); // chunk size
        writeString(output, "WAVE"); // format
        writeString(output, "fmt "); // subchunk 1 id
        writeInt(output, 16); // subchunk 1 size
        writeShort(output, (short) 1); // audio format (1 = PCM)
        writeShort(output, (short) 1); // number of channels
        writeInt(output, 44100); // sample rate
        writeInt(output, RECORDER_SAMPLERATE * 2); // byte rate
        writeShort(output, (short) 2); // block align
        writeShort(output, (short) 16); // bits per sample
        writeString(output, "data"); // subchunk 2 id
        writeInt(output, rawData.length); // subchunk 2 size
        // Audio data (conversion big endian -> little endian)
        short[] shorts = new short[rawData.length / 2];
        ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
        for (short s : shorts) {
            bytes.putShort(s);
        }
    
        output.write(fullyReadFileToBytes(rawFile));
    } finally {
        if (output != null) {
            output.close();
        }
    }
    }
    byte[] fullyReadFileToBytes(File f) throws IOException {
    int size = (int) f.length();
    byte bytes[] = new byte[size];
    byte tmpBuff[] = new byte[size];
    FileInputStream fis= new FileInputStream(f);
    try { 
    
        int read = fis.read(bytes, 0, size);
        if (read < size) {
            int remain = size - read;
            while (remain > 0) {
                read = fis.read(tmpBuff, 0, remain);
                System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
                remain -= read;
            } 
        } 
    }  catch (IOException e){
        throw e;
    } finally { 
        fis.close();
    } 
    
    return bytes;
    } 
    private void writeInt(final DataOutputStream output, final int value) throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
    output.write(value >> 16);
    output.write(value >> 24);
    }
    
    private void writeShort(final DataOutputStream output, final short value) throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
    }
    
    private void writeString(final DataOutputStream output, final String value) throws IOException {
    for (int i = 0; i < value.length(); i++) {
        output.write(value.charAt(i));
        }
    }
    

    How to use

    It's quite simple to use. Just call it like this:

    File f1 = new File("/sdcard/44100Sampling-16bit-mono-mic.pcm"); // The location of your PCM file
    File f2 = new File("/sdcard/44100Sampling-16bit-mono-mic.wav"); // The location where you want your WAV file
    try {
    rawToWave(f1, f2);
    } catch (IOException e) {
    e.printStackTrace();
    }
    

    How all this works

    As you can see, the WAV header is the only difference between WAV and PCM file formats. The assumption is that you are recording 16 bit PCM MONO audio (which according to your code, you are). The rawToWave function just neatly adds headers to the WAV file, so that music players know what to expect when your file is opened, and then after the headers, it just writes the PCM data from the last bit onwards.

    Cool Tip

    If you want to shift the pitch of your voice, or make a voice changer app, all you got to do is increase/decrease the value of writeInt(output, 44100); // sample rate in your code. Decreasing it will tell the player to play it at a different rate thereby changing the output pitch. Just a little extra 'good to know' thing. :)

    0 讨论(0)
  • 2020-12-18 11:04

    I cannot yet leave comments, but be aware that the get16BitPcm method in devflow's answer is [oddly] scaling the input data. If you already have 16 bit pcm data to write to the wav file, the method should look something like this:

    public byte[] get16BitPcm(short[] data) {
        byte[] resultData = new byte[2 * data.length];
        int iter = 0;
        for (short sample : data) {
            resultData[iter++] = (byte)(sample & 0x00ff);
            resultData[iter++] = (byte)((sample & 0xff00) >>> 8);
        }
        return resultData;
    }
    
    0 讨论(0)
  • 2020-12-18 11:04

    This resource, WAVE PCM soundfile format, helped me to parse PCM data to WAVE. I've built a library based on it and it works fine for me.

    0 讨论(0)
提交回复
热议问题