Nahid M
Nahid M

Reputation: 13

Seperating two audio channels on Android by Stereo recording

I am trying to record an audio using AudioRecord on android and seperate the right and left channel recordings into two different files and then convert it to wav to be able to play on the phone.But the recorded files have fast speed and it has high pitch.

I read all the samples and wrote this code but I am not sure which part is causing the problem.

This is my AudioRecord definition.

    minBufLength = AudioTrack.getMinBufferSize(48000,AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);

    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 48000, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufLength);

Then i read the short data and then convert the short data to byte and seperate it finally into byte array of both channels.

 shortData = new short[minBufLength/2];
 int readSize = recorder.read(shortData,0,minBufLength/2);

 byte bData[] = short2byte(shortData);

 for(int i = 0; i < readSize/2; i++)
  {

    final int offset = i * 2 * 2; // two bytes per sample and 2 channels
    rightChannelFos.write(bData, offset , 2);
    leftChannelFos.write(bData, offset + 2 , 2 );
  }

File rightChannelF1 = new File("/sdcard/rightChannelaudio"); // The location of your PCM file
File leftChannelF1 = new File("/sdcard/leftChannelaudio"); // The location of your PCM file
File rightChannelF2 = new File("/sdcard/rightChannelaudio.wav"); // The location where you want your WAV file
File leftChannelF2 = new File("/sdcard/leftChannelaudio.wav"); // The location where you want your WAV file
rawToWave(rightChannelF1, rightChannelF2);
rawToWave(leftChannelF1, leftChannelF2);

// convert short to byte
private byte[] short2byte(short[] sData) {
    int shortArrsize = sData.length;
    byte[] bytes = new byte[shortArrsize * 2];
    for (int i = 0; i < shortArrsize; i++) {
        bytes[i * 2] = (byte) (sData[i] & 0x00FF);
        bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
        sData[i] = 0;
    }
    return bytes;

}

This is the rawToWave function. I didn't inclue the other write functions to keep the post simple.

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) 2); // number of channels
        writeInt(output, 48000); // sample rate
        writeInt(output, 48000 * 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();
        }
    }
}

UPDATE:

I am adding this as an update just in case someone else is facing a problem like this. For some reason which I do not understand, channel updating loop is not working correcting. So I updated the byte array of each channel separately. Now since it is a 16 bit scheme, then it means there are 2 bytes per sample so the samples from the original data are in this format [LL][RR][LL][RR] which is why the loop should be based on the following

 for(int i = 0; i < readSize; i= i + 2)
        {
            leftChannelAudioData[i] = bData[2*i];
            leftChannelAudioData[i+1] = bData[2*i+1];

            rightChannelAudioData[i] =  bData[2*i+2];
            rightChannelAudioData[i+1] = bData[2*i+3];
        }

Upvotes: 1

Views: 558

Answers (1)

AterLux
AterLux

Reputation: 4654

In the WAV-header you have 2 channels (stereo) output format:

writeShort(output, (short) 2); // number of channels

If so, then byterate should be 48000 * 4 (= 2 bytes per channel * 2 channels per sample) also the block alignment should be 4 for the same reason.

Also, you need to write each sample twice, because your output is stereo: once for each channel. E.g.:

    rightChannelFos.write(bData, offset , 2);
    rightChannelFos.write(bData, offset , 2);
    leftChannelFos.write(bData, offset + 2 , 2 );
    leftChannelFos.write(bData, offset + 2 , 2 );

But more simpler solution is just to change output format to mono (1 channel):

writeShort(output, (short) 1); // number of channels

UPD

For the input buffer, you need to select its size large enough (e.g. 1 second) for it not to underrun while you're reading it by small chunks. It will be kept filled by the system while you're processing data E.g.:

recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 48000, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, 48000 * 4); // 1 second long

You may keep the reading buffer small but of some predefined size small. (e.g. 1024-4096 samples). When you call recorder.read it returns the actual size of the obtained data, not more than the buffer size (passed as the parameter) and no more than data available in the buffer.

Upvotes: 1

Related Questions