⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 g726.cpp

📁 G.726带测试和在DM642实现的完整工程。测试程序可修改自行填入数据。实现部分设计具体产品板的定义
💻 CPP
📖 第 1 页 / 共 2 页
字号:
@brief UPA2 function from %G726 Section 4.2.6 - Adaptative predictor and reconstructed signal calculator
*/
inline static void UPA2(int PK0,int PK1,int PK2,int A1,int A2,uint SIGPK,int& A2T)
	{
	CHECK_TC(PK0,1);
	CHECK_TC(PK1,1);
	CHECK_TC(PK2,1);
	CHECK_TC(A1,16);
	CHECK_TC(A2,16);
	CHECK_UNSIGNED(SIGPK,1);

	uint UGA2;
	if(SIGPK==0)
		{
		int UGA2A = (PK0^PK2) ? -16384 : 16384;

		int FA1;
		if(A1<-8191)	 FA1 = -8191<<2;
		else if(A1>8191) FA1 = 8191<<2;
		else			 FA1 = A1<<2;

		int FA = (PK0^PK1) ? FA1 : -FA1;

		UGA2 = (UGA2A+FA) >> 7;
		}
	else
		UGA2 = 0;
	A2T = (int16)(A2+UGA2-(A2>>7));
		
	CHECK_TC(A2T,16);
	}


/**
@brief UPB function from %G726 Section 4.2.6 - Adaptative predictor and reconstructed signal calculator
*/
inline static void UPB(uint RATE,int Un,int Bn,uint DQ,int& BnP)
	{
	CHECK_TC(Un,1);
	CHECK_TC(Bn,16);
	CHECK_SM(DQ,16);
	int UGBn;
	if(DQ&32767)
		UGBn = Un ? -128 : 128;
	else
		UGBn = 0;
	int ULBn = (RATE==5) ? Bn>>9 : Bn>>8;
	BnP = (int16)(Bn+UGBn-ULBn);
	CHECK_TC(BnP,16);
	}


/**
@brief XOR function from %G726 Section 4.2.6 - Adaptative predictor and reconstructed signal calculator
*/
inline static void XOR(uint DQn,uint DQ,int& Un)
	{
	CHECK_FL(DQn,11);
	CHECK_SM(DQ,16);
	Un = -(int)((DQn>>10)^(DQ>>15));
	CHECK_TC(Un,1);
	}


/**
@brief TONE function from %G726 Section 4.2.7 - Tone and transition detector
*/
inline static void TONE(int A2P,uint& TDP)
	{
	CHECK_TC(A2P,16);
	TDP = A2P<(53760-65536);
	CHECK_UNSIGNED(TDP,1);
	}


/**
@brief TRANS function from %G726 Section 4.2.7 - Tone and transition detector
*/
inline static void TRANS(uint TD,uint YL,uint DQ,uint& TR)
	{
	CHECK_UNSIGNED(TD,1);
	CHECK_UM(YL,19);
	CHECK_SM(DQ,16);
	uint DQMAG = DQ&32767;
	uint YLINT = YL>>15;
	uint YLFRAC = (YL>>10) & 31;
	uint THR1 = (32+YLFRAC)<<YLINT;
	uint THR2;
	if(YLINT>9)
		THR2 = 31<<10;
	else
		THR2 = THR1;
	uint DQTHR = (THR2+(THR2>>1)) >> 1;
	TR = DQMAG>DQTHR && TD;
	CHECK_UNSIGNED(TR,1);
	}


/**
@brief COMPRESS function from %G726 Section 4.2.8 - Output PCM format conversion and synchronous coding adjustment
*/
inline static void COMPRESS(int SR,uint LAW,uint& SP)
	{
	CHECK_TC(SR,16);
	CHECK_UNSIGNED(LAW,1);
	int x = SR;

#ifdef IMPLEMENT_G191_BUGS
	// reproduce bugs in G191 reference implementation...
	if(x==-0x8000)
		x=-1; 
	else
		if(!LAW && x<0) x--;
#endif

	// Clamp to 14 bits...
	if(x>=(1<<13))
		x = (1<<13)-1;
	else if(x<-(1<<13))
		x = -(1<<13);

	if(LAW)
		SP = G711::ALawEncode(x<<2);
	else
		SP = G711::ULawEncode(x<<2);

	CHECK_UNSIGNED(SP,8);
	}


/**
@brief SYNC function from %G726 Section 4.2.8 - Output PCM format conversion and synchronous coding adjustment
*/
inline static void SYNC(uint RATE,uint I,uint SP,int DLNX,int DSX,uint LAW,uint& SD)
	{
	CHECK_UNSIGNED(SP,8);
	CHECK_TC(DLNX,12);
	CHECK_TC(DSX,1);
	CHECK_UNSIGNED(LAW,1);

	uint ID;
	uint IM;
	QUAN(RATE,DLNX,DSX,ID);
	uint signMask = 1<<(RATE-1);
	ID = ID^signMask;
	IM = I^signMask;

	uint s;
	if(LAW)
		{
		s = SP^0x55;
		if(!(s&0x80))
			s = s^0x7f;
		}
	else
		{
		s = SP;
		if(s&0x80)
			s = s^0x7f;
		}
	// s = ALAW/uLAW code converted to range 0x00..0xff
	// where 0x00 is most-negative and 0xff is most-positive

	if(ID<IM)
		{
		if(s<0xff)
			++s;
		}
	else if(ID>IM)
		{
		if(s>0x00)
			{
			--s;
			if(s==0x7f && !LAW) --s; // TABLE 20/G.726 says uLaw 0xFF decrements to 0x7e and not 0x7f (!?)
			}
		}

	// convert s back to ALAW/uLAW code
	if(LAW)
		{
		if(!(s&0x80))
			s = s^0x7f;
		s = s^0x55;
		}
	else
		{
		if(s&0x80)
			s = s^0x7f;
		}
	SD = s;
	CHECK_UNSIGNED(SD,8);
	}


/**
@brief LIMO function from %G726 Section A.3.5 - Output limiting (decoder only)
*/
inline static void LIMO(int SR,int& SO)
	{
	CHECK_TC(SR,16);
	if(SR>=(1<<13))
		SO = (1<<13)-1;
	else if(SR<-(1<<13))
		SO = -(1<<13);
	else
		SO = SR;
	CHECK_TC(SO,14);
	}


/** @} */ // End of group


/**
@defgroup g726_section4B Internal - Functional blocks from Section 4 of G726
@ingroup g726
Some of these have been broken into two parts, the first of which can generate
it's outputs using only the saved internal state from the previous itteration
of the algorithm.
@{
*/

/**
@brief FIGURE 4/G.726 from Section 4.2.1 - Input PCM format conversion and difference signal computation
*/
inline void G726::InputPCMFormatConversionAndDifferenceSignalComputation(uint S,int SE,int& D)
	{
	int SL;
	EXPAND(S,LAW,SL);
	SUBTA(SL,SE,D);
	}


/**
@brief FIGURE 5/G.726 from Section 4.2.2 - Adaptive quantizer
*/
inline void G726::AdaptiveQuantizer(int D,uint Y,uint& I)
	{
	uint DL;
	int DS;
	LOG(D,DL,DS);

	int DLN;
	SUBTB(DL,Y,DLN);

	QUAN(RATE,DLN,DS,I);
	}


/**
@brief FIGURE 6/G.726 from Section 4.2.3 - Inverse adaptive quantizer
*/
inline void G726::InverseAdaptiveQuantizer(uint I,uint Y,uint& DQ)
	{
	int DQLN;
	int DQS;
	RECONST(RATE,I,DQLN,DQS);

	int DQL;
	ADDA(DQLN,Y,DQL);

	ANTILOG(DQL,DQS,DQ);
	}


/**
@brief FIGURE 7/G.726 (Part 1) from Section 4.2.4 - Quantizer scale factor adaptation
*/
inline void G726::QuantizerScaleFactorAdaptation1(uint AL,uint& Y)
	{
	MIX(AL,YU,YL,Y);
	}
/**
@brief FIGURE 7/G.726 (Part 2) from Section 4.2.4 - Quantizer scale factor adaptation
*/
inline void G726::QuantizerScaleFactorAdaptation2(uint I,uint Y)
	{
	int WI;
	FUNCTW(RATE,I,WI);

	uint YUT;
	FILTD(WI,Y,YUT);

	uint YUP;
	LIMB(YUT,YUP);

	uint YLP;
	FILTE(YUP,YL,YLP);

	YU = YUP; // Delay
	YL = YLP; // Delay
	}


/**
@brief FIGURE 8/G.726 (Part 1) from Section 4.2.5 - Adaptation speed control
*/
inline void G726::AdaptationSpeedControl1(uint& AL)
	{
	LIMA(AP,AL);
	}
/**
@brief FIGURE 8/G.726 (Part 2) from Section 4.2.5 - Adaptation speed control
*/
inline void G726::AdaptationSpeedControl2(uint I,uint Y,uint TDP,uint TR)
	{
	uint FI;
	FUNCTF(RATE,I,FI);

	FILTA(FI,DMS,DMS); // Result 'DMSP' straight to delay storage 'DMS'
	FILTB(FI,DML,DML); // Result 'DMSP' straight to delay storage 'DMS'

	uint AX;
	SUBTC(DMS,DML,TDP,Y,AX); // DMSP and DMLP are read from delay storage 'DMS' and 'DML'

	uint APP;
	FILTC(AX,AP,APP);

	TRIGA(TR,APP,AP); // Result 'APR' straight to delay storage 'AP'
	}


/**
@brief FIGURE 9/G.726 (Part1) from Section 4.2.6 - Adaptative predictor and reconstructed signal calculator
*/
inline void G726::AdaptativePredictorAndReconstructedSignalCalculator1(int& SE,int& SEZ)
	{
	int WBn[6];
	for(int i=0; i<6; i++)
		FMULT(Bn[i],DQn[i],WBn[i]);
	int WAn[2];
	FMULT(A1,SR1,WAn[0]);
	FMULT(A2,SR2,WAn[1]);
	ACCUM(WAn,WBn,SE,SEZ);
	}
/**
@brief FIGURE 9/G.726 (Part2) from Section 4.2.6 - Adaptative predictor and reconstructed signal calculator
*/
inline void G726::AdaptativePredictorAndReconstructedSignalCalculator2(uint DQ,uint TR,int SE,int SEZ,int& SR,int& A2P)
	{
	int PK0;
	uint SIGPK;
	ADDC(DQ,SEZ,PK0,SIGPK);

	ADDB(DQ,SE,SR);
	SR2 = SR1; // Delay
	FLOATB(SR,SR1);  // Result 'SR0' straight to delay storage 'SR1'

	uint DQ0;
	FLOATA(DQ,DQ0);

	int i;
	for(i=0; i<6; i++)
		{
		int Un;
		XOR(DQn[i],DQ,Un);
		int BnP;
		UPB(RATE,Un,Bn[i],DQ,BnP);
		TRIGB(TR,BnP,Bn[i]); // Result 'BnR' straight to delay storage 'Bn'
		}

	int A2T;
	UPA2(PK0,PK1,PK2,A1,A2,SIGPK,A2T);
	LIMC(A2T,A2P);
	TRIGB(TR,A2P,A2); // Result 'A2R' straight to delay storage 'A2'

	int A1T;
	UPA1(PK0,PK1,A1,SIGPK,A1T);
	int A1P;
	LIMD(A1T,A2P,A1P);
	TRIGB(TR,A1P,A1); // Result 'A1R' straight to delay storage 'A1'

	PK2 = PK1; // Delay
	PK1 = PK0; // Delay

	for(i=5; i>0; i--)
		DQn[i] = DQn[i-1]; // Delay
	DQn[0] = DQ0; // Delay
	}


/**
@brief FIGURE 10/G.726 (Part 1) from Section 4.2.7 - Tone and transition detector
*/
inline void G726::ToneAndTransitionDetector1(uint DQ,uint& TR)
	{
	TRANS(TD,YL,DQ,TR);
	}
/**
@brief FIGURE 10/G.726 (Part 2) from Section 4.2.7 - Tone and transition detector
*/
inline void G726::ToneAndTransitionDetector2(int A2P,uint TR,uint& TDP)
	{
	TONE(A2P,TDP);
	TRIGB(TR,TDP,(int&)TD);  // Result 'TDR' straight to delay storage 'TD'
	}


/**
@brief FIGURE 11/G.726 from Section 4.2.8 - Output PCM format conversion and synchronous coding adjustment
*/
inline void G726::OutputPCMFormatConversionAndSynchronousCodingAdjustment(int SR,int SE,uint Y,uint I,uint& SD)
	{
	uint SP;
	COMPRESS(SR,LAW,SP);
	int SLX;
	EXPAND(SP,LAW,SLX);
	int DX;
	SUBTA(SLX,SE,DX);
	uint DLX;
	int DSX;
	LOG(DX,DLX,DSX);
	int DLNX;
	SUBTB(DLX,Y,DLNX);
	SYNC(RATE,I,SP,DLNX,DSX,LAW,SD);
	}


/**
@brief FIGURE A.4/G.726 from Section A.3.3 - Difference signal computation
*/
inline void G726::DifferenceSignalComputation(int SL,int SE,int& D)
	{
	SUBTA(SL,SE,D);
	}


/**
@brief FIGURE A.5/G.726 from Section A.3.5 - Output limiting (decoder only)
*/
inline void G726::OutputLimiting(int SR,int& SO)
	{
	LIMO(SR,SO);
	}


/** @} */ // End of group


/**
@brief The top level method which implements the complete algorithm for both
encoding and decoding.
@param input Either the PCM input to the encoder or the ADPCM input to the decoder.
@param encode A flag which if true makes this method perform the encode function.
			  If the flag is false then the decode function is performed.
@return Either the ADPCM output to the encoder or the PCM output to the decoder.
*/
uint G726::EncodeDecode(uint input,bool encode)
	{
	uint AL;
	AdaptationSpeedControl1(AL);
	uint Y;
	QuantizerScaleFactorAdaptation1(AL,Y);
	int SE;
	int SEZ;
	AdaptativePredictorAndReconstructedSignalCalculator1(SE,SEZ);

	uint I;
	if(encode)
		{
		int D;
		if(LAW==G726::PCM16)
			{
			int SL = (int16)input;
			SL >>= 2; // Convert input from 16bit to 14bit
			DifferenceSignalComputation(SL,SE,D);
			}
		else
			InputPCMFormatConversionAndDifferenceSignalComputation(input,SE,D);
		AdaptiveQuantizer(D,Y,I);
		}
	else
		I = input;

	uint DQ;
	InverseAdaptiveQuantizer(I,Y,DQ);
	uint TR;
	ToneAndTransitionDetector1(DQ,TR);
	int SR;
	int A2P;
	AdaptativePredictorAndReconstructedSignalCalculator2(DQ,TR,SE,SEZ,SR,A2P);
	uint TDP;
	ToneAndTransitionDetector2(A2P,TR,TDP);
	AdaptationSpeedControl2(I,Y,TDP,TR);
	QuantizerScaleFactorAdaptation2(I,Y);

	if(encode)
		return I;

	if(LAW==G726::PCM16)
		{
		int SO;
		OutputLimiting(SR,SO);
		return SO<<2; // Convert result from 14bit to 16 bit
		}
	else
		{
		uint SD;
		OutputPCMFormatConversionAndSynchronousCodingAdjustment(SR,SE,Y,I,SD);
		return SD;
		}
	}


/*
Public members of class G726
*/


EXPORT void G726::Reset()
	{
	int i;
	for(i=0; i<6; i++)
		{
		Bn[i] = 0;
		DQn[i] = 32;
		}
	A1 = 0;
	A2 = 0;
	AP = 0;
	DML = 0;
	DMS = 0;
	PK1 = 0;
	PK2 = 0;
	SR1 = 32;
	SR2 = 32;
	TD = 0;
	YL = 34816;
	YU = 544;
	}


EXPORT void G726::SetLaw(Law law)
	{
	ASSERT_DEBUG((uint)law<=PCM16);
	LAW = law;
	}


EXPORT void G726::SetRate(Rate rate)
	{
	ASSERT_DEBUG((uint)(rate-Rate16kBits)<=(uint)(Rate40kBits-Rate16kBits));
	RATE = rate;
	}


EXPORT uint G726::Encode(uint S)
	{
	return EncodeDecode(S,true);
	}


EXPORT uint G726::Decode(uint I)
	{
	I &= (1<<RATE)-1; // Mask off un-needed bits
	return EncodeDecode(I,false);
	}


EXPORT uint G726::Encode(void* dst, int dstOffset, const void* src, uint srcSize)
	{
	// convert pointers into more useful types
	uint8* out = (uint8*)dst;
	const uint8* in = (const uint8*)src;

	// use given bit offset
	out += dstOffset>>3;
	uint bitOffset = dstOffset&7;

	uint bits = RATE;			// bits per adpcm sample
	uint mask = (1<<bits)-1;	// bitmask for an adpcm sample

	// calculate number of bits to be written
	uint outBits;
	if(LAW!=PCM16)
		outBits = bits*srcSize;
	else
		{
		outBits = bits*(srcSize>>1);
		srcSize &= ~1; // make sure srcSize represents a whole number of samples
		}

	// calculate end of input buffer
	const uint8* end = in+srcSize;

	while(in<end)
		{
		// read a single PCM value from input
		uint pcm;
		if(LAW==PCM16)
			pcm = *((int16*&)in)++;
		else
			pcm = *in++;

		// encode the pcm value as an adpcm value
		uint adpcm = Encode(pcm);
		// shift it to the required output position
		adpcm <<= bitOffset;

		// write adpcm value to buffer...
		uint b = *out;			   // get byte from ouput
		b &= ~(mask<<bitOffset);   // clear bits which we want to write to
		b |= adpcm; 			   // or in adpcm value
		*out = (uint8)b;		   // write value back to output

		// update bitOffset for next adpcm value
		bitOffset += bits;

		// loop if not moved on to next byte
		if(bitOffset<8)
			continue;

		// move pointers on to next byte
		++out;
		bitOffset &= 7;

		// write any left-over bits from the last adpcm value
		if(bitOffset)
			*out = (uint8)(adpcm>>8);
		}

	// return number bits written to dst
	return outBits;
	}


EXPORT uint G726::Decode(void* dst, const void* src, int srcOffset, uint srcSize)
	{
	// convert pointers into more useful types
	uint8* out = (uint8*)dst;
	const uint8* in = (const uint8*)src;

	// use given bit offset
	in += srcOffset>>3;
	uint bitOffset = srcOffset&7;

	uint bits = RATE;		  // bits per adpcm sample

	while(srcSize>=bits)
		{
		// read adpcm value from input
		uint adpcm = *in;
		if(bitOffset+bits>8)
			adpcm |= in[1]<<8;	// need bits from next byte as well

		// allign adpcm value to bit 0
		adpcm >>= bitOffset;

		// decode the adpcm value into a pcm value
		uint pcm = Decode(adpcm);

		// write pcm value to output
		if(LAW==PCM16)
			*((int16*&)out)++ = (int16)pcm;
		else
			*out++ = (uint8)pcm;

		// update bit values for next adpcm value
		bitOffset += bits;
		srcSize -= bits;

		// move on to next byte of input if required
		if(bitOffset>=8)
			{
			bitOffset &= 7;
			++in;
			}
		}

	// return number of bytes written to dst
	return out-(uint8*)dst;
	}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -