1

Below is the code I have used to read 16-bit and 32-bit per sample wavs which work just fine.

My question is, how can I read the remaining 8-bit unsigned, 24-bit signed, and 32-bit float wavs?

Read one sample of a 16-bit signed wav:

short buffer;

file.read( ( char * ) &readbuffer, 2 );

Read one sample of a 32-bit signed wav:

int buffer;

file.read( ( char * ) &readbuffer, 4 );
Tek
  • 2,888
  • 5
  • 45
  • 73
  • 2
    It seems weird to use sizeof() there when what you explicitly want is the number of bytes/bits to read. Especially as the C++ standard doesn't restrict these types to a certain size. – Jeffrey Theobald Jan 01 '13 at 14:30
  • @JeffreyTheobald Well I did want to read just one sample of the size of an int/short. But I've changed it so that we can focus on the question. – Tek Jan 01 '13 at 15:01

1 Answers1

1

You're making a few assumptions about the target machine. According to the Microsoft WAV format, All sample data is little-endian. You're also expecting the various data types to be the size that you want, which may not always be the case.

But as your current routines work for you, we won't focus on that for the moment (but you probably should fix these things at some point)

32 bit float

If we forget about the scary endian-ness and non-standard type sizes, the 32-bit float case becomes relatively straightforward using your other code as a template:

float buffer;
file.read( ( char * ) &buffer, 4 );

This question covers reading floats from a binary source in a lot more detail.

x bit unsigned

Since we know that your machine is correctly interpreting the 16 and 32 bit cases, we can assume it is little endian. Which means you can just read everything into an unsigned int that has been initialized to zero and the remaining bytes are already correctly padded for you:

unsigned int buffer = 0;
file.read( ( char * ) &buffer, 1 );   // 8bit unsigned integer

buffer = 0;
file.read( ( char * ) &buffer, 3 );   // 24bit unsigned integer

x bit signed

Finally, if you're reading a signed integer, you need to pad the remaining bytes of your buffer variable depending on the value of the number you just read:

  • If the number was positive you can just pad with 0
  • If the number was negative (highest bit of the most significant byte is set) then you pad with with \xFF bytes.

This code works on a 24 bit signed integer:

long buffer;
int number_of_bytes = 3;             // 24 bit signed integer

file.read( (char *) &buffer, number_of_bytes);

// Determine the padding byte
unsigned char padding_byte = 0;
if ( ((char*) &buffer)[number_of_bytes - 1] & 128) {
    padding_byte = 255;
}

// Pad the data
for (int i = number_of_bytes; i < sizeof(buffer); i++) {
    ((char*) &buffer)[i] = padding_byte;
}

Again, I feel I should point out that this code will fail on some machines because you're not checking endian-ness. But all you need to do to fix that is check the endian-ness of the machine that's running the code and reverse the order of the bytes if you're on a big-endian machine.

Community
  • 1
  • 1
Jeffrey Theobald
  • 2,469
  • 18
  • 15
  • Yeah, this program will be only used on my machine. Whenever I want to use it on another computer I'll worry about it later :P – Tek Jan 01 '13 at 22:23
  • I noticed that I forgot to handle the 24-bit unsigned case, so I've updated my answer with those details. – Jeffrey Theobald Jan 02 '13 at 01:21
  • My mistake, should have been `buffer`. – Jeffrey Theobald Jan 02 '13 at 03:49
  • Thanks a lot man, it works wonderfully. I also had no idea about the padding, there's a lot of examples online but no one talks about padding with signed integers. – Tek Jan 02 '13 at 05:49