added MS-ADPCM
This commit is contained in:
parent
441e320e79
commit
83faac5a6d
3 changed files with 335 additions and 26 deletions
|
@ -4,8 +4,8 @@
|
|||
* Author(s):
|
||||
* Volker Fischer, Erik de Castro Lopo
|
||||
*
|
||||
* This code is based on the Open-Source implementation of IMA-ADPCM written
|
||||
* by Erik de Castro Lopo <erikd[at-#]mega-nerd[dot*]com> in 1999-2004
|
||||
* This code is based on the Open-Source implementation of IMA-ADPCM / MS-ADPCM
|
||||
* written by Erik de Castro Lopo <erikd[at-#]mega-nerd[dot*]com> in 1999-2004
|
||||
*
|
||||
* Changes:
|
||||
* - only support for one channel
|
||||
|
@ -46,7 +46,11 @@ int CAudioCompression::Init ( const int iNewAudioLen,
|
|||
case CT_IMAADPCM:
|
||||
return ImaAdpcm.Init ( iNewAudioLen );
|
||||
|
||||
default: return 0;
|
||||
case CT_MSADPCM:
|
||||
return MsAdpcm.Init ( iNewAudioLen );
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +64,7 @@ CVector<unsigned char> CAudioCompression::Encode ( const CVector<short>& vecsAud
|
|||
|
||||
for ( int i = 0; i < iAudSize; i++ )
|
||||
{
|
||||
vecbyOut[2 * i] = vecsAudio[i] & 0xFF;
|
||||
vecbyOut[2 * i] = vecsAudio[i] & 0xFF;
|
||||
vecbyOut[2 * i + 1] = ( vecsAudio[i] >> 8 ) & 0xFF;
|
||||
}
|
||||
return vecbyOut;
|
||||
|
@ -72,6 +76,9 @@ CVector<unsigned char> CAudioCompression::Encode ( const CVector<short>& vecsAud
|
|||
case CT_IMAADPCM:
|
||||
return ImaAdpcm.Encode ( vecsAudio ); // IMA-ADPCM
|
||||
|
||||
case CT_MSADPCM:
|
||||
return MsAdpcm.Encode ( vecsAudio ); // MS-ADPCM
|
||||
|
||||
default:
|
||||
return CVector<unsigned char> ( 0 );
|
||||
}
|
||||
|
@ -105,6 +112,9 @@ CVector<short> CAudioCompression::Decode ( const CVector<unsigned char>& vecbyAd
|
|||
case CT_IMAADPCM:
|
||||
return ImaAdpcm.Decode ( vecbyAdpcm ); // IMA-ADPCM
|
||||
|
||||
case CT_MSADPCM:
|
||||
return MsAdpcm.Decode ( vecbyAdpcm ); // MS-ADPCM
|
||||
|
||||
default:
|
||||
return CVector<short> ( 0 );
|
||||
}
|
||||
|
@ -112,7 +122,10 @@ CVector<short> CAudioCompression::Decode ( const CVector<unsigned char>& vecbyAd
|
|||
}
|
||||
|
||||
|
||||
/* IMA-ADPCM implementation ------------------------------------------------- */
|
||||
|
||||
/******************************************************************************\
|
||||
* IMA-ADPCM implementation *
|
||||
\******************************************************************************/
|
||||
int CImaAdpcm::Init ( const int iNewAudioLen )
|
||||
{
|
||||
// set lengths for audio and compressed data
|
||||
|
@ -132,10 +145,11 @@ CVector<unsigned char> CImaAdpcm::Encode ( const CVector<short>& vecsAudio )
|
|||
CVector<unsigned char> vecbyAdpcmTemp;
|
||||
|
||||
// init size
|
||||
vecbyAdpcm.Init ( iAdpcmSize );
|
||||
vecbyAdpcm.Init ( iAdpcmSize );
|
||||
vecbyAdpcmTemp.Init ( iAudSize );
|
||||
|
||||
/* encode the block header ----------------------------------------------- */
|
||||
|
||||
/* Encode the block header ---------------------------------------------- */
|
||||
vecbyAdpcm[0] = vecsAudio[0] & 0xFF;
|
||||
vecbyAdpcm[1] = ( vecsAudio[0] >> 8 ) & 0xFF;
|
||||
vecbyAdpcm[2] = iStepindEnc;
|
||||
|
@ -143,7 +157,7 @@ CVector<unsigned char> CImaAdpcm::Encode ( const CVector<short>& vecsAudio )
|
|||
int iPrevAudio = vecsAudio[0];
|
||||
|
||||
|
||||
/* encode the samples as 4 bit ------------------------------------------- */
|
||||
/* Encode the samples as 4 bit ------------------------------------------ */
|
||||
for ( i = 1; i < iAudSize; i++ )
|
||||
{
|
||||
// init diff and step
|
||||
|
@ -187,15 +201,15 @@ CVector<unsigned char> CImaAdpcm::Encode ( const CVector<short>& vecsAudio )
|
|||
iStepindEnc += ima_indx_adjust[bytecode];
|
||||
|
||||
// check that values do not exceed the bounds
|
||||
iPrevAudio = CheckBounds ( iPrevAudio, _MINSHORT, _MAXSHORT );
|
||||
iPrevAudio = CheckBounds ( iPrevAudio, _MINSHORT, _MAXSHORT );
|
||||
iStepindEnc = CheckBounds ( iStepindEnc, 0, IMA_STEP_SIZE_TAB_LEN - 1 );
|
||||
|
||||
// use the input buffer as an intermediate result buffer
|
||||
// use a temporary buffer as an intermediate result buffer
|
||||
vecbyAdpcmTemp[i] = bytecode;
|
||||
}
|
||||
|
||||
|
||||
/* pack the 4 bit encoded samples ---------------------------------------- */
|
||||
/* Pack the 4 bit encoded samples --------------------------------------- */
|
||||
// The first encoded audio sample is in header
|
||||
vecbyAdpcm[3] = vecbyAdpcmTemp[1] & 0x0F;
|
||||
|
||||
|
@ -216,7 +230,7 @@ CVector<short> CImaAdpcm::Decode ( const CVector<unsigned char>& vecbyAdpcm )
|
|||
vecsAudio.Init ( iAudSize );
|
||||
|
||||
|
||||
/* read and check the block header --------------------------------------- */
|
||||
/* Read the block header ------------------------------------------------ */
|
||||
int current = vecbyAdpcm[0] | ( vecbyAdpcm[1] << 8 );
|
||||
if ( current & 0x8000 )
|
||||
{
|
||||
|
@ -230,10 +244,10 @@ CVector<short> CImaAdpcm::Decode ( const CVector<unsigned char>& vecbyAdpcm )
|
|||
vecsAudio[0] = current;
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
pull apart the packed 4 bit samples and store them in their correct sample
|
||||
positions */
|
||||
// The first encoded audio sample is in header
|
||||
/* -------------------------------------------------------------------------
|
||||
pull apart the packed 4 bit samples and store them in their correct
|
||||
sample positions */
|
||||
// the first encoded audio sample is in header
|
||||
vecsAudio[1] = vecbyAdpcm[3] & 0x0F;
|
||||
|
||||
for ( i = 4; i < iAdpcmSize; i++ )
|
||||
|
@ -244,7 +258,7 @@ CVector<short> CImaAdpcm::Decode ( const CVector<unsigned char>& vecbyAdpcm )
|
|||
}
|
||||
|
||||
|
||||
/* decode the encoded 4 bit samples -------------------------------------- */
|
||||
/* Decode the encoded 4 bit samples ------------------------------------- */
|
||||
for ( i = 1; i < iAudSize; i++ )
|
||||
{
|
||||
const short bytecode = vecsAudio[i] & 0xF ;
|
||||
|
@ -286,3 +300,255 @@ CVector<short> CImaAdpcm::Decode ( const CVector<unsigned char>& vecbyAdpcm )
|
|||
|
||||
return vecsAudio;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************\
|
||||
* MS-ADPCM implementation *
|
||||
\******************************************************************************/
|
||||
/*
|
||||
MS ADPCM block layout:
|
||||
byte purpose
|
||||
0 block predictor [0..6]
|
||||
1,2 initial idelta (positive)
|
||||
3,4 sample 1
|
||||
5,6 sample 0
|
||||
7..n packed bytecodes
|
||||
*/
|
||||
int CMsAdpcm::Init ( const int iNewAudioLen )
|
||||
{
|
||||
// set lengths for audio and compressed data
|
||||
iAudSize = iNewAudioLen;
|
||||
iAdpcmSize = 7 /* bytes header */ + (int) ceil (
|
||||
(double) ( iAudSize - 2 /* first two samples are in header */ ) / 2 );
|
||||
|
||||
return iAdpcmSize;
|
||||
}
|
||||
|
||||
CVector<unsigned char> CMsAdpcm::Encode ( const CVector<short>& vecsAudio )
|
||||
{
|
||||
CVector<short> vecsAudioTemp;
|
||||
CVector<unsigned char> vecbyAdpcm;
|
||||
|
||||
// init size
|
||||
vecsAudioTemp.Init ( iAudSize );
|
||||
vecbyAdpcm.Init ( iAdpcmSize );
|
||||
|
||||
// copy input vector (because we want to overwrite it)
|
||||
vecsAudioTemp = vecsAudio;
|
||||
|
||||
// choose predictor
|
||||
int bpred;
|
||||
int idelta;
|
||||
ChoosePredictor ( vecsAudio, bpred, idelta );
|
||||
|
||||
|
||||
/* Encode the block header ---------------------------------------------- */
|
||||
vecbyAdpcm[0] = bpred;
|
||||
vecbyAdpcm[1] = idelta & 0xFF;
|
||||
vecbyAdpcm[2] = ( idelta >> 8 ) & 0xFF;
|
||||
vecbyAdpcm[3] = vecsAudio[1] & 0xFF;
|
||||
vecbyAdpcm[4] = ( vecsAudio[1] >> 8 ) & 0xFF;
|
||||
vecbyAdpcm[5] = vecsAudio[0] & 0xFF;
|
||||
vecbyAdpcm[6] = ( vecsAudio[0] >> 8 ) & 0xFF;
|
||||
|
||||
|
||||
/* Encode the samples as 4 bit ------------------------------------------ */
|
||||
unsigned int blockindx = 7;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for ( int k = 2; k < iAudSize; k++ )
|
||||
{
|
||||
const int predict = ( vecsAudioTemp[k - 1] * ms_AdaptCoeff1[bpred] +
|
||||
vecsAudioTemp[k - 2] * ms_AdaptCoeff2[bpred] ) >> 8;
|
||||
|
||||
int errordelta = ( vecsAudio[k] - predict ) / idelta;
|
||||
|
||||
if ( errordelta < -8 )
|
||||
{
|
||||
errordelta = -8 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errordelta > 7)
|
||||
{
|
||||
errordelta = 7;
|
||||
}
|
||||
}
|
||||
int newsamp = predict + ( idelta * errordelta );
|
||||
|
||||
if ( newsamp > 32767 )
|
||||
{
|
||||
newsamp = 32767;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( newsamp < -32768 )
|
||||
{
|
||||
newsamp = -32768;
|
||||
}
|
||||
}
|
||||
if ( errordelta < 0 )
|
||||
{
|
||||
errordelta += 0x10;
|
||||
}
|
||||
|
||||
byte = ( byte << 4 ) | ( errordelta & 0xF );
|
||||
|
||||
if ( k % 2 )
|
||||
{
|
||||
vecbyAdpcm[blockindx++] = byte;
|
||||
byte = 0;
|
||||
}
|
||||
|
||||
idelta = ( idelta * ms_AdaptationTable[errordelta] ) >> 8;
|
||||
|
||||
if ( idelta < 16 )
|
||||
{
|
||||
idelta = 16;
|
||||
}
|
||||
vecsAudioTemp[k] = newsamp;
|
||||
}
|
||||
|
||||
return vecbyAdpcm;
|
||||
}
|
||||
|
||||
CVector<short> CMsAdpcm::Decode ( const CVector<unsigned char>& vecbyAdpcm )
|
||||
{
|
||||
CVector<short> vecsAudio;
|
||||
short bytecode;
|
||||
|
||||
vecsAudio.Init ( iAudSize );
|
||||
|
||||
|
||||
/* Read the block header ------------------------------------------------ */
|
||||
short bpred = vecbyAdpcm[0];
|
||||
|
||||
if ( bpred >= 7 )
|
||||
{
|
||||
// no valid MS ADPCM stream, do not decode
|
||||
return vecsAudio;
|
||||
}
|
||||
|
||||
short chan_idelta = vecbyAdpcm[1] | ( vecbyAdpcm[2] << 8 );
|
||||
|
||||
vecsAudio[1] = vecbyAdpcm[3] | ( vecbyAdpcm[4] << 8 );
|
||||
vecsAudio[0] = vecbyAdpcm[5] | ( vecbyAdpcm[6] << 8 );
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
pull apart the packed 4 bit samples and store them in their correct
|
||||
sample positions */
|
||||
for ( int i = 7; i < iAdpcmSize; i++ )
|
||||
{
|
||||
bytecode = vecbyAdpcm[i];
|
||||
vecsAudio[2 * i - 12] = ( bytecode >> 4 ) & 0x0F;
|
||||
vecsAudio[2 * i - 11] = bytecode & 0x0F;
|
||||
}
|
||||
|
||||
|
||||
/* Decode the encoded 4 bit samples ------------------------------------- */
|
||||
for ( int k = 2; k < iAudSize; k ++ )
|
||||
{
|
||||
bytecode = vecsAudio[k] & 0xF;
|
||||
|
||||
// compute next Adaptive Scale Factor (ASF)
|
||||
int idelta = chan_idelta;
|
||||
|
||||
// => / 256 => FIXED_POINT_ADAPTATION_BASE == 256
|
||||
chan_idelta = ( ms_AdaptationTable[bytecode] * idelta ) >> 8;
|
||||
|
||||
if ( chan_idelta < 16 )
|
||||
{
|
||||
chan_idelta = 16;
|
||||
}
|
||||
|
||||
if ( bytecode & 0x8 )
|
||||
{
|
||||
bytecode -= 0x10;
|
||||
}
|
||||
|
||||
// => / 256 => FIXED_POINT_COEFF_BASE == 256
|
||||
const int predict = ( ( vecsAudio[k - 1] * ms_AdaptCoeff1[bpred] ) +
|
||||
( vecsAudio[k - 2] * ms_AdaptCoeff2[bpred] ) ) >> 8;
|
||||
|
||||
int current = ( bytecode * idelta ) + predict;
|
||||
|
||||
if ( current > 32767 )
|
||||
{
|
||||
current = 32767 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( current < -32768 )
|
||||
{
|
||||
current = -32768;
|
||||
}
|
||||
}
|
||||
|
||||
vecsAudio[k] = current;
|
||||
}
|
||||
|
||||
return vecsAudio;
|
||||
}
|
||||
|
||||
void CMsAdpcm::ChoosePredictor ( const CVector<short>& vecsAudio,
|
||||
int& block_pred,
|
||||
int& idelta )
|
||||
{
|
||||
/*
|
||||
Choosing the block predictor:
|
||||
Each block requires a predictor and an idelta for each channel. The
|
||||
predictor is in the range [0..6] which is an index into the two AdaptCoeff
|
||||
tables. The predictor is chosen by trying all of the possible predictors on
|
||||
a small set of samples at the beginning of the block. The predictor with the
|
||||
smallest average abs (idelta) is chosen as the best predictor for this
|
||||
block. The value of idelta is chosen to to give a 4 bit code value of +/- 4
|
||||
(approx. half the max. code value). If the average abs (idelta) is zero, the
|
||||
sixth predictor is chosen. If the value of idelta is less then 16 it is set
|
||||
to 16.
|
||||
*/
|
||||
unsigned int best_bpred = 0;
|
||||
unsigned int best_idelta = 0;
|
||||
|
||||
/* Microsoft uses an IDELTA_COUNT (number of sample pairs used to choose
|
||||
best predictor) value of 3. The best possible results would be obtained
|
||||
by using all the samples to choose the predictor. */
|
||||
unsigned int idelta_count = min ( MSADPCM_IDELTA_COUNT, vecsAudio.Size() - 1 );
|
||||
|
||||
for ( unsigned int bpred = 0; bpred < MSADPCM_ADAPT_COEFF_COUNT; bpred++ )
|
||||
{
|
||||
unsigned int idelta_sum = 0 ;
|
||||
|
||||
for ( unsigned int k = 2 ; k < 2 + idelta_count ; k++ )
|
||||
{
|
||||
idelta_sum += abs ( vecsAudio[k] -
|
||||
( ( vecsAudio[k - 1] * ms_AdaptCoeff1[bpred] +
|
||||
vecsAudio[k - 2] * ms_AdaptCoeff2[bpred] ) >> 8 ) );
|
||||
}
|
||||
idelta_sum /= ( 4 * idelta_count );
|
||||
|
||||
if ( bpred == 0 || idelta_sum < best_idelta )
|
||||
{
|
||||
best_bpred = bpred;
|
||||
best_idelta = idelta_sum;
|
||||
}
|
||||
|
||||
if ( !idelta_sum )
|
||||
{
|
||||
best_bpred = bpred;
|
||||
best_idelta = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( best_idelta < 16 )
|
||||
{
|
||||
best_idelta = 16;
|
||||
}
|
||||
|
||||
block_pred = best_bpred;
|
||||
idelta = best_idelta;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -31,18 +31,20 @@
|
|||
|
||||
|
||||
/* Definitions ****************************************************************/
|
||||
// tables
|
||||
// tables IMA-ADPCM
|
||||
#define IMA_INDX_ADJUST_TAB_LEN 16
|
||||
static int ima_indx_adjust[IMA_INDX_ADJUST_TAB_LEN] =
|
||||
{ -1, -1, -1, -1, /* +0 - +3, decrease the step size */
|
||||
2, 4, 6, 8, /* +4 - +7, increase the step size */
|
||||
-1, -1, -1, -1, /* -0 - -3, decrease the step size */
|
||||
2, 4, 6, 8, /* -4 - -7, increase the step size */
|
||||
{
|
||||
-1, -1, -1, -1, /* +0 - +3, decrease the step size */
|
||||
2, 4, 6, 8, /* +4 - +7, increase the step size */
|
||||
-1, -1, -1, -1, /* -0 - -3, decrease the step size */
|
||||
2, 4, 6, 8, /* -4 - -7, increase the step size */
|
||||
};
|
||||
|
||||
#define IMA_STEP_SIZE_TAB_LEN 89
|
||||
static int ima_step_size[IMA_STEP_SIZE_TAB_LEN] =
|
||||
{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
{
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
|
||||
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
|
||||
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
|
||||
|
@ -51,6 +53,26 @@ static int ima_step_size[IMA_STEP_SIZE_TAB_LEN] =
|
|||
32767
|
||||
};
|
||||
|
||||
// tables MS-ADPCM
|
||||
#define MSADPCM_IDELTA_COUNT 20
|
||||
|
||||
#define MSADPCM_ADAPT_COEFF_COUNT 7
|
||||
static int ms_AdaptCoeff1[MSADPCM_ADAPT_COEFF_COUNT] =
|
||||
{
|
||||
256, 512, 0, 192, 240, 460, 392
|
||||
};
|
||||
|
||||
static int ms_AdaptCoeff2[MSADPCM_ADAPT_COEFF_COUNT] =
|
||||
{
|
||||
0, -256, 0, 64, 0, -208, -232
|
||||
};
|
||||
|
||||
static int ms_AdaptationTable[] =
|
||||
{
|
||||
230, 230, 230, 230, 307, 409, 512, 614,
|
||||
768, 614, 512, 409, 307, 230, 230, 230
|
||||
};
|
||||
|
||||
|
||||
/* Classes ********************************************************************/
|
||||
/* IMA-ADPCM ---------------------------------------------------------------- */
|
||||
|
@ -87,11 +109,32 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
/* MS-ADPCM ----------------------------------------------------------------- */
|
||||
class CMsAdpcm
|
||||
{
|
||||
public:
|
||||
CMsAdpcm() {}
|
||||
virtual ~CMsAdpcm() {}
|
||||
|
||||
int Init ( const int iNewAudioLen );
|
||||
CVector<unsigned char> Encode ( const CVector<short>& vecsAudio );
|
||||
CVector<short> Decode ( const CVector<unsigned char>& vecbyAdpcm );
|
||||
|
||||
protected:
|
||||
int iAudSize;
|
||||
int iAdpcmSize;
|
||||
|
||||
void ChoosePredictor ( const CVector<short>& vecsAudio,
|
||||
int& block_pred,
|
||||
int& idelta );
|
||||
};
|
||||
|
||||
|
||||
/* Audio compression class -------------------------------------------------- */
|
||||
class CAudioCompression
|
||||
{
|
||||
public:
|
||||
enum EAudComprType { CT_NONE, CT_IMAADPCM };
|
||||
enum EAudComprType { CT_NONE, CT_IMAADPCM, CT_MSADPCM };
|
||||
|
||||
CAudioCompression() {}
|
||||
virtual ~CAudioCompression() {}
|
||||
|
@ -104,8 +147,8 @@ public:
|
|||
protected:
|
||||
EAudComprType eAudComprType;
|
||||
CImaAdpcm ImaAdpcm;
|
||||
CMsAdpcm MsAdpcm;
|
||||
int iCodeSize;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !defined ( AUDIOCOMPR_H_OIHGE76GEKJH3249_GEG98EG3_43441912__INCLUDED_ ) */
|
||||
|
|
|
@ -300,7 +300,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : QDialog ( parent )
|
|||
"<li>Qt cross-platform application framework: <i>http://trolltech.com</li>"
|
||||
"<li>Audio reverberation code: by Perry R. Cook and Gary P. Scavone, "
|
||||
"1995 - 2004 (taken from \"The Synthesis ToolKit in C++ (STK)\")</li>"
|
||||
"<li>IMA-ADPCM: by Erik de Castro Lopo</li>"
|
||||
"<li>ADPCM coders by Erik de Castro Lopo</li>"
|
||||
"<li>Parts from Dream DRM Receiver by Volker Fischer and Alexander "
|
||||
"Kurpiers: <i>http://drm.sf.net</li>"
|
||||
"</ul>"
|
||||
|
|
Loading…
Reference in a new issue