Is 8-bit Audio Unsigned?

Started by Chris Barrett January 19, 2007
I've been working on this problem for some time now, and I can't seem to 
understand what's going on.  I have data in the range of -1.0 to 1.0. 
For 8-bit audio  I scale it to range of 0 to 256 and for 16-bit audio I 
scale it to the range of -32768 to 32767.  Why can't I scale 8-bit audio 
to the range of -128 to 127? Why does it appear that 8-bit audio is not 
signed?

Below is some code that might give you a rough idea of what I am doing.


//-------- Here is Some Code ----------------------------------

long unsigned data32;

for( i = 0; i < length; i++)
{

	if (bits2 == 8)
		data32 = (long)( array[i]*127.0+128.5 );
		
	if (bits2 == 16)
		data32 = (long)( array[i]*32767.0+0.5 );


	fwrite(&data32,sampleSize,1,file_out);

}

//-------------------------------------------------------------

Chris Barrett wrote:

> I've been working on this problem for some time now, and I can't seem to > understand what's going on. I have data in the range of -1.0 to 1.0. > For 8-bit audio I scale it to range of 0 to 256 and for 16-bit audio I > scale it to the range of -32768 to 32767. Why can't I scale 8-bit audio > to the range of -128 to 127? Why does it appear that 8-bit audio is not > signed?
Yes, this is correct. The 8 bit wave audio is binary unsigned, whereas all other formats are twos complement. Why? Because Bill Gates did it that way. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
Chris Barrett wrote:
> I've been working on this problem for some time now, and I can't seem to > understand what's going on. I have data in the range of -1.0 to 1.0. > For 8-bit audio I scale it to range of 0 to 256 and for 16-bit audio I > scale it to the range of -32768 to 32767. Why can't I scale 8-bit audio > to the range of -128 to 127? Why does it appear that 8-bit audio is not > signed?
(snip)
> if (bits2 == 8) > data32 = (long)( array[i]*127.0+128.5 ); > > if (bits2 == 16) > data32 = (long)( array[i]*32767.0+0.5 );
Why do you add 128.5 to the eight bit data, but only 0.5 to 16 bit data? -- glen
glen herrmannsfeldt wrote:
> Chris Barrett wrote: > >> I've been working on this problem for some time now, and I can't seem >> to understand what's going on. I have data in the range of -1.0 to >> 1.0. For 8-bit audio I scale it to range of 0 to 256 and for 16-bit >> audio I scale it to the range of -32768 to 32767. Why can't I scale >> 8-bit audio to the range of -128 to 127? Why does it appear that 8-bit >> audio is not signed? > > > (snip) > >> if (bits2 == 8) >> data32 = (long)( array[i]*127.0+128.5 ); >> if (bits2 == 16) >> data32 = (long)( array[i]*32767.0+0.5 ); > > > Why do you add 128.5 to the eight bit data, but only 0.5 to 16 bit data? > > -- glen >
Because 8-bit audio is scaled from -128 to 127, and 16-bit audio is scaled from -32768 to 32767. The compiled code always rounds down when converting floating point numbers to integers. Adding the extra 0.5 will cause half of them to effectively be rounded up.
Chris Barrett wrote:
> glen herrmannsfeldt wrote: > >> Chris Barrett wrote: >> >>> I've been working on this problem for some time now, and I can't seem >>> to understand what's going on. I have data in the range of -1.0 to >>> 1.0. For 8-bit audio I scale it to range of 0 to 256 and for 16-bit >>> audio I scale it to the range of -32768 to 32767. Why can't I scale >>> 8-bit audio to the range of -128 to 127? Why does it appear that >>> 8-bit audio is not signed? >> >> >> >> (snip) >> >>> if (bits2 == 8) >>> data32 = (long)( array[i]*127.0+128.5 ); >>> if (bits2 == 16) >>> data32 = (long)( array[i]*32767.0+0.5 ); >> >> >> >> Why do you add 128.5 to the eight bit data, but only 0.5 to 16 bit data? >> >> -- glen >> > > Because 8-bit audio is scaled from -128 to 127, and 16-bit audio is > scaled from -32768 to 32767. The compiled code always rounds down when > converting floating point numbers to integers. Adding the extra 0.5 > will cause half of them to effectively be rounded up.
I made an error. The 8-bit audio is scaled from 0 to 256.
In your case, it seems to me like you can do whatever you like yourself, 
also do -128..127 for internal use.

But if you are planning to save data into a specific format (on disk) 
like G711 a-Law or u-Law (8 bit), then you need to follow the rules for 
that format.

The 16 bit data you make is pcm format, as saved in a wav file in 
Windows.

Saving G711 in Windows, you need to convert each 16 bit value using a 
function like pcm2ulaw()

g711Byte := pcm2ulaw ( pcm_word )
or
g711Byte := pcm2ulaw ( array[i]*32000 )

g711 format is 0 to 255 based, but that is not something you really need 
to think about in most cases.

I do a lot of VoIP handling using G711,ulaw on the IP connection, and as 
diskfiles if needed.
Internal I keep g711 as strings for easy passing along between 
functions.
When I do look at data (or generate tones), I use 16bit pcm.
I have 2 function between those 2 worlds, pcm2ulaw and ulaw2pcm.

-- 
Christen Fihl
http://HSPascal.Fihl.net/


Chris Barrett wrote:

>>> Why do you add 128.5 to the eight bit data, but only 0.5 to 16 bit data? >> >> Because 8-bit audio is scaled from -128 to 127, and 16-bit audio is >> scaled from -32768 to 32767. The compiled code always rounds down >> when converting floating point numbers to integers. Adding the extra >> 0.5 will cause half of them to effectively be rounded up. > > I made an error. The 8-bit audio is scaled from 0 to 256.
My question would be "why the 0.5 ?" --- correct me if I'm wrong, but I believe that in the 2's complement format, the 0V of the input analog signal maps to a 0. For the 8-bit unsigned format, I'm not sure, but I would find it severely wrong that the 0V does not map to an exact, integer value (such as 128, I would guess). If the 0V maps to something-point-five, then when you have a very weak signal, you're bound to have a very annoying and gratuitous +/- 1 bit noise. For very weak signals, you're amplifying the floor noise, instead of just thresholding it out (when the signal, or the floor noise, is lower than +/- 0.5 bits, then you make it 0 to completely eliminate it) Right? Carlos --
Chris Barrett wrote:

> I made an error. The 8-bit audio is scaled from 0 to 256.
WAV files store 8 bit samples as unsigned while AIFF and AU files store 8 bit samples as signed values. HTH, Erik -- +-----------------------------------------------------------+ Erik de Castro Lopo +-----------------------------------------------------------+ "It is forbidden for a Muslim to be a loyal friend to someone who does not believe in God and His Prophet, or someone who fights the religion of Islam." -- Fifth grade text book from Saudi Arabia http://www.washingtonpost.com/wp-dyn/content/article/2006/05/19/AR2006051901769_pf.html
Carlos Moreno wrote:
> Chris Barrett wrote: > > >>> Why do you add 128.5 to the eight bit data, but only 0.5 to 16 bit data? > >> > >> Because 8-bit audio is scaled from -128 to 127, and 16-bit audio is > >> scaled from -32768 to 32767. The compiled code always rounds down > >> when converting floating point numbers to integers. Adding the extra > >> 0.5 will cause half of them to effectively be rounded up. > > > > I made an error. The 8-bit audio is scaled from 0 to 256.
actually, in keeping with your previous statement (-128 to 127), 8-bit audio in WAV files has a range of 0 to 255 (not 256). and this format is often called "offset binary" as opposed to "2's complement". and the only difference between the two is the inversion of the MSB.
> > My question would be "why the 0.5 ?" --- correct me if I'm wrong, but I > believe that in the 2's complement format, the 0V of the input analog > signal maps to a 0. > > For the 8-bit unsigned format, I'm not sure, but I would find it > severely wrong that the 0V does not map to an exact, integer value > (such as 128, I would guess). If the 0V maps to something-point-five, > then when you have a very weak signal, you're bound to have a very > annoying and gratuitous +/- 1 bit noise. For very weak signals, you're > amplifying the floor noise, instead of just thresholding it out (when > the signal, or the floor noise, is lower than +/- 0.5 bits, then you > make it 0 to completely eliminate it)
the addition of 0.5 to a floating-point representation of integer values *almost* makes sense just before quantization by rounding down causing it to round-to-nearest. it's a small DC offset if you don't and rounding to nearest is a problem if you are within 1/2 LSB from the positive rail because you are rounding to a value (+128 or +32768) that is outside of your range. despite the DC bias, i might recommend just dropping the bits or the low-order portion (which is rounding down). then it is clear that every long word maps unambiguously to an appropriate short word and there are no funny exceptions (clipping at the +rails but no clipping at the -rail). if you're dithering are doing something else that may extend the signal out of range and clipping is possible, might as well add the bias (causing round-to-nearest) to the dither and deal with the possibility of clipping on either upper or lower rail. r b-j
I've found that I've been forced to use an if statement to read 24-bit 
audio.  I'm doing this with the following code:


//-------------------------------------------------
long data24;

fread(&data24,sampleSize,1,file_In);
if(data24 > 8388607)
	array1[i] =  (data24)/8388608.0 - 2.0;
if(data24 <= 8388607)
	array1[i] =  (data24)/8388608.0;
//-----------------------------------------------


The strange thing is that I've been able to write it without using an if 
statement.  I've done this using the following code:


//------------------------------------------------
long signed data24;

data24 = (long)floor((array2[i])*8388608.0+0.5);
fwrite(&data24,sampleSize,1,file_out);
//-----------------------------------------------


This makes no sense to me.  How can it require an if statement to read, 
but not one to write? Is there a way around this?