# Is 8-bit Audio Unsigned?

Started by 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.

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;

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?
```