package cn.org.hentai.jtt1078.codec.g726;
import cn.org.hentai.jtt1078.codec.G711Codec;
import cn.org.hentai.jtt1078.codec.G711UCodec;
/** Common routines for G.721 and G.723 conversions.
*
* This implementation is based on the ANSI-C language reference implementations
* of the CCITT (International Telegraph and Telephone Consultative Committee)
* G.711, G.721 and G.723 voice compressions, provided by Sun Microsystems, Inc.
*
* Acknowledgement to Sun Microsystems, Inc. for having released the original
* ANSI-C source code to the public domain.
*/
public abstract class G726 {
// ##### C-to-Java conversion: #####
// short becomes int
// char becomes int
// unsigned char becomes int
// *************************** STATIC ***************************
/** ISDN u-law */
public static final int AUDIO_ENCODING_ULAW=1;
/** ISDN A-law */
public static final int AUDIO_ENCODING_ALAW=2;
/** PCM 2's-complement (0-center) */
public static final int AUDIO_ENCODING_LINEAR=3;
/** The first 15 values, powers of 2. */
private static final /*short*/int[] power2 = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 };
/** Quantizes the input val against the table of size short integers.
* It returns i if table[i-1]<=val
* Using linear search for simple coding. */
private static int quan(int val, /*short*/int[] table, int size) {
int i;
for (i=0; i
* @param d - Raw difference signal sample
* @param y - Step size multiplier
* @param table - Quantization table
* @param size - Table size of short integers
*/
protected static int quantize(int d, int y, /*short*/int[] table, int size) {
/* LOG
* Compute base 2 log of 'd', and store in 'dl'.
*/
/*short*/int dqm=Math.abs(d); /* Magnitude of 'd' */
/*short*/int exp=quan(dqm>>1, power2, 15); /* Integer part of base 2 log of 'd' */
/*short*/int mant=((dqm<<7)>>exp)&0x7F; /* Fractional part of base 2 log */
/*short*/int dl=(exp<<7)+mant; /* Log of magnitude of 'd' */
/* SUBTB
* "Divide" by step size multiplier.
*/
/* Step size scale factor normalized log */
/*short*/int dln=dl-(y>>2);
/* QUAN
* Obtain codword i for 'd'.
*/
int i=quan(dln, table, size);
if (d<0) /* take 1's complement of i */
return ((size<<1)+1-i);
else if (i==0) /* take 1's complement of 0 */
return ((size<<1)+1); /* new in 1988 */
else
return (i);
}
/** Returns reconstructed difference signal 'dq' obtained from
* codeword 'i' and quantization step size scale factor 'y'.
* Multiplication is performed in log base 2 domain as addition.
* @param sign - 0 for non-negative value
* @param dqln - G.72x codeword
* @param y - Step size multiplier
*/
protected static int reconstruct(int sign, int dqln, int y) {
/* Log of 'dq' magnitude */
/*short*/int dql=dqln+(y>>2); /* ADDA */
if (dql<0) {
return ((sign!=0)? -0x8000 : 0);
}
else {
/* ANTILOG */
/* Integer part of log */
/*short*/int dex=(dql>>7)&15;
/*short*/int dqt=128+(dql&127);
/* Reconstructed difference signal sample */
/*short*/int dq=(dqt<<7)>>(14-dex);
return ((sign!=0)? (dq-0x8000) : dq);
}
}
/** updates the state variables for each output code
* @param code_size - distinguish 723_40 with others
* @param y - quantizer step size
* @param wi - scale factor multiplier
* @param fi - for long/short term energies
* @param dq - quantized prediction difference
* @param sr - reconstructed signal
* @param dqsez - difference from 2-pole predictor
* @param state - coder state
*/
protected static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, G726State state) {
int cnt;
/*short*/int mag, exp, mant; /* Adaptive predictor, FLOAT A */
/*short*/int a2p; /* LIMC */
/*short*/int a1ul; /* UPA1 */
/*short*/int ua2, pks1; /* UPA2 */
/*short*/int uga2a, fa1;
/*short*/int uga2b;
/*char*/int tr; /* tone/transition detector */
/*short*/int ylint, thr2, dqthr;
/*short*/int ylfrac, thr1;
/*short*/int pk0;
// ##### C-to-Java conversion: #####
// init a2p
a2p=0;
pk0=(dqsez<0)? 1 : 0; /* needed in updating predictor poles */
mag=dq&0x7FFF; /* prediction difference magnitude */
/* TRANS */
ylint=state.yl>>15; /* exponent part of yl */
ylfrac=(state.yl>>10)&0x1F; /* fractional part of yl */
thr1=(32+ylfrac)<9)? 31<<10 : thr1; /* limit thr2 to 31<<10 */
dqthr=(thr2+(thr2>>1))>>1; /* dqthr=0.75 * thr2 */
if (state.td==0) /* signal supposed voice */
tr=0;
else
if (mag<=dqthr) /* supposed data, but small mag */
tr=0; /* treated as voice */
else /* signal is data (modem) */
tr=1;
/* Quantizer scale factor adaptation. */
/* FUNCTW&FILTD&DELAY */
/* update non-steady state step size multiplier */
state.yu=y+((wi-y)>>5);
/* LIMB */
if (state.yu<544) /* 544<=yu<=5120 */
state.yu=544;
else
if (state.yu>5120)
state.yu=5120;
/* FILTE&DELAY */
/* update steady state step size multiplier */
state.yl+=state.yu+((-state.yl)>>6);
/*
* Adaptive predictor coefficients.
*/
if (tr==1) {
/* reset a's and b's for modem signal */
state.a[0]=0;
state.a[1]=0;
state.b[0]=0;
state.b[1]=0;
state.b[2]=0;
state.b[3]=0;
state.b[4]=0;
state.b[5]=0;
}
else {
/* update a's and b's */
pks1=pk0^state.pk[0]; /* UPA2 */
/* update predictor pole a[1] */
a2p=state.a[1]-(state.a[1]>>7);
if (dqsez != 0) {
fa1=(pks1!=0)? state.a[0] : -state.a[0];
if (fa1<-8191) /* a2p=function of fa1 */
a2p-=0x100;
else
if (fa1>8191)
a2p+=0xFF;
else
a2p+=fa1>>5;
if ((pk0^state.pk[1])!=0) {
/* LIMC */
if (a2p<=-12160)
a2p=-12288;
else
if (a2p>=12416)
a2p=12288;
else
a2p-=0x80;
}
else
if (a2p<=-12416)
a2p=-12288;
else
if (a2p>=12160)
a2p=12288;
else
a2p+=0x80;
}
/* TRIGB&DELAY */
state.a[1]=a2p;
/* UPA1 */
/* update predictor pole a[0] */
state.a[0] -= state.a[0]>>8;
if (dqsez != 0)
if (pks1==0)
state.a[0]+=192;
else
state.a[0] -= 192;
/* LIMD */
a1ul=15360-a2p;
if (state.a[0]<-a1ul)
state.a[0]=-a1ul;
else if (state.a[0]>a1ul)
state.a[0]=a1ul;
/* UPB : update predictor zeros b[6] */
for (cnt=0; cnt<6; cnt++) {
if (code_size==5) /* for 40Kbps G.723 */
state.b[cnt]-=state.b[cnt]>>9;
else /* for G.721 and 24Kbps G.723 */
state.b[cnt]-=state.b[cnt]>>8;
if ((dq&0x7FFF)!=0) {
/* XOR */
if ((dq^state.dq[cnt])>=0)
state.b[cnt]+=128;
else
state.b[cnt]-=128;
}
}
}
for (cnt=5; cnt>0; cnt--) state.dq[cnt]=state.dq[cnt-1];
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
if (mag==0) {
state.dq[0]=(dq>=0)? 0x20 : 0xFC20;
}
else {
exp=quan(mag, power2, 15);
state.dq[0]=(dq>=0) ? (exp<<6)+((mag<<6)>>exp) : (exp<<6)+((mag<<6)>>exp)-0x400;
}
state.sr[1]=state.sr[0];
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
if (sr==0) {
state.sr[0]=0x20;
}
else
if (sr>0) {
exp=quan(sr, power2, 15);
state.sr[0]=(exp<<6)+((sr<<6)>>exp);
}
else
if (sr>-32768) {
mag=-sr;
exp=quan(mag, power2, 15);
state.sr[0]=(exp<<6)+((mag<<6)>>exp)-0x400;
}
else
state.sr[0]=0xFC20;
/* DELAY A */
state.pk[1]=state.pk[0];
state.pk[0]=pk0;
/* TONE */
if (tr==1) /* this sample has been treated as data */
state.td=0; /* next one will be treated as voice */
else
if (a2p<-11776) /* small sample-to-sample correlation */
state.td=1; /* signal may be data */
else /* signal is voice */
state.td=0;
/*
* Adaptation speed control.
*/
state.dms+=(fi-state.dms)>>5; /* FILTA */
state.dml+=(((fi<<2)-state.dml)>>7); /* FILTB */
if (tr==1)
state.ap=256;
else
if (y<1536) /* SUBTC */
state.ap+=(0x200-state.ap)>>4;
else
if (state.td==1)
state.ap+=(0x200-state.ap)>>4;
else
if (Math.abs((state.dms<<2)-state.dml)>=(state.dml>>3))
state.ap+=(0x200-state.ap)>>4;
else
state.ap+=(-state.ap)>>4;
}
/** At the end of ADPCM decoding, it simulates an encoder which may be receiving
* the output of this decoder as a tandem process. If the output of the
* simulated encoder differs from the input to this decoder, the decoder output
* is adjusted by one level of A-law or u-law codes.
*
* @param sr - decoder output linear PCM sample,
* @param se - predictor estimate sample,
* @param y - quantizer step size,
* @param i - decoder input code,
* @param sign - sign bit of code i
*
* @return adjusted A-law or u-law compressed sample.
*/
protected static int tandem_adjust_alaw(int sr, int se, int y, int i, int sign, /*short*/int[] qtab) {
/*unsigned char*/int sp; /* A-law compressed 8-bit code */
/*short*/int dx; /* prediction error */
/*char*/int id; /* quantized prediction error */
int sd; /* adjusted A-law decoded sample value */
int im; /* biased magnitude of i */
int imx; /* biased magnitude of id */
if (sr<=-32768) sr=-1;
sp= G711Codec.linear2alaw((short)((sr>>1)<<3)); /* short to A-law compression */
dx=(G711Codec.alaw2linear((byte)sp)>>2)-se; /* 16-bit prediction error */
id=quantize(dx, y, qtab, sign-1);
if (id==i) {
/* no adjustment on sp */
return (sp);
}
else {
/* sp adjustment needed */
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
im=i^sign; /* 2's complement to biased unsigned */
imx=id^sign;
if (imx>im) {
/* sp adjusted to next lower value */
if ((sp&0x80)!=0) {
sd=(sp==0xD5)? 0x55 : ((sp^0x55)-1)^0x55;
}
else {
sd=(sp==0x2A)? 0x2A : ((sp^0x55)+1)^0x55;
}
}
else {
/* sp adjusted to next higher value */
if ((sp&0x80)!=0)
sd=(sp==0xAA)? 0xAA : ((sp^0x55)+1)^0x55;
else
sd=(sp==0x55)? 0xD5 : ((sp^0x55)-1)^0x55;
}
return (sd);
}
}
/** @param sr - decoder output linear PCM sample
* @param se - predictor estimate sample
* @param y - quantizer step size
* @param i - decoder input code
* @param sign
* @param qtab
*/
protected static int tandem_adjust_ulaw(int sr, int se, int y, int i, int sign, /*short*/int[] qtab) {
/*unsigned char*/int sp; /* u-law compressed 8-bit code */
/*short*/int dx; /* prediction error */
/*char*/int id; /* quantized prediction error */
int sd; /* adjusted u-law decoded sample value */
int im; /* biased magnitude of i */
int imx; /* biased magnitude of id */
if (sr<=-32768) sr=0;
sp= G711UCodec.linear2ulaw((short)(sr<<2)); /* short to u-law compression */
dx=(G711UCodec.ulaw2linear((byte)sp)>>2)-se; /* 16-bit prediction error */
id=quantize(dx, y, qtab, sign-1);
if (id==i) {
return (sp);
}
else {
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
im=i^sign; /* 2's complement to biased unsigned */
imx=id^sign;
if (imx>im) {
/* sp adjusted to next lower value */
if ((sp&0x80)!=0)
sd=(sp==0xFF)? 0x7E : sp+1;
else
sd=(sp==0)? 0 : sp-1;
}
else {
/* sp adjusted to next higher value */
if ((sp&0x80)!=0)
sd=(sp==0x80)? 0x80 : sp-1;
else
sd=(sp==0x7F)? 0xFE : sp+1;
}
return (sd);
}
}
// ##### C-to-Java conversion: #####
/** Converts a byte into an unsigned int. */
protected static int unsignedInt(byte b) {
return ((int)b+0x100)&0xFF;
}
// ##### 2 bytes to int conversion: #####
/** Converts 2 little-endian-bytes into an unsigned int. */
public static int unsignedIntLittleEndian(byte hi_b, byte lo_b) {
return (unsignedInt(hi_b)<<8) + unsignedInt(lo_b);
}
/** Converts 2 little-endian-bytes into a signed int. */
public static int signedIntLittleEndian(byte hi_b, byte lo_b) {
int sign_bit=hi_b>>7;
return (sign_bit==0)? (unsignedInt(hi_b)<<8) + unsignedInt(lo_b) : (-1^0x7FFF)^(((unsignedInt(hi_b)&0x7F)<<8) + unsignedInt(lo_b));
}
// ************************* NON-STATIC *************************
/** Encoding state */
G726State state;
int type;
/** Creates a new G726 processor, that can be used to encode from or decode do PCM audio data. */
public G726(int type) {
this.type = type;
state=new G726State();
}
public int getType() {
return type;
}
/** Encodes the input vale of linear PCM, A-law or u-law data sl and returns
* the resulting code. -1 is returned for unknown input coding value. */
public abstract int encode(int sl, int in_coding);
/** Encodes the input chunk in_buff of linear PCM, A-law or u-law data and returns
* the G726 encoded chuck into out_buff.
* It returns the actual size of the output data, or -1 in case of unknown
* in_coding value. */
public abstract int encode(byte[] in_buff, int in_offset, int in_len, int in_coding, byte[] out_buff, int out_offset);
/** Decodes a 4-bit code of G.72x encoded data of i and
* returns the resulting linear PCM, A-law or u-law value.
* return -1 for unknown out_coding value. */
public abstract int decode(int i, int out_coding);
/** Decodes the input chunk in_buff of G726 encoded data and returns
* the linear PCM, A-law or u-law chunk into out_buff.
* It returns the actual size of the output data, or -1 in case of unknown
* out_coding value. */
public abstract int decode(byte[] in_buff, int in_offset, int in_len, int out_coding, byte[] out_buff, int out_offset);
}