📄 adpcm.dsp
字号:
{
The code below represents a full duplex Adaptive Differential
Pulse Code Modulation (ADPCM) transcoder. This program has been
developed in accordance with ANSI specification T1.301-1987 and
CCITT G.721 (bis). It is fully bit-compatible with the test
vectors supplied by both of these organizations.
An Application Note is available which describes the operation
of the algorithm in detail. A copy of this Note can be obtained
from Analog Devices, DSP Division.
Analog Devices American National Consultive Committee
DSP Division Standards Institute on International
P.O. Box 9106 1430 Broadway Telephone and Telegraph
Norwood, Ma 02062-9106 New York, N.Y. 10018
(617) 461 - 3672
Gordon A. Sterling
Analog Devices
DSP Division
6/28/88
Calling Parameters
AR = Companded PCM value (encoder)
ADPCM I value (decoder)
M0=3; L0=18;
M1=1; L1=6;
M2=-1
L3=0;
M4=0 L4=6;
M5=1 L5=2
M6=-1 L6=5
Return Values
AR = ADPCM I value (encoder)
Companded PCM value (decoder)
Altered Registers
AX0, AX1, AY0, AY1, AF, AR,
MX0, MX1, MY0, MY1, MR,
I0, I1, I3, I4, I5, I6
SI, SR
M3
Cycle Count
467 cycles for encode
514 cycles for decode
}
.MODULE Adaptive_Differential_PCM;
.ENTRY adpcm_encode, adpcm_decode;
.VAR/PM/CIRC b_buf[6]; {b coefficients for encode}
.VAR/PM/CIRC a_buf[2]; {a coefficients for encode}
.VAR/PM/CIRC b_buf_r[6]; {b coefficients for decode}
.VAR/PM/CIRC a_buf_r[2]; {a coefficients for decode}
.VAR/DM/CIRC b_delay_r[18]; {dq delay for decode}
.VAR/DM/CIRC a_delay_r[6]; {sr delay for decode}
.VAR/DM/CIRC b_delay[18]; {dq delay for encode}
.VAR/DM/CIRC a_delay[6]; {sr delay for encode}
.VAR/DM/CIRC mult_data[5]; {Predictor immediate data}
.VAR/DM qn_values[10],dq_values[8]; {quantizer and dequantizer data}
.VAR/DM f_values[12], w_values[8]; {Update coefficient data}
.VAR/DM a_data[10];
.VAR/DM s_e,s_r,a_ik,dq,p;
.VAR/DM sez,sl,yu,yl_h,yl_l,y,y_2,ap,p_o,p_o_o,dms,dml,tdp,tr;
.VAR/DM a_ik_r,dq_r,p_r;
.VAR/DM yu_r,yl_h_r,yl_l_r,ap_r,p_o_r;
.VAR/DM p_o_o_r,dms_r,dml_r,tdp_r;
.VAR/DM sp_r; {PCM code word for synchronous adj}
.VAR/DM hld_a_t, hld_b_t, hld_a_r, hld_b_r;
.INIT qn_values: 7, 14, H#3F80,
400, 349, 300, 246, 178, 80, H#FF84;
.INIT dq_values : h#F800, 4, 135, 213, 273, 323, 373, 425;
.INIT f_values : -5, 0, 5120, 544,
0, 0, 0, 512, 512, 512, 1536, 3584;
.INIT w_values: 65344, 288, 656, 1024, 1792, 3168, 5680, 17952;
.INIT mult_data : H#1FFF, H#4000, h#7E00, H#7FFF, H#FFFE;
.INIT a_data : H#1FFF, 2, 16384, 0, -7, 192, H#3000, H#D000,
H#D200, H#3C00;
.INIT hld_a_t : ^a_delay;
.INIT hld_b_t : ^b_delay;
.INIT hld_a_r : ^a_delay_r;
.INIT hld_b_r : ^b_delay_r;
.INIT b_buf : 0,0,0,0,0,0; {2.14}
.INIT a_buf : 0,0; {2.14}
.INIT b_delay : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0; {16.0, 16.0, 0.16}
.INIT a_delay : 0,0,0,0,0,0; {16.0, 16.0, 0.16}
.INIT p : 0; {16.0}
.INIT yu :0; {7.9}
.INIT yl_h : 0; {7.9}
.INIT yl_l : 0; {0.16}
.INIT ap : 0; {8.8}
.INIT p_o : 0; {16.0}
.INIT p_o_o : 0; {16.0}
.INIT dms : 0; {7.9}
.INIT dml : 0; {5.11}
.INIT tdp : 0; {16.0}
.INIT b_buf_r : 0,0,0,0,0,0; {2.14}
.INIT a_buf_r : 0,0; {2.14}
.INIT b_delay_r : 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;{16.0, 16.0, 0.16}
.INIT a_delay_r : 0,0,0,0,0,0; {16.0, 16.0, 0.16}
.INIT p_r : 0; {16.0}
.INIT yu_r :0; {7.9}
.INIT yl_h_r : 0; {7.9}
.INIT yl_l_r : 0; {0.16}
.INIT ap_r : 0; {8.8}
.INIT p_o_r : 0; {16.0}
.INIT p_o_o_r : 0; {16.0}
.INIT dms_r : 0; {7.9}
.INIT dml_r : 0; {5.11}
.INIT tdp_r : 0; {16.0}
adpcm_encode: I4=^b_buf; {Set pointer to b-coefficients}
I5=^a_buf; {Set pointer to a-coefficients}
I6=^mult_data; {Set pointer to predictor data}
I1=DM(hld_a_t); {Restore pointer to s_r delay}
I0=DM(hld_b_t); {Restore pointer to dq delay}
CALL expand; {Expand 8-bit log-PCM to12 bits}
DM(sl)=AR; {Store linear PCM value in sl}
CALL predict; {Call s_e and sez predictors}
AX1=DM(ap);
AY0=DM(yl_h);
AX0=DM(yu);
CALL lima; {Limit ap and compute y}
DM(y)=AR; {Save y for later updates}
DM(y_2)=SR1; {Save y>>2 for log and reconst}
AX0=DM(sl);
AY0=DM(s_e);
AY1=SR1, AR=AX0-AY0; {Compute difference signal, d}
CALL log; {Determine I value from d}
DM(a_ik)=AR;
CALL reconst; {Compute dq based ONLY on }
DM(dq)=AR;
AY0=DM(s_e);
AR=AR+AY0; {Compute reconstructed signal}
DM(s_r)=AR;
DM(I1,M1)=AR, AR=ABS AR; {Convert s_r to floating point}
SR1=H#4000; {Set SR1 to minimum value}
SE=EXP AR (HI); {Determine exponent adjust}
AX0=SE, SR=SR OR NORM AR (HI); {Normalize into SR}
SR=LSHIFT SR1 BY -9 (HI); {Delete lower bits}
AY0=11; {Base exponent}
SR=LSHIFT SR1 BY 2 (HI); {Adjust for ADSP-210x version}
AR=AX0+AY0; {Compute exponent}
DM(I1,M1)=AR; {Save exponent}
DM(I1,M1)=SR1; {Save mantissa}
MR1=DM(tdp);
SI=DM(yl_h);
AX1=DM(dq);
CALL trans; {Compute new trigger }
DM(tr)=AR;
AR=PASS AR; {Check state of trigger}
IF EQ CALL update_filter; {Update filter if trigger false}
MR0=DM(ap); {Load variables for updating}
MR1=DM(y);
MR2=DM(tdp); {Always load MR2 after MR1!}
MY0=DM(yl_h);
MY1=DM(yl_l);
AY0=DM(y);
MX0=DM(dms);
MX1=DM(dml);
CALL functw; {Update variables}
DM(ap)=AR; {Store updated variables}
DM(yu)=AX1;
DM(yl_l)=MY1;
DM(yl_h)=MY0;
DM(dms)=MX0;
DM(dml)=MX1;
AY1=DM(tr); {Load trigger }
AF=PASS AY1; {Check state of trigger}
IF NE CALL trigger_true; {Call only if trigger true}
AX0=DM(a_ik); {Get I value for return}
AY0=H#F; {Only 4 LSBs are used}
AR=AX0 AND AY0; {So mask redundant sign bits}
DM(hld_a_t)=I1; {Save s_r delay pointer}
DM(hld_b_t)=I0; {Save dq delay pointer}
RTS; {Return to caller}
adpcm_decode: I1=DM(hld_a_r); {Restore s_r delay pointer}
I0=DM(hld_b_r); {Restore dq delay pointer}
I4=^b_buf_r; {Set pointer to b-coefficients}
I5=^a_buf_r; {Set pointer to a-coefficients}
I6=^mult_data; {Set pointer to predictor data}
SR=LSHIFT AR BY 12 (HI); {Get sign of ADPCM I value here}
SR=ASHIFT SR1 BY -12 (HI); {Sign extend ADPCM value to 16}
DM(a_ik_r)=SR1; {Save I value}
CALL predict; {Call s_e and sez predictor}
AX1=DM(ap_r);
AY0=DM(yl_h_r);
AX0=DM(yu_r);
CALL lima; {Limit ap and compute y}
DM(y)=AR;
DM(y_2)=SR1;
AY1=DM(y_2);
AR=DM(a_ik_r);
CALL reconst; {Compute dq from received I}
DM(dq_r)=AR;
AY0=DM(s_e);
AR=AR+AY0; {Compute reconstructed signal}
DM(s_r)=AR;
DM(I1,M1)=AR, AR=ABS AR; {Make s_r floating point}
SR1=H#4000; {Set SR1 to minimum value}
SE=EXP AR (HI); {Determine exponent adjust}
AX0=SE, SR=SR OR NORM AR (HI); {Normalize value}
SR=LSHIFT SR1 BY -9 (HI); {Remove LSBs per spec}
AY0=11; {Base exponent}
SR=LSHIFT SR1 BY 2 (HI); {Adjust for ADSP-210x version}
AR=AX0+AY0; {Compute exponent}
DM(I1,M1)=AR; {Store exponent}
DM(I1,M1)=SR1; {Store mantissa}
MR1=DM(tdp_r);
SI=DM(yl_h_r);
AX1=DM(dq_r);
CALL trans; {Compute new trigger}
DM(tr)=AR;
AR=PASS AR; {Check state of trigger}
IF EQ CALL update_filter_r; {Update filter if trigger false}
AY0=DM(y); {Load uariables for updating}
MY1=DM(yl_l_r);
MY0=DM(yl_h_r);
MR0=DM(ap_r);
MR1=DM(y);
MR2=DM(tdp_r); {Always load MR2 after MR1!}
MX0=DM(dms_r);
MX1=DM(dml_r);
CALL functw; {Update variables}
DM(yu_r)=AX1; {Stored updated variables}
DM(yl_l_r)=MY1;
DM(yl_h_r)=MY0;
DM(ap_r)=AR;
DM(dms_r)=MX0;
DM(dml_r)=MX1;
AY1=DM(tr); {Load current trigger}
AF=PASS AY1; {Check state of trigger}
IF NE CALL trigger_true_r; {Call only if trigger true}
CALL compress; {Compress PCM value}
DM(sp_r)=AR; {Save original value for sync}
CALL expand; {Expand for sync coding adj}
AY0=DM(s_e);
AR=AR-AY0; {Compute dx for sync coding}
AY1=DM(y_2);
CALL log; {Compute new dqx value}
CALL sync; {Adjust PCM value by +1,-1, 0}
DM(hld_a_r)=I1; {Save s_r delay pointer}
DM(hld_b_r)=I0; {Save dq delay pointer}
RTS;
compress: AR=DM(s_r); {Get reconstructed signal}
AR=ABS AR; {Take absolute value}
AY0=33; {Add offset of boundries}
AR=AR+AY0;
AY0=8191; {Maximum PCM value}
AF=AR-AY0; {Cap input}
IF GT AR=PASS AY0; {If in excess}
SE=EXP AR (HI); {Find exponent adjustmet}
AX0=SE, SR=NORM AR (LO); {Normalize input}
AY0=H#4000;
AR=SR0 XOR AY0; {Remove first significant bit}
SR=LSHIFT AR BY -10 (LO); {Shift position bits}
AR=PASS AY0;
IF POS AR=PASS 0; {Create sign bit}
SR=SR OR LSHIFT AR BY -7 (LO); {Position sign bit}
AY0=9;
AR=AX0+AY0; {Compute segment}
IF LT AR=PASS 0;
SR=SR OR LSHIFT AR BY 4 (LO); {Position segment bits}
AY0=H#FF;
AR=SR0 XOR AY0; {Invert bits}
RTS;
expand: AY0=H#FF; {Mask unwanted bits}
AF=AR AND AY0, AX0=AY0;
AF=AX0 XOR AF; {Invert bits}
AX0=H#70;
AR=AX0 AND AF; {Isolate segment bits}
SR=LSHIFT AR BY -4 (LO); {Shift to LSBs}
SE=SR0, AR=AR XOR AF; {Remove segment bits}
AY0=H#FF80;
AF=AR+AY0;
IF LT JUMP posval; {Detemine sign}
AR=PASS AF;
AR=AR+AF; {Shift left by 1 bit}
AY0=33;
AR=AR+AY0; {Add segment offset}
SR=ASHIFT AR (LO); {Position bits}
AR=AY0-SR0; {Remove segment offset}
RTS;
posval: AF=PASS AR;
AR=AR+AF; {Shift left by 1}
AY0=33;
AR=AR+AY0; {Add segment offset}
SR=ASHIFT AR (LO);
AR=SR0-AY0; {Remove segment offset}
RTS;
predict: AX1=DM(I0,M2), AY1=PM(I4,M6); {Point to dq6 and b6}
AF=PASS 0, SI=PM(I4,M4); {AF hold partial sum}
AY0=DM(I6,M5);
MX1=3; {This multiply will give the}
MY1=32768; {+48>>4 term}
SR=ASHIFT SI BY -2 (HI); {Downshift b6 per spec}
CNTR=6; {Loop once for each b}
DO sez_cmp UNTIL CE;
AR=ABS SR1, SR1=DM(I6,M5); {Get absolute value of b}
AR=AR AND AY0, AY0=DM(I6,M5);{Mask bits per spec}
SE=EXP AR (HI), MY0=DM(I0,M2);{Find exponent adjust}
AX0=SE, SR=SR OR NORM AR (HI);{Compute bnMANT}
AR=SR1 AND AY0, AY0=DM(I0,M2);{Mask bits per spec}
MR=AR*MY0 (SS), AX1=DM(I0,M2), AY1=PM(I4,M6);
AR=AX0+AY0, AY0=DM(I6,M5); {Compute WbEXP}
SE=AR, MR=MR+MX1*MY1 (SU); {Compute WbnMANT}
SR=LSHIFT MR1 (HI), SE=DM(I6,M5);{Compute Wbn}
AR=SR1 AND AY0, SI=PM(I4,M4);{Mask Wbn per spec}
AX0=AR, AR=AX1 XOR AY1; {Determine sign of Wbn}
AR=AX0, SR=ASHIFT SI (HI); {Downshift b(n-1) per spec}
IF LT AR=-AX0; {Negate Wbn if necessary}
sez_cmp: AF=AR+AF, AY0=DM(I6,M5); {Add Wbn to partial sum}
AR=PASS AF, AX1=DM(I0,M1), AY1=PM(I5,M6);{Get sezi}
SR=ASHIFT AR BY -1 (HI); {Downshift to produce sez}
DM(sez)=SR1;
SI=PM(I5,M4); {Get a2}
SR=ASHIFT SI (HI); {Downshift a2 per spec}
AX1=DM(I1,M2), AY1=PM(I4,M5); {Restore bn and dqn pointers}
CNTR=2; {Loop once for each a}
DO s_e_cmp UNTIL CE;
AR=ABS SR1, SR1=DM(I6,M5); {Get absolute value of a}
AR=AR AND AY0, AY0=DM(I6,M5);{Mask bits per spec}
SE=EXP AR (HI), MY0=DM(I1,M2);{Get exponent adjust for a}
AX0=SE, SR=SR OR NORM AR (HI);{Compute anMANT}
AR=SR1 AND AY0, AY0=DM(I1,M2);{Mask bits per spec}
MR=AR*MY0(SS), AX1=DM(I1,M2), AY1=PM(I5,M6);
AR=AX0+AY0, AY0=DM(I6,M5); {Compute WanEXP}
SE=AR, MR=MR+MX1*MY1 (SU); {Complete WanMANT computation}
SR=LSHIFT MR1 (HI), SE=DM(I6,M5);{Compute Wan}
AR=SR1 AND AY0, SI=PM(I5,M4);{Mask Wan per spec}
AX0=AR, AR=AX1 XOR AY1; {Determine sign of Wan}
AR=AX0, SR=ASHIFT SI (HI); {Downshift a1 per spec}
IF LT AR=-AX0; {Negate Wan if necessary}
s_e_cmp: AF=AR+AF, AY0=DM(I6,M5); {Add Wan to partial sum}
AR=PASS AF, AX1=DM(I1,M1), AY1=PM(I5,M5);{Get sei}
SR=ASHIFT AR BY -1 (HI); {Compute se}
DM(s_e)=SR1;
RTS;
lima: AY1=256; {Maximum value for ap}
AR=AX1, AF=AX1-AY1; {Cap if it exceeds}
IF GE AR=PASS AY1;
SR=ASHIFT AR BY -2 (HI); {>>2 to produce al}
SR=LSHIFT SR1 BY 9 (HI); {Adjust for ADSP-210x version}
mix: MY0=SR1, AR=AX0-AY0; {MY0=al, AR=diff}
AR=ABS AR; {Take absolute value of diff}
MR=AR*MY0 (SU); {Generate prod}
AR=MR1+AY0; {Add to yu}
IF NEG AR=AY0-MR1; {Subtract if diff < 0}
SR=ASHIFT AR BY -2 (HI); {Generate y>>2}
RTS;
log: I3=^qn_values; {Point to data array}
AR=ABS AR, AX1=DM(I3,M1); {Take absolute of d}
SE=EXP AR (HI), AX0=DM(I3,M1); {Determine exponent adjust}
AY0=SE, SR=NORM AR (HI); {Normalize}
AR=AX0+AY0, AY0=DM(I3,M1); {Compute exponent}
IF LT AR=PASS 0; {Check for exponent -1}
SI=AR, AR=SR1 AND AY0; {Mask mantissa bits}
SR=LSHIFT AR BY -7 (HI); {Position mantissa}
SR=SR OR LSHIFT SI BY 7 (HI); {Position exponent}
subtb: AR=SR1-AY1, AY0=DM(I3,M1); {Subtract y>>2 for log}
AX0=AR, AF=PASS AX1; {Setup for quantizing}
quan: AR=AX0-AY0, AY0=DM(I3,M1); {Is dl less then upper limit?}
IF LT AF=AF-1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -