source/LDandFix.c

/*
**  Apple Macintosh Developer Technical Support
**
**  Routines demonstrating how to convert to and from long double and Fixed types.
**
**  by Mark Cookson, Apple Developer Technical Support
**
**  File:   LDandFix.c
**
**  Copyright ©1996 Apple Computer, Inc.
**  All rights reserved.
**
**  You may incorporate this sample code into your applications without
**  restriction, though the sample code has been provided "AS IS" and the
**  responsibility for its operation is 100% yours.  However, what you are
**  not permitted to do is to redistribute the source as "Apple Sample
**  Code" after having made changes. If you're going to re-distribute the
**  source, we require that you make it clear in the source that the code
**  was descended from Apple Sample Code, but that you've made changes.
*/
 
#include "LDandFix.h"
 
Fixed           ASoundLongDoubleToFix   (long double theLD)
{
/*
    A Fixed number is of the type 12345.67890.  It is 32 bits in size with the
    high order bits representing the significant value (that before the point)
    and the lower 16 bits representing the fractional part of the number.
 
    The Sound Manager further complicates matters by using Fixed numbers, but
    needing to represent numbers larger than what the Fixed is capable of.
 
    To do this the Sound Manager treats the sign bit as having the value 32768
    which will cause any number greater or equal to 32768 to look like it is
    negative.
 
    This routine is designed to "do the right thing" and convert any long double
    into the Fixed number it represents.
 
    long double is the input type because AIFF files use extended80 numbers and
    there are routines that will convert from an extended80 to a long double.
 
    A long double has far greater precision than a Fixed, so any number whose
    significant or fraction is larger than 65535 will not convert correctly.
*/
 
    unsigned long   theResult       = 0;
    unsigned short  theSignificant  = 0,
                    theFraction     = 0;
 
    if (theLD < kMaxValue) {
        theSignificant = theLD;
        theFraction = theLD - theSignificant;
        if (theFraction > kMaxValue) {
            /* Won't be able to convert */
            theSignificant  = 0;
            theFraction     = 0;
        }
    }
 
    theResult |= theSignificant;
    theResult = theResult << (sizeof (unsigned short) * kBitsPerByte);
    theResult |= theFraction;
 
    return theResult;
}
 
/*
    I'm still trying to figure out why I need the correction factor, but the
    number returned by this function is only for our own internal calculation
    of buffer sizing so we can afford to loose a little precision in the
    fraction.
*/
long double     ASoundFixToLongDouble   (Fixed theFixed)
{
    long double     theResult   = 0.0;
    unsigned short  high16Bits  = 0,
                    low16Bits   = 0;
 
    high16Bits = theFixed >> (sizeof (unsigned short) * kBitsPerByte);
    low16Bits = theFixed + 0x496E;      /* Correction factor */
 
    theResult = high16Bits + (low16Bits * kFraction);
 
    return theResult;
}