;
; This program, originally available on the Motorola DSP bulletin board,
; is provided under a DISCLAIMER OF WARRANTY available from Motorola DSP
; Operation, 6501 William Cannon Drive, West, Austin, Texas  78735-8598.
;
        ident   1,1
        page    132,56,1,1

        opt     mex,nomd,cex
;
;       Discrete Cosine Transform (DCT)
;
;	V1.2
;	03 Oct 88
;
;       The DCT is implemented by using the method described in
;       "On the Computation of the Discrete Cosine Transform", IEEE
;       Transactions on Communications. Vol COM-26, No. 6, June 1978
;
;       The operation of this transform is as follows:
;           1.  Resort the original sequence.
;           2.  Perform an FFT on the modified sequence.
;           3.  Multiply the output of the FFT by a complex exponential
;               and take the real part.
;           4.  Perform a bit reversed sort to unscramble the result.
;
;       After the transform, the data needs to be scaled (according to
;       the previously cited reference):
;           g(0) = g(0)*1.414/N
;           g(k) = g(k)*2.0/N       k=1,2,...,N-1
;       This scaling is NOT performed by this program.  This type of scaling
;       is application dependent and some implementations may not require
;       the scaling.
;


        include 'sincos'
        include 'fftr2aa'

start   equ     $100            ;beginning of program in P memory
points  equ     16              ;number of points in dct
data    equ     0               ;address of data in Y memory
coef    equ     16              ;address of coefficients

        sincos  points,coef     ;generate twiddle factor for FFT.

;       Generate exponential table after twiddle factor table.
;
;       This generates the scale factor of EXP(-j*pi*k/(2*N)).
;       The real part is in Y memory and the imaginary part is
;       in X memory.  Note that the negative of the part in Y memory
;       is actually stored so that a -1 (exactly) can be represented
;       with the fractional arithmetic.  This negative sign is
;       compensated when the actual rotation is performed.
;
rot     equ     pi/@cvf(2*points)

        org     x:
exptbl
count   set     0
        dup     points
        dc      -@sin(@cvf(count)*rot)
count   set     count+1
        endm

        org     y:
count   set     0
        dup     points
        dc      -@cos(@cvf(count)*rot)
count   set     count+1
        endm



        org     p:start
;
;       Do inital sort. The input data is in Y, the sorted data goes to X.
;       This forms a new sequence in X memory from the sequence in Y memory
;       according to the definition:
;               x(k)=y(2k)
;               x(N-1-K)=x(2k+1)      k=0,1,...,N/2-1
;
        move    #$ffff,m0               ;set linear
        move    m0,m4                   ;ditto
        move    #data,r0                ;point to data
        move    #2,n0                   ;jump by even numbers
        move    r0,r4                   ;copy data pointer
        move    y:(r0)+n0,a             ;get first point
        rep     #points/2               ;sort even points
        move    y:(r0)+n0,a  a,x:(r4)+
        move    #data+1,r0              ;point to odds
        move    #data+points-1,r4       ;odds output
        move    y:(r0)+n0,a             ;get first odd
        rep     #points/2               ;sort odd points
        move    y:(r0)+n0,a  a,x:(r4)-
        clr     a       #data,r0        ;get a zero, point r0 to data
        rep     #points                 ;clear out original data
        move    a,y:(r0)+

;
;       Do an FFT on the new sequence
;
        fftr2aa  points,data,coef        ;do FFT

;
;       Multiply the output by a complex exponential and take the
;       real part.  dct=re[ (a+jb)*(c+jd)] = a*c-b*d where a+jb is the
;       output of the FFT and c+jd is the rotation factor. Note that
;       the data is still in bit reversed order but the rotation
;       table is in sequential order.  Thus, the data is accessed with
;       bit reversed addressing but the rotation table is addressed
;       with linear addressing.
;
        move    #exptbl,r0              ;point to exponential table
        move    #$ffff,m0               ;linear addressing

        move    #data,r4                ;point to output of fft
        move    r4,r5                   ;copy data pointer
        move    #0,m4                   ;bit reversed addressing
        move    m4,m5
        move    #points/2,n4
        move    n4,n5

        move    x:(r4),x0  y:(r0),y0                    ;get a,-c
        do      #points,_gf                             ;do all points
        mpy     -x0,y0,a  x:(r0)+,x1   y:(r4)+n4,y1     ;-a*c, get d,b
        macr    -x1,y1,a  x:(r4),x0    y:(r0),y0        ;-b*d, get a,c
        move              a,x:(r5)+n5                   ;save dct
_gf

;
;       Bit reverse the output. The rotated and bit reversed data from X
;       memory is transfered to Y memory and unscrambled.  The resulting
;       DCT is in Y memory starting at DATA with length POINTS.
;
        move    #data,r0                ;point to data
        move    #points/2,n0            ;number of points/2
        move    #0,m0                   ;set reverse carry

        move    r0,r4                   ;copy pointer
        move    #$ffff,m4               ;set linear

        move    x:(r0)+n0,a             ;do preload
        rep     #points                 ;unscramble
        move    x:(r0)+n0,a   a,y:(r4)+

        end
^Z
