summaryrefslogtreecommitdiff
path: root/utils/xbox/MakeGameData/resample.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/xbox/MakeGameData/resample.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/xbox/MakeGameData/resample.cpp')
-rw-r--r--utils/xbox/MakeGameData/resample.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/utils/xbox/MakeGameData/resample.cpp b/utils/xbox/MakeGameData/resample.cpp
new file mode 100644
index 0000000..a0ce0a7
--- /dev/null
+++ b/utils/xbox/MakeGameData/resample.cpp
@@ -0,0 +1,381 @@
+//========= 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));
+ }
+}
+