Re: using integer audio data
Re: using integer audio data
- Subject: Re: using integer audio data
- From: Ian Ollmann <email@hidden>
- Date: Thu, 23 Aug 2001 17:15:56 -0700
On Thu, 23 Aug 2001, Timothy J. Wood wrote:
>
By default CoreAudio wants -1.0..1.0, but there is a
>
'kAudioDevicePropertyVolumeScalar' property that is commented as:
>
>
// a Float32 between 0 and 1 that scales the volume of the
>
device/channel.
>
>
I'm not sure if this is something that the hardware supports or
>
whether this scaling done in software. Is there any way to tell? If
>
this was done in hardware, then I could set this to 1.0/32768.0 and get
>
free conversion to -1.0 .. 1.0.
I doubt our sound hardware magically started accepting floating point
input when OS X appeared. Did they already accept it? Otherwise, my guess
is that probably the OS does the mixing in software and then does a final
float->SInt16 conversion before sending the data to the hardware, except
where the hardware accepts floating point input.
Why do you need floats for mixing? You can be very successful with longs.
>
I'll try writing something up tonight and if I get something useful,
>
I'll post it to the list. I'll probably look something like:
>
>
// build a mask of 0x0 or 0xffffffff by replicating sign bit of input
>
// negate input
>
// choose the positive input by ((neg & mask) | (pos & ~mask))
>
// count leading zeros of positive value
>
// shift exponent and positive input around to get resulting value
>
// or in the top bit of the mask to get the sign bit
That would work. Dont forget to rotate so that the first bit of your
significand is cut off when you insert the exponent and sign bit. I am not
quite sure if this method is faster, though. Lets see, give or take a bug
or two it would probably look very roughly like this:
long mask = value >> 31;
long negValue = -value;
value = (negValue & mask) | (value & ~mask);
long zeros = __cntlzw( value );
long exponent = (mask & 256) + (127 - zeros);
value <<= 8 + zeros;
value = __rlwimi( value, exponent, 23, 0, 8 );
So, 12 instructions, quite a few of which can overlap. Even with good
store to load data forwarding you will lose at least 6 cycles just for the
transfer to the FPU plus another three for dealing with the silent 1 bit
in the FP format, so there is a good chance you can beat the standard
conversion this way by a cycle or two. More importantly some CPU's will be
able to do one or more conversions concurrently because they have 2-3
integer units.
However, you will never get 1.0 as a result and I think the value 0 fails
to generate 0.0, though it does make a suitably small number that it may
not matter. The worry is that the reverse float->int conversion (if any)
before the value hits hardware will cause a replacement of all of these
with a 1 or that (1/2)/32768 appearing where a 0 should be will cause some
unfortunate rounding in the mixer.
What is more important in the SInt16->float conversion, that 32767 becomes
1.0 or that 0 becomes 0.0? How do you scale it? Ints are not symmetrically
distributed about 0.
Ian
---------------------------------------------------
Ian Ollmann, Ph.D. email@hidden
---------------------------------------------------