www.pudn.com > ADPCM语音压缩算法C源码.rar > AD_PCM.asm


****************************************************************************** 
****************************************************************************** 
****                 TMS320C54x用ADPCM编解码程序V0.1                      **** 
****                      All right reserved                              **** 
****                         版权所有                                     **** 
****                     程序设计:罗茂才                                  ****  
****                 E-mail: luomc@neusoft.com                            **** 
****                         luomao2000@163.net                           **** 
****                         luomao1977@sina.com                          **** 
****                                                                      **** 
****  本程序参照Stichting Mathematisch Centrum, Amsterdam,The Netherlands **** 
****  所写的C语言ADPCM编解码程序设计,作者不承担任何可能侵犯版权的后果。  **** 
****                                                                      **** 
****  允许自由使用、复制、修改、传播该程序,可免费用于商业用途,但不得以  **** 
****  该程序作为主体获得利益。无论在什么情况下使用,都请保留该版权信息。  ****                  
****  作者不保证该程序能完全正确按照你的要求运行,所有由于使用该程序      **** 
****  造成的损失,后果自负(呵呵,我可没有特意留下什么隐患啊)。          **** 
****  如果你利用了该程序,请告诉一声(我想知道有多少人会使用这个程序)。    **** 
****  如果你对该程序有任何建议、错误信息反馈等,敬请与作者联系            **** 
****  (请采用Algebraic assembly方式汇编该文件)                            **** 
****                                                                      **** 
****            感谢我的老婆给予我的爱、关心以及支持。                    ****  
****                                                  2003年7月31日       **** 
****************************************************************************** 
****************************************************************************** 
 
* 
* 编码函数C语言声明 
* extern void AdpcmEncoder(int* pBufferIn, int* pBufferOut,  
*		   			       int* pPrevValue,int* pPrevIndex, int Length); 
* 解码函数C语言声明(解码长度为实际解码后长度的1/4) 
* extern void AdpcmDecoder(int* pBufferIn, int* pBufferOut,  
*					       int* pPrevValue,int* pPrevIndex, int Length); 
* 
* 编解码后的PrevValue和PrevIndex都被修改,在后续的编解码中将继续被使用 
* 
* CCS2.1下测试通过 
 
 .title "Intel/DVI ADPCM coder/decoder" 
 .def _AdpcmEncoder 
 .def _AdpcmDecoder 
 .mmregs 
 
 ;索引表  
 .data 
IndexTable:    ; 实际上只用了15个,考虑到速度问题,有一个舍弃了  
   .word  -8, -5, -3, -1, 1, 3, 5, 8 
   .word  8,  5,  3,  1, -1,-3,-5,-8 
    
 ;步进量    
StepSizeTable:  ; 共84个 
   .word     4,     5,     6,     7,    8,     9,   10,    11,    12,    14 
   .word    16,    18,    20,    22,   25,    28,   32,    36,    42,    49 
   .word    57,    67,    78,    90,  103,   118,  134,   152,   170,   189  
   .word   209,   230,   253,   279,  307,   337,  371,   408,   449,   494 
   .word   544,   598,   658,   724,  796,   876,  963,  1060,  1166,  1282 
   .word  1411,  1552,  1707,  1878, 2066,  2272, 2499,  2749,  3024,  3327 
   .word  3660,  4026,  4428,  4871, 5358,  5894, 6484,  7132,  7845,  8630 
   .word  9493, 10442, 11487, 12635,13899, 15289,16818, 18500, 20350, 22385 
   .word 24623, 27086, 29794, 32767 
  
     
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
; 寄存器使用规则(调用时不设置) 
; AR0: 临时变量 
; AR2: 输入缓冲区指针 
; AR3: 输出缓冲区指针 
; AR4: 步进量地址指针 
; AR5: 当前输出数据计数器(0--3: 16位长度可保存4个编码数据) 
	.asg *SP(3), pBufferOut 
	.asg *SP(4), pPrevValue 
	.asg *SP(5), pPrevIndex 
	.asg *SP(6), Length 
	 
	.asg *SP(0), PrevValue      ; 占用了这两个堆栈位置,存放临时数据 
	.asg *SP(1), PrevIndex      ; 
   .text 
_AdpcmEncoder: 
    TC = (*SP(4) == #0)         ; 首先检测缓冲区长度是否为0,为0则结束 
    if(TC) dgoto EncoderEnd 
    AR5 = #4                    ; 设置计数器初值 
    SP += -2                    ; 调整堆栈指针,以便利用其中的两个子 
	AR2 = A                     ; 读取输入缓冲区地址 
    B = pBufferOut              ; 读入输出缓冲区地址 
    AR3 = B 
    B = pPrevValue              ; 读入上次转换值地址  
    AR0 = B 
    ASM = #0 
    SXM = 1                     ; 设置符号位扩展 
    Length -= 1                 ; 长度减1 
    A = pPrevIndex              ; 读取上次转换的索引 
    B = *AR0                   
    AR0 = A 
    PrevValue = B               ; 读取上次转换值         
    FRCT = 0  
    A = *AR0                     
    PrevIndex = A               ; 保存上次转换索引 
    A = Length                  ; 读取转换长度  
    BRC = A                     ; 设置块循环计数器 
    A = PrevIndex  
    DBLOCKREPEAT(EncoderLoopEnd-1)    ; 启动块循环(根据循环最后一条指令确定是1还是2) 
    *AR3 = #0                   ; 输出缓冲区第一个字清零 
EncoderLoop: 
    A += #StepSizeTable         ; 偏移  
    AR4 = A                     ; 取得步进基地址 + 偏移 
    B = *AR2+                   ; 取得输入缓冲区的值(没有必要规范到-32768...+32767) 
    B -= PrevValue              ; 获得当前值与上次计算值之间的差值 
	 
    A = |B|                     ; 计算delta=diff/step,并将商规范到-8...+7 
    REPEAT(#16)                 ; 循环减(做除法)多除了一次,相当于商×2 
    SUBC(*AR4, A)  
    A += #1                     ; 调整0.5的差值 
    A &= #0FFFFh                ; (清除高位无效数据)  
    A = A >> 1 
    if(BGEQ) DGOTO EncoderSetDelta  ; 检测是否是负数 
    B = #7                      ; 将Delta数据规范到-8...+7 
    A = MIN(A, B) 
     
    A = -A                      ; 是负数,商取负 
EncoderSetDelta:     
    ;B = #-8                    ; 已经规范到0--7了,取负数后也没有关系 
    ;A =MAX(A, B) 
 
    T = A     
                                ; 计算PrevValue值,并将其规范到(-32768)--(+32767)  
    B = T*(*AR4)                ; 获得Delta*Step的值,保存在B寄存器中 
    B += PrevValue              ; 计算上次值与这次差值的和 
    ;B += *AR4 >> 1 
    B = B <> 1 
    B = B <> 16                   ; 调整PrevIndex的值 
	A &= #0Fh                     ; 并将其调整在0...83之间 
    AR0 = A 
    B = #0 
    A = PrevIndex 
    A += *AR0(IndexTable) 
    A = MAX(A, B)                  
    B = #83 
    A = MIN(A, B) 
    PrevIndex = A 
DecoderLoopEnd:     
    B = pPrevValue                 ; 设置PrevValue和PrevIndex 
    AR0 = B 
    B = PrevValue 
    A = pPrevIndex 
    AR2 = A 
    A = PrevIndex 
    *AR0 = B 
    *AR2 = A 
    SP += 2                        ; 将堆栈指针调整回原来的值 
    NOP                            ; 避免冲突用的 
DecoderEnd:     
    RETURN 
     
 .end