Is 8-bit Audio Unsigned?

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);
}
//-------------------------------------------------------------

Posted by Vladimir Vassilevsky●January 19, 2007

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

Posted by glen herrmannsfeldt●January 20, 2007

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?

Why do you add 128.5 to the eight bit data, but only 0.5 to 16 bit data?
-- glen

Posted by Chris Barrett●January 20, 2007

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.

Posted by Chris Barrett●January 20, 2007

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.

Posted by Christen Fihl●January 20, 2007

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/

Posted by Carlos Moreno●January 20, 2007

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

Posted by Erik de Castro Lopo●January 20, 2007

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

Posted by robert bristow-johnson●January 20, 2007

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

Posted by Chris Barrett●January 21, 2007

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?