0

Using below code I want to convert .pcm file to .wav file in android application.

public class WavConvertor {
public 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.readFully(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, MyApplicationVar.getInstance().SAMPLING_RATE); // sample rate
        writeInt(output, MyApplicationVar.getInstance().SAMPLING_RATE * 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));
    }
}
}

for small files it is ok but for large files when convertin I get this error . I searched and used some solutions but they didn't work

java.lang.OutOfMemoryError: Failed to allocate a 160369676 byte allocation with 16777216 free bytes and 46MB until OOM

Is there any way to read the pcm file part by part and write them?

BTW

I had set

    android:largeHeap="true"
    android:hardwareAccelerated="false"

in manifest but didn't work

unos baghaii
  • 2,539
  • 4
  • 25
  • 42
  • 1
    "Is there any way to read the pcm file part by part and write them?" -- all that you appear to be doing is copying the bytes from the old file to the new one. Rather than reading in the entire file, have both your `FileInputStream` and your `DataOutputStream` open at once, and copy in smaller chunks (e.g., 8KB). This has little to do with Android and everything to do with standard Java I/O. – CommonsWare Feb 13 '17 at 20:08
  • 1
    The scenario is like you have 2 buckets of water and you want to move water from 1 (pcm) to 2 (wav) using a glass ( android memory )... instead of filling the whole bucket in the glass at once , you try to do in chunks.... #1. keep a pointer to count last amount of byte read like 0-1023 , 1024-2047 .... #2. take bytes and append to the wav file... #4. also use global variable name instead of local because the garbage collector might fail and with global you will be referencing the same variable instead of new ones.... – Ahmad Feb 13 '17 at 20:12
  • see http://stackoverflow.com/questions/3641920/how-to-encode-a-wav-to-a-mp3-on-a-android-device – petey Feb 13 '17 at 20:13
  • I got it. I read my file in small parts and append to my .wav file @Ahmad – unos baghaii Feb 14 '17 at 05:32

0 Answers0