Skip to content Skip to sidebar Skip to footer

How To Convert .pcm File To .wav Or .mp3?

I am currently developing an Android Application that has audio recording and playing. I am new to dealing with audio and I'm having some trouble with encoding and formats. I am a

Solution 1:

You've got most of the code correct. The only issue that I can see is the part where you write the PCM data to the WAV file. This should be quite simple to do because WAV = Metadata + PCM (in that order). This should work:

privatevoidrawToWave(final File rawFile, final File waveFile)throws IOException {

    byte[] rawData = newbyte[(int) rawFile.length()];
    DataInputStreaminput=null;
    try {
        input = newDataInputStream(newFileInputStream(rawFile));
        input.read(rawData);
    } finally {
        if (input != null) {
            input.close();
        }
    }

    DataOutputStreamoutput=null;
    try {
        output = newDataOutputStream(newFileOutputStream(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 = newshort[rawData.length / 2];
        ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        ByteBufferbytes= 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 {
    intsize= (int) f.length();
    byte bytes[] = newbyte[size];
    byte tmpBuff[] = newbyte[size];
    FileInputStream fis= newFileInputStream(f);
    try { 

        intread= fis.read(bytes, 0, size);
        if (read < size) {
            intremain= 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;
} 
privatevoidwriteInt(final DataOutputStream output, finalint value)throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
    output.write(value >> 16);
    output.write(value >> 24);
}

privatevoidwriteShort(final DataOutputStream output, finalshort value)throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
}

privatevoidwriteString(final DataOutputStream output, final String value)throws IOException {
    for (inti=0; i < value.length(); i++) {
        output.write(value.charAt(i));
    }
}

How to use

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

Filef1=newFile("/sdcard/44100Sampling-16bit-mono-mic.pcm"); // The location of your PCM fileFilef2=newFile("/sdcard/44100Sampling-16bit-mono-mic.wav"); // The location where you want your WAV filetry {
    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. :)

Solution 2:

I know it is late and you got your stuff working with MediaRecorder. But thought of sharing my answer as it took me some good time to find it. :)

When you record your audio, the data is read as short from your AudioRecord object and it is then converted to bytes before storing in the .pcm file.

Now, when you write the .wav file, you're again doing the short conversion. This is not required. So, in your code if you remove the following block and write the rawData directly to the end of .wav file. It will work just fine.

short[] shorts = newshort[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);
    }

Check the below piece of code you'll get after removing the duplicate block of code.

writeInt(output, rawData.length); // subchunk 2 size// removed the duplicate short conversion
    output.write(rawData);

Solution 3:

Just to register, I solved my need of recording an audio playable in common players using MediaRecorder instead of Audio Recorder.

To start recording:

MediaRecordermRecorder=newMediaRecorder();
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    mRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
    mRecorder.setOutputFile(Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "/recording.3gp");

    mRecorder.prepare();
    mRecorder.start();

And to play the recording:

    mPlayer = newMediaPlayer();
    mPlayer.setDataSource(Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "/recording.3gp");

    mPlayer.prepare();
    mPlayer.start();

Solution 4:

I tried the above code for audio recording writeAudioDataToFile(). It perfectly records and convert the audio into .wav format. But when I played the recorded audio, it was too fast. 5sec audio completed in 2.5 sec. Then I observed it was because of this short2byte() function.

For those how are having same problem should not use short2byte() and directly write sData in line os.write(sData, 0, Constants.BufferElements2Rec * Constants.BytesPerElement); where sData should be byte[].

Post a Comment for "How To Convert .pcm File To .wav Or .mp3?"