mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-26 08:06:58 +00:00
382 lines
9.6 KiB
C++
382 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 ExtractFloatSamples( 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 ExtractShortSamples( 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++ )
|
||
|
{
|
||
|
ExtractFloatSamples( pTmpBuf, pInputBuffer+i, sampleCount, channelCount );
|
||
|
DecimateSampleBlock( pTmpBuf, sampleCount );
|
||
|
ExtractShortSamples( 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));
|
||
|
}
|
||
|
}
|
||
|
|