mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2421 lines
56 KiB
2421 lines
56 KiB
//==========================================================================;
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|
// PURPOSE.
|
|
//
|
|
// Copyright (c) 1993-1999 Microsoft Corporation
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// gsm610.c
|
|
//
|
|
// Description:
|
|
// This file contains encode and decode routines for the
|
|
// GSM 06.10 standard.
|
|
//
|
|
//==========================================================================;
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <mmsystem.h>
|
|
#include <mmreg.h>
|
|
#include <msacm.h>
|
|
#include <msacmdrv.h>
|
|
|
|
#include "codec.h"
|
|
#include "gsm610.h"
|
|
|
|
#include "debug.h"
|
|
|
|
typedef BYTE HUGE *HPBYTE;
|
|
|
|
#ifdef WIN32
|
|
typedef WORD UNALIGNED *HPWORD;
|
|
#else
|
|
typedef WORD HUGE *HPWORD;
|
|
#endif
|
|
|
|
|
|
//**************************************************************************
|
|
/*
|
|
|
|
This source module has the following structure.
|
|
|
|
Section 1:
|
|
|
|
Highest level functions. These functions are called from outside
|
|
this module.
|
|
|
|
Section 2:
|
|
|
|
Encoding support functions. These functions support
|
|
the encoding process.
|
|
|
|
Section 3:
|
|
|
|
Decoding support functions. These functions support
|
|
the decoding process.
|
|
|
|
Section 4:
|
|
|
|
Math functions used by any of the above functions.
|
|
|
|
|
|
Most of the encode and decode support routines are direct implementations of
|
|
the pseudocode algorithms described in the GSM 6.10 specification. Some
|
|
changes were made where necessary or where optimization was obvious or
|
|
necessary.
|
|
|
|
Most variables are named as in the GSM 6.10 spec, departing from the common
|
|
hungarian notation. This facilitates referencing the specification when
|
|
studying this implementation.
|
|
|
|
Some of the functions are conditionally compiled per the definition of
|
|
the WIN32 and _X86_ symbol. These functions have analogous alternate
|
|
implementations in 80386 assembler (in GSM61016.ASM and GSM61032.ASM) for
|
|
the purposes of execution speed. The 'C' implementations of these functions
|
|
are left intact for portability and can also be referenced when studying the
|
|
assembler implementations. Symbols accessed in/from GSM610xx.ASM are
|
|
declared with the EXTERN_C linkage macro.
|
|
|
|
*/
|
|
//**************************************************************************
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// Typedefs
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
|
|
#ifndef LPSHORT
|
|
typedef SHORT FAR *LPSHORT;
|
|
#endif
|
|
|
|
//
|
|
// XM is an RPE sequence containing 13 samples. There is one
|
|
// RPE sequence per sub-frame. This is typedefed in order to
|
|
// facilitate passing the array thru function calls.
|
|
//
|
|
typedef SHORT XM[13];
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// Macros
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
|
|
#define BITSHIFTLEFT(x,c) ( ((c)>=0) ? ((x)<<(c)) : ((x)>>(-(c))) )
|
|
#define BITSHIFTRIGHT(x,c) ( ((c)>=0) ? ((x)>>(c)) : ((x)<<(-(c))) )
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// function protos
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
|
|
//
|
|
//
|
|
// Math function protos
|
|
//
|
|
|
|
__inline SHORT add(SHORT var1, SHORT var2);
|
|
__inline SHORT sub(SHORT var1, SHORT var2);
|
|
__inline SHORT mult(SHORT var1, SHORT var2);
|
|
__inline SHORT mult_r(SHORT var1, SHORT var2);
|
|
__inline SHORT gabs(SHORT var1);
|
|
__inline SHORT gdiv(SHORT var1, SHORT var2);
|
|
__inline LONG l_mult(SHORT var1, SHORT var2);
|
|
__inline LONG l_add(LONG l_var1, LONG l_var2);
|
|
__inline LONG l_sub(LONG l_var1, LONG l_var2);
|
|
__inline SHORT norm(LONG l_var1);
|
|
__inline LONG IsNeg(LONG x);
|
|
|
|
//
|
|
// helper functions
|
|
//
|
|
__inline SHORT Convert8To16BitPCM(BYTE);
|
|
__inline BYTE Convert16To8BitPCM(SHORT);
|
|
|
|
//
|
|
//
|
|
// encode functions
|
|
//
|
|
|
|
void encodePreproc
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT sop,
|
|
LPSHORT s );
|
|
|
|
void encodeLPCAnalysis
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT s,
|
|
LPSHORT LARc );
|
|
|
|
void encodeLPCFilter
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT LARc,
|
|
LPSHORT s,
|
|
LPSHORT d );
|
|
|
|
EXTERN_C void encodeLTPAnalysis
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT d,
|
|
LPSHORT pNc,
|
|
LPSHORT pbc );
|
|
|
|
void encodeLTPFilter
|
|
( PSTREAMINSTANCE psi,
|
|
SHORT bc,
|
|
SHORT Nc,
|
|
LPSHORT d,
|
|
LPSHORT e,
|
|
LPSHORT dpp );
|
|
|
|
void encodeRPE
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT e,
|
|
LPSHORT pMc,
|
|
LPSHORT pxmaxc,
|
|
LPSHORT xMc,
|
|
LPSHORT ep );
|
|
|
|
void encodeUpdate
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT ep,
|
|
LPSHORT dpp );
|
|
|
|
void PackFrame0
|
|
( BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[] );
|
|
|
|
void PackFrame1
|
|
( BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[] );
|
|
|
|
//
|
|
//
|
|
// decode functions
|
|
//
|
|
|
|
void decodeRPE
|
|
( PSTREAMINSTANCE psi,
|
|
SHORT Mcr,
|
|
SHORT xmaxcr,
|
|
LPSHORT xMcr,
|
|
LPSHORT erp );
|
|
|
|
EXTERN_C void decodeLTP
|
|
( PSTREAMINSTANCE psi,
|
|
SHORT bcr,
|
|
SHORT Ncr,
|
|
LPSHORT erp );
|
|
|
|
void decodeLPC
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT LARcr,
|
|
LPSHORT wt,
|
|
LPSHORT sr );
|
|
|
|
EXTERN_C void decodePostproc
|
|
( PSTREAMINSTANCE psi,
|
|
LPSHORT sr,
|
|
LPSHORT srop );
|
|
|
|
void UnpackFrame0
|
|
( BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[] );
|
|
|
|
void UnpackFrame1
|
|
( BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[] );
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Functions
|
|
//
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// gsm610Reset(PSTREAMINSTANCE psi)
|
|
//
|
|
// Description:
|
|
// Resets the gsm610-specific stream instance data for
|
|
// the encode/decode routines
|
|
//
|
|
// Arguments:
|
|
// PSTREAMINSTANCE psi
|
|
// Pointer to stream instance structure
|
|
//
|
|
// Return value:
|
|
// void
|
|
// No return value
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void FNGLOBAL gsm610Reset(PSTREAMINSTANCE psi)
|
|
{
|
|
|
|
// For our gsm610 codec, almost all our instance data resets to 0
|
|
|
|
UINT i;
|
|
|
|
for (i=0; i<SIZEOF_ARRAY(psi->dp); i++) psi->dp[i] = 0;
|
|
for (i=0; i<SIZEOF_ARRAY(psi->drp); i++) psi->drp[i] = 0;
|
|
psi->z1 = 0;
|
|
psi->l_z2 = 0;
|
|
psi->mp = 0;
|
|
for (i=0; i<SIZEOF_ARRAY(psi->OldLARpp); i++) psi->OldLARpp[i] = 0;
|
|
for (i=0; i<SIZEOF_ARRAY(psi->u); i++) psi->u[i] = 0;
|
|
psi->nrp = 40; // The only non-zero init
|
|
for (i=0; i<SIZEOF_ARRAY(psi->OldLARrpp); i++) psi->OldLARrpp[i] = 0;
|
|
psi->msr = 0;
|
|
for (i=0; i<SIZEOF_ARRAY(psi->v); i++) psi->v[i] = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// LRESULT gsm610Encode
|
|
//
|
|
// Description:
|
|
// This function handles the ACMDM_STREAM_CONVERT message. This is the
|
|
// whole purpose of writing an ACM driver--to convert data. This message
|
|
// is sent after a stream has been opened (the driver receives and
|
|
// succeeds the ACMDM_STREAM_OPEN message).
|
|
//
|
|
// Arguments:
|
|
// LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
|
|
// conversion stream. This structure was allocated by the ACM and
|
|
// filled with the most common instance data needed for conversions.
|
|
// The information in this structure is exactly the same as it was
|
|
// during the ACMDM_STREAM_OPEN message--so it is not necessary
|
|
// to re-verify the information referenced by this structure.
|
|
//
|
|
// LPACMDRVSTREAMHEADER padsh: Pointer to stream header structure
|
|
// that defines the source data and destination buffer to convert.
|
|
//
|
|
// Return (LRESULT):
|
|
// The return value is zero (MMSYSERR_NOERROR) if this function
|
|
// succeeds with no errors. The return value is a non-zero error code
|
|
// if the function fails.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
LRESULT FNGLOBAL gsm610Encode
|
|
(
|
|
LPACMDRVSTREAMINSTANCE padsi,
|
|
LPACMDRVSTREAMHEADER padsh
|
|
)
|
|
{
|
|
#if (GSM610_FRAMESPERMONOBLOCK != 2)
|
|
#error THIS WAS WRITTEN FOR 2 FRAMES PER BLOCK!!!
|
|
#endif
|
|
#if (GSM610_MAXCHANNELS > 1)
|
|
#error THIS WAS WRITTEN FOR MONO ONLY!!!
|
|
#endif
|
|
|
|
PSTREAMINSTANCE psi;
|
|
DWORD cbSrcLen;
|
|
BOOL fBlockAlign;
|
|
DWORD cb;
|
|
DWORD dwcSamples; // dw count of samples
|
|
DWORD cBlocks;
|
|
UINT i;
|
|
HPBYTE hpbSrc, hpbDst;
|
|
|
|
SHORT sop[GSM610_SAMPLESPERFRAME];
|
|
SHORT s[GSM610_SAMPLESPERFRAME];
|
|
SHORT d[GSM610_SAMPLESPERFRAME];
|
|
SHORT e[GSM610_SAMPLESPERSUBFRAME];
|
|
SHORT dpp[GSM610_SAMPLESPERSUBFRAME];
|
|
SHORT ep[GSM610_SAMPLESPERSUBFRAME];
|
|
|
|
// The GSM610 stream data:
|
|
SHORT LARc[9]; // LARc[1..8] (one array per frame)
|
|
SHORT Nc[GSM610_NUMSUBFRAMES]; // Nc (one per sub-frame)
|
|
SHORT bc[GSM610_NUMSUBFRAMES]; // bc (one per sub-frame)
|
|
SHORT Mc[GSM610_NUMSUBFRAMES]; // Mc (one per sub-frame)
|
|
SHORT xmaxc[GSM610_NUMSUBFRAMES]; // Xmaxc (one per sub-frame)
|
|
XM xMc[GSM610_NUMSUBFRAMES]; // xMc (one sequence per sub-frame)
|
|
|
|
// Temp buffer to hold a block (two frames) of packed stream data
|
|
BYTE abBlock[ GSM610_BYTESPERMONOBLOCK ];
|
|
|
|
UINT nFrame;
|
|
UINT cSamples;
|
|
|
|
#ifdef DEBUG
|
|
// ProfSetup(1000,0);
|
|
// ProfStart();
|
|
#endif
|
|
|
|
psi = (PSTREAMINSTANCE)padsi->dwDriver;
|
|
|
|
//
|
|
// If this is flagged as the first block of a conversion
|
|
// then reset the stream instance data.
|
|
//
|
|
if (0 != (ACM_STREAMCONVERTF_START & padsh->fdwConvert))
|
|
{
|
|
gsm610Reset(psi);
|
|
}
|
|
|
|
fBlockAlign = (0 != (ACM_STREAMCONVERTF_BLOCKALIGN & padsh->fdwConvert));
|
|
|
|
|
|
//
|
|
// -= encode PCM to GSM 6.10 =-
|
|
//
|
|
//
|
|
//
|
|
dwcSamples = PCM_BYTESTOSAMPLES(((LPPCMWAVEFORMAT)(padsi->pwfxSrc)), padsh->cbSrcLength);
|
|
cBlocks = dwcSamples / GSM610_SAMPLESPERMONOBLOCK;
|
|
if (!fBlockAlign)
|
|
{
|
|
//
|
|
// Add on another block to hold the fragment of
|
|
// data at the end of our source data.
|
|
//
|
|
if (0 != dwcSamples % GSM610_SAMPLESPERMONOBLOCK)
|
|
cBlocks++;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
cb = cBlocks * GSM610_BLOCKALIGNMENT(padsi->pwfxDst);
|
|
if (cb > padsh->cbDstLength)
|
|
{
|
|
return (ACMERR_NOTPOSSIBLE);
|
|
}
|
|
padsh->cbDstLengthUsed = cb;
|
|
|
|
if (fBlockAlign)
|
|
{
|
|
dwcSamples = cBlocks * GSM610_SAMPLESPERMONOBLOCK;
|
|
cb = PCM_SAMPLESTOBYTES(((LPPCMWAVEFORMAT)(padsi->pwfxSrc)), dwcSamples);
|
|
}
|
|
else
|
|
{
|
|
cb = padsh->cbSrcLength;
|
|
}
|
|
padsh->cbSrcLengthUsed = cb;
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
cbSrcLen = padsh->cbSrcLengthUsed;
|
|
|
|
// Setup huge pointers to our src and dst buffers
|
|
hpbSrc = (HPBYTE)padsh->pbSrc;
|
|
hpbDst = (HPBYTE)padsh->pbDst;
|
|
|
|
// Loop thru entire source buffer
|
|
while (cbSrcLen)
|
|
{
|
|
|
|
// Process source buffer as two full GSM610 frames
|
|
|
|
for (nFrame=0; nFrame < 2; nFrame++)
|
|
{
|
|
//
|
|
// the src contains 8- or 16-bit PCM. currently we only
|
|
// handle mono conversions.
|
|
//
|
|
|
|
//
|
|
// we will fill sop[] with one frame of 16-bit PCM samples
|
|
//
|
|
|
|
//
|
|
// copy min( cSrcSamplesLeft, GSM610_SAMPLESPERFRAME ) samples
|
|
// to array sop[].
|
|
//
|
|
dwcSamples = PCM_BYTESTOSAMPLES(((LPPCMWAVEFORMAT)(padsi->pwfxSrc)), cbSrcLen);
|
|
cSamples = (int) min(dwcSamples, (DWORD) GSM610_SAMPLESPERFRAME);
|
|
|
|
if (padsi->pwfxSrc->wBitsPerSample == 16)
|
|
{
|
|
// copy 16-bit samples from hpbSrc to sop
|
|
for (i=0; i < cSamples; i++)
|
|
{
|
|
sop[i] = *( ((HPWORD)hpbSrc)++ );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// copy 8-bit samples from hpbSrc to 16-bit samples in sop
|
|
for (i=0; i < cSamples; i++)
|
|
{
|
|
sop[i] = Convert8To16BitPCM(*hpbSrc++);
|
|
}
|
|
}
|
|
|
|
cbSrcLen -= PCM_SAMPLESTOBYTES(((LPPCMWAVEFORMAT)(padsi->pwfxSrc)), cSamples);
|
|
|
|
// fill out sop[] with silence if necessary.
|
|
for ( ; i < GSM610_SAMPLESPERFRAME; i++)
|
|
{
|
|
sop[i] = 0;
|
|
}
|
|
|
|
//
|
|
// Encode a frame of data
|
|
//
|
|
|
|
encodePreproc(psi, sop, s);
|
|
encodeLPCAnalysis(psi, s, LARc);
|
|
encodeLPCFilter(psi, LARc, s, d);
|
|
|
|
// For each of four sub-frames
|
|
for (i=0; i<4; i++)
|
|
{
|
|
encodeLTPAnalysis(psi, &d[i*40], &Nc[i], &bc[i]);
|
|
encodeLTPFilter(psi, bc[i], Nc[i], &d[i*40], e, dpp);
|
|
encodeRPE(psi, e, &Mc[i], &xmaxc[i], xMc[i], ep);
|
|
encodeUpdate(psi, ep, dpp);
|
|
}
|
|
|
|
//
|
|
// Pack the data and store in dst buffer
|
|
//
|
|
if (nFrame == 0)
|
|
PackFrame0(abBlock, LARc, Nc, bc, Mc, xmaxc, xMc);
|
|
else
|
|
{
|
|
PackFrame1(abBlock, LARc, Nc, bc, Mc, xmaxc, xMc);
|
|
for (i=0; i<GSM610_BYTESPERMONOBLOCK; i++)
|
|
*(hpbDst++) = abBlock[i];
|
|
}
|
|
} // for (nFrame...
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
// ProfStop();
|
|
#endif
|
|
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// LRESULT gsm610Decode
|
|
//
|
|
// Description:
|
|
// This function handles the ACMDM_STREAM_CONVERT message. This is the
|
|
// whole purpose of writing an ACM driver--to convert data. This message
|
|
// is sent after a stream has been opened (the driver receives and
|
|
// succeeds the ACMDM_STREAM_OPEN message).
|
|
//
|
|
// Arguments:
|
|
// LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
|
|
// conversion stream. This structure was allocated by the ACM and
|
|
// filled with the most common instance data needed for conversions.
|
|
// The information in this structure is exactly the same as it was
|
|
// during the ACMDM_STREAM_OPEN message--so it is not necessary
|
|
// to re-verify the information referenced by this structure.
|
|
//
|
|
// LPACMDRVSTREAMHEADER padsh: Pointer to stream header structure
|
|
// that defines the source data and destination buffer to convert.
|
|
//
|
|
// Return (LRESULT):
|
|
// The return value is zero (MMSYSERR_NOERROR) if this function
|
|
// succeeds with no errors. The return value is a non-zero error code
|
|
// if the function fails.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
LRESULT FNGLOBAL gsm610Decode
|
|
(
|
|
LPACMDRVSTREAMINSTANCE padsi,
|
|
LPACMDRVSTREAMHEADER padsh
|
|
)
|
|
{
|
|
#if (GSM610_FRAMESPERMONOBLOCK != 2)
|
|
#error THIS WAS WRITTEN FOR 2 FRAMES PER BLOCK!!!
|
|
#endif
|
|
#if (GSM610_MAXCHANNELS > 1)
|
|
#error THIS WAS WRITTEN FOR MONO ONLY!!!
|
|
#endif
|
|
|
|
PSTREAMINSTANCE psi;
|
|
DWORD cbSrcLen;
|
|
BOOL fBlockAlign;
|
|
DWORD cb;
|
|
DWORD dwcSamples;
|
|
DWORD cBlocks;
|
|
HPBYTE hpbSrc, hpbDst;
|
|
|
|
SHORT erp[GSM610_SAMPLESPERSUBFRAME];
|
|
SHORT wt[GSM610_SAMPLESPERFRAME];
|
|
SHORT sr[GSM610_SAMPLESPERFRAME];
|
|
SHORT srop[GSM610_SAMPLESPERFRAME];
|
|
|
|
// The GSM610 stream data:
|
|
SHORT LARcr[9]; // LARc[1..8] (one array per frame)
|
|
SHORT Ncr[GSM610_NUMSUBFRAMES]; // Nc (one per sub-frame)
|
|
SHORT bcr[GSM610_NUMSUBFRAMES]; // bc (one per sub-frame)
|
|
SHORT Mcr[GSM610_NUMSUBFRAMES]; // Mc (one per sub-frame)
|
|
SHORT xmaxcr[GSM610_NUMSUBFRAMES]; // Xmaxc (one per sub-frame)
|
|
XM xMcr[GSM610_NUMSUBFRAMES]; // xMc (one sequence per sub-frame)
|
|
|
|
UINT i,j;
|
|
UINT nFrame;
|
|
|
|
// Temp buffer to hold a block (two frames) of packed stream data
|
|
BYTE abBlock[ GSM610_BYTESPERMONOBLOCK ];
|
|
|
|
|
|
#ifdef DEBUG
|
|
// ProfStart();
|
|
#endif
|
|
|
|
psi = (PSTREAMINSTANCE)padsi->dwDriver;
|
|
|
|
// If this is flagged as the first block of a conversion
|
|
// then reset the stream instance data.
|
|
if (0 != (ACM_STREAMCONVERTF_START & padsh->fdwConvert))
|
|
{
|
|
gsm610Reset(psi);
|
|
}
|
|
|
|
fBlockAlign = (0 != (ACM_STREAMCONVERTF_BLOCKALIGN & padsh->fdwConvert));
|
|
|
|
|
|
|
|
//
|
|
// -= decode GSM 6.10 to PCM =-
|
|
//
|
|
//
|
|
cb = padsh->cbSrcLength;
|
|
|
|
cBlocks = cb / GSM610_BLOCKALIGNMENT(padsi->pwfxSrc);
|
|
|
|
if (0L == cBlocks)
|
|
{
|
|
padsh->cbSrcLengthUsed = cb;
|
|
padsh->cbDstLengthUsed = 0L;
|
|
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
|
|
//
|
|
// Compute bytes we will use in destination buffer. Carefull! Look
|
|
// out for overflow in our calculations!
|
|
//
|
|
if ((0xFFFFFFFFL / GSM610_SAMPLESPERMONOBLOCK) < cBlocks)
|
|
return (ACMERR_NOTPOSSIBLE);
|
|
dwcSamples = cBlocks * GSM610_SAMPLESPERMONOBLOCK;
|
|
|
|
if (PCM_BYTESTOSAMPLES(((LPPCMWAVEFORMAT)(padsi->pwfxDst)), 0xFFFFFFFFL) < dwcSamples)
|
|
return (ACMERR_NOTPOSSIBLE);
|
|
cb = PCM_SAMPLESTOBYTES(((LPPCMWAVEFORMAT)(padsi->pwfxDst)), dwcSamples);
|
|
|
|
if (cb > padsh->cbDstLength)
|
|
{
|
|
return (ACMERR_NOTPOSSIBLE);
|
|
}
|
|
|
|
padsh->cbDstLengthUsed = cb;
|
|
padsh->cbSrcLengthUsed = cBlocks * GSM610_BLOCKALIGNMENT(padsi->pwfxSrc);
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
cbSrcLen = padsh->cbSrcLengthUsed;
|
|
|
|
|
|
// Setup huge pointers to our src and dst buffers
|
|
hpbSrc = (HPBYTE)padsh->pbSrc;
|
|
hpbDst = (HPBYTE)padsh->pbDst;
|
|
|
|
|
|
// while at least another full block of coded data
|
|
while (cbSrcLen >= GSM610_BYTESPERMONOBLOCK)
|
|
{
|
|
|
|
// copy a block of data from stream buffer to our temp buffer
|
|
for (i=0; i<GSM610_BYTESPERMONOBLOCK; i++) abBlock[i] = *(hpbSrc++);
|
|
cbSrcLen -= GSM610_BYTESPERMONOBLOCK;
|
|
|
|
// for each of the two frames in the block
|
|
for (nFrame=0; nFrame < 2; nFrame++)
|
|
{
|
|
// Unpack data from stream
|
|
if (nFrame == 0)
|
|
UnpackFrame0(abBlock, LARcr, Ncr, bcr, Mcr, xmaxcr, xMcr);
|
|
else
|
|
UnpackFrame1(abBlock, LARcr, Ncr, bcr, Mcr, xmaxcr, xMcr);
|
|
|
|
|
|
for (i=0; i<4; i++) // for each of 4 sub-blocks
|
|
{
|
|
// reconstruct the long term residual signal erp[0..39]
|
|
// from Mcr, xmaxcr, and xMcr
|
|
decodeRPE(psi, Mcr[i], xmaxcr[i], xMcr[i], erp);
|
|
|
|
// reconstruct the short term residual signal drp[0..39]
|
|
// and also update drp[-120..-1]
|
|
decodeLTP(psi, bcr[i], Ncr[i], erp);
|
|
|
|
// accumulate the four sub-blocks of reconstructed short
|
|
// term residual signal drp[0..39] into wt[0..159]
|
|
for (j=0; j<40; j++) wt[(i*40) + j] = psi->drp[120+j];
|
|
|
|
}
|
|
|
|
// reconstruct the signal s
|
|
decodeLPC(psi, LARcr, wt, sr);
|
|
|
|
// post-process the signal s
|
|
decodePostproc(psi, sr, srop);
|
|
|
|
//
|
|
// write decoded 16-bit PCM to dst. our dst format
|
|
// may be 8- or 16-bit PCM.
|
|
//
|
|
if (padsi->pwfxDst->wBitsPerSample == 16)
|
|
{
|
|
// copy 16-bit samples from srop to hpbDst
|
|
for (j=0; j < GSM610_SAMPLESPERFRAME; j++)
|
|
{
|
|
*( ((HPWORD)hpbDst)++ ) = srop[j];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// copy 16-bit samples from srop to 8-bit samples in hpbDst
|
|
for (j=0; j < GSM610_SAMPLESPERFRAME; j++)
|
|
{
|
|
*(hpbDst++) = Convert16To8BitPCM(srop[j]);
|
|
}
|
|
}
|
|
|
|
|
|
} // for (nFrame...
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// ProfStop();
|
|
#endif
|
|
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
//=====================================================================
|
|
//
|
|
// Encode routines
|
|
//
|
|
//=====================================================================
|
|
//=====================================================================
|
|
|
|
//---------------------------------------------------------------------
|
|
//--------------------------------------------------------------------
|
|
//
|
|
// Function protos
|
|
//
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
EXTERN_C void CompACF(LPSHORT s, LPLONG l_ACF);
|
|
void Compr(PSTREAMINSTANCE psi, LPLONG l_ACF, LPSHORT r);
|
|
void CompLAR(PSTREAMINSTANCE psi, LPSHORT r, LPSHORT LAR);
|
|
void CompLARc(PSTREAMINSTANCE psi, LPSHORT LAR, LPSHORT LARc);
|
|
|
|
void CompLARpp(PSTREAMINSTANCE psi, LPSHORT LARc, LPSHORT LARpp);
|
|
void CompLARp(PSTREAMINSTANCE psi, LPSHORT LARpp, LPSHORT LARp1, LPSHORT LARp2, LPSHORT LARp3, LPSHORT LARp4);
|
|
void Comprp(PSTREAMINSTANCE psi, LPSHORT LARp, LPSHORT rp);
|
|
EXTERN_C void Compd(PSTREAMINSTANCE psi, LPSHORT rp, LPSHORT s, LPSHORT d, UINT k_start, UINT k_end);
|
|
|
|
void WeightingFilter(PSTREAMINSTANCE psi, LPSHORT e, LPSHORT x);
|
|
void RPEGridSelect(PSTREAMINSTANCE psi, LPSHORT x, LPSHORT pMc, LPSHORT xM);
|
|
void APCMQuantize(PSTREAMINSTANCE psi, LPSHORT xM, LPSHORT pxmaxc, LPSHORT xMc, LPSHORT pexp, LPSHORT pmant);
|
|
void APCMInvQuantize(PSTREAMINSTANCE psi, SHORT exp, SHORT mant, LPSHORT xMc, LPSHORT xMp);
|
|
void RPEGridPosition(PSTREAMINSTANCE psi, SHORT Mc, LPSHORT xMp, LPSHORT ep);
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Global constant data
|
|
//
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
|
|
const SHORT BCODE A[9] = {
|
|
0, // not used
|
|
20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036 };
|
|
|
|
const SHORT BCODE B[9] = {
|
|
0, // not used
|
|
0, 0, 2048, -2560, 94, -1792, -341, -1144 };
|
|
|
|
const SHORT BCODE MIC[9] = {
|
|
0, // not used
|
|
-32, -32, -16, -16, -8, -8, -4, -4 };
|
|
|
|
const SHORT BCODE MAC[9] = {
|
|
0, // not used
|
|
31, 31, 15, 15, 7, 7, 3, 3 };
|
|
|
|
const SHORT BCODE INVA[9] = {
|
|
0, // unused
|
|
13107, 13107, 13107, 13107, 19223, 17476, 31454, 29708 };
|
|
|
|
EXTERN_C const SHORT BCODE DLB[4] = { 6554, 16384, 26214, 32767 };
|
|
EXTERN_C const SHORT BCODE QLB[4] = { 3277, 11469, 21299, 32767 };
|
|
|
|
const SHORT BCODE H[11] = { -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 };
|
|
const SHORT BCODE NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 };
|
|
const SHORT BCODE FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 };
|
|
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Procedures
|
|
//
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// PackFrame0
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void PackFrame0
|
|
(
|
|
BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[]
|
|
)
|
|
{
|
|
int i;
|
|
|
|
// Pack the LAR[1..8] into the first 4.5 bytes
|
|
ab[0] = ((LAR[1] ) & 0x3F) | ((LAR[2] << 6) & 0xC0);
|
|
ab[1] = ((LAR[2] >> 2) & 0x0F) | ((LAR[3] << 4) & 0xF0);
|
|
ab[2] = ((LAR[3] >> 4) & 0x01) | ((LAR[4] << 1) & 0x3E) | ((LAR[5] << 6) & 0xC0);
|
|
ab[3] = ((LAR[5] >> 2) & 0x03) | ((LAR[6] << 2) & 0x3C) | ((LAR[7] << 6) & 0xC0);
|
|
ab[4] = ((LAR[7] >> 2) & 0x01) | ((LAR[8] << 1) & 0x0E);
|
|
|
|
// Pack N, b, M, Xmax, and X for each of the 4 sub-frames
|
|
for (i=0; i<4; i++)
|
|
{
|
|
|
|
ab[4+i*7+0] |= ((N[i] << 4) & 0xF0);
|
|
ab[4+i*7+1] = ((N[i] >> 4) & 0x07) | ((b[i] << 3) & 0x18) | ((M[i] << 5) & 0x60) | ((Xmax[i] << 7) & 0x80);
|
|
ab[4+i*7+2] = ((Xmax[i] >> 1) & 0x1F) | ((X[i][0] << 5) & 0xE0);
|
|
ab[4+i*7+3] = (X[i][1] & 0x07) | ((X[i][2] << 3) & 0x38) | ((X[i][3] << 6) & 0xC0);
|
|
ab[4+i*7+4] = ((X[i][3] >> 2) & 0x01) | ((X[i][4] << 1) & 0x0E) | ((X[i][5] << 4) & 0x70) | ((X[i][6] << 7) & 0x80);
|
|
ab[4+i*7+5] = ((X[i][6] >> 1) & 0x03) | ((X[i][7] << 2) & 0x1C) | ((X[i][8] << 5) & 0xE0);
|
|
ab[4+i*7+6] = (X[i][9] & 0x07) | ((X[i][10] << 3) & 0x38) | ((X[i][11] << 6) & 0xC0);
|
|
ab[4+i*7+7] = ((X[i][11] >> 2) & 0x01) | ((X[i][12] << 1) & 0x0E);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// PackFrame1
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void PackFrame1
|
|
(
|
|
BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[]
|
|
)
|
|
{
|
|
int i;
|
|
|
|
// Pack the LAR[1..8] into the first 4.5 bytes, starting with the
|
|
// more significant nibble of the first byte.
|
|
ab[32] |= ((LAR[1] << 4) & 0xF0);
|
|
ab[33] = ((LAR[1] >> 4) & 0x03) | ((LAR[2] << 2) & 0xFC);
|
|
ab[34] = ((LAR[3] ) & 0x1F) | ((LAR[4] << 5) & 0xE0);
|
|
ab[35] = ((LAR[4] >> 3) & 0x03) | ((LAR[5] << 2) & 0x3C) | ((LAR[6] << 6) & 0xC0);
|
|
ab[36] = ((LAR[6] >> 2) & 0x03) | ((LAR[7] << 2) & 0x1C) | ((LAR[8] << 5) & 0xE0);
|
|
|
|
// Pack N, b, M, Xmax, and X for each of the 4 sub-frames
|
|
for (i=0; i<4; i++)
|
|
{
|
|
ab[37+i*7+0] = (N[i] & 0x7F) | ((b[i] << 7) & 0x80);
|
|
ab[37+i*7+1] = ((b[i] >> 1) & 0x01) | ((M[i] << 1) & 0x06) | ((Xmax[i] << 3) & 0xF8);
|
|
ab[37+i*7+2] = ((Xmax[i] >> 5) & 0x01) | ((X[i][0] << 1) & 0x0E) | ((X[i][1] << 4) & 0x70) | ((X[i][2] << 7) & 0x80);
|
|
ab[37+i*7+3] = ((X[i][2] >> 1) & 0x03) | ((X[i][3] << 2) & 0x1C) | ((X[i][4] << 5) & 0xE0);
|
|
ab[37+i*7+4] = ((X[i][5] ) & 0x07) | ((X[i][6] << 3) & 0x38) | ((X[i][7] << 6) & 0xC0);
|
|
ab[37+i*7+5] = ((X[i][7] >> 2) & 0x01) | ((X[i][8] << 1) & 0x0E) | ((X[i][9] << 4) & 0x70) | ((X[i][10] << 7) & 0x80);
|
|
ab[37+i*7+6] = ((X[i][10] >> 1) & 0x03) | ((X[i][11] << 2) & 0x1C) | ((X[i][12] << 5) & 0xE0);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodePreproc()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodePreproc(PSTREAMINSTANCE psi, LPSHORT sop, LPSHORT s)
|
|
{
|
|
|
|
SHORT so[160];
|
|
SHORT sof[160];
|
|
|
|
UINT k;
|
|
SHORT s1;
|
|
SHORT temp;
|
|
SHORT msp, lsp;
|
|
LONG l_s2;
|
|
|
|
// downscale
|
|
for (k=0; k<160; k++)
|
|
{
|
|
so[k] = sop[k] >> 3;
|
|
so[k] = so[k] << 2;
|
|
}
|
|
|
|
// offset compensation
|
|
for (k=0; k<160; k++)
|
|
{
|
|
|
|
// Compute the non-recursive part
|
|
s1 = sub(so[k], psi->z1);
|
|
psi->z1 = so[k];
|
|
|
|
// compute the recursive part
|
|
l_s2 = s1;
|
|
l_s2 = l_s2 << 15;
|
|
|
|
// execution of 31 by 16 bits multiplication
|
|
msp = (SHORT) (psi->l_z2 >> 15);
|
|
lsp = (SHORT) l_sub(psi->l_z2, ( ((LONG)msp) << 15));
|
|
temp = mult_r(lsp, 32735);
|
|
l_s2 = l_add(l_s2, temp);
|
|
psi->l_z2 = l_add(l_mult(msp, 32735) >> 1, l_s2);
|
|
|
|
// compute sof[k] with rounding
|
|
sof[k] = (SHORT) (l_add(psi->l_z2, 16384) >> 15);
|
|
}
|
|
|
|
// preemphasis
|
|
for (k=0; k<160; k++)
|
|
{
|
|
s[k] = add(sof[k], mult_r(psi->mp, -28180));
|
|
psi->mp = sof[k];
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodeLPCAnalysis()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodeLPCAnalysis(PSTREAMINSTANCE psi, LPSHORT s, LPSHORT LARc)
|
|
{
|
|
|
|
LONG l_ACF[9];
|
|
SHORT r[9];
|
|
SHORT LAR[9];
|
|
|
|
CompACF(s, l_ACF);
|
|
Compr(psi, l_ACF, r);
|
|
CompLAR(psi, r, LAR);
|
|
CompLARc(psi, LAR, LARc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// CompACF()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void CompACF(LPSHORT s, LPLONG l_ACF)
|
|
{
|
|
SHORT smax, temp, scalauto;
|
|
UINT i, k;
|
|
|
|
//
|
|
// Dynamic scaling of array s[0..159]
|
|
//
|
|
|
|
// Search for the maximum
|
|
smax = 0;
|
|
for (k=0; k<160; k++)
|
|
{
|
|
temp = gabs(s[k]);
|
|
if (temp > smax) smax = temp;
|
|
}
|
|
|
|
// Computation of the scaling factor
|
|
if (smax == 0) scalauto = 0;
|
|
else scalauto = sub( 4, norm( ((LONG)smax)<<16 ) );
|
|
|
|
// Scaling of the array s
|
|
if (scalauto > 0)
|
|
{
|
|
temp = BITSHIFTRIGHT(16384, sub(scalauto,1));
|
|
for (k=0; k<160; k++)
|
|
{
|
|
// s[k] = mult_r(s[k], temp);
|
|
s[k] = HIWORD( ( (((LONG)s[k])<<(15-scalauto)) + 0x4000L ) << 1 );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Compute the l_ACF[..]
|
|
//
|
|
|
|
for (k=0; k<9; k++)
|
|
{
|
|
l_ACF[k] = 0;
|
|
for (i=k; i<160; i++)
|
|
{
|
|
l_ACF[k] = l_add(l_ACF[k], l_mult(s[i], s[i-k]));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Rescaling of array s
|
|
//
|
|
|
|
if (scalauto > 0)
|
|
{
|
|
for (k=0; k<160; k++)
|
|
{
|
|
// We don't need the BITSHIFTLEFT macro
|
|
// cuz we know scalauto>0 due to above test
|
|
s[k] = s[k] << scalauto;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Compr()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void Compr(PSTREAMINSTANCE psi, LPLONG l_ACF, LPSHORT r)
|
|
{
|
|
|
|
UINT i, k, m, n;
|
|
SHORT temp, ACF[9];
|
|
SHORT K[9], P[9]; // K[2..8], P[0..8]
|
|
|
|
//
|
|
// Schur recursion with 16 bits arithmetic
|
|
//
|
|
|
|
if (l_ACF[0] == 0)
|
|
{
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
r[i] = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
temp = norm(l_ACF[0]);
|
|
|
|
for (k=0; k<=8; k++)
|
|
{
|
|
ACF[k] = (SHORT) ((BITSHIFTLEFT(l_ACF[k], temp)) >> 16);
|
|
}
|
|
|
|
|
|
//
|
|
// Init array P and K for the recursion
|
|
//
|
|
|
|
for (i=1; i<=7; i++)
|
|
{
|
|
K[9-i] = ACF[i];
|
|
}
|
|
|
|
for (i=0; i<=8; i++)
|
|
{
|
|
P[i] = ACF[i];
|
|
}
|
|
|
|
|
|
//
|
|
// Compute reflection coefficients
|
|
//
|
|
|
|
for (n=1; n<=8; n++)
|
|
{
|
|
if (P[0] < gabs(P[1]))
|
|
{
|
|
for (i=n; i<=8; i++)
|
|
{
|
|
r[i] = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
r[n] = gdiv(gabs(P[1]),P[0]);
|
|
|
|
if (P[1] > 0) r[n] = sub(0,r[n]);
|
|
|
|
// Here's the real exit from this for loop
|
|
if (n==8) return;
|
|
|
|
|
|
// Schur recursion
|
|
P[0] = add(P[0], mult_r(P[1], r[n]));
|
|
for (m=1; m<=8-n; m++)
|
|
{
|
|
P[m] = add( P[m+1], mult_r(K[9-m],r[n]) );
|
|
K[9-m] = add( K[9-m], mult_r(P[m+1], r[n]) );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// CompLAR()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void CompLAR(PSTREAMINSTANCE psi, LPSHORT r, LPSHORT LAR)
|
|
{
|
|
|
|
UINT i;
|
|
SHORT temp;
|
|
|
|
//
|
|
// Computation of LAR[1..8] from r[1..8]
|
|
//
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
temp = gabs(r[i]);
|
|
|
|
if (temp < 22118)
|
|
{
|
|
temp = temp >> 1;
|
|
}
|
|
else if (temp < 31130)
|
|
{
|
|
temp = sub(temp, 11059);
|
|
}
|
|
else
|
|
{
|
|
temp = sub(temp, 26112) << 2;
|
|
}
|
|
|
|
LAR[i] = temp;
|
|
|
|
if (r[i] < 0)
|
|
{
|
|
LAR[i] = sub(0, LAR[i]);
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// CompLARc()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void CompLARc(PSTREAMINSTANCE psi, LPSHORT LAR, LPSHORT LARc)
|
|
{
|
|
|
|
UINT i;
|
|
SHORT temp;
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
temp = mult(A[i], LAR[i]);
|
|
temp = add(temp, B[i]);
|
|
temp = add(temp, 256);
|
|
LARc[i] = temp >> 9;
|
|
|
|
// Check if LARc[i] between MIN and MAX
|
|
if (LARc[i] > MAC[i]) LARc[i] = MAC[i];
|
|
if (LARc[i] < MIC[i]) LARc[i] = MIC[i];
|
|
|
|
// This is used to make all LARc positive
|
|
LARc[i] = sub(LARc[i], MIC[i]);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodeLPCFilter()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodeLPCFilter(PSTREAMINSTANCE psi, LPSHORT LARc, LPSHORT s, LPSHORT d)
|
|
{
|
|
SHORT LARpp[9]; // array [1..8]
|
|
SHORT LARp1[9], LARp2[9], LARp3[9], LARp4[9]; // array [1..8]
|
|
SHORT rp[9]; // array [1..8]
|
|
|
|
CompLARpp(psi, LARc, LARpp);
|
|
CompLARp(psi, LARpp, LARp1, LARp2, LARp3, LARp4);
|
|
|
|
Comprp(psi, LARp1, rp);
|
|
Compd(psi, (LPSHORT)rp, s, d, 0, 12);
|
|
|
|
Comprp(psi, LARp2, rp);
|
|
Compd(psi, (LPSHORT)rp, s, d, 13, 26);
|
|
|
|
Comprp(psi, LARp3, rp);
|
|
Compd(psi, (LPSHORT)rp, s, d, 27, 39);
|
|
|
|
Comprp(psi, LARp4, rp);
|
|
Compd(psi, (LPSHORT)rp, s, d, 40, 159);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// CompLARpp()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void CompLARpp(PSTREAMINSTANCE psi, LPSHORT LARc, LPSHORT LARpp)
|
|
{
|
|
UINT i;
|
|
SHORT temp1, temp2;
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
temp1 = add(LARc[i], MIC[i]) << 10;
|
|
temp2 = B[i] << 1;
|
|
temp1 = sub(temp1,temp2);
|
|
temp1 = mult_r(INVA[i], temp1);
|
|
LARpp[i] = add(temp1, temp1);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// CompLARp()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void CompLARp(PSTREAMINSTANCE psi, LPSHORT LARpp, LPSHORT LARp1, LPSHORT LARp2, LPSHORT LARp3, LPSHORT LARp4)
|
|
{
|
|
UINT i;
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
LARp1[i] = add( (SHORT)(psi->OldLARpp[i] >> 2), (SHORT)(LARpp[i] >> 2) );
|
|
LARp1[i] = add( LARp1[i], (SHORT)(psi->OldLARpp[i] >> 1) );
|
|
|
|
LARp2[i] = add( (SHORT)(psi->OldLARpp[i] >> 1), (SHORT)(LARpp[i] >> 1) );
|
|
|
|
LARp3[i] = add( (SHORT)(psi->OldLARpp[i] >> 2), (SHORT)(LARpp[i] >> 2) );
|
|
LARp3[i] = add( LARp3[i], (SHORT)(LARpp[i] >> 1) );
|
|
|
|
LARp4[i] = LARpp[i];
|
|
}
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
psi->OldLARpp[i] = LARpp[i];
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Comprp()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void Comprp(PSTREAMINSTANCE psi, LPSHORT LARp, LPSHORT rp)
|
|
{
|
|
UINT i;
|
|
SHORT temp;
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
temp = gabs(LARp[i]);
|
|
if (temp < 11059)
|
|
{
|
|
temp = temp << 1;
|
|
}
|
|
else if (temp < 20070)
|
|
{
|
|
temp = add(temp, 11059);
|
|
}
|
|
else
|
|
{
|
|
temp = add((SHORT)(temp>>2), 26112);
|
|
}
|
|
|
|
rp[i] = temp;
|
|
|
|
if (LARp[i] < 0)
|
|
{
|
|
rp[i] = sub(0,rp[i]);
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Compd()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void Compd(PSTREAMINSTANCE psi, LPSHORT rp, LPSHORT s, LPSHORT d, UINT k_start, UINT k_end)
|
|
{
|
|
UINT k, i;
|
|
|
|
SHORT sav;
|
|
SHORT di;
|
|
SHORT temp;
|
|
|
|
for (k=k_start; k<=k_end; k++)
|
|
{
|
|
di = s[k];
|
|
sav = di;
|
|
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
temp = add( psi->u[i-1], mult_r(rp[i],di) );
|
|
di = add( di, mult_r(rp[i], psi->u[i-1]) );
|
|
psi->u[i-1] = sav;
|
|
sav = temp;
|
|
}
|
|
|
|
d[k] = di;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodeLTPAnalysis()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodeLTPAnalysis(PSTREAMINSTANCE psi, LPSHORT d, LPSHORT pNc, LPSHORT pbc)
|
|
{
|
|
SHORT dmax;
|
|
SHORT temp;
|
|
SHORT scal;
|
|
SHORT wt[40];
|
|
SHORT lambda;
|
|
LONG l_max, l_power;
|
|
SHORT R, S;
|
|
SHORT Nc;
|
|
|
|
int k; // k must be int, not UINT!
|
|
|
|
Nc = *pNc;
|
|
|
|
// Search of the optimum scaling of d[0..39]
|
|
|
|
dmax = 0;
|
|
|
|
for (k=39; k>=0; k--)
|
|
{
|
|
temp = gabs( d[k] );
|
|
if (temp > dmax) dmax = temp;
|
|
}
|
|
|
|
temp = 0;
|
|
|
|
if (dmax == 0) scal = 0;
|
|
else temp = norm( ((LONG)dmax) << 16);
|
|
|
|
if (temp > 6) scal = 0;
|
|
else scal = sub(6,temp);
|
|
|
|
|
|
// Init of working array wt[0..39]
|
|
ASSERT( scal >= 0 );
|
|
for (k=39; k>=0; k--)
|
|
{
|
|
wt[k] = d[k] >> scal;
|
|
}
|
|
|
|
// Search for max cross-correlation and coding of LTP lag
|
|
|
|
l_max = 0;
|
|
Nc = 40;
|
|
|
|
for (lambda=40; lambda<=120; lambda++)
|
|
{
|
|
register LONG l_result = 0;
|
|
for (k=39; k>=0; k--)
|
|
{
|
|
l_result += (LONG)(wt[k]) * (LONG)(psi->dp[120-lambda+k]);
|
|
}
|
|
if (l_result > l_max)
|
|
{
|
|
Nc = lambda;
|
|
l_max = l_result;
|
|
}
|
|
}
|
|
l_max <<= 1; // This operation should be on l_result as part of the
|
|
// multiply/add, but for efficiency we shift it all
|
|
// the way out of the loops.
|
|
|
|
// Rescaling of l_max
|
|
ASSERT( sub(6,scal) >= 0 );
|
|
l_max = l_max >> sub(6,scal);
|
|
|
|
// Compute the power of the reconstructed short term residual
|
|
// signal dp[..].
|
|
l_power = 0;
|
|
{
|
|
SHORT s;
|
|
for (k=39; k>=0; k--)
|
|
{
|
|
s = psi->dp[120-Nc+k] >> 3;
|
|
l_power += s*s; // This sum can never overflow!!!
|
|
}
|
|
ASSERT( l_power >= 0 );
|
|
if( l_power >= 1073741824 ) { // 2**30
|
|
l_power = 2147483647; // 2**31 - 1
|
|
} else {
|
|
l_power <<= 1; // This shift is normally part of l_mult().
|
|
}
|
|
}
|
|
|
|
*pNc = Nc;
|
|
|
|
// Normalization of l_max and l_power
|
|
if (l_max <= 0)
|
|
{
|
|
*pbc = 0;
|
|
return;
|
|
}
|
|
|
|
if (l_max >= l_power)
|
|
{
|
|
*pbc = 3;
|
|
return;
|
|
}
|
|
|
|
temp = norm(l_power);
|
|
ASSERT( temp >= 0 );
|
|
R = (SHORT) ((l_max<<temp) >> 16);
|
|
S = (SHORT) ((l_power<<temp) >> 16);
|
|
|
|
// Codeing of the LTP gain
|
|
|
|
for ( *pbc=0; *pbc<=2; (*pbc)++ )
|
|
{
|
|
if (R <= mult(S, DLB[*pbc]))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
*pbc = 3;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodeLTPFilter()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodeLTPFilter(PSTREAMINSTANCE psi, SHORT bc, SHORT Nc, LPSHORT d, LPSHORT e, LPSHORT dpp)
|
|
{
|
|
SHORT bp;
|
|
UINT k;
|
|
|
|
// Decoding of the coded LTP gain
|
|
bp = QLB[bc];
|
|
|
|
// Calculating the array e[0..39] and the array dpp[0..39]
|
|
for (k=0; k<=39; k++)
|
|
{
|
|
dpp[k] = mult_r(bp, psi->dp[120+k-Nc]);
|
|
e[k] = sub(d[k], dpp[k]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodeRPE()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodeRPE(PSTREAMINSTANCE psi, LPSHORT e, LPSHORT pMc, LPSHORT pxmaxc, LPSHORT xMc, LPSHORT ep)
|
|
{
|
|
SHORT x[40];
|
|
SHORT xM[13];
|
|
SHORT exp, mant;
|
|
SHORT xMp[13];
|
|
|
|
WeightingFilter(psi, e, x);
|
|
RPEGridSelect(psi, x, pMc, xM);
|
|
APCMQuantize(psi, xM, pxmaxc, xMc, &exp, &mant);
|
|
APCMInvQuantize(psi, exp, mant, xMc, xMp);
|
|
RPEGridPosition(psi, *pMc, xMp, ep);
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// WeightingFilter()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void WeightingFilter(PSTREAMINSTANCE psi, LPSHORT e, LPSHORT x)
|
|
{
|
|
UINT i, k;
|
|
|
|
LONG l_result, l_temp;
|
|
SHORT wt[50];
|
|
|
|
|
|
// Initialization of a temporary working array wt[0..49]
|
|
for (k= 0; k<= 4; k++) wt[k] = 0;
|
|
for (k= 5; k<=44; k++) wt[k] = e[k-5];
|
|
for (k=45; k<=49; k++) wt[k] = 0;
|
|
|
|
// Compute the signal x[0..39]
|
|
for (k=0; k<=39; k++)
|
|
{
|
|
l_result = 8192; // rounding of the output of the filter
|
|
|
|
for (i=0; i<=10; i++)
|
|
{
|
|
l_temp = l_mult(wt[k+i], H[i]);
|
|
l_result = l_add(l_result, l_temp);
|
|
}
|
|
|
|
l_result = l_add(l_result, l_result); // scaling x2
|
|
l_result = l_add(l_result, l_result); // scaling x4
|
|
|
|
x[k] = (SHORT) (l_result >> 16);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// RPEGridSelect()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void RPEGridSelect(PSTREAMINSTANCE psi, LPSHORT x, LPSHORT pMc, LPSHORT xM)
|
|
{
|
|
UINT m, i;
|
|
|
|
LONG l_EM;
|
|
SHORT temp1;
|
|
LONG l_result, l_temp;
|
|
|
|
// the signal x[0..39] is used to select the RPE grid which is
|
|
// represented by Mc
|
|
l_EM = 0;
|
|
*pMc = 0;
|
|
|
|
for (m=0; m<=3; m++)
|
|
{
|
|
l_result = 0;
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
temp1 = x[m+(3*i)] >> 2;
|
|
l_temp = l_mult(temp1, temp1);
|
|
l_result = l_add(l_temp, l_result);
|
|
}
|
|
if (l_result > l_EM)
|
|
{
|
|
*pMc = (SHORT)m;
|
|
l_EM = l_result;
|
|
}
|
|
}
|
|
|
|
// down-sampling by a factor of 3 to get the selected xM[0..12]
|
|
// RPE sequence
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
xM[i] = x[*pMc + (3*i)];
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// APCMQuantize()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void APCMQuantize(PSTREAMINSTANCE psi, LPSHORT xM, LPSHORT pxmaxc, LPSHORT xMc, LPSHORT pexp, LPSHORT pmant)
|
|
{
|
|
UINT i;
|
|
SHORT xmax;
|
|
SHORT temp;
|
|
SHORT itest;
|
|
SHORT temp1, temp2;
|
|
|
|
// find the maximum absolute value xmax or xM[0..12]
|
|
xmax = 0;
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
temp = gabs(xM[i]);
|
|
if (temp > xmax) xmax = temp;
|
|
}
|
|
|
|
// quantizing and coding of xmax to get xmaxc
|
|
*pexp = 0;
|
|
temp = xmax >> 9;
|
|
itest = 0;
|
|
for (i=0; i<=5; i++)
|
|
{
|
|
if (temp <=0) itest = 1;
|
|
temp = temp >> 1;
|
|
if (itest == 0) *pexp = add(*pexp,1);
|
|
}
|
|
temp = add(*pexp,5);
|
|
*pxmaxc = add( (SHORT)BITSHIFTRIGHT(xmax,temp), (SHORT)(*pexp << 3) );
|
|
|
|
//
|
|
// quantizing and coding of the xM[0..12] RPE sequence to get
|
|
// the xMc[0..12]
|
|
//
|
|
|
|
// compute exponent and mantissa of the decoded version of xmaxc
|
|
*pexp = 0;
|
|
if (*pxmaxc > 15) *pexp = sub((SHORT)(*pxmaxc >> 3),1);
|
|
*pmant = sub(*pxmaxc,(SHORT)(*pexp<<3));
|
|
|
|
// normalize mantissa 0 <= mant <= 7
|
|
if (*pmant==0)
|
|
{
|
|
*pexp = -4;
|
|
*pmant = 15;
|
|
}
|
|
else
|
|
{
|
|
itest = 0;
|
|
for (i=0; i<=2; i++)
|
|
{
|
|
if (*pmant > 7) itest = 1;
|
|
if (itest == 0) *pmant = add((SHORT)(*pmant << 1),1);
|
|
if (itest == 0) *pexp = sub(*pexp,1);
|
|
}
|
|
}
|
|
|
|
*pmant = sub(*pmant,8);
|
|
|
|
// direct computation of xMc[0..12] using table
|
|
temp1 = sub(6,*pexp); // normalization by the exponent
|
|
temp2 = NRFAC[*pmant]; // see table (inverse mantissa)
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
temp = BITSHIFTLEFT(xM[i], temp1);
|
|
temp = mult( temp, temp2 );
|
|
xMc[i] = add( (SHORT)(temp >> 12), 4 ); // makes all xMc[i] positive
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// APCMInvQuantize()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void APCMInvQuantize(PSTREAMINSTANCE psi, SHORT exp, SHORT mant, LPSHORT xMc, LPSHORT xMp)
|
|
{
|
|
SHORT temp1, temp2, temp3, temp;
|
|
UINT i;
|
|
|
|
temp1 = FAC[mant];
|
|
temp2 = sub(6,exp);
|
|
temp3 = BITSHIFTLEFT(1, sub(temp2,1));
|
|
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
temp = sub( (SHORT)(xMc[i] << 1), 7); // restores sign of xMc[i]
|
|
temp = temp << 12;
|
|
temp = mult_r(temp1, temp);
|
|
temp = add(temp, temp3);
|
|
xMp[i] = BITSHIFTRIGHT(temp,temp2);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// RPEGridPosition(SHORT Mc, LPSHORT xMp, LPSHORT ep)
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void RPEGridPosition(PSTREAMINSTANCE psi, SHORT Mc, LPSHORT xMp, LPSHORT ep)
|
|
{
|
|
UINT k, i;
|
|
|
|
for (k=0; k<=39; k++)
|
|
{
|
|
ep[k] = 0;
|
|
}
|
|
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
ep[Mc + (3*i)] = xMp[i];
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// encodeUpdate()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void encodeUpdate(PSTREAMINSTANCE psi, LPSHORT ep, LPSHORT dpp)
|
|
{
|
|
UINT k;
|
|
|
|
for (k=0; k<=79; k++)
|
|
psi->dp[120-120+k] = psi->dp[120-80+k];
|
|
|
|
for (k=0; k<=39; k++)
|
|
psi->dp[120-40+k] = add(ep[k], dpp[k]);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
//=====================================================================
|
|
//
|
|
// Decode routines
|
|
//
|
|
//=====================================================================
|
|
//=====================================================================
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Function protos
|
|
//
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
|
|
EXTERN_C void Compsr(PSTREAMINSTANCE psi, LPSHORT wt, LPSHORT rrp, UINT k_start, UINT k_end, LPSHORT sr);
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Procedures
|
|
//
|
|
//---------------------------------------------------------------------
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// UnpackFrame0
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void UnpackFrame0
|
|
(
|
|
BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[]
|
|
)
|
|
{
|
|
UINT i;
|
|
|
|
// Unpack the LAR[1..8] from the first 4.5 bytes
|
|
LAR[1] = (ab[0] & 0x3F);
|
|
LAR[2] = ((ab[0] & 0xC0) >> 6) | ((ab[1] & 0x0F) << 2);
|
|
LAR[3] = ((ab[1] & 0xF0) >> 4) | ((ab[2] & 0x01) << 4);
|
|
LAR[4] = ((ab[2] & 0x3E) >> 1);
|
|
LAR[5] = ((ab[2] & 0xC0) >> 6) | ((ab[3] & 0x03) << 2);
|
|
LAR[6] = ((ab[3] & 0x3C) >> 2);
|
|
LAR[7] = ((ab[3] & 0xC0) >> 6) | ((ab[4] & 0x01) << 2);
|
|
LAR[8] = ((ab[4] & 0x0E) >> 1);
|
|
|
|
// Unpack N, b, M, Xmax, and X for each of the four sub-frames
|
|
for (i=0; i<4; i++)
|
|
{
|
|
// A convenient macro for getting bytes out of the array for
|
|
// construction of the subframe parameters
|
|
#define sfb(x) (ab[4+i*7+x])
|
|
|
|
N[i] = ((sfb(0) & 0xF0) >> 4) | ((sfb(1) & 0x07) << 4);
|
|
b[i] = ((sfb(1) & 0x18) >> 3);
|
|
M[i] = ((sfb(1) & 0x60) >> 5);
|
|
Xmax[i] = ((sfb(1) & 0x80) >> 7) | ((sfb(2) & 0x1F) << 1);
|
|
X[i][0] = ((sfb(2) & 0xE0) >> 5);
|
|
X[i][1] = (sfb(3) & 0x07);
|
|
X[i][2] = ((sfb(3) & 0x3C) >> 3);
|
|
X[i][3] = ((sfb(3) & 0xC0) >> 6) | ((sfb(4) & 0x01) << 2);
|
|
X[i][4] = ((sfb(4) & 0x0E) >> 1);
|
|
X[i][5] = ((sfb(4) & 0x70) >> 4);
|
|
X[i][6] = ((sfb(4) & 0x80) >> 7) | ((sfb(5) & 0x03) << 1);
|
|
X[i][7] = ((sfb(5) & 0x1C) >> 2);
|
|
X[i][8] = ((sfb(5) & 0xE0) >> 5);
|
|
X[i][9] = (sfb(6) & 0x07);
|
|
X[i][10] = ((sfb(6) & 0x38) >> 3);
|
|
X[i][11] = ((sfb(6) & 0xC0) >> 6) | ((sfb(7) & 0x01) << 2);
|
|
X[i][12] = ((sfb(7) & 0x0E) >> 1);
|
|
|
|
#undef sfb
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// UnpackFrame1
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void UnpackFrame1
|
|
(
|
|
BYTE FAR ab[],
|
|
SHORT FAR LAR[],
|
|
SHORT FAR N[],
|
|
SHORT FAR b[],
|
|
SHORT FAR M[],
|
|
SHORT FAR Xmax[],
|
|
XM FAR X[]
|
|
)
|
|
{
|
|
UINT i;
|
|
|
|
// Unpack the LAR[1..8] from the first 4.5 bytes
|
|
LAR[1] = ((ab[32] & 0xF0) >> 4) | ((ab[33] & 0x03) << 4);
|
|
LAR[2] = ((ab[33] & 0xFC) >> 2);
|
|
LAR[3] = ((ab[34] & 0x1F) );
|
|
LAR[4] = ((ab[34] & 0xE0) >> 5) | ((ab[35] & 0x03) << 3);
|
|
LAR[5] = ((ab[35] & 0x3C) >> 2);
|
|
LAR[6] = ((ab[35] & 0xC0) >> 6) | ((ab[36] & 0x03) << 2);
|
|
LAR[7] = ((ab[36] & 0x1C) >> 2);
|
|
LAR[8] = ((ab[36] & 0xE0) >> 5);
|
|
|
|
// Unpack N, b, M, Xmax, and X for each of the four sub-frames
|
|
for (i=0; i<4; i++)
|
|
{
|
|
// A convenient macro for getting bytes out of the array for
|
|
// construction of the subframe parameters
|
|
#define sfb(x) (ab[37+i*7+x])
|
|
|
|
N[i] = sfb(0) & 0x7F;
|
|
b[i] = ((sfb(0) & 0x80) >> 7) | ((sfb(1) & 0x01) << 1);
|
|
M[i] = ((sfb(1) & 0x06) >> 1);
|
|
Xmax[i] = ((sfb(1) & 0xF8) >> 3) | ((sfb(2) & 0x01) << 5);
|
|
|
|
X[i][0] = ((sfb(2) & 0x0E) >> 1);
|
|
X[i][1] = ((sfb(2) & 0x70) >> 4);
|
|
X[i][2] = ((sfb(2) & 0x80) >> 7) | ((sfb(3) & 0x03) << 1);
|
|
X[i][3] = ((sfb(3) & 0x1C) >> 2);
|
|
X[i][4] = ((sfb(3) & 0xE0) >> 5);
|
|
X[i][5] = ((sfb(4) & 0x07) );
|
|
X[i][6] = ((sfb(4) & 0x38) >> 3);
|
|
X[i][7] = ((sfb(4) & 0xC0) >> 6) | ((sfb(5) & 0x01) << 2);
|
|
X[i][8] = ((sfb(5) & 0x0E) >> 1);
|
|
X[i][9] = ((sfb(5) & 0x70) >> 4);
|
|
X[i][10] = ((sfb(5) & 0x80) >> 7) | ((sfb(6) & 0x03) << 1);
|
|
X[i][11] = ((sfb(6) & 0x1C) >> 2);
|
|
X[i][12] = ((sfb(6) & 0xE0) >> 5);
|
|
|
|
#undef sfb
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// decodeRPE()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void decodeRPE(PSTREAMINSTANCE psi, SHORT Mcr, SHORT xmaxcr, LPSHORT xMcr, LPSHORT erp)
|
|
{
|
|
|
|
SHORT exp, mant;
|
|
SHORT itest;
|
|
UINT i;
|
|
SHORT temp1, temp2, temp3, temp;
|
|
SHORT xMrp[13];
|
|
UINT k;
|
|
|
|
// compute the exponent and mantissa of the decoded
|
|
// version of xmaxcr
|
|
|
|
exp = 0;
|
|
if (xmaxcr > 15) exp = sub( (SHORT)(xmaxcr >> 3), 1 );
|
|
mant = sub( xmaxcr, (SHORT)(exp << 3) );
|
|
|
|
// normalize the mantissa 0 <= mant <= 7
|
|
if (mant == 0)
|
|
{
|
|
exp = -4;
|
|
mant = 15;
|
|
}
|
|
else
|
|
{
|
|
itest = 0;
|
|
for (i=0; i<=2; i++)
|
|
{
|
|
if (mant > 7) itest = 1;
|
|
if (itest == 0) mant = add((SHORT)(mant << 1),1);
|
|
if (itest == 0) exp = sub(exp,1);
|
|
}
|
|
}
|
|
|
|
mant = sub(mant, 8);
|
|
|
|
// APCM inverse quantization
|
|
temp1 = FAC[mant];
|
|
temp2 = sub(6,exp);
|
|
temp3 = BITSHIFTLEFT(1, sub(temp2, 1));
|
|
|
|
for (i=0; i<=12; i++)
|
|
{
|
|
temp = sub( (SHORT)(xMcr[i] << 1), 7 );
|
|
temp = temp << 12;
|
|
temp = mult_r(temp1, temp);
|
|
temp = add(temp, temp3);
|
|
xMrp[i] = BITSHIFTRIGHT(temp, temp2);
|
|
}
|
|
|
|
// RPE grid positioning
|
|
for (k=0; k<=39; k++) erp[k] = 0;
|
|
for (i=0; i<=12; i++) erp[Mcr + (3*i)] = xMrp[i];
|
|
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// decodeLTP()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void decodeLTP(PSTREAMINSTANCE psi, SHORT bcr, SHORT Ncr, LPSHORT erp)
|
|
{
|
|
SHORT Nr;
|
|
SHORT brp;
|
|
UINT k;
|
|
SHORT drpp;
|
|
|
|
// check limits of Nr
|
|
Nr = Ncr;
|
|
if (Ncr < 40) Nr = psi->nrp;
|
|
if (Ncr > 120) Nr = psi->nrp;
|
|
psi->nrp = Nr;
|
|
|
|
// decoding of the LTP gain bcr
|
|
brp = QLB[bcr];
|
|
|
|
// computation of the reconstructed short term residual
|
|
// signal drp[0..39]
|
|
for (k=0; k<=39; k++)
|
|
{
|
|
drpp = mult_r( brp, psi->drp[120+k-Nr] );
|
|
psi->drp[120+k] = add( erp[k], drpp );
|
|
}
|
|
|
|
// update of the reconstructed short term residual
|
|
// signal drp[-1..-120]
|
|
for (k=0; k<=119; k++)
|
|
{
|
|
psi->drp[120-120+k] = psi->drp[120-80+k];
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// decodeLPC
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void decodeLPC
|
|
(
|
|
PSTREAMINSTANCE psi, // instance data
|
|
LPSHORT LARcr, // received coded Log.-Area Ratios [1..8]
|
|
LPSHORT wt, // accumulated drp signal [0..159]
|
|
LPSHORT sr // reconstructed s [0..159]
|
|
)
|
|
{
|
|
|
|
UINT i;
|
|
SHORT LARrpp[9]; // LARrpp[1..8], decoded LARcr
|
|
SHORT LARrp[9]; // LARrp[1..9], interpolated LARrpp
|
|
SHORT rrp[9]; // rrp[1..8], reflection coefficients
|
|
SHORT temp1, temp2;
|
|
|
|
//
|
|
// decoding of the coded log area ratios to get LARrpp[1..8]
|
|
//
|
|
|
|
// compute LARrpp[1..8]
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
temp1 = add( LARcr[i], MIC[i] ) << 10;
|
|
temp2 = B[i] << 1;
|
|
temp1 = sub( temp1, temp2);
|
|
temp1 = mult_r( INVA[i], temp1 );
|
|
LARrpp[i] = add( temp1, temp1 );
|
|
}
|
|
|
|
|
|
//
|
|
// for k_start=0 to k_end=12
|
|
//
|
|
|
|
// interpolation of LARrpp[1..8] to get LARrp[1..8]
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
// for k_start=0 to k_end=12
|
|
LARrp[i] = add( (SHORT)(psi->OldLARrpp[i] >> 2), (SHORT)(LARrpp[i] >> 2) );
|
|
LARrp[i] = add( LARrp[i], (SHORT)(psi->OldLARrpp[i] >> 1) );
|
|
}
|
|
|
|
// computation of reflection coefficients rrp[1..8]
|
|
Comprp(psi, LARrp, rrp);
|
|
|
|
// short term synthesis filtering
|
|
Compsr(psi, wt, rrp, 0, 12, sr);
|
|
|
|
|
|
//
|
|
// for k_start=13 to k_end=26
|
|
//
|
|
|
|
// interpolation of LARrpp[1..8] to get LARrp[1..8]
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
// for k_start=13 to k_end=26
|
|
LARrp[i] = add( (SHORT)(psi->OldLARrpp[i] >> 1), (SHORT)(LARrpp[i] >> 1) );
|
|
}
|
|
|
|
// computation of reflection coefficients rrp[1..8]
|
|
Comprp(psi, LARrp, rrp);
|
|
|
|
// short term synthesis filtering
|
|
Compsr(psi, wt, rrp, 13, 26, sr);
|
|
|
|
//
|
|
// for k_start=27 to k_end=39
|
|
//
|
|
|
|
// interpolation of LARrpp[1..8] to get LARrp[1..8]
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
// for k_start=27 to k_end=39
|
|
LARrp[i] = add( (SHORT)(psi->OldLARrpp[i] >> 2), (SHORT)(LARrpp[i] >> 2) );
|
|
LARrp[i] = add( LARrp[i], (SHORT)(LARrpp[i] >> 1) );
|
|
}
|
|
|
|
// computation of reflection coefficients rrp[1..8]
|
|
Comprp(psi, LARrp, rrp);
|
|
|
|
// short term synthesis filtering
|
|
Compsr(psi, wt, rrp, 27, 39, sr);
|
|
|
|
//
|
|
// for k_start=40 to k_end=159
|
|
//
|
|
|
|
// interpolation of LARrpp[1..8] to get LARrp[1..8]
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
// for k_start=40 to k_end=159
|
|
LARrp[i] = LARrpp[i];
|
|
}
|
|
|
|
// computation of reflection coefficients rrp[1..8]
|
|
Comprp(psi, LARrp, rrp);
|
|
|
|
// short term synthesis filtering
|
|
Compsr(psi, wt, rrp, 40, 159, sr);
|
|
|
|
|
|
//
|
|
// update oldLARrpp[1..8]
|
|
//
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
psi->OldLARrpp[i] = LARrpp[i];
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// decodePostproc()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void decodePostproc(PSTREAMINSTANCE psi, LPSHORT sr, LPSHORT srop)
|
|
{
|
|
UINT k;
|
|
|
|
// deemphasis filtering
|
|
for (k=0; k<=159; k++)
|
|
{
|
|
srop[k] = psi->msr = add(sr[k], mult_r(psi->msr, 28180));
|
|
|
|
// upscaling and truncation of the output signal
|
|
srop[k] = (add(srop[k], srop[k])) & 0xFFF8;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Compsr()
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
void Compsr(PSTREAMINSTANCE psi, LPSHORT wt, LPSHORT rrp, UINT k_start, UINT k_end, LPSHORT sr)
|
|
{
|
|
UINT i, k;
|
|
SHORT sri;
|
|
|
|
for (k=k_start; k<=k_end; k++)
|
|
{
|
|
sri = wt[k];
|
|
for (i=1; i<=8; i++)
|
|
{
|
|
sri = sub( sri, mult_r(rrp[9-i], psi->v[8-i]) );
|
|
psi->v[9-i] = add( psi->v[8-i], mult_r( rrp[9-i], sri ) );
|
|
}
|
|
sr[k] = sri;
|
|
psi->v[0] = sri;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
//=====================================================================
|
|
//
|
|
// Math and helper routines
|
|
//
|
|
//=====================================================================
|
|
//=====================================================================
|
|
|
|
|
|
//
|
|
// The 8-/16-bit PCM conversion routines are implemented as seperate
|
|
// functions to allow easy modification if we someday wish to do
|
|
// something more sophisticated that simple truncation... They are
|
|
// prototyped as inline so there should be no performance penalty.
|
|
//
|
|
//
|
|
SHORT Convert8To16BitPCM(BYTE bPCM8)
|
|
{
|
|
return ( ((SHORT)bPCM8) - 0x80 ) << 8;
|
|
}
|
|
|
|
BYTE Convert16To8BitPCM(SHORT iPCM16)
|
|
{
|
|
return (BYTE)((iPCM16 >> 8) + 0x80);
|
|
}
|
|
|
|
SHORT add(SHORT var1, SHORT var2)
|
|
{
|
|
LONG sum;
|
|
|
|
sum = (LONG) var1 + (LONG) var2;
|
|
|
|
if (sum < -32768L) return -32768;
|
|
if (sum > 32767L) return 32767;
|
|
return (SHORT) sum;
|
|
|
|
}
|
|
|
|
SHORT sub(SHORT var1, SHORT var2)
|
|
{
|
|
LONG diff;
|
|
|
|
diff = (LONG) var1 - (LONG) var2;
|
|
if (diff < -32768L) return -32768;
|
|
if (diff > 32767L) return 32767;
|
|
return (SHORT) diff;
|
|
|
|
}
|
|
|
|
SHORT mult(SHORT var1, SHORT var2)
|
|
{
|
|
LONG product;
|
|
|
|
product = (LONG) var1 * (LONG) var2;
|
|
if (product >= 0x40000000) product=0x3FFFFFFF;
|
|
return ( (SHORT) HIWORD((DWORD)(product<<1)) );
|
|
}
|
|
|
|
SHORT mult_r(SHORT var1, SHORT var2)
|
|
{
|
|
LONG product;
|
|
|
|
product = ((LONG) var1 * (LONG) var2) + 16384L;
|
|
if (product >= 0x40000000) product=0x3FFFFFFF;
|
|
return ( (SHORT) HIWORD((DWORD)(product<<1)) );
|
|
}
|
|
|
|
SHORT gabs(SHORT var1)
|
|
{
|
|
if (var1 >= 0) return var1;
|
|
if (var1 == -32768) return 32767;
|
|
return -var1;
|
|
}
|
|
|
|
SHORT gdiv(SHORT num, SHORT denum)
|
|
{
|
|
UINT k;
|
|
LONG l_num, l_denum;
|
|
SHORT div;
|
|
|
|
l_num = num;
|
|
l_denum = denum;
|
|
|
|
div = 0;
|
|
|
|
for (k=0; k<15; k++)
|
|
{
|
|
div = div << 1;
|
|
l_num = l_num << 1;
|
|
if (l_num >= l_denum)
|
|
{
|
|
l_num = l_sub(l_num, l_denum);
|
|
div = add(div,1);
|
|
}
|
|
}
|
|
|
|
return div;
|
|
}
|
|
|
|
LONG l_mult(SHORT var1, SHORT var2)
|
|
{
|
|
LONG product;
|
|
|
|
product = (LONG) var1 * (LONG) var2;
|
|
return product << 1;
|
|
}
|
|
|
|
LONG l_add(LONG l_var1, LONG l_var2)
|
|
{
|
|
LONG l_sum;
|
|
|
|
// perform long addition
|
|
l_sum = l_var1 + l_var2;
|
|
|
|
// check for under or overflow
|
|
if (IsNeg(l_var1))
|
|
{
|
|
if (IsNeg(l_var2) && !IsNeg(l_sum))
|
|
{
|
|
return 0x80000000;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsNeg(l_var2) && IsNeg(l_sum))
|
|
{
|
|
return 0x7FFFFFFF;
|
|
}
|
|
}
|
|
|
|
return l_sum;
|
|
|
|
}
|
|
|
|
LONG l_sub(LONG l_var1, LONG l_var2)
|
|
{
|
|
LONG l_diff;
|
|
|
|
// perform subtraction
|
|
l_diff = l_var1 - l_var2;
|
|
|
|
// check for underflow
|
|
if ( (l_var1<0) && (l_var2>0) && (l_diff>0) ) l_diff=0x80000000;
|
|
// check for overflow
|
|
if ( (l_var1>0) && (l_var2<0) && (l_diff<0) ) l_diff=0x7FFFFFFF;
|
|
|
|
return l_diff;
|
|
}
|
|
|
|
SHORT norm(LONG l_var)
|
|
{
|
|
UINT i;
|
|
|
|
i=0;
|
|
|
|
if (l_var > 0)
|
|
{
|
|
while (l_var < 1073741824)
|
|
{
|
|
i++;
|
|
l_var = l_var << 1;
|
|
}
|
|
}
|
|
else if (l_var < 0)
|
|
{
|
|
while (l_var > -1073741824)
|
|
{
|
|
i++;
|
|
l_var = l_var << 1;
|
|
}
|
|
}
|
|
|
|
return (SHORT)i;
|
|
}
|
|
|
|
LONG IsNeg(LONG x)
|
|
{
|
|
return(x & 0x80000000);
|
|
}
|