css_enhanced_waf/utils/xbox/MakeGameData/resample.cpp
unknown d03c92b6f0 We have now better angle update
Since it was previously based on old frametime,
you would see your angle changes from previous frametime,
not the current one...
It's now fixed.
2024-09-12 22:33:24 +02:00

381 lines
9.6 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
#include <windows.h>
#include <mmreg.h>
#include "../toollib/toollib.h"
#include "tier1/strtools.h"
#include "resample.h"
#define clamp(a,b,c) ( (a) > (c) ? (c) : ( (a) < (b) ? (b) : (a) ) )
const int NUM_COEFFS = 7;
static const float g_ResampleCoefficients[NUM_COEFFS] =
{
0.0457281f, 0.168088f, 0.332501f, 0.504486f, 0.663202f, 0.803781f, 0.933856f
};
// generates 1 output sample for 2 input samples
inline float DecimateSamplePair(float input0, float input1, const float pCoefficients[7], float xState[2], float yState[7] )
{
float tmp_0 = xState[0];
float tmp_1 = xState[1];
xState[0] = input0;
xState[1] = input1;
input0 = (input0 - yState[0]) * pCoefficients[0] + tmp_0;
input1 = (input1 - yState[1]) * pCoefficients[1] + tmp_1;
tmp_0 = yState[0];
tmp_1 = yState[1];
yState[0] = input0;
yState[1] = input1;
input0 = (input0 - yState[2]) * pCoefficients[2] + tmp_0;
input1 = (input1 - yState[3]) * pCoefficients[3] + tmp_1;
tmp_0 = yState[2];
tmp_1 = yState[3];
yState[2] = input0;
yState[3] = input1;
input0 = (input0 - yState[4]) * pCoefficients[4] + tmp_0;
input1 = (input1 - yState[5]) * pCoefficients[5] + tmp_1;
tmp_0 = yState[4];
yState[4] = input0;
yState[5] = input1;
input0 = (input0 - yState[6]) * pCoefficients[6] + tmp_0;
yState[6] = input0;
return (input0 + input1);
}
static void ExtraMovementSamples( float *pOut, const short *pInputBuffer, int sampleCount, int stride )
{
for ( int i = 0; i < sampleCount; i++ )
{
pOut[i] = pInputBuffer[0] * 1.0f / 32768.0f;
pInputBuffer += stride;
}
}
static void ExtraMovementSamples( short *pOut, const float *pInputBuffer, float scale, int sampleCount, int stride )
{
for ( int i = 0; i < sampleCount; i++ )
{
int sampleOut = (int)(pInputBuffer[i] * scale);
sampleOut = clamp( sampleOut, -32768, 32767 );
pOut[0] = (short)(sampleOut);
pOut += stride;
}
}
struct decimatestate_t
{
float xState[2];
float yState[7];
};
void DecimateSampleBlock( float *pInOut, int sampleCount )
{
decimatestate_t block;
int outCount = sampleCount >> 1;
int pos = 0;
memset( &block, 0, sizeof(block) );
do
{
float input0 = pInOut[pos*2+0];
float input1 = pInOut[pos*2+1];
pInOut[pos] = DecimateSamplePair( input0, input1, g_ResampleCoefficients, block.xState, block.yState );
pos++;
} while( pos < outCount );
}
void DecimateSampleRateBy2_16( const short *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount )
{
float *pTmpBuf = new float[sampleCount];
for ( int i = 0; i < channelCount; i++ )
{
ExtraMovementSamples( pTmpBuf, pInputBuffer+i, sampleCount, channelCount );
DecimateSampleBlock( pTmpBuf, sampleCount );
ExtraMovementSamples( pOutputBuffer+i, pTmpBuf, 0.5f * 32768.0f, sampleCount>>1, channelCount );
}
delete [] pTmpBuf;
}
struct adpcmstate_t
{
const ADPCMWAVEFORMAT *pFormat;
const ADPCMCOEFSET *pCoefficients;
int blockSize;
};
static int error_sign_lut[] = { 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 };
static int error_coefficients_lut[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 };
void ParseADPCM( adpcmstate_t &out, const byte *pFormatChunk )
{
out.pFormat = (const ADPCMWAVEFORMAT *)pFormatChunk;
if ( out.pFormat )
{
out.pCoefficients = out.pFormat->aCoef;
// number of bytes for samples
out.blockSize = ((out.pFormat->wSamplesPerBlock - 2) * out.pFormat->wfx.nChannels ) / 2;
// size of channel header
out.blockSize += 7 * out.pFormat->wfx.nChannels;
}
}
void DecompressBlockMono( const adpcmstate_t &state, short *pOut, const char *pIn, int count )
{
int pred = *pIn++;
int co1 = state.pCoefficients[pred].iCoef1;
int co2 = state.pCoefficients[pred].iCoef2;
// read initial delta
int delta = *((short *)pIn);
pIn += 2;
// read initial samples for prediction
int samp1 = *((short *)pIn);
pIn += 2;
int samp2 = *((short *)pIn);
pIn += 2;
// write out the initial samples (stored in reverse order)
*pOut++ = (short)samp2;
*pOut++ = (short)samp1;
// subtract the 2 samples in the header
count -= 2;
// this is a toggle to read nibbles, first nibble is high
int high = 1;
int error, sample=0;
// now process the block
while ( count )
{
// read the error nibble from the input stream
if ( high )
{
sample = (unsigned char) (*pIn++);
// high nibble
error = sample >> 4;
// cache low nibble for next read
sample = sample & 0xf;
// Next read is from cache, not stream
high = 0;
}
else
{
// stored in previous read (low nibble)
error = sample;
// next read is from stream
high = 1;
}
// convert to signed with LUT
int errorSign = error_sign_lut[error];
// interpolate the new sample
int predSample = (samp1 * co1) + (samp2 * co2);
// coefficients are fixed point 8-bit, so shift back to 16-bit integer
predSample >>= 8;
// Add in current error estimate
predSample += (errorSign * delta);
// Correct error estimate
delta = (delta * error_coefficients_lut[error]) >> 8;
// Clamp error estimate
if ( delta < 16 )
delta = 16;
// clamp
if ( predSample > 32767L )
predSample = 32767L;
else if ( predSample < -32768L )
predSample = -32768L;
// output
*pOut++ = (short)predSample;
// move samples over
samp2 = samp1;
samp1 = predSample;
count--;
}
}
//-----------------------------------------------------------------------------
// Purpose: Decode a single block of stereo ADPCM audio
// Input : *pOut - 16-bit output buffer
// *pIn - ADPCM encoded block data
// count - number of sample pairs to decode
//-----------------------------------------------------------------------------
void DecompressBlockStereo( const adpcmstate_t &state, short *pOut, const char *pIn, int count )
{
int pred[2], co1[2], co2[2];
int i;
for ( i = 0; i < 2; i++ )
{
pred[i] = *pIn++;
co1[i] = state.pCoefficients[pred[i]].iCoef1;
co2[i] = state.pCoefficients[pred[i]].iCoef2;
}
int delta[2], samp1[2], samp2[2];
for ( i = 0; i < 2; i++, pIn += 2 )
{
// read initial delta
delta[i] = *((short *)pIn);
}
// read initial samples for prediction
for ( i = 0; i < 2; i++, pIn += 2 )
{
samp1[i] = *((short *)pIn);
}
for ( i = 0; i < 2; i++, pIn += 2 )
{
samp2[i] = *((short *)pIn);
}
// write out the initial samples (stored in reverse order)
*pOut++ = (short)samp2[0]; // left
*pOut++ = (short)samp2[1]; // right
*pOut++ = (short)samp1[0]; // left
*pOut++ = (short)samp1[1]; // right
// subtract the 2 samples in the header
count -= 2;
// this is a toggle to read nibbles, first nibble is high
int high = 1;
int error, sample=0;
// now process the block
while ( count )
{
for ( i = 0; i < 2; i++ )
{
// read the error nibble from the input stream
if ( high )
{
sample = (unsigned char) (*pIn++);
// high nibble
error = sample >> 4;
// cache low nibble for next read
sample = sample & 0xf;
// Next read is from cache, not stream
high = 0;
}
else
{
// stored in previous read (low nibble)
error = sample;
// next read is from stream
high = 1;
}
// convert to signed with LUT
int errorSign = error_sign_lut[error];
// interpolate the new sample
int predSample = (samp1[i] * co1[i]) + (samp2[i] * co2[i]);
// coefficients are fixed point 8-bit, so shift back to 16-bit integer
predSample >>= 8;
// Add in current error estimate
predSample += (errorSign * delta[i]);
// Correct error estimate
delta[i] = (delta[i] * error_coefficients_lut[error]) >> 8;
// Clamp error estimate
if ( delta[i] < 16 )
delta[i] = 16;
// clamp
if ( predSample > 32767L )
predSample = 32767L;
else if ( predSample < -32768L )
predSample = -32768L;
// output
*pOut++ = (short)predSample;
// move samples over
samp2[i] = samp1[i];
samp1[i] = predSample;
}
count--;
}
}
int ADPCMSampleCountShortBlock( const adpcmstate_t &state, int shortBlockSize )
{
if ( shortBlockSize < 8 )
return 0;
int sampleCount = state.pFormat->wSamplesPerBlock;
// short block?, fixup sample count (2 samples per byte, divided by number of channels per sample set)
sampleCount -= ((state.blockSize - shortBlockSize) * 2) / state.pFormat->wfx.nChannels;
return sampleCount;
}
int ADPCMSampleCount( const byte *pFormatChunk, const byte *pDataChunk, int dataSize )
{
adpcmstate_t state;
ParseADPCM( state, pFormatChunk );
int numBlocks = dataSize / state.blockSize;
int mod = dataSize % state.blockSize;
return numBlocks * state.pFormat->wSamplesPerBlock + ADPCMSampleCountShortBlock(state, mod);
}
void DecompressADPCMSamples( const byte *pFormatChunk, const byte *pDataChunk, int dataSize, short *pOutputBuffer )
{
adpcmstate_t state;
ParseADPCM( state, pFormatChunk );
while ( dataSize > 0 )
{
int block = dataSize;
int sampleCount = state.pFormat->wSamplesPerBlock;
if ( block > state.blockSize )
{
block = state.blockSize;
}
else
{
sampleCount = ADPCMSampleCountShortBlock( state, block );
}
if ( state.pFormat->wfx.nChannels == 1 )
{
DecompressBlockMono( state, pOutputBuffer, (const char *)pDataChunk, sampleCount );
}
else
{
DecompressBlockStereo( state, pOutputBuffer, (const char *)pDataChunk, sampleCount );
}
pOutputBuffer += sampleCount * state.pFormat->wfx.nChannels;
dataSize -= block;
pDataChunk += block;
}
}
void Convert8To16( const byte *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount )
{
for ( int i = 0; i < sampleCount*channelCount; i++ )
{
unsigned short signedSample = (byte)((int)((unsigned)pInputBuffer[i]) - 128);
pOutputBuffer[i] = (short) (signedSample | (signedSample<<8));
}
}