F1sher
F1sher

Reputation: 7310

Convert 24 bit signed int signal to 16 bit signed int signal

To put it as simply as I can.

  1. I receive data from device and the signal is 24 bit signed int.
  2. I want to create 16 bit WAV file.
  3. For this purpose I want to keep writing upcoming audio buffer with 256 samples to *.wav file stream.
  4. How can I convert buffer values (well values written in simple pointer to 256 element array) from [24 bit signed int] to [16 bit signed int].

Is there any scaling value? For example when I wanted to cast [24 bit signed int] to [24 bit signed double] I did it like this:

for (int i=0; i<256; i++) {
   bufferInDouble = *((int*)bufferRawData[currentPan]+i) / (double)0x7fffffff;
}

Any similar method could be there?

Upvotes: 3

Views: 6265

Answers (2)

Tony Delroy
Tony Delroy

Reputation: 106096

The general answer is to divide by 256. Note that bit-shifting right won't work portably with signed ints (which are specified in your question): 5.8/3 in the C++ Standard says behaviour of E1 >> E2, where E1 is a negative signed value, is implementation defined.

An alternative that may retain higher audio quality is to find the highest amplitude values in the existing data (so you can only do this if you receive all the data before starting scaling) - let's call it M - then work out a scaling factor F such that that highest value has a new amplitude that's as high as 16 bit signed values can go: i.e. 32767.

M / F = 32767.0, so
F = M / 32767.0

Upvotes: 0

jaket
jaket

Reputation: 9341

The method is going to vary depending on whether you're 24-bit data is packed or is just 24-bits stored in a 32-bit word. I'm going to assume it is not packed and is left justified within the integer because that is most common.

The technique is to simply shift the data down into a 16-bit data type

ABCDEFxx => ABCD 

Here I've shown the nibbles of a 32-bit integer where ABCDEF contain the 24-bit audio data and the xx byte contains nothing of value. Shifting right by 16 will discard the EFxx.

short outBuffer[256]
int* inBuffer = ((int*)bufferRawData);
for (int i = 0 ; i < 256 ; ++i)
{
    outBuffer[i] = (short)(inBuffer[i] >> 16);
}

On a side note, it is often desirable when reducing the bit-depth to add some low level noise in the LSB to reduce the quantization distortion. This is known as dither. For information refer to this article on wikipedia Dither

Upvotes: 3

Related Questions