pcsx2/plugins/spu2ghz/asio/ASIOConvertSamples.cpp

879 lines
15 KiB
C++

#include "ginclude.h"
#include "ASIOConvertSamples.h"
#include <math.h>
#if MAC
#define TRUNCATE 0
#elif ASIO_CPU_X86 || ASIO_CPU_SPARC || ASIO_CPU_MIPS
#define TRUNCATE 1
#undef MAXFLOAT
#define MAXFLOAT 0x7fffff00L
#endif
ASIOConvertSamples::ASIOConvertSamples()
{
}
//-------------------------------------------------------------------------------------------
// mono
void ASIOConvertSamples::convertMono8Unsigned(long *source, char *dest, long frames)
{
unsigned char *c = (unsigned char *)source;
unsigned char a;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = c[3];
#else
a = c[0];
#endif
c += 4;
a -= 0x80U;
*++dest = a;
}
}
void ASIOConvertSamples::convertMono8(long *source, char *dest, long frames)
{
char *c = (char *)source;
char a;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = c[3];
#else
a = c[0];
#endif
c += 4;
*++dest = a;
}
}
void ASIOConvertSamples::convertMono16(long *source, short *dest, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* s = (char*)source;
char* d = (char*)dest;
while(--frames >= 0)
{
*d++ = s[3]; // dest big endian, msb first
*d++ = s[2];
s += 4;
}
#else
long l;
source--;
dest--;
while(--frames >= 0)
{
l = *++source;
*++dest = (short)(l >> 16);
}
#endif
}
void ASIOConvertSamples::convertMono24(long *source, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *s = (char *)source;
char a, b, c;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3]; // msb
b = s[2];
c = s[1]; // lsb
#else
a = s[0];
b = s[1];
c = s[2];
#endif
s += 4;
*++dest = a; // big endian, msb first
*++dest = b;
*++dest = c;
}
}
// small endian
void ASIOConvertSamples::convertMono16SmallEndian(long *source, short *dest, long frames)
{
char *s = (char *)source;
char *d = (char *)dest;
char a, b;
d--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3];
b = s[2];
#else
a = s[0];
b = s[1];
#endif
s += 4;
*++d = b; // dest small endian, lsb first
*++d = a;
}
}
void ASIOConvertSamples::convertMono24SmallEndian(long *source, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *s = (char *)source;
char a, b, c;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3];
b = s[2];
c = s[1];
#else
a = s[0];
b = s[1];
c = s[2];
#endif
s += 4;
*++dest = c; // lsb first
*++dest = b;
*++dest = a;
}
}
//-------------------------------------------------------------------------------------------
// stereo interleaved
void ASIOConvertSamples::convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
a -= 0x80U;
b -= 0x80U;
*++dest = a;
*++dest = b;
}
}
void ASIOConvertSamples::convertStereo8Interleaved(long *left, long *right, char *dest, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
*++dest = a;
*++dest = b;
}
}
void ASIOConvertSamples::convertStereo16Interleaved(long *left, long *right, short *dest, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* sl = (char*)left;
char* sr = (char*)right;
char* d = (char*)dest;
while(--frames >= 0)
{
*d++ = sl[3]; // msb first
*d++ = sl[2];
*d++ = sr[3];
*d++ = sr[2];
sl += 4;
sr += 4;
}
#else
long l, r;
left--;
right--;
dest--;
while(--frames >= 0)
{
l = *++left;
r = *++right;
*++dest = (short)(l >> 16);
*++dest = (short)(r >> 16);
}
#endif
}
void ASIOConvertSamples::convertStereo24Interleaved(long *left, long *right, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dest = al;
*++dest = bl;
*++dest = cl;
*++dest = ar;
*++dest = br;
*++dest = cr;
}
}
void ASIOConvertSamples::convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames)
{
char *sl = (char *)left;
char *sr = (char *)right;
char *d = (char *)dest;
char al, bl, ar, br;
d--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
ar = sr[3];
br = sr[2];
#else
al = sl[0];
bl = sl[1];
ar = sr[0];
br = sr[1];
#endif
sl += 4;
sr += 4;
*++d = bl; // lsb first
*++d = al;
*++d = br;
*++d = ar;
}
}
void ASIOConvertSamples::convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dest = cl;
*++dest = bl;
*++dest = al;
*++dest = cr;
*++dest = br;
*++dest = ar;
}
}
//-------------------------------------------------------------------------------------------
// stereo split
void ASIOConvertSamples::convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
a -= 0x80U;
b -= 0x80U;
*++dLeft = a;
*++dRight = b;
}
}
void ASIOConvertSamples::convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
*++dLeft = a;
*++dRight = b;
}
}
void ASIOConvertSamples::convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* sl = (char*)left;
char* sr = (char*)right;
char* dl = (char*)dLeft;
char* dr = (char*)dRight;
while(--frames >= 0)
{
*dl++ = sl[3]; // msb first
*dl++ = sl[2];
*dr++ = sr[3];
*dr++ = sr[2];
sl += 4;
sr += 4;
}
#else
long l, r;
left--;
right--;
dLeft--;
dRight--;
while(--frames >= 0)
{
l = *++left;
r = *++right;
*++dLeft = (short)(l >> 16);
*++dRight = (short)(r >> 16);
}
#endif
}
void ASIOConvertSamples::convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dLeft = al;
*++dLeft = bl;
*++dLeft = cl;
*++dRight = ar;
*++dRight = br;
*++dRight = cr;
}
}
// small endian
void ASIOConvertSamples::convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames)
{
char *sl = (char *)left;
char *sr = (char *)right;
char *dl = (char *)dLeft;
char *dr = (char *)dRight;
char al, bl, ar, br;
dl--;
dr--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
ar = sr[3];
br = sr[2];
#else
al = sl[0];
bl = sl[1];
ar = sr[0];
br = sr[1];
#endif
sl += 4;
sr += 4;
*++dl = bl;
*++dl = al;
*++dr = br;
*++dr = ar;
}
}
void ASIOConvertSamples::convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dLeft = cl;
*++dLeft = bl;
*++dLeft = al;
*++dRight = cr;
*++dRight = br;
*++dRight = ar;
}
}
//------------------------------------------------------------------------------------------
// in place integer conversions
void ASIOConvertSamples::int32msb16to16inPlace(long *in, long frames)
{
short *d1 = (short *)in;
short* out = d1;
#if ASIO_LITTLE_ENDIAN
d1++;
#endif
while(--frames >= 0)
{
*out++ = *d1;
d1 += 2;
}
}
void ASIOConvertSamples::int32lsb16to16inPlace(long *in, long frames)
{
short *d1 = (short *)in;
short* out = d1;
#if !ASIO_LITTLE_ENDIAN
d1++;
#endif
while(--frames >= 0)
{
*out++ = *d1;
d1 += 2;
}
}
void ASIOConvertSamples::int32msb16shiftedTo16inPlace(long *in, long frames, long shift)
{
short* out = (short*)in;
while(--frames >= 0)
*out++ = (short)(*in++ >> shift);
}
void ASIOConvertSamples::int24msbto16inPlace(unsigned char *in, long frames)
{
short a;
short* out = (short*)in;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = (short)in[2];
a <<= 8;
a |= (in[1] & 0xff);
#else
a = (short)in[0];
a <<= 8;
a |= (in[1] & 0xff);
#endif
*out++ = a;
in += 3;
}
}
//-----------------------------------------------------------------------------------------
void ASIOConvertSamples::shift32(void* buffer, long shiftAmount, long targetByteWidth,
bool revertEndian, long sampleFrames)
{
long a;
long frames = sampleFrames;
long* source = (long*)buffer;
if(revertEndian)
{
reverseEndian(buffer, 4, sampleFrames);
revertEndian = false;
}
if(targetByteWidth == 2)
{
short* dest = (short*)buffer;
short* al = (short*)&a;
#if ASIO_LITTLE_ENDIAN
al++;
#endif
while(--frames >= 0)
{
a = *source++;
a <<= shiftAmount;
*dest++ = *al;
}
}
else if(targetByteWidth == 3)
{
char* dest = (char*)buffer;
source = (long*)buffer;
char* aa = (char*)&a;
while(--frames >= 0)
{
a = *source++;
a <<= shiftAmount;
#if ASIO_LITTLE_ENDIAN
dest[0] = aa[1]; // lsb
dest[1] = aa[2];
dest[2] = aa[3]; // msb
#else
dest[0] = aa[0]; // msb
dest[1] = aa[1];
dest[2] = aa[2]; // lsb
#endif
dest += 3;
}
}
else if(targetByteWidth == 4)
{
long* dest = source;
while(--frames >= 0)
*dest++ = *source++ << shiftAmount;
}
}
void ASIOConvertSamples::reverseEndian(void* buffer, long byteWidth, long frames)
{
char* a = (char*)buffer;
char* b = a;
char c;
if(byteWidth == 2)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[1];
a[1] = c;
a += 2;
}
}
else if(byteWidth == 3)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[2];
a[2] = c;
a += 3;
}
}
else if(byteWidth == 4)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[3];
a[3] = c;
c = a[1];
a[1] = a[2];
a[2] = c;
a += 4;
}
}
else if(byteWidth == 8)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[7];
a[7] = c;
c = a[1];
a[1] = a[6];
a[6] = c;
c = a[2];
a[2] = a[5];
a[5] = c;
c = a[3];
a[3] = a[4];
a[4] = c;
a += 4;
}
}
}
//-------------------------------------------------------------------------------------------------
void ASIOConvertSamples::int32to16inPlace(void* buffer, long frames)
{
short* in = (short*)buffer;
short* out = in;
#if ASIO_LITTLE_ENDIAN
in++;
#endif
while(--frames >= 0)
{
*out++ = *in;
in += 2;
}
}
void ASIOConvertSamples::int24to16inPlace(void* buffer, long frames)
{
char* from = (char*)buffer;
char* to = from;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
to[0] = from[1];
to[1] = from[2];
#else
to[0] = from[0];
to[1] = from[1];
#endif
from += 3;
to += 2;
}
}
void ASIOConvertSamples::int32to24inPlace(void* buffer, long frames)
{
long* in = (long*)buffer;
char* out = (char*)buffer;
long a;
while(--frames >= 0)
{
a = *in++;
a >>= 8; // 32->24
#if ASIO_LITTLE_ENDIAN
out[0] = (char)a; // lsb
a >>= 8;
out[1] = (char)a;
a >>= 8;
out[2] = (char)a;
#else
out[2] = (char)a; // lsb
a >>= 8;
out[1] = (char)a;
a >>= 8;
out[0] = (char)a;
#endif
out += 3;
}
}
void ASIOConvertSamples::int16to24inPlace(void* buffer, long frames)
{
char* in = (char*)buffer;
char* out = (char*)buffer;
in += frames * 2;
out += frames * 3;
while(--frames >= 0)
{
out -= 3;
in -= 2;
#if ASIO_LITTLE_ENDIAN
out[2] = in[1]; // msb
out[1] = in[0]; // lsb
out[0] = 0;
#else
out[2] = 0;
out[1] = in[1]; // lsb
out[0] = in[0]; // msb
#endif
}
}
void ASIOConvertSamples::int24to32inPlace(void* buffer, long frames)
{
long a, b, c;
char* in = (char*)buffer;
long* out = (long*)buffer;
in += (frames * 3);
out += frames;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = (long)in[-1]; // msb
b = (long)in[-2];
c = (long)in[-3];
#else
a = (long)in[-3]; // msb
b = (long)in[-2];
c = (long)in[-1];
#endif
a <<= 24;
b <<= 16;
b &= 0x00ff0000;
a |= b;
c <<= 8;
c &= 0x0000ff00;
a |= c;
*--out = a;
in -= 3;
}
}
void ASIOConvertSamples::int16to32inPlace(void* buffer, long frames)
{
short* in = (short*)buffer;
long* out = (long*)buffer;
in += frames;
out += frames;
while(--frames >= 0)
*--out = ((long)(*--in)) << 16;
}
//------------------------------------------------------------------------------------------
// float to int
const double fScaler16 = (double)0x7fffL;
const double fScaler24 = (double)0x7fffffL;
const double fScaler32 = (double)0x7fffffffL;
void ASIOConvertSamples::float32toInt16inPlace(float* buffer, long frames)
{
double sc = fScaler16 + .49999;
short* b = (short*)buffer;
while(--frames >= 0)
*b++ = (short)((double)(*buffer++) * sc);
}
void ASIOConvertSamples::float32toInt24inPlace(float* buffer, long frames)
{
double sc = fScaler24 + .49999;
long a;
char* b = (char*)buffer;
char* aa = (char*)&a;
while(--frames >= 0)
{
a = (long)((double)(*buffer++) * sc);
#if ASIO_LITTLE_ENDIAN
*b++ = aa[3];
*b++ = aa[2];
*b++ = aa[1];
#else
*b++ = aa[1];
*b++ = aa[2];
*b++ = aa[3];
#endif
}
}
void ASIOConvertSamples::float32toInt32inPlace(float* buffer, long frames)
{
double sc = fScaler32 + .49999;
long* b = (long*)buffer;
while(--frames >= 0)
*b++ = (long)((double)(*buffer++) * sc);
}