SamRowley
SamRowley

Reputation: 3485

AudioRecord PCM data of no use?

I have recorded using the Mic in my android app and this plays perfectly well when using the AudioPlayer class having streamed the data in. My problem is I want to append a wav header to this data so it can be played outside of the application. I am pretty sure the methods to create the header work after playing around in a hex editor with other audio files, which leads to the pcm data recorded to not being useful as raw data in a wav file?

Can anybody shed any light on this? I can import the pcm/wav file into audacity as a raw file and it plays perfectly but when I try it as just opening the wav I just get noise, again hinting the pcm data is at fault.

Recording Settings:

int frequency = 22050;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

Header Variables:

byte[] clipData = data;
long myDataSize = clipData.length;
long mySubChunk1Size = 16;
int myBitsPerSample= 16;
int myFormat = 1;
long myChannels = 1;
long mySampleRate = 22050;
long myByteRate = mySampleRate * myChannels * myBitsPerSample/8;
int myBlockAlign = (int) (myChannels * myBitsPerSample/8);
long myChunk2Size =  myDataSize * myChannels * myBitsPerSample/8;
long myChunkSize = 36 + myChunk2Size;

try
        {
            File audioDirectory = new File(Environment
                    .getExternalStorageDirectory().getAbsolutePath()
                    + "/Directory/");
            audioDirectory.mkdir();
            File file = new File(audioDirectory, "test.wav");
            if (file.exists())
                file.delete();

            // Create the new file.
            try {
                file.createNewFile();
            } catch (IOException e) {
                throw new IllegalStateException("Failed to create "
                        + file.toString());
            }
            OutputStream os = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            DataOutputStream outFile = new DataOutputStream(bos);

            // write the wav file per the wav file format
            outFile.writeBytes("RIFF");                 // 00 - RIFF
            outFile.write(intToByteArray((int)myChunkSize), 0, 4);      // 04 - how big is the rest of this file?
            outFile.writeBytes("WAVE");                 // 08 - WAVE
            outFile.writeBytes("fmt ");                 // 12 - fmt 
            outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4);  // 16 - size of this chunk
            outFile.write(shortToByteArray((short)myFormat), 0, 2);     // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
            outFile.write(shortToByteArray((short)myChannels), 0, 2);   // 22 - mono or stereo? 1 or 2?  (or 5 or ???)
            outFile.write(intToByteArray((int)mySampleRate), 0, 4);     // 24 - samples per second (numbers per second)
            outFile.write(intToByteArray((int)myByteRate), 0, 4);       // 28 - bytes per second
            outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); // 32 - # of bytes in one sample, for all channels
            outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2);  // 34 - how many bits in a sample(number)?  usually 16 or 24
            outFile.writeBytes("data");                 // 36 - data
            outFile.write(intToByteArray((int)myDataSize), 0, 4);       // 40 - how big is this data chunk
            outFile.write(clipData);                        // 44 - the actual data itself - just a long string of numbers
        }

Convertors

public static int byteArrayToInt(byte[] b)
    {
        int start = 0;
        int low = b[start] & 0xff;
        int high = b[start+1] & 0xff;
        return (int)( high << 8 | low );
    }


    // these two routines convert a byte array to an unsigned integer
    public static long byteArrayToLong(byte[] b)
    {
        int start = 0;
        int i = 0;
        int len = 4;
        int cnt = 0;
        byte[] tmp = new byte[len];
        for (i = start; i < (start + len); i++)
        {
            tmp[cnt] = b[i];
            cnt++;
        }
        long accum = 0;
        i = 0;
        for ( int shiftBy = 0; shiftBy < 32; shiftBy += 8 )
        {
            accum |= ( (long)( tmp[i] & 0xff ) ) << shiftBy;
            i++;
        }
        return accum;
    }


// ===========================
// CONVERT JAVA TYPES TO BYTES
// ===========================
    // returns a byte array of length 4
    private static byte[] intToByteArray(int i)
    {
        byte[] b = new byte[4];
        b[0] = (byte) (i & 0x00FF);
        b[1] = (byte) ((i >> 8) & 0x000000FF);
        b[2] = (byte) ((i >> 16) & 0x000000FF);
        b[3] = (byte) ((i >> 24) & 0x000000FF);
        return b;
    }

    // convert a short to a byte array
    public static byte[] shortToByteArray(short data)
    {
        return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)};
    }

Upvotes: 2

Views: 2980

Answers (2)

dickwan
dickwan

Reputation: 337

Take a look at the rehearshal assistant code for writing the wav header here

Upvotes: 0

MusiGenesis
MusiGenesis

Reputation: 75356

You're probably just setting the header properties wrong. The WAV format header should be 44 bytes, followed by the raw audio data. Here is a description of the WAV format:

http://www.sonicspot.com/guide/wavefiles.html

If you've created a header and appended the raw data, and the resulting file plays without error but sounds like noise, then the most likely culprit is that the raw audio uses 2 bytes per sample but you set the BitsPerSample property in the header to 8.

The approach that you're using (prepending a WAV header to raw audio) is perfectly valid and should work fine.

Update: Hey, shouldn't your conversion method be

    // convert a short to a byte array
    public static byte[] shortToByteArray(short data)
    {
        return new byte[]{(byte)(data & 0xff),(byte)((data >> 8) & 0xff)};
    }

? I'm not sure what >>> means in the bit-shifting world.

Upvotes: 1

Related Questions