fmodex/fmod/src/fmod_dsp_connectioni.cpp

2613 lines
78 KiB
C++
Executable file

#include "fmod_settings.h"
#include "fmod_dspi.h"
#include "fmod_dsp_connectioni.h"
#include "fmod_globals.h"
#include "fmod_localcriticalsection.h"
#ifdef PLATFORM_PS3_SPU
#include "fmod_systemi_spu.h"
#else
#include "fmod_systemi.h"
#endif
namespace FMOD
{
#ifdef FMOD_SUPPORT_SIMD
extern "C"
{
void FMOD_DSP_Connection_MixMonoToStereo_SIMD (float *inbuffer, float *outbuffer, unsigned int length, float lvolume, float rvolume);
void FMOD_DSP_Connection_MixStereoToStereo_SIMD(float *inbuffer, float *outbuffer, unsigned int length, float lvolume, float rvolume);
void FMOD_DSP_Connection_MixMonoTo5_1_SIMD (float *inbuffer, float *outbuffer, unsigned int length, float *volume0to3, float *volume4to1, float *volume2to5);
void FMOD_DSP_Connection_Mix5_1To5_1_SIMD (float *inbuffer, float *outbuffer, unsigned int length, float *volume0to3, float *volume4to1, float *volume2to5);
void FMOD_DSP_Connection_MixMonoTo7_1_SIMD (float *inbuffer, float *outbuffer, unsigned int length, float *volume0to3, float *volume4to7);
void FMOD_DSP_Connection_Mix7_1To7_1_SIMD (float *inbuffer, float *outbuffer, unsigned int length, float *volume0to3, float *volume4to7);
void FMOD_DSP_Connection_MixStereoTo7_1_SIMD (float *inbuffer, float *outbuffer, unsigned int length, float *volume0to3, float *volume01to31, float *volume4to7, float *volume41to71);
}
#endif
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::validate(DSPConnection *dspconnection, DSPConnectionI **dspconnectioni)
{
if (!dspconnectioni)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!dspconnection)
{
return FMOD_ERR_INVALID_HANDLE;
}
*dspconnectioni = (DSPConnectionI *)dspconnection;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::init(DSP_LEVEL_TYPE * &levelmemory, int maxoutputlevels, int maxinputlevels)
{
#ifdef FMOD_SUPPORT_SOFTWARE
mMaxOutputLevels = maxoutputlevels;
mMaxInputLevels = maxinputlevels;
if (maxoutputlevels < 2)
{
maxoutputlevels = 2;
}
if (mMaxInputLevels < mMaxOutputLevels)
{
mMaxInputLevels = mMaxOutputLevels;
}
#ifdef PLATFORM_PS3_PPU
mMramAddress = (unsigned int)this;
mMramAddressLevels = (unsigned int)levelmemory;
#endif
int count;
for (count = 0; count < DSP_MAXLEVELS_OUT; count++)
{
if (count < mMaxOutputLevels)
{
mLevel[count] = levelmemory;
levelmemory += mMaxInputLevels;
mLevelCurrent[count] = levelmemory;
levelmemory += mMaxInputLevels;
mLevelDelta[count] = levelmemory;
levelmemory += mMaxInputLevels;
}
else
{
mLevel[count] = 0;
mLevelCurrent[count] = 0;
mLevelDelta[count] = 0;
}
}
return FMOD_OK;
#else
return FMOD_ERR_NEEDSSOFTWARE;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getInput(DSPI **input)
{
#ifdef FMOD_SUPPORT_SOFTWARE
if (!input)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!mInputUnit)
{
*input = 0;
return FMOD_ERR_NOTREADY;
}
*input = mInputUnit;
return FMOD_OK;
#else
return FMOD_ERR_NEEDSSOFTWARE;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getOutput(DSPI **output)
{
if (!output)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!mOutputUnit)
{
*output = 0;
return FMOD_ERR_NOTREADY;
}
*output = mOutputUnit;
return FMOD_OK;
}
#ifdef FMOD_SUPPORT_SOFTWARE
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::reset()
{
int count, count2;
mVolume = 1.0f;
mUserData = 0;
mRampCount = 0;
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
mLevel [count][count2] = 0;
mLevelCurrent[count][count2] = 0;
mLevelDelta [count][count2] = 0;
}
}
mSetLevelsUsed = false;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::setUnity()
{
int count, count2;
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
if (count == count2)
{
mLevelCurrent[count][count2] = DSP_LEVEL_COMPRESS(1.0f);
mLevel[count][count2] = DSP_LEVEL_COMPRESS(1.0f);
}
else
{
mLevel[count][count2] = 0;
mLevelCurrent[count][count2] = 0;
}
}
}
mVolume = 1.0f;
mRampCount = 0;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::mix(float * FMOD_RESTRICT outbuffer, float * FMOD_RESTRICT inbuffer, int outchannels, int inchannels, unsigned int length)
{
unsigned int count;
float l00, l10;
float l01, l11;
#if (DSP_MAXLEVELS_OUT > 2)
float l20, l30, l40, l50;
float l21, l31, l41, l51;
float l22, l33, l44, l55;
#endif
#if (DSP_MAXLEVELS_OUT > 6)
float l60, l70;
float l61, l71;
float l66, l77;
#endif
bool supportssimd;
float levelcurrent[DSP_MAXLEVELS_OUT][DSP_MAXLEVELS_IN] = { 0 };
if (!inbuffer)
{
return FMOD_OK;
}
supportssimd = FMOD_OS_SupportsSIMD();
if (mRampCount)
{
unsigned int len = mRampCount;
if (len > length)
{
len = length;
}
mixAndRamp(outbuffer, inbuffer, outchannels, inchannels, len);
length -= len;
outbuffer += (len * outchannels);
inbuffer += (len * inchannels);
}
if (!length)
{
return FMOD_OK;
}
if (FMOD_FABS(mVolume) < DSP_LEVEL_SMALLVAL)
{
return FMOD_OK;
}
for (count = 0; count < (unsigned int)mMaxOutputLevels; count++)
{
int count2;
if (mLevelCurrent[count])
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
levelcurrent[count][count2] = DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][count2]);
}
}
}
/*
Because mLevelCurrent could be misaligned this could hopefully put the values into registers. (confirmed on ps2).
*/
l00 = levelcurrent[0][0];
l10 = levelcurrent[1][0];
#if (DSP_MAXLEVELS_OUT > 2)
l20 = levelcurrent[2][0];
l30 = levelcurrent[3][0];
l40 = levelcurrent[4][0];
l50 = levelcurrent[5][0];
#endif
#if (DSP_MAXLEVELS_OUT > 6)
l60 = levelcurrent[6][0];
l70 = levelcurrent[7][0];
#endif
l01 = levelcurrent[0][1];
l11 = levelcurrent[1][1];
#if (DSP_MAXLEVELS_OUT > 2)
l21 = levelcurrent[2][1];
l31 = levelcurrent[3][1];
l41 = levelcurrent[4][1];
l51 = levelcurrent[5][1];
l22 = levelcurrent[2][2];
l33 = levelcurrent[3][3];
l44 = levelcurrent[4][4];
l55 = levelcurrent[5][5];
#endif
#if (DSP_MAXLEVELS_OUT > 6)
l61 = levelcurrent[6][1];
l71 = levelcurrent[7][1];
l66 = levelcurrent[6][6];
l77 = levelcurrent[7][7];
#endif
/*
The most common configuration is mono or stereo coming in, and stereo going out, so we special case these for speed.
Other combinations go through generic for loop code.
*/
if (0)
{
}
#if !defined(PLATFORM_PS3_SPU)
else if (outchannels == 2 && (inchannels == 1 || inchannels == 2))
{
if (inchannels == 1)
{
#ifdef FMOD_SUPPORT_SIMD
if (supportssimd)
{
/*
First 16byte align destination for simd.
*/
while ((((unsigned int)outbuffer & 0xF) || ((unsigned int)inbuffer & 0xF)) && length)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
inbuffer ++;
outbuffer += 2;
length --;
}
FMOD_DSP_Connection_MixMonoToStereo_SIMD(inbuffer, outbuffer, length, l00, l10);
}
else
#endif
{
unsigned int len;
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[2] += (inbuffer[1] * l00);
outbuffer[3] += (inbuffer[1] * l10);
outbuffer[4] += (inbuffer[2] * l00);
outbuffer[5] += (inbuffer[2] * l10);
outbuffer[6] += (inbuffer[3] * l00);
outbuffer[7] += (inbuffer[3] * l10);
inbuffer += 4;
outbuffer += 8;
len --;
}
len = length & 3;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
inbuffer ++;
outbuffer += 2;
len --;
}
}
}
else if (inchannels == 2)
{
unsigned int len;
if (FMOD_FABS(l01) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l10) < DSP_LEVEL_SMALLVAL) /* Pan matrix looks like [l 0] which is the normal way. */
{ /* [0 r] */
#ifdef FMOD_SUPPORT_SIMD
if (supportssimd)
{
/*
First 16byte align destination for simd.
*/
while ((unsigned int)outbuffer & 0xF && length)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
inbuffer += 2;
outbuffer += 2;
length --;
}
FMOD_DSP_Connection_MixStereoToStereo_SIMD(inbuffer, outbuffer, length, l00, l11);
}
else
#endif
{
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
outbuffer[2] += (inbuffer[2] * l00);
outbuffer[3] += (inbuffer[3] * l11);
outbuffer[4] += (inbuffer[4] * l00);
outbuffer[5] += (inbuffer[5] * l11);
outbuffer[6] += (inbuffer[6] * l00);
outbuffer[7] += (inbuffer[7] * l11);
inbuffer += 8;
outbuffer += 8;
len --;
}
len = length & 3;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
inbuffer += 2;
outbuffer += 2;
len --;
}
}
}
else /* Pan matrix looks like [l ?] must have used setSpeakerMix. */
{ /* [? r] */
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[0] += (inbuffer[1] * l01);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[1] += (inbuffer[1] * l11);
outbuffer[2] += (inbuffer[2] * l00);
outbuffer[2] += (inbuffer[3] * l01);
outbuffer[3] += (inbuffer[2] * l10);
outbuffer[3] += (inbuffer[3] * l11);
outbuffer[4] += (inbuffer[4] * l00);
outbuffer[4] += (inbuffer[5] * l01);
outbuffer[5] += (inbuffer[4] * l10);
outbuffer[5] += (inbuffer[5] * l11);
outbuffer[6] += (inbuffer[6] * l00);
outbuffer[6] += (inbuffer[7] * l01);
outbuffer[7] += (inbuffer[6] * l10);
outbuffer[7] += (inbuffer[7] * l11);
inbuffer += 8;
outbuffer += 8;
len --;
}
len = length & 3;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[0] += (inbuffer[1] * l01);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[1] += (inbuffer[1] * l11);
inbuffer += 2;
outbuffer += 2;
len --;
}
}
}
}
#if (DSP_MAXLEVELS_OUT > 2) && !defined(PLATFORM_PS3_PPU)
else if (outchannels == 6 && (inchannels == 1 || inchannels == 2 || inchannels == 6))//(inchannels == 6 && checkUnity(outchannels, inchannels) == FMOD_OK)))
{
if (inchannels == 1)
{
#ifdef FMOD_SUPPORT_SIMD
if (supportssimd)
{
float volume0to3[4] = { l00, l10, l20, l30 };
float volume4to1[4] = { l40, l50, l00, l10 };
float volume2to5[4] = { l20, l30, l40, l50 };
/*
First 16byte align destination for simd.
*/
while ((unsigned int)outbuffer & 0xF && length)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[5] += (inbuffer[0] * l50);
inbuffer ++;
outbuffer +=6;
length --;
}
FMOD_DSP_Connection_MixMonoTo5_1_SIMD(inbuffer, outbuffer, length, volume0to3, volume4to1, volume2to5);
}
else
#endif
{
unsigned int len;
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[6] += (inbuffer[1] * l00);
outbuffer[7] += (inbuffer[1] * l10);
outbuffer[8] += (inbuffer[1] * l20);
outbuffer[9] += (inbuffer[1] * l30);
outbuffer[10] += (inbuffer[1] * l40);
outbuffer[11] += (inbuffer[1] * l50);
outbuffer[12] += (inbuffer[2] * l00);
outbuffer[13] += (inbuffer[2] * l10);
outbuffer[14] += (inbuffer[2] * l20);
outbuffer[15] += (inbuffer[2] * l30);
outbuffer[16] += (inbuffer[2] * l40);
outbuffer[17] += (inbuffer[2] * l50);
outbuffer[18] += (inbuffer[3] * l00);
outbuffer[19] += (inbuffer[3] * l10);
outbuffer[20] += (inbuffer[3] * l20);
outbuffer[21] += (inbuffer[3] * l30);
outbuffer[22] += (inbuffer[3] * l40);
outbuffer[23] += (inbuffer[3] * l50);
outbuffer += 24;
inbuffer += 4;
len--;
}
len = length & 3;
if (len)
{
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[5] += (inbuffer[0] * l50);
inbuffer ++;
outbuffer +=6;
len --;
}
}
}
}
else if (inchannels == 2)
{
unsigned int len;
/* Pan matrix looks like [l 0] which is the normal way. */
/* [0 r] */
/* [0 0] */
/* [0 0] */
/* [0 0] */
/* [0 0] */
if (FMOD_FABS(l01) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l10) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l20) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l21) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l30) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l31) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l40) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l41) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l50) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l51) < DSP_LEVEL_SMALLVAL)
{
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
// outbuffer[2 += 0;
// outbuffer[3] += 0;
// outbuffer[4] += 0;
// outbuffer[5] += 0;
outbuffer[6] += (inbuffer[2] * l00);
outbuffer[7] += (inbuffer[3] * l11);
// outbuffer[8] += 0;
// outbuffer[9] += 0;
// outbuffer[10] += 0;
// outbuffer[11] += 0;
outbuffer[12] += (inbuffer[4] * l00);
outbuffer[13] += (inbuffer[5] * l11);
// outbuffer[14] += 0;
// outbuffer[15] += 0;
// outbuffer[16] += 0;
// outbuffer[17] += 0;
outbuffer[18] += (inbuffer[6] * l00);
outbuffer[19] += (inbuffer[7] * l11);
// outbuffer[20] += 0;
// outbuffer[21] += 0;
// outbuffer[22] += 0;
// outbuffer[23] += 0;
outbuffer += 24;
inbuffer += 8;
len--;
}
len = length & 3;
if (len)
{
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
//outbuffer[2] += 0;
//outbuffer[3] += 0;
//outbuffer[4] += 0;
//outbuffer[5] += 0;
inbuffer += 2;
outbuffer += 6;
len --;
}
}
}
else /* Pan matrix looks like [l ?] must have used setSpeakerMix. */
{ /* [? r] */
len = length >> 1;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[0] += (inbuffer[1] * l01);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[1] += (inbuffer[1] * l11);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[2] += (inbuffer[1] * l21);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[3] += (inbuffer[1] * l31);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[4] += (inbuffer[1] * l41);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[5] += (inbuffer[1] * l51);
outbuffer[6] += (inbuffer[2] * l00);
outbuffer[6] += (inbuffer[3] * l01);
outbuffer[7] += (inbuffer[2] * l10);
outbuffer[7] += (inbuffer[3] * l11);
outbuffer[8] += (inbuffer[2] * l20);
outbuffer[8] += (inbuffer[3] * l21);
outbuffer[9] += (inbuffer[2] * l30);
outbuffer[9] += (inbuffer[3] * l31);
outbuffer[10] += (inbuffer[2] * l40);
outbuffer[10] += (inbuffer[3] * l41);
outbuffer[11] += (inbuffer[2] * l50);
outbuffer[11] += (inbuffer[3] * l51);
inbuffer += 4;
outbuffer += 12;
len --;
}
len = length & 1;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[0] += (inbuffer[1] * l01);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[1] += (inbuffer[1] * l11);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[2] += (inbuffer[1] * l21);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[3] += (inbuffer[1] * l31);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[4] += (inbuffer[1] * l41);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[5] += (inbuffer[1] * l51);
inbuffer += 2;
outbuffer += 6;
len --;
}
}
}
else if (inchannels == 6)
{
FMOD_RESULT unity = checkUnity(outchannels, inchannels);
FMOD_RESULT mono = FMOD_ERR_TOOMANYCHANNELS;
if (unity != FMOD_OK)
{
mono = checkMono(outchannels, inchannels);
}
if (unity == FMOD_OK || mono == FMOD_OK)
{
float l[6];
if (unity == FMOD_OK)
{
l[0] = l00;
l[1] = l11;
l[2] = l22;
l[3] = l33;
l[4] = l44;
l[5] = l55;
}
else
{
l[0] = l00;
l[1] = l10;
l[2] = l20;
l[3] = l30;
l[4] = l40;
l[5] = l50;
}
#ifdef FMOD_SUPPORT_SIMD
if (supportssimd)
{
float volume0to3[4] = { l[0], l[1], l[2], l[3] };
float volume4to1[4] = { l[4], l[5], l[0], l[1] };
float volume2to5[4] = { l[2], l[3], l[4], l[5] };
/*
First 16byte align destination for simd.
*/
while ((unsigned int)outbuffer & 0xF && length)
{
outbuffer[0] += (inbuffer[0] * l[0]);
outbuffer[1] += (inbuffer[1] * l[1]);
outbuffer[2] += (inbuffer[2] * l[2]);
outbuffer[3] += (inbuffer[3] * l[3]);
outbuffer[4] += (inbuffer[4] * l[4]);
outbuffer[5] += (inbuffer[5] * l[5]);
inbuffer +=6;
outbuffer +=6;
length --;
}
FMOD_DSP_Connection_Mix5_1To5_1_SIMD(inbuffer, outbuffer, length, volume0to3, volume4to1, volume2to5);
}
else
#endif
{
unsigned int len;
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l[0]);
outbuffer[1] += (inbuffer[1] * l[1]);
outbuffer[2] += (inbuffer[2] * l[2]);
outbuffer[3] += (inbuffer[3] * l[3]);
outbuffer[4] += (inbuffer[4] * l[4]);
outbuffer[5] += (inbuffer[5] * l[5]);
outbuffer[6] += (inbuffer[6] * l[0]);
outbuffer[7] += (inbuffer[7] * l[1]);
outbuffer[8] += (inbuffer[8] * l[2]);
outbuffer[9] += (inbuffer[9] * l[3]);
outbuffer[10] += (inbuffer[10] * l[4]);
outbuffer[11] += (inbuffer[11] * l[5]);
outbuffer[12] += (inbuffer[12] * l[0]);
outbuffer[13] += (inbuffer[13] * l[1]);
outbuffer[14] += (inbuffer[14] * l[2]);
outbuffer[15] += (inbuffer[15] * l[3]);
outbuffer[16] += (inbuffer[16] * l[4]);
outbuffer[17] += (inbuffer[17] * l[5]);
outbuffer[18] += (inbuffer[18] * l[0]);
outbuffer[19] += (inbuffer[19] * l[1]);
outbuffer[20] += (inbuffer[20] * l[2]);
outbuffer[21] += (inbuffer[21] * l[3]);
outbuffer[22] += (inbuffer[22] * l[4]);
outbuffer[23] += (inbuffer[23] * l[5]);
outbuffer += 24;
inbuffer += 24;
len--;
}
len = length & 3;
if (len)
{
while (len)
{
outbuffer[0] += (inbuffer[0] * l[0]);
outbuffer[1] += (inbuffer[1] * l[1]);
outbuffer[2] += (inbuffer[2] * l[2]);
outbuffer[3] += (inbuffer[3] * l[3]);
outbuffer[4] += (inbuffer[4] * l[4]);
outbuffer[5] += (inbuffer[5] * l[5]);
inbuffer +=6;
outbuffer +=6;
len --;
}
}
}
}
else
{
#if 0
for (count = 0; count < length; count++)
{
int count2;
for (count2 = 0; count2 < outchannels; count2++)
{
float srcval = 0;
float destval = *outbuffer;
int count3;
for (count3 = 0; count3 < inchannels; count3++)
{
srcval += (inbuffer[count3] * levelcurrent[count2][count3]);
}
destval += srcval;
*outbuffer++ = destval;
}
inbuffer += inchannels;
}
#else
for (count = 0; count < length; count++)
{
float srcval;
srcval = (inbuffer[0] * levelcurrent[0][0]);
srcval += (inbuffer[1] * levelcurrent[0][1]);
srcval += (inbuffer[2] * levelcurrent[0][2]);
srcval += (inbuffer[3] * levelcurrent[0][3]);
srcval += (inbuffer[4] * levelcurrent[0][4]);
srcval += (inbuffer[5] * levelcurrent[0][5]);
outbuffer[0] += srcval;
srcval = (inbuffer[0] * levelcurrent[1][0]);
srcval += (inbuffer[1] * levelcurrent[1][1]);
srcval += (inbuffer[2] * levelcurrent[1][2]);
srcval += (inbuffer[3] * levelcurrent[1][3]);
srcval += (inbuffer[4] * levelcurrent[1][4]);
srcval += (inbuffer[5] * levelcurrent[1][5]);
outbuffer[1] += srcval;
srcval = (inbuffer[0] * levelcurrent[2][0]);
srcval += (inbuffer[1] * levelcurrent[2][1]);
srcval += (inbuffer[2] * levelcurrent[2][2]);
srcval += (inbuffer[3] * levelcurrent[2][3]);
srcval += (inbuffer[4] * levelcurrent[2][4]);
srcval += (inbuffer[5] * levelcurrent[2][5]);
outbuffer[2] += srcval;
srcval = (inbuffer[0] * levelcurrent[3][0]);
srcval += (inbuffer[1] * levelcurrent[3][1]);
srcval += (inbuffer[2] * levelcurrent[3][2]);
srcval += (inbuffer[3] * levelcurrent[3][3]);
srcval += (inbuffer[4] * levelcurrent[3][4]);
srcval += (inbuffer[5] * levelcurrent[3][5]);
outbuffer[3] += srcval;
srcval = (inbuffer[0] * levelcurrent[4][0]);
srcval += (inbuffer[1] * levelcurrent[4][1]);
srcval += (inbuffer[2] * levelcurrent[4][2]);
srcval += (inbuffer[3] * levelcurrent[4][3]);
srcval += (inbuffer[4] * levelcurrent[4][4]);
srcval += (inbuffer[5] * levelcurrent[4][5]);
outbuffer[4] += srcval;
srcval = (inbuffer[0] * levelcurrent[5][0]);
srcval += (inbuffer[1] * levelcurrent[5][1]);
srcval += (inbuffer[2] * levelcurrent[5][2]);
srcval += (inbuffer[3] * levelcurrent[5][3]);
srcval += (inbuffer[4] * levelcurrent[5][4]);
srcval += (inbuffer[5] * levelcurrent[5][5]);
outbuffer[5] += srcval;
outbuffer += 6;
inbuffer += 6;
}
#endif
}
}
}
#endif
#endif /* #if (DSP_MAXLEVELS_OUT != 8) */
#if (DSP_MAXLEVELS_OUT > 6) && !defined(PLATFORM_PS3_PPU)
else if (outchannels == 8 && (inchannels == 1 || inchannels == 2 || inchannels == 8)) // && checkUnity(outchannels, inchannels) == FMOD_OK)))
{
if (inchannels == 1)
{
#ifdef FMOD_SUPPORT_SIMD
if (supportssimd)
{
float volume0to3[4] = { l00, l10, l20, l30 };
float volume4to7[4] = { l40, l50, l60, l70 };
FMOD_DSP_Connection_MixMonoTo7_1_SIMD(inbuffer, outbuffer, length, volume0to3, volume4to7);
}
else
#endif
{
unsigned int len;
len = length >> 1;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[6] += (inbuffer[0] * l60);
outbuffer[7] += (inbuffer[0] * l70);
outbuffer[8] += (inbuffer[1] * l00);
outbuffer[9] += (inbuffer[1] * l10);
outbuffer[10] += (inbuffer[1] * l20);
outbuffer[11] += (inbuffer[1] * l30);
outbuffer[12] += (inbuffer[1] * l40);
outbuffer[13] += (inbuffer[1] * l50);
outbuffer[14] += (inbuffer[1] * l60);
outbuffer[15] += (inbuffer[1] * l70);
outbuffer += 16;
inbuffer += 2;
len--;
}
len = length & 1;
if (len)
{
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[6] += (inbuffer[0] * l60);
outbuffer[7] += (inbuffer[0] * l70);
inbuffer ++;
outbuffer +=8;
len --;
}
}
}
}
else if (inchannels == 2)
{
unsigned int len;
/* Pan matrix looks like [l 0] which is the normal way. */
/* [0 r] */
/* [0 0] */
/* [0 0] */
/* [0 0] */
/* [0 0] */
if (FMOD_FABS(l01) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l10) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l20) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l21) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l30) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l31) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l40) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l41) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l50) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l51) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l60) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l61) < DSP_LEVEL_SMALLVAL &&
FMOD_FABS(l70) < DSP_LEVEL_SMALLVAL && FMOD_FABS(l71) < DSP_LEVEL_SMALLVAL)
{
len = length >> 2;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
// outbuffer[2 += 0;
// outbuffer[3] += 0;
// outbuffer[4] += 0;
// outbuffer[5] += 0;
// outbuffer[6] += 0;
// outbuffer[7] += 0;
outbuffer[8] += (inbuffer[2] * l00);
outbuffer[9] += (inbuffer[3] * l11);
// outbuffer[10] += 0;
// outbuffer[11] += 0;
// outbuffer[12] += 0;
// outbuffer[13] += 0;
// outbuffer[14] += 0;
// outbuffer[15] += 0;
outbuffer[16] += (inbuffer[4] * l00);
outbuffer[17] += (inbuffer[5] * l11);
// outbuffer[18] += 0;
// outbuffer[19] += 0;
// outbuffer[20] += 0;
// outbuffer[21] += 0;
// outbuffer[22] += 0;
// outbuffer[23] += 0;
outbuffer[24] += (inbuffer[6] * l00);
outbuffer[25] += (inbuffer[7] * l11);
// outbuffer[26] += 0;
// outbuffer[27] += 0;
// outbuffer[28] += 0;
// outbuffer[29] += 0;
// outbuffer[30] += 0;
// outbuffer[31] += 0;
outbuffer += 32;
inbuffer += 8;
len--;
}
len = length & 3;
if (len)
{
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[1] += (inbuffer[1] * l11);
//outbuffer[2] += 0;
//outbuffer[3] += 0;
//outbuffer[4] += 0;
//outbuffer[5] += 0;
//outbuffer[6] += 0;
//outbuffer[7] += 0;
inbuffer += 2;
outbuffer += 8;
len --;
}
}
}
else /* Pan matrix looks like [l ?] must have used setSpeakerMix. */
{ /* [? r] */
#ifdef PLATFORM_XENON
float volume0to3[4] = { l00, l10, l20, l30 };
float volume01to31[4] = { l01, l11, l21, l31 };
float volume4to7[4] = { l40, l50, l60, l70 };
float volume41to71[4] = { l41, l51, l61, l71 };
FMOD_DSP_Connection_MixStereoTo7_1_SIMD(inbuffer, outbuffer, length, volume0to3, volume01to31, volume4to7, volume41to71);
#else
len = length >> 1;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[0] += (inbuffer[1] * l01);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[1] += (inbuffer[1] * l11);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[2] += (inbuffer[1] * l21);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[3] += (inbuffer[1] * l31);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[4] += (inbuffer[1] * l41);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[5] += (inbuffer[1] * l51);
outbuffer[6] += (inbuffer[0] * l60);
outbuffer[6] += (inbuffer[1] * l61);
outbuffer[7] += (inbuffer[0] * l70);
outbuffer[7] += (inbuffer[1] * l71);
outbuffer[8] += (inbuffer[2] * l00);
outbuffer[8] += (inbuffer[3] * l01);
outbuffer[9] += (inbuffer[2] * l10);
outbuffer[9] += (inbuffer[3] * l11);
outbuffer[10] += (inbuffer[2] * l20);
outbuffer[10] += (inbuffer[3] * l21);
outbuffer[11] += (inbuffer[2] * l30);
outbuffer[11] += (inbuffer[3] * l31);
outbuffer[12] += (inbuffer[2] * l40);
outbuffer[12] += (inbuffer[3] * l41);
outbuffer[13] += (inbuffer[2] * l50);
outbuffer[13] += (inbuffer[3] * l51);
outbuffer[14] += (inbuffer[2] * l60);
outbuffer[14] += (inbuffer[3] * l61);
outbuffer[15] += (inbuffer[2] * l70);
outbuffer[15] += (inbuffer[3] * l71);
inbuffer += 4;
outbuffer += 16;
len --;
}
#endif
len = length & 1;
while (len)
{
outbuffer[0] += (inbuffer[0] * l00);
outbuffer[0] += (inbuffer[1] * l01);
outbuffer[1] += (inbuffer[0] * l10);
outbuffer[1] += (inbuffer[1] * l11);
outbuffer[2] += (inbuffer[0] * l20);
outbuffer[2] += (inbuffer[1] * l21);
outbuffer[3] += (inbuffer[0] * l30);
outbuffer[3] += (inbuffer[1] * l31);
outbuffer[4] += (inbuffer[0] * l40);
outbuffer[4] += (inbuffer[1] * l41);
outbuffer[5] += (inbuffer[0] * l50);
outbuffer[5] += (inbuffer[1] * l51);
outbuffer[6] += (inbuffer[0] * l60);
outbuffer[6] += (inbuffer[1] * l61);
outbuffer[7] += (inbuffer[0] * l70);
outbuffer[7] += (inbuffer[1] * l71);
inbuffer += 2;
outbuffer += 8;
len --;
}
}
}
else if (inchannels == 8)
{
#if 0
if (mUnity)
{
mUnity = mUnity;
}
else
#endif
FMOD_RESULT unity = checkUnity(outchannels, inchannels);
FMOD_RESULT mono = FMOD_ERR_TOOMANYCHANNELS;
if (unity != FMOD_OK)
{
mono = checkMono(outchannels, inchannels);
}
if (unity == FMOD_OK || mono == FMOD_OK)
{
float l[8];
if (unity == FMOD_OK)
{
l[0] = l00;
l[1] = l11;
l[2] = l22;
l[3] = l33;
l[4] = l44;
l[5] = l55;
l[6] = l66;
l[7] = l77;
}
else
{
l[0] = l00;
l[1] = l10;
l[2] = l20;
l[3] = l30;
l[4] = l40;
l[5] = l50;
l[6] = l60;
l[7] = l70;
}
#ifdef FMOD_SUPPORT_SIMD
if (supportssimd)
{
float volume0to3[4] = { l[0], l[1], l[2], l[3] };
float volume4to7[4] = { l[4], l[5], l[6], l[7] };
FMOD_DSP_Connection_Mix7_1To7_1_SIMD(inbuffer, outbuffer, length, volume0to3, volume4to7);
}
else
#endif
{
unsigned int len;
len = length >> 1;
while (len)
{
outbuffer[0] += (inbuffer[0] * l[0]);
outbuffer[1] += (inbuffer[1] * l[1]);
outbuffer[2] += (inbuffer[2] * l[2]);
outbuffer[3] += (inbuffer[3] * l[3]);
outbuffer[4] += (inbuffer[4] * l[4]);
outbuffer[5] += (inbuffer[5] * l[5]);
outbuffer[6] += (inbuffer[6] * l[6]);
outbuffer[7] += (inbuffer[7] * l[7]);
outbuffer[8] += (inbuffer[8] * l[0]);
outbuffer[9] += (inbuffer[9] * l[1]);
outbuffer[10] += (inbuffer[10] * l[2]);
outbuffer[11] += (inbuffer[11] * l[3]);
outbuffer[12] += (inbuffer[12] * l[4]);
outbuffer[13] += (inbuffer[13] * l[5]);
outbuffer[14] += (inbuffer[14] * l[6]);
outbuffer[15] += (inbuffer[15] * l[7]);
outbuffer += 16;
inbuffer += 16;
len--;
}
len = length & 1;
if (len)
{
while (len)
{
outbuffer[0] += (inbuffer[0] * l[0]);
outbuffer[1] += (inbuffer[1] * l[1]);
outbuffer[2] += (inbuffer[2] * l[2]);
outbuffer[3] += (inbuffer[3] * l[3]);
outbuffer[4] += (inbuffer[4] * l[4]);
outbuffer[5] += (inbuffer[5] * l[5]);
outbuffer[6] += (inbuffer[6] * l[6]);
outbuffer[7] += (inbuffer[7] * l[7]);
inbuffer +=8;
outbuffer +=8;
len --;
}
}
}
}
else
{
for (count = 0; count < length; count++)
{
int count2;
for (count2 = 0; count2 < outchannels; count2++)
{
float srcval = 0;
float destval = *outbuffer;
int count3;
for (count3 = 0; count3 < inchannels; count3++)
{
srcval += (inbuffer[count3] * levelcurrent[count2][count3]);
}
destval += srcval;
*outbuffer++ = destval;
}
inbuffer += inchannels;
}
}
}
}
#endif
else
{
for (count = 0; count < length; count++)
{
int count2;
for (count2 = 0; count2 < outchannels; count2++)
{
float srcval = 0;
float destval = *outbuffer;
int count3;
for (count3 = 0; count3 < inchannels; count3++)
{
srcval += (inbuffer[count3] * levelcurrent[count2][count3]);
}
destval += srcval;
*outbuffer++ = destval;
}
inbuffer += inchannels;
}
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::mixAndRamp(float * FMOD_RESTRICT outbuffer, float * FMOD_RESTRICT inbuffer, int outchannels, int inchannels, unsigned int length)
{
unsigned int count;
#if (DSP_LEVEL_PRECISION == 16)
float levelcurrent[DSP_MAXLEVELS_OUT][DSP_MAXLEVELS_IN];
float leveldelta[DSP_MAXLEVELS_OUT][DSP_MAXLEVELS_IN];
for (count = 0; count < (unsigned int)outchannels; count++)
{
int count2;
for (count2 = 0; count2 < inchannels; count2++)
{
levelcurrent[count][count2] = DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][count2]);
leveldelta[count][count2] = DSP_LEVEL_DECOMPRESS(mLevelDelta[count][count2]);
}
}
#endif
for (count = 0; count < length; count++)
{
int count2;
for (count2 = 0; count2 < outchannels; count2++)
{
float srcval = 0;
float destval = *outbuffer;
int count3;
for (count3 = 0; count3 < inchannels; count3++)
{
#if (DSP_LEVEL_PRECISION == 32)
srcval += (inbuffer[count3] * mLevelCurrent[count2][count3]);
mLevelCurrent[count2][count3] += mLevelDelta[count2][count3];
#else
srcval += (inbuffer[count3] * levelcurrent[count2][count3]);
levelcurrent[count2][count3] += leveldelta[count2][count3];
#endif
}
destval += srcval;
*outbuffer++ = destval;
}
inbuffer += inchannels;
}
#if (DSP_LEVEL_PRECISION == 16)
for (count = 0; count < (unsigned int)outchannels; count++)
{
int count2;
for (count2 = 0; count2 < inchannels; count2++)
{
mLevelCurrent[count][count2] = DSP_LEVEL_COMPRESS(levelcurrent[count][count2]);
mLevelDelta[count][count2] = DSP_LEVEL_COMPRESS(leveldelta[count][count2]);
}
}
#endif
mRampCount -= length;
/*
Snap the current to the mlevel
*/
if (!mRampCount)
{
int count, count2;
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
mLevelCurrent[count][count2] = DSP_LEVEL_COMPRESS(DSP_LEVEL_DECOMPRESS(mLevel[count][count2]) * mVolume);
}
}
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::rampTo()
{
int count;
float oorampcount, delta = 0;
oorampcount = 1.0f / DSP_RAMPCOUNT;
if (mMaxInputLevels == 6)
{
for (count = 0; count < mMaxOutputLevels; count++)
{
float value;
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][0]) * mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][0])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][0] = DSP_LEVEL_COMPRESS(value);
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][1]) * mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][1])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][1] = DSP_LEVEL_COMPRESS(value);
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][2]) * mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][2])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][2] = DSP_LEVEL_COMPRESS(value);
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][3]) * mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][3])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][3] = DSP_LEVEL_COMPRESS(value);
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][4]) * mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][4])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][4] = DSP_LEVEL_COMPRESS(value);
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][5]) * mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][5])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][5] = DSP_LEVEL_COMPRESS(value);
}
}
else
{
int count2;
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
float value;
value = ((DSP_LEVEL_DECOMPRESS(mLevel[count][count2]) *mVolume) - DSP_LEVEL_DECOMPRESS(mLevelCurrent[count][count2])) * oorampcount;
delta += FMOD_FABS(value);
mLevelDelta[count][count2] = DSP_LEVEL_COMPRESS(value);
}
}
}
if (DSP_LEVEL_COMPRESS(delta) >= 0.000001f)
{
mRampCount = DSP_RAMPCOUNT; /* Only trigger the ramp if anything has changed. */
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::checkUnity(int outchannels, int inchannels)
{
int count, count2;
if (inchannels != outchannels)
{
return FMOD_ERR_INVALID_PARAM;
}
if (mRampCount != 0)
{
return FMOD_ERR_PAN;
}
if (mVolume != 1.0f)
{
return FMOD_ERR_PAN;
}
for (count = 0; count < outchannels; count++)
{
for (count2 = 0; count2 < inchannels; count2++)
{
if (count == count2 && DSP_LEVEL_DECOMPRESS(mLevel[count][count2]) != 1.0f)
{
return FMOD_ERR_PAN;
}
else if (count != count2 && mLevel[count][count2] != 0)
{
return FMOD_ERR_PAN;
}
}
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::checkMono(int outchannels, int inchannels)
{
int count, count2;
if (inchannels == 1)
{
return FMOD_OK;
}
for (count = 0; count < outchannels; count++)
{
for (count2 = 1; count2 < inchannels; count2++)
{
if (mLevel[count][count2] != 0)
{
return FMOD_ERR_TOOMANYCHANNELS;
}
}
}
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::setPan(float pan, int outchannels, int inchannels, FMOD_SPEAKERMODE speakermode)
{
int count, count2;
#ifndef PLATFORM_PS3_SPU
if (!mInputUnit->mSystem)
{
return FMOD_ERR_INTERNAL;
}
#endif
/*
First clear out all levels to 0.
*/
for (count = 0; count < outchannels; count++)
{
for (count2 = 0; count2 < inchannels; count2++)
{
mLevel[count][count2] = 0;
}
}
switch (speakermode)
{
#ifdef FMOD_SUPPORT_SPEAKERMODE_RAW
case FMOD_SPEAKERMODE_RAW:
{
/*
Map 1 input channel to each output channel sequentially. For example.
1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1 or 1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0
0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
*/
for (count = 0; count < outchannels; count++)
{
for (count2 = 0; count2 < inchannels; count2++)
{
if (count == count2)
{
mLevel[count][count2] = DSP_LEVEL_COMPRESS(1.0f);
}
}
}
break;
}
#endif
#ifdef FMOD_SUPPORT_SPEAKERMODE_MONO
case FMOD_SPEAKERMODE_MONO:
{
for (count = 0; count < inchannels; count++)
{
mLevel[0][count] = DSP_LEVEL_COMPRESS(1.0f);
}
break;
}
#endif
#ifdef FMOD_SUPPORT_SPEAKERMODE_STEREO
case FMOD_SPEAKERMODE_STEREO:
case FMOD_SPEAKERMODE_STEREO_LINEAR:
{
float l,r;
pan = (pan + 1.0f) / 2.0f;
if (inchannels == 1)
{
l = 1.0f - pan;
r = pan;
if (speakermode == FMOD_SPEAKERMODE_STEREO)
{
l = FMOD_SQRT(l);
r = FMOD_SQRT(r);
}
mLevel[0][0] = DSP_LEVEL_COMPRESS(l);
mLevel[1][0] = DSP_LEVEL_COMPRESS(r);
}
else if (inchannels == 2 || inchannels == 4 || inchannels == 6 || inchannels == 8)
{
/*
Stereo source panning is 0 = 1.0:0.0. 0.5 = 1.0:1.0. 1.0 = 0:1.0.
*/
if (pan <= 0.5f)
{
l = 1.0f;
r = pan * 2.0f;
}
else
{
l = (1.0f - pan) * 2.0f;
r = 1.0f;
}
if (inchannels == 2)
{
mLevel[0][0] = DSP_LEVEL_COMPRESS(l);
mLevel[1][1] = DSP_LEVEL_COMPRESS(r);
}
else if (inchannels == 4)
{
/*
Prologic downmix. Assuming LCRS
*/
mLevel[0][0] = DSP_LEVEL_COMPRESS( 1.0f * l);
mLevel[0][1] = DSP_LEVEL_COMPRESS( 0.0f * l);
mLevel[0][2] = DSP_LEVEL_COMPRESS( 0.707f * l);
mLevel[0][3] = DSP_LEVEL_COMPRESS( -0.707f * l); /* Discard LFE */
mLevel[1][0] = DSP_LEVEL_COMPRESS( 0.0f * r);
mLevel[1][1] = DSP_LEVEL_COMPRESS( 1.0f * r);
mLevel[1][2] = DSP_LEVEL_COMPRESS( 0.707f * r);
mLevel[1][3] = DSP_LEVEL_COMPRESS( -0.707f * r); /* Discard LFE */
}
else if (inchannels == 6)
{
/*
Prologic 2 downmix.
*/
mLevel[0][0] = DSP_LEVEL_COMPRESS( 1.0f * l);
mLevel[0][1] = DSP_LEVEL_COMPRESS( 0.0f * l);
mLevel[0][2] = DSP_LEVEL_COMPRESS( 0.707f * l);
mLevel[0][3] = DSP_LEVEL_COMPRESS( 0.0f * l); /* Discard LFE */
mLevel[0][4] = DSP_LEVEL_COMPRESS(-0.872f * l);
mLevel[0][5] = DSP_LEVEL_COMPRESS(-0.49f * l);
mLevel[1][0] = DSP_LEVEL_COMPRESS( 0.0f * r);
mLevel[1][1] = DSP_LEVEL_COMPRESS( 1.0f * r);
mLevel[1][2] = DSP_LEVEL_COMPRESS( 0.707f * r);
mLevel[1][3] = DSP_LEVEL_COMPRESS( 0.0f * r); /* Discard LFE */
mLevel[1][4] = DSP_LEVEL_COMPRESS( 0.49f * r);
mLevel[1][5] = DSP_LEVEL_COMPRESS( 0.872f * r);
}
else if (inchannels == 8)
{
/*
Prologic 2x downmix?
*/
mLevel[0][0] = DSP_LEVEL_COMPRESS( 1.0f * l);
mLevel[0][1] = DSP_LEVEL_COMPRESS( 0.0f * l);
mLevel[0][2] = DSP_LEVEL_COMPRESS( 0.707f * l);
mLevel[0][3] = DSP_LEVEL_COMPRESS( 0.0f * l); /* Discard LFE */
mLevel[0][4] = DSP_LEVEL_COMPRESS(-0.872f * l);
mLevel[0][5] = DSP_LEVEL_COMPRESS(-0.49f * l);
mLevel[0][6] = DSP_LEVEL_COMPRESS( 1.0f * l); /* Not sure here. Need PLIIx coefficients for 7.1? */
mLevel[0][7] = DSP_LEVEL_COMPRESS( 0.0f * l); /* Not sure here. Need PLIIx coefficients for 7.1? */
mLevel[1][0] = DSP_LEVEL_COMPRESS( 0.0f * r);
mLevel[1][1] = DSP_LEVEL_COMPRESS( 1.0f * r);
mLevel[1][2] = DSP_LEVEL_COMPRESS( 0.707f * r);
mLevel[1][3] = DSP_LEVEL_COMPRESS( 0.0f * r); /* Discard LFE */
mLevel[1][4] = DSP_LEVEL_COMPRESS( 0.49f * r);
mLevel[1][5] = DSP_LEVEL_COMPRESS( 0.872f * r);
mLevel[1][6] = DSP_LEVEL_COMPRESS( 0.0f * r); /* Not sure here. Need PLIIx coefficients for 7.1? */
mLevel[1][7] = DSP_LEVEL_COMPRESS( 1.0f * r); /* Not sure here. Need PLIIx coefficients for 7.1? */
}
}
else
{
/*
Map 1 input channel to each output channel sequentially. For example.
1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1 or 1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0
0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
*/
for (count = 0; count < outchannels; count++)
{
for (count2 = 0; count2 < inchannels; count2++)
{
if (count == count2)
{
mLevel[count][count2] = DSP_LEVEL_COMPRESS(1.0f);
}
}
}
}
break;
}
#endif
case FMOD_SPEAKERMODE_QUAD:
case FMOD_SPEAKERMODE_SURROUND:
case FMOD_SPEAKERMODE_5POINT1:
case FMOD_SPEAKERMODE_7POINT1:
{
float l,r;
pan = (pan + 1.0f) / 2.0f;
if (inchannels == 1)
{
l = 1.0f - pan;
r = pan;
l = FMOD_SQRT(l);
r = FMOD_SQRT(r);
mLevel[0][0] = DSP_LEVEL_COMPRESS(l);
mLevel[1][0] = DSP_LEVEL_COMPRESS(r);
}
else if (inchannels == 2)
{
/*
Stereo source panning is 0.0 = 1.0:0.0. 0.5 = 1.0:1.0. 1.0 = 0.0:1.0.
*/
if (pan <= 0.5f)
{
l = 1.0f;
r = pan * 2.0f;
}
else
{
l = (1.0f - pan) * 2.0f;
r = 1.0f;
}
mLevel[0][0] = DSP_LEVEL_COMPRESS(l);
mLevel[1][1] = DSP_LEVEL_COMPRESS(r);
}
else
{
/*
Map 1 input channel to each output channel sequentially. For example.
1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1 or 1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0
0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
*/
for (count = 0; count < outchannels; count++)
{
for (count2 = 0; count2 < inchannels; count2++)
{
if (count == count2)
{
mLevel[count][count2] = DSP_LEVEL_COMPRESS(1.0f);
}
}
}
}
break;
}
#ifdef FMOD_SUPPORT_SPEAKERMODE_PROLOGIC
case FMOD_SPEAKERMODE_PROLOGIC:
{
float l,r;
pan = (pan + 1.0f) / 2.0f;
if (inchannels == 1)
{
l = 1.0f - pan;
r = pan;
l = FMOD_SQRT(l);
r = FMOD_SQRT(r);
mLevel[0][0] = DSP_LEVEL_COMPRESS(l);
mLevel[1][0] = DSP_LEVEL_COMPRESS(r);
}
else if (inchannels == 2)
{
/*
Stereo source panning is 0.0 = 1.0:0.0. 0.5 = 1.0:1.0. 1.0 = 0:1.0.
*/
if (pan < 0.5f)
{
l = 1.0f;
r = pan * 2.0f;
}
else
{
l = (1.0f - pan) * 2.0f;
r = 1.0f;
}
mLevel[0][0] = DSP_LEVEL_COMPRESS(l);
mLevel[1][1] = DSP_LEVEL_COMPRESS(r);
}
else
{
/*
Map 1 input channel to each output channel sequentially. For example.
1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1 or 1 0 0 0 0 0 0 0 or 1 0 0 0 or 1 0 or 1
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0
0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
*/
for (count = 0; count < outchannels; count++)
{
for (count2 = 0; count2 < inchannels; count2++)
{
if (count == count2)
{
mLevel[count][count2] = DSP_LEVEL_COMPRESS(1.0f);
}
}
}
}
break;
}
#endif
default:
{
break;
}
};
mSetLevelsUsed = true;
return rampTo();
}
/*
[
[DESCRIPTION]
[PARAMETERS]
1 [RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::setLevels(float *levels, int numinputlevels)
{
int count, count2;
if (!levels)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!numinputlevels)
{
return FMOD_OK;
}
#if (DSP_MAXLEVELS_OUT > 2)
if (mMaxOutputLevels == 6 && numinputlevels < 3)
{
if (numinputlevels == 1)
{
mLevel[0][0] = DSP_LEVEL_COMPRESS(levels[0]);
mLevel[1][0] = DSP_LEVEL_COMPRESS(levels[1]);
mLevel[2][0] = DSP_LEVEL_COMPRESS(levels[2]);
mLevel[3][0] = DSP_LEVEL_COMPRESS(levels[3]);
mLevel[4][0] = DSP_LEVEL_COMPRESS(levels[4]);
mLevel[5][0] = DSP_LEVEL_COMPRESS(levels[5]);
}
else
{
mLevel[0][0] = DSP_LEVEL_COMPRESS(levels[0]);
mLevel[0][1] = DSP_LEVEL_COMPRESS(levels[1]);
mLevel[1][0] = DSP_LEVEL_COMPRESS(levels[2]);
mLevel[1][1] = DSP_LEVEL_COMPRESS(levels[3]);
mLevel[2][0] = DSP_LEVEL_COMPRESS(levels[4]);
mLevel[2][1] = DSP_LEVEL_COMPRESS(levels[5]);
mLevel[3][0] = DSP_LEVEL_COMPRESS(levels[6]);
mLevel[3][1] = DSP_LEVEL_COMPRESS(levels[7]);
mLevel[4][0] = DSP_LEVEL_COMPRESS(levels[8]);
mLevel[4][1] = DSP_LEVEL_COMPRESS(levels[9]);
mLevel[5][0] = DSP_LEVEL_COMPRESS(levels[10]);
mLevel[5][1] = DSP_LEVEL_COMPRESS(levels[11]);
}
}
else
#endif
{
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
if (count2 < numinputlevels)
{
mLevel[count][count2] = DSP_LEVEL_COMPRESS(levels[(count * numinputlevels) + count2]);
}
else
{
mLevel[count][count2] = 0;
}
}
}
}
mSetLevelsUsed = true;
return rampTo();
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getLevels(float *levels, int numinputlevels)
{
int count, count2;
if (!levels)
{
return FMOD_ERR_INVALID_PARAM;
}
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < numinputlevels; count2++)
{
if (count2 < mMaxInputLevels)
{
levels[(count * numinputlevels) + count2] = DSP_LEVEL_DECOMPRESS(mLevel[count][count2]);
}
else
{
levels[(count * numinputlevels) + count2] = 0;
}
}
}
return FMOD_OK;
}
#endif /* #ifdef FMOD_SUPPORT_SOFTWARE */
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::setMix(float volume)
{
#ifdef FMOD_SUPPORT_SOFTWARE
if (volume < -1.0f)
{
volume = -1.0f;
}
if (volume > 1.0f)
{
volume = 1.0f;
}
if (mVolume == volume)
{
return FMOD_OK;
}
mVolume = volume;
return rampTo();
#else
return FMOD_ERR_NEEDSSOFTWARE;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getMix(float *volume)
{
#ifdef FMOD_SUPPORT_SOFTWARE
if (!volume)
{
return FMOD_ERR_INVALID_PARAM;
}
*volume = mVolume;
return FMOD_OK;
#else
return FMOD_ERR_NEEDSSOFTWARE;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::setLevels(FMOD_SPEAKER speaker, float *levels, int numinputlevels)
{
#ifdef FMOD_SUPPORT_SOFTWARE
int count;
if (!levels)
{
return FMOD_ERR_INVALID_PARAM;
}
if (!numinputlevels)
{
return FMOD_OK;
}
if (speaker >= mMaxOutputLevels)
{
return FMOD_ERR_INVALID_SPEAKER;
}
for (count = 0; count < mMaxInputLevels; count++)
{
if (count < numinputlevels)
{
mLevel[speaker][count] = DSP_LEVEL_COMPRESS(levels[count]);
}
else
{
mLevel[speaker][count] = 0;
}
}
mSetLevelsUsed = true;
return rampTo();
#else
return FMOD_ERR_NEEDSSOFTWARE;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getLevels(FMOD_SPEAKER speaker, float *levels, int numinputlevels)
{
#ifdef FMOD_SUPPORT_SOFTWARE
int count;
if (!levels)
{
return FMOD_ERR_INVALID_PARAM;
}
for (count = 0; count < numinputlevels; count++)
{
if (count < mMaxInputLevels)
{
levels[count] = DSP_LEVEL_DECOMPRESS(mLevel[speaker][count]);
}
else
{
levels[count] = 0;
}
}
return FMOD_OK;
#else
return FMOD_ERR_NEEDSSOFTWARE;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::setUserData(void *userdata)
{
mUserData = userdata;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getUserData(void **userdata)
{
if (!userdata)
{
return FMOD_ERR_INVALID_PARAM;
}
*userdata = mUserData;
return FMOD_OK;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
FMOD_OK
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
#ifdef FMOD_SUPPORT_SOFTWARE
FMOD_RESULT DSPConnectionI::copy(DSPConnectionI *source)
{
int count, count2;
mVolume = source->mVolume;
for (count = 0; count < mMaxOutputLevels; count++)
{
for (count2 = 0; count2 < mMaxInputLevels; count2++)
{
mLevel [count][count2] = source->mLevel [count][count2];
mLevelCurrent[count][count2] = source->mLevelCurrent[count][count2];
mLevelDelta [count][count2] = source->mLevelDelta [count][count2];
}
}
mRampCount = source->mRampCount;
mSetLevelsUsed = source->mSetLevelsUsed;
return FMOD_OK;
}
#endif
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[SEE_ALSO]
]
*/
FMOD_RESULT DSPConnectionI::getMemoryInfo(unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details)
{
#ifdef FMOD_SUPPORT_MEMORYTRACKER
GETMEMORYINFO_IMPL
#else
return FMOD_ERR_UNIMPLEMENTED;
#endif
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
#if defined(FMOD_SUPPORT_MEMORYTRACKER) && !defined(PLATFORM_PS3_SPU)
FMOD_RESULT DSPConnectionI::getMemoryUsedImpl(MemoryTracker *tracker)
{
tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, sizeof(*this));
// LinkedListNode mInputNode;
// LinkedListNode mOutputNode;
// LinkedListNode *mNode; /* Make it a pointer so we can store the node data externally. PS3 will corrupt it otherwise. */
// DSP_LEVEL_TYPE *mLevel[DSP_MAXLEVELS_OUT];
// DSP_LEVEL_TYPE *mLevelCurrent[DSP_MAXLEVELS_OUT];
// DSP_LEVEL_TYPE *mLevelDelta[DSP_MAXLEVELS_OUT];
// DSPI *mInputUnit;
// DSPI *mOutputUnit;
return FMOD_OK;
}
#endif
#if (DSP_LEVEL_PRECISION == 16) && !defined(PLATFORM_XENON)
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
unsigned short FMOD_DSP_ConnectionI_Single2HalfP(float source)
{
typedef union
{
float f;
unsigned int i;
} floatdata;
floatdata x;
unsigned short hs, he, hm;
unsigned int xs, xe, xm;
int hes;
x.f = source;
if( (x.i & 0x7FFFFFFFu) == 0 )
{ // Signed zero
return (unsigned short) (x.i >> 16); // Return the signed zero
}
else
{ // Not zero
xs = x.i & 0x80000000u; // Pick off sign bit
xe = x.i & 0x7F800000u; // Pick off exponent bits
xm = x.i & 0x007FFFFFu; // Pick off mantissa bits
if( xe == 0 )
{ // Denormal will underflow, return a signed zero
return (unsigned short) (xs >> 16);
} else if( xe == 0x7F800000u )
{ // Inf or NaN (all the exponent bits are set)
if( xm == 0 )
{ // If mantissa is zero ...
return (unsigned short) ((xs >> 16) | 0x7C00u); // Signed Inf
} else
{
return (unsigned short) 0xFE00u; // NaN, only 1st mantissa bit set
}
} else
{ // Normalized number
hs = (unsigned short) (xs >> 16); // Sign bit
hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp
if( hes >= 0x1F )
{ // Overflow
return (unsigned short) ((xs >> 16) | 0x7C00u); // Signed Inf
} else if( hes <= 0 )
{ // Underflow
if( (14 - hes) > 24 )
{ // Mantissa shifted all the way off & no rounding possibility
hm = (unsigned short) 0u; // Set mantissa to zero
}
else
{
xm |= 0x00800000u; // Add the hidden leading bit
hm = (unsigned short) (xm >> (14 - hes)); // Mantissa
if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding
hm += (unsigned short) 1u; // Round, might overflow into exp bit, but this is OK
}
return (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero
} else
{
he = (unsigned short) (hes << 10); // Exponent
hm = (unsigned short) (xm >> 13); // Mantissa
if( xm & 0x00001000u ) // Check for rounding
return (hs | he | hm) + (unsigned short) 1u; // Round, might overflow to inf, this is OK
else
return (hs | he | hm); // No rounding
}
}
}
return 0;
}
/*
[
[DESCRIPTION]
[PARAMETERS]
[RETURN_VALUE]
[REMARKS]
[PLATFORMS]
[SEE_ALSO]
]
*/
float FMOD_DSP_ConnectionI_HalfP2Single(unsigned short h)
{
typedef union
{
float f;
unsigned int i;
} floatdata;
unsigned short hs, he, hm;
unsigned int xs, xe, xm;
signed int xes;
floatdata xp;
int e;
if( (h & 0x7FFFu) == 0 )
{ // Signed zero
xp.i = ((unsigned int) h) << 16; // Return the signed zero
}
else
{ // Not zero
hs = h & 0x8000u; // Pick off sign bit
he = h & 0x7C00u; // Pick off exponent bits
hm = h & 0x03FFu; // Pick off mantissa bits
if( he == 0 )
{ // Denormal will convert to normalized
e = -1; // The following loop figures out how much extra to adjust the exponent
do
{
e++;
hm <<= 1;
} while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit
xs = ((unsigned int) hs) << 16; // Sign bit
xes = ((signed int) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single
xe = (unsigned int) (xes << 23); // Exponent
xm = ((unsigned int) (hm & 0x03FFu)) << 13; // Mantissa
xp.i = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits
}
else if( he == 0x7C00u )
{ // Inf or NaN (all the exponent bits are set)
if( hm == 0 )
{ // If mantissa is zero ...
xp.i = (((unsigned int) hs) << 16) | ((unsigned int) 0x7F800000u); // Signed Inf
} else
{
xp.i = (unsigned int) 0xFFC00000u; // NaN, only 1st mantissa bit set
}
}
else
{ // Normalized number
xs = ((unsigned int) hs) << 16; // Sign bit
xes = ((signed int) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single
xe = (unsigned int) (xes << 23); // Exponent
xm = ((unsigned int) hm) << 13; // Mantissa
xp.i = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits
}
}
return xp.f;
}
#endif
}