mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-14 07:35:12 +01:00
434 lines
12 KiB
C++
434 lines
12 KiB
C++
/*
|
|
* FixPoint.h - Provides fixed point arithmetic (for use in SID.cpp)
|
|
*
|
|
* (C) 1997 Andreas Dehmel
|
|
*
|
|
* Frodo (C) 1994-1997,2002-2005 Christian Bauer
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* You need to define FIXPOINT_PREC (number of fractional bits) and
|
|
* ldSINTAB (ld of the size of the sinus table) as well M_PI
|
|
* _before_ including this file.
|
|
* Requires at least 32bit ints!
|
|
*/
|
|
|
|
|
|
#define FIXPOINT_BITS 32
|
|
// Sign-bit
|
|
#define FIXPOINT_SIGN (1<<(FIXPOINT_BITS-1))
|
|
|
|
|
|
/*
|
|
* Elementary functions for the FixPoint class
|
|
*/
|
|
|
|
// Multiplies two fixpoint numbers, result is a fixpoint number.
|
|
static inline int fixmult(int x, int y)
|
|
{
|
|
register unsigned int a,b;
|
|
register bool sign;
|
|
|
|
sign = (x ^ y) < 0;
|
|
if (x < 0) {x = -x;}
|
|
if (y < 0) {y = -y;}
|
|
// a, b : integer part; x, y : fractional part. All unsigned now (for shift right)!!!
|
|
a = (((unsigned int)x) >> FIXPOINT_PREC); x &= ~(a << FIXPOINT_PREC);
|
|
b = (((unsigned int)y) >> FIXPOINT_PREC); y &= ~(b << FIXPOINT_PREC);
|
|
x = ((a*b) << FIXPOINT_PREC) + (a*y + b*x) +
|
|
((unsigned int)((x*y) + (1 << (FIXPOINT_PREC-1))) >> FIXPOINT_PREC);
|
|
#ifdef FIXPOINT_SIGN
|
|
if (x < 0) {x ^= FIXPOINT_SIGN;}
|
|
#endif
|
|
if (sign) {x = -x;}
|
|
return(x);
|
|
}
|
|
|
|
|
|
// Multiplies a fixpoint number with an integer, result is a 32 bit (!) integer in
|
|
// contrast to using the standard member-functions which can provide only (32-FIXPOINT_PREC)
|
|
// valid bits.
|
|
static inline int intmult(int x, int y) // x is fixpoint, y integer
|
|
{
|
|
register unsigned int i,j;
|
|
register bool sign;
|
|
|
|
sign = (x ^ y) < 0;
|
|
if (x < 0) {x = -x;}
|
|
if (y < 0) {y = -y;}
|
|
i = (((unsigned int)x) >> 16); x &= ~(i << 16); // split both into 16.16 parts
|
|
j = (((unsigned int)y) >> 16); y &= ~(j << 16);
|
|
#if FIXPOINT_PREC <= 16
|
|
// This '32' is independent of the number of bits used, it's due to the 16 bit shift
|
|
i = ((i*j) << (32 - FIXPOINT_PREC)) + ((i*y + j*x) << (16 - FIXPOINT_PREC)) +
|
|
((unsigned int)(x*y + (1 << (FIXPOINT_PREC - 1))) >> FIXPOINT_PREC);
|
|
#else
|
|
{
|
|
register unsigned int h;
|
|
|
|
h = (i*y + j*x);
|
|
i = ((i*j) << (32 - FIXPOINT_PREC)) + (h >> (FIXPOINT_PREC - 16));
|
|
h &= ((1 << (FIXPOINT_PREC - 16)) - 1); x *= y;
|
|
i += (x >> FIXPOINT_PREC); x &= ((1 << FIXPOINT_PREC) - 1);
|
|
i += (((h + (x >> 16)) + (1 << (FIXPOINT_PREC - 17))) >> (FIXPOINT_PREC - 16));
|
|
}
|
|
#endif
|
|
#ifdef FIXPOINT_SIGN
|
|
if (i < 0) {i ^= FIXPOINT_SIGN;}
|
|
#endif
|
|
if (sign) {i = -i;}
|
|
return(i);
|
|
}
|
|
|
|
|
|
// Computes the product of a fixpoint number with itself.
|
|
static inline int fixsquare(int x)
|
|
{
|
|
register unsigned int a;
|
|
|
|
if (x < 0) {x = -x;}
|
|
a = (((unsigned int)x) >> FIXPOINT_PREC); x &= ~(a << FIXPOINT_PREC);
|
|
x = ((a*a) << FIXPOINT_PREC) + ((a*x) << 1) +
|
|
((unsigned int)((x*x) + (1 << (FIXPOINT_PREC-1))) >> FIXPOINT_PREC);
|
|
#ifdef FIXPOINT_SIGN
|
|
if (x < 0) {x ^= FIXPOINT_SIGN;}
|
|
#endif
|
|
return(x);
|
|
}
|
|
|
|
|
|
// Computes the square root of a fixpoint number.
|
|
static inline int fixsqrt(int x)
|
|
{
|
|
register int test, step;
|
|
|
|
if (x < 0) return(-1); if (x == 0) return(0);
|
|
step = (x <= (1<<FIXPOINT_PREC)) ? (1<<FIXPOINT_PREC) : (1<<((FIXPOINT_BITS - 2 + FIXPOINT_PREC)>>1));
|
|
test = 0;
|
|
while (step != 0)
|
|
{
|
|
register int h;
|
|
|
|
h = fixsquare(test + step);
|
|
if (h <= x) {test += step;}
|
|
if (h == x) break;
|
|
step >>= 1;
|
|
}
|
|
return(test);
|
|
}
|
|
|
|
|
|
// Divides a fixpoint number by another fixpoint number, yielding a fixpoint result.
|
|
static inline int fixdiv(int x, int y)
|
|
{
|
|
register int res, mask;
|
|
register bool sign;
|
|
|
|
sign = (x ^ y) < 0;
|
|
if (x < 0) {x = -x;}
|
|
if (y < 0) {y = -y;}
|
|
mask = (1<<FIXPOINT_PREC); res = 0;
|
|
while (x > y) {y <<= 1; mask <<= 1;}
|
|
while (mask != 0)
|
|
{
|
|
if (x >= y) {res |= mask; x -= y;}
|
|
mask >>= 1; y >>= 1;
|
|
}
|
|
#ifdef FIXPOINT_SIGN
|
|
if (res < 0) {res ^= FIXPOINT_SIGN;}
|
|
#endif
|
|
if (sign) {res = -res;}
|
|
return(res);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* The C++ Fixpoint class. By no means exhaustive...
|
|
* Since it contains only one int data, variables of type FixPoint can be
|
|
* passed directly rather than as a reference.
|
|
*/
|
|
|
|
class FixPoint
|
|
{
|
|
private:
|
|
int x;
|
|
|
|
public:
|
|
FixPoint(void);
|
|
FixPoint(int y);
|
|
~FixPoint(void);
|
|
|
|
// conversions
|
|
int Value(void);
|
|
int round(void);
|
|
operator int(void);
|
|
|
|
// unary operators
|
|
FixPoint sqrt(void);
|
|
FixPoint sqr(void);
|
|
FixPoint abs(void);
|
|
FixPoint operator+(void);
|
|
FixPoint operator-(void);
|
|
FixPoint operator++(void);
|
|
FixPoint operator--(void);
|
|
|
|
// binary operators
|
|
int imul(int y);
|
|
FixPoint operator=(FixPoint y);
|
|
FixPoint operator=(int y);
|
|
FixPoint operator+(FixPoint y);
|
|
FixPoint operator+(int y);
|
|
FixPoint operator-(FixPoint y);
|
|
FixPoint operator-(int y);
|
|
FixPoint operator/(FixPoint y);
|
|
FixPoint operator/(int y);
|
|
FixPoint operator*(FixPoint y);
|
|
FixPoint operator*(int y);
|
|
FixPoint operator+=(FixPoint y);
|
|
FixPoint operator+=(int y);
|
|
FixPoint operator-=(FixPoint y);
|
|
FixPoint operator-=(int y);
|
|
FixPoint operator*=(FixPoint y);
|
|
FixPoint operator*=(int y);
|
|
FixPoint operator/=(FixPoint y);
|
|
FixPoint operator/=(int y);
|
|
FixPoint operator<<(int y);
|
|
FixPoint operator>>(int y);
|
|
FixPoint operator<<=(int y);
|
|
FixPoint operator>>=(int y);
|
|
|
|
// conditional operators
|
|
bool operator<(FixPoint y);
|
|
bool operator<(int y);
|
|
bool operator<=(FixPoint y);
|
|
bool operator<=(int y);
|
|
bool operator>(FixPoint y);
|
|
bool operator>(int y);
|
|
bool operator>=(FixPoint y);
|
|
bool operator>=(int y);
|
|
bool operator==(FixPoint y);
|
|
bool operator==(int y);
|
|
bool operator!=(FixPoint y);
|
|
bool operator!=(int y);
|
|
};
|
|
|
|
|
|
/*
|
|
* int gets treated differently according to the case:
|
|
*
|
|
* a) Equations (=) or condition checks (==, <, <= ...): raw int (i.e. no conversion)
|
|
* b) As an argument for an arithmetic operation: conversion to fixpoint by shifting
|
|
*
|
|
* Otherwise loading meaningful values into FixPoint variables would be very awkward.
|
|
*/
|
|
|
|
FixPoint::FixPoint(void) {x = 0;}
|
|
|
|
FixPoint::FixPoint(int y) {x = y;}
|
|
|
|
FixPoint::~FixPoint(void) {;}
|
|
|
|
inline int FixPoint::Value(void) {return(x);}
|
|
|
|
inline int FixPoint::round(void) {return((x + (1 << (FIXPOINT_PREC-1))) >> FIXPOINT_PREC);}
|
|
|
|
inline FixPoint::operator int(void) {return(x);}
|
|
|
|
|
|
// unary operators
|
|
inline FixPoint FixPoint::sqrt(void) {return(fixsqrt(x));}
|
|
|
|
inline FixPoint FixPoint::sqr(void) {return(fixsquare(x));}
|
|
|
|
inline FixPoint FixPoint::abs(void) {return((x < 0) ? -x : x);}
|
|
|
|
inline FixPoint FixPoint::operator+(void) {return(x);}
|
|
|
|
inline FixPoint FixPoint::operator-(void) {return(-x);}
|
|
|
|
inline FixPoint FixPoint::operator++(void) {x += (1 << FIXPOINT_PREC); return x;}
|
|
|
|
inline FixPoint FixPoint::operator--(void) {x -= (1 << FIXPOINT_PREC); return x;}
|
|
|
|
|
|
// binary operators
|
|
inline int FixPoint::imul(int y) {return(intmult(x,y));}
|
|
|
|
inline FixPoint FixPoint::operator=(FixPoint y) {x = y.Value(); return x;}
|
|
|
|
inline FixPoint FixPoint::operator=(int y) {x = y; return x;}
|
|
|
|
inline FixPoint FixPoint::operator+(FixPoint y) {return(x + y.Value());}
|
|
|
|
inline FixPoint FixPoint::operator+(int y) {return(x + (y << FIXPOINT_PREC));}
|
|
|
|
inline FixPoint FixPoint::operator-(FixPoint y) {return(x - y.Value());}
|
|
|
|
inline FixPoint FixPoint::operator-(int y) {return(x - (y << FIXPOINT_PREC));}
|
|
|
|
inline FixPoint FixPoint::operator/(FixPoint y) {return(fixdiv(x,y.Value()));}
|
|
|
|
inline FixPoint FixPoint::operator/(int y) {return(x/y);}
|
|
|
|
inline FixPoint FixPoint::operator*(FixPoint y) {return(fixmult(x,y.Value()));}
|
|
|
|
inline FixPoint FixPoint::operator*(int y) {return(x*y);}
|
|
|
|
inline FixPoint FixPoint::operator+=(FixPoint y) {x += y.Value(); return x;}
|
|
|
|
inline FixPoint FixPoint::operator+=(int y) {x += (y << FIXPOINT_PREC); return x;}
|
|
|
|
inline FixPoint FixPoint::operator-=(FixPoint y) {x -= y.Value(); return x;}
|
|
|
|
inline FixPoint FixPoint::operator-=(int y) {x -= (y << FIXPOINT_PREC); return x;}
|
|
|
|
inline FixPoint FixPoint::operator*=(FixPoint y) {x = fixmult(x,y.Value()); return x;}
|
|
|
|
inline FixPoint FixPoint::operator*=(int y) {x *= y; return x;}
|
|
|
|
inline FixPoint FixPoint::operator/=(FixPoint y) {x = fixdiv(x,y.Value()); return x;}
|
|
|
|
inline FixPoint FixPoint::operator/=(int y) {x /= y; return x;}
|
|
|
|
inline FixPoint FixPoint::operator<<(int y) {return(x << y);}
|
|
|
|
inline FixPoint FixPoint::operator>>(int y) {return(x >> y);}
|
|
|
|
inline FixPoint FixPoint::operator<<=(int y) {x <<= y; return x;}
|
|
|
|
inline FixPoint FixPoint::operator>>=(int y) {x >>= y; return x;}
|
|
|
|
|
|
// conditional operators
|
|
inline bool FixPoint::operator<(FixPoint y) {return(x < y.Value());}
|
|
|
|
inline bool FixPoint::operator<(int y) {return(x < y);}
|
|
|
|
inline bool FixPoint::operator<=(FixPoint y) {return(x <= y.Value());}
|
|
|
|
inline bool FixPoint::operator<=(int y) {return(x <= y);}
|
|
|
|
inline bool FixPoint::operator>(FixPoint y) {return(x > y.Value());}
|
|
|
|
inline bool FixPoint::operator>(int y) {return(x > y);}
|
|
|
|
inline bool FixPoint::operator>=(FixPoint y) {return(x >= y.Value());}
|
|
|
|
inline bool FixPoint::operator>=(int y) {return(x >= y);}
|
|
|
|
inline bool FixPoint::operator==(FixPoint y) {return(x == y.Value());}
|
|
|
|
inline bool FixPoint::operator==(int y) {return(x == y);}
|
|
|
|
inline bool FixPoint::operator!=(FixPoint y) {return(x != y.Value());}
|
|
|
|
inline bool FixPoint::operator!=(int y) {return(x != y);}
|
|
|
|
|
|
|
|
/*
|
|
* In case the first argument is an int (i.e. member-operators not applicable):
|
|
* Not supported: things like int/FixPoint. The same difference in conversions
|
|
* applies as mentioned above.
|
|
*/
|
|
|
|
|
|
// binary operators
|
|
inline FixPoint operator+(int x, FixPoint y) {return((x << FIXPOINT_PREC) + y.Value());}
|
|
|
|
inline FixPoint operator-(int x, FixPoint y) {return((x << FIXPOINT_PREC) - y.Value());}
|
|
|
|
inline FixPoint operator*(int x, FixPoint y) {return(x*y.Value());}
|
|
|
|
|
|
// conditional operators
|
|
inline bool operator==(int x, FixPoint y) {return(x == y.Value());}
|
|
|
|
inline bool operator!=(int x, FixPoint y) {return(x != y.Value());}
|
|
|
|
inline bool operator<(int x, FixPoint y) {return(x < y.Value());}
|
|
|
|
inline bool operator<=(int x, FixPoint y) {return(x <= y.Value());}
|
|
|
|
inline bool operator>(int x, FixPoint y) {return(x > y.Value());}
|
|
|
|
inline bool operator>=(int x, FixPoint y) {return(x >= y.Value());}
|
|
|
|
|
|
|
|
/*
|
|
* For more convenient creation of constant fixpoint numbers from constant floats.
|
|
*/
|
|
|
|
#define FixNo(n) (FixPoint)((int)(n*(1<<FIXPOINT_PREC)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Stuff re. the sinus table used with fixpoint arithmetic
|
|
*/
|
|
|
|
|
|
// define as global variable
|
|
FixPoint SinTable[(1<<ldSINTAB)];
|
|
|
|
|
|
#define FIXPOINT_SIN_COS_GENERIC \
|
|
if (angle >= 3*(1<<ldSINTAB)) {return(-SinTable[(1<<(ldSINTAB+2)) - angle]);}\
|
|
if (angle >= 2*(1<<ldSINTAB)) {return(-SinTable[angle - 2*(1<<ldSINTAB)]);}\
|
|
if (angle >= (1<<ldSINTAB)) {return(SinTable[2*(1<<ldSINTAB) - angle]);}\
|
|
return(SinTable[angle]);
|
|
|
|
|
|
// sin and cos: angle is fixpoint number 0 <= angle <= 2 (*PI)
|
|
static inline FixPoint fixsin(FixPoint x)
|
|
{
|
|
int angle = x;
|
|
|
|
angle = (angle >> (FIXPOINT_PREC - ldSINTAB - 1)) & ((1<<(ldSINTAB+2))-1);
|
|
FIXPOINT_SIN_COS_GENERIC
|
|
}
|
|
|
|
|
|
static inline FixPoint fixcos(FixPoint x)
|
|
{
|
|
int angle = x;
|
|
|
|
// cos(x) = sin(x+PI/2)
|
|
angle = (angle + (1<<(FIXPOINT_PREC-1)) >> (FIXPOINT_PREC - ldSINTAB - 1)) & ((1<<(ldSINTAB+2))-1);
|
|
FIXPOINT_SIN_COS_GENERIC
|
|
}
|
|
|
|
|
|
|
|
static inline void InitFixSinTab(void)
|
|
{
|
|
int i;
|
|
float step;
|
|
|
|
for (i=0, step=0; i<(1<<ldSINTAB); i++, step+=0.5/(1<<ldSINTAB))
|
|
{
|
|
SinTable[i] = FixNo(sin(M_PI * step));
|
|
}
|
|
}
|