**
**
** Misc_funcs.asm
**
** $VER: Misc_funcs.asm 1.5 (22.10.99)
**
** Fonctions specialement optimisees en assembleur
**
** $Revision: 1.4 $
** $State: Exp $
** $Date: 1998/08/16 19:03:42 $
**
** $Log: Misc_funcs.asm $
** Revision 1.4  1998/08/16 19:03:42  kakace
** Version Beta3+
**
** Revision 1.3  1998/08/09 19:20:42  kakace
** Correction d'un bug dans la routine Fast_FFT_T
**
** Revision 1.2  1998/08/02 15:17:08  kakace
** Fonctionnement OK (Layer 1/2 + Stereo/JStereo)
**
**

        OPT P=68030/68882,ALINK


        INCLUDE "Exec/Types.i"
        INCLUDE "Exec.i"


        USE_QUICK_PUTBITS:      EQU     1


*----------------------------------------------------------------------------------------------------*
*======================================= Définitions diverses =======================================*
*----------------------------------------------------------------------------------------------------*

 IFND   FLOAT_DOUBLE
        FLOAT_DOUBLE:   EQU     1
 ENDC


* Les fonctions sont conçues pour utiliser des DOUBLE.

 IFEQ   FLOAT_DOUBLE
        FAIL    FLOAT_DOUBLE != 1
 ENDC


* La version 68020 n'utilise pas le FPU

        XREF    _a_dAnaWindow


 SECTION "CPU_TYPE",DATA

 IFNE   CPU_TYPE=68030
        dc.b    "68030",0
 ENDC
 IFNE   CPU_TYPE=68040
        dc.b    "68040",0
 ENDC
 IFNE   CPU_TYPE=68060
        dc.b    "68060",0
 ENDC



*----------------------------------------------------------------------------------------------------*
*======================================= Fonctions optimisées =======================================*
*----------------------------------------------------------------------------------------------------*

        IFEQ CPU_TYPE=68020

        SECTION INITFPU

;        XDEF    _INIT_0_FPU
;_INIT_0_FPU

        XDEF    _InitFPCR
        XREF    _SysBase

_InitFPCR:      movea.l   _SysBase,a0
                btst      #4,$129(a0)           ; AFB_68881
                beq.s     .exit

                fmove.l   FPCR,d0
                and.l     #$000000CF,d0
                or.l      #$00000010,d0         ; ROUND = Toward Zero (RZ)
                fmove.l   d0,FPCR               ; PREC  = Extended
.exit           rts

*/// SetupWinSamples_1024
******* Misc_funcs/SetupWinSamples_1024 *************************************
*
*   NAME
*   PsychoC::SetupWinSamples_1024 -- Préparer les données pour la FFT.
*
*   SYNOPSIS
*   PsychoC::SetupWinSamples_1024(pSamples, wNumChannels, pdHANNWindow,
*                                 pdWsmpls)
*
*   void PsychoC::SetupWinSamples_1024(WORD *, UWORD, const REAL *, REAL *);
*
*   FUNCTION
*   Initialise le tampon d'entrée de la FFT à partir d'un bloc contenant 1024
*   échantillons.
*   Lorsque le fichier audio traité est stéréo, les deux canaux sont préparés
*   simultanément.
*
*   INPUTS
*   pSamples     - Pointeur vers les échantillons.
*   wNumChannels - Nombre de canaux.
*   pdHANNWindow - Pointeur vers la table des coeffs.
*   pdWSmpls     - Pointeur vers le tableau d'entrée de la FFT.
*
*   NOTES
*   Afin de tirer partie des symétries de la FFT, les deux canaux sont
*   préparés de sorte que l'un corresponde à la partie réelle, et l'autre
*   à la partie imaginaire. De fait, la FFT effectue son calcul sur les deux
*   canaux simultanément.
*
*   Pour un fichier mono, les échantillons sont alternativement placés dans
*   la partie réelle (échantillons d'indices pairs) ou la partie imaginaire
*   (échantillons d'indices impairs) du tampon d'entrée. De cette façon, la
*   fonction FFT peut être fortement optimisée.
*
*   BUGS
*   Fonction contrôlée conforme le 09.07.98
*
*****************************************************************************
*
*

        SECTION "_SetupWinSamples_1024:0",CODE

;void SetupWinSamples_1024(WORD *pSamples, UWORD wNumChannels, const REAL *pdHANNWindow, REAL *pdWSmpls)

                XDEF    _SetupWinSamples_1024

ShuffleArray:   dc.b    0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15
                EVEN

SHUFFLE_8       MACRO
                move.w  d1,d0
                move.w  d1,d2
                and.w   #$F,d0                  ; bits 0-3
                lsr.w   #4,d2                   ; bits 4-7
                move.b  0(a4,d0.w),d0           ; nouveaux bits 4-7
                move.b  0(a4,d2.w),d2           ; nouveaux bits 0-3
                asl.b   #4,d0                   ; Mise en forme.
                or.b    d2,d0                   ; Index (bit-reverse) dans d0.
                ENDM


_SetupWinSamples_1024

                PUSH    d2/a2-a4,SetupWinSamples_1024

                DEFINE  SetupWinSamples_1024
                CPTR    pSamples
                UWORD   wNumChannels
                CPTR    pdHANNWindow
                CPTR    pdWSmpls

                move.w  wNumChannels(sp),d0
                move.l  pdWSmpls(sp),a0
                move.l  pdHANNWindow(sp),a1
                move.l  pSamples(sp),a3
                lea     ShuffleArray(pc),a4

        ;------ La préparation des échantillons diffère selon que l'on opère sur un
        ;       fichier Mono ou Stereo.

                moveq   #0,d1                   ; Initialiser l'indice de boucle.
                subq.w  #1,d0
                beq     .Mono_loop

        ;------ Boucle principale pour un fichier Stereo.

.Stereo_loop

        ;------ Obtenir l'index permettant de placer les échantillons dans l'ordre
        ;       attendu par la FFT.

                SHUFFLE_8

        ;------ Appliquer les coeffs et mémoriser les échantillons.

                fmove.s (a1)+,fp0               ; f = *pdHANNWindow++
                lea     0(a3,d0.w*4),a2         ; pwSmpl = &pSamples[k]
                fmove.w (a2),fp1                ; *pdWSmpls++ = pwSmpl[0] * f
                fmul.x  fp0,fp1
                fmove.s fp1,(a0)+
                fmul.w  2(a2),fp0               ; *pdWSmpls++ = pwSmpl[1] * f
                fmove.s fp0,(a0)+

                fmove.s (a1)+,fp0               ; f = *pdHANNWindow++
                fmove.w $800(a2),fp1            ; *pdWSmpls++ = pwSmpl[512*2] * f
                fmul.x  fp0,fp1
                fmove.s fp1,(a0)+
                fmul.w  $802(a2),fp0            ; *pdWSmpls++ = pwSmpl[512*2+1] * f
                fmove.s fp0,(a0)+

                fmove.s (a1)+,fp0               ; f = *pdHANNWindow++
                fmove.w $400(a2),fp1            ; *pdWSmpls++ = pwSmpl[256*2] * f
                fmul.x  fp0,fp1
                fmove.s fp1,(a0)+
                fmul.w  $402(a2),fp0            ; *pdWSmpls++ = pwSmpl[256*2+1] * f
                fmove.s fp0,(a0)+

                fmove.s (a1)+,fp0               ; f = *pdHANNWindow++
                fmove.w $C00(a2),fp1            ; *pdWSmpls++ = pwSmpl[768*2] * f
                fmul.x  fp0,fp1
                fmove.s fp1,(a0)+
                fmul.w  $C02(a2),fp0            ; *pdWSmpls++ = pwSmpl[768*2+1] * f
                addq.w  #1,d1
                fmove.s fp0,(a0)+
                cmp.w   #$100,d1
                blo     .Stereo_loop

                POP     SetupWinSamples_1024
                rts


        ;------ Boucle principale pour un fichier Mono.

.Mono_loop
        ;------ Obtenir l'index permettant de placer les échantillons dans l'ordre
        ;       attendu par la FFT.

                SHUFFLE_8

        ;------ Appliquer les coeffs et mémoriser les échantillons.

                lea     0(a3,d0.w*4),a2         ; pwSmpl = &pSamples[k]

                fmove.w (a2),fp0                ; *pdWSmpls++ = pwSmpl[0] * *pdHANNWindow++
                fmul.s  (a1)+,fp0
                fmove.s fp0,(a0)+

                fmove.w 2(a2),fp0               ; *pdWSmpls++ = pwSmpl[1] * pdHANNWindow[511]
                fmul.s  $7FC(a1),fp0
                fmove.s fp0,(a0)+

                fmove.w $400(a2),fp0             ; *pdWSmpls++ = pwSmpl[512] * *pdHANNWindow++
                fmul.s  (a1)+,fp0
                fmove.s fp0,(a0)+

                fmove.w $402(a2),fp0             ; *pdWSmpls++ = pwSmpl[513] * pdHANNWindow[511]
                fmul.s  $7FC(a1),fp0
                addq.w  #1,d1
                fmove.s fp0,(a0)+
                cmp.w   #$100,d1
                blo.s   .Mono_loop

                POP     SetupWinSamples_1024
                rts
*///
*/// FixFFT_Stereo
******* Misc_funcs/FixFFT_Stereo ********************************************
*
*   NAME
*   PsychoC::FixFFT_Stereo -- Calcule une FFT.
*
*   SYNOPSIS
*   PsychoC::FixFFT_Stereo(pd_FFTIn, iFFTSize)
*
*   void PsychoC::FixFFT_Stereo(REAL *, UWORD);
*
*   FUNCTION
*   Calcule la FFT d'un ensemble d'échantillons stéréo.
*
*   INPUTS
*   pd_FFTIn - Pointeur vers le tableau d'entrée.
*   iFFTSize - Nombre d'échantillons à traiter.
*
*   NOTES
*   La routine FFT effectue son calcul sur les deux canaux simultanément (les
*   échantillons ayant été placés dans l'ordre correct auparavant).
*   Dès lors, il suffit de réordonner les valeurs fournies par la FFT en
*   profitant des symétries pour obtenir la véritable FFT de chacun des deux
*   canaux.
*
*   BUGS
*   Fonction contrôlée conforme le 09.07.98
*
*****************************************************************************
*
*

        SECTION "_FixFFT_Stereo:0",CODE

;void FixFFT_Stereo(REAL *pd_FFTIn, UWORD iFFTSize)

                XDEF    _FixFFT_Stereo

_FixFFT_Stereo  move.w  d0,d1
                lea     $2000(a0),a1            ; pd_FFTOut
                movea.l a0,a2
                asl.w   #2+1,d0
                add.w   d0,a2                   ; pd_FFTIn2

                addq.w  #4,a0
                move.l  (a0),(a1)+              ; pd_FFTOut[0] = pd_FFTIn[1]
                clr.l   (a0)+
                clr.l   (a1)+                   ; pd_FFTIn[1] = pd_FFTOut[1] = 0.0

                asr.w   #1,d1                   ; iFFTLen = iFFTSize >> 1
                subq.w  #1,d1
                fmove.s #0.5,fp0                ; dOneHalf = 0.5

        ;------ Boucle principale.

.loop           subq.w  #$8,a2                  ; pd_FFTIn2 -= 2

                fmove.s $4(a0),fp1              ; aip = dOneHalf * (pd_FFTIn[1]  + pd_FFTIn2[1])
                fadd.s  $4(a2),fp1
                fmul.x  fp0,fp1
                fmove.s fp1,(a1)+               ; pd_FFTOut++ = aip

                fmove.s (a2),fp1                ; rem = dOneHalf * (pd_FFTIn2[0] - pd_FFTIn[0])
                fsub.s  (a0),fp1
                fmul.x  fp0,fp1
                fmove.s fp1,(a1)+               ; pd_FFTOut++ = aim

                fmove.s (a2),fp1                ; *pd_FFTIn++ = dOneHalf * (*pd_FFTIn + pd_FFTIn2[0])
                fadd.s  (a0),fp1
                fmul.x  fp0,fp1
                fmove.s fp1,(a0)+

                fmove.s (a0),fp1                ; *pd_FFTIn++ = dOneHalf * (*pd_FFTIn - pd_FFTIn2[1])
                fsub.s  $4(a2),fp1
                fmul.x  fp0,fp1
                fmove.s fp1,(a0)+
                dbra    d1,.loop

                rts
*///
*/// FixFFT_Mono
******* Misc_funcs/FixFFT_Mono **********************************************
*
*   NAME
*   PsychoC::FixFFT_Mono -- Calcule une FFT
*
*   SYNOPSIS
*   PsychoC::FixFFT_Mono_C(pd_FFTIn, dSinCos, iFFTSize)
*   PsychoC::FixFFT_Mono_T(pd_FFTIn, Cosin, iFFTSize)
*
*   void PsychoC::FixFFT_Mono_C(REAL *, REAL *, UWORD);
*   void PsychoC::FixFFT_Mono_T(REAL *, REAL *, UWORD);
*
*   FUNCTION
*   Calcule une FFT sur un groupe d'échantillons (fichier mono).
*
*   INPUTS
*   iFFTSize - Taille de la fenêtre FFT (est égale à la moitié du nombre d'
*       échantillons à analyser).
*   pd_FFTIn - Pointeur vers le tableaud d'entrée de la FFT.
*   dSinCos  - Valeurs angulaires (= intervalle)
*   Cosin    - Pointeur vers la table SinCos[]
*
*   NOTES
*   Les échantillons sont placés dans un ordre particulier afin de limiter
*   le nombre de calculs (échantillons d'index pair comme partie réelle,
*   échantillons d'index impair comme partie imaginaire).
*   Cette solution permet de limiter la taille de la fenêtre FFT à la moitié
*   de sa taille normale.
*   Il suffit de réordonner les nombres complexes en sortie de FFT pour
*   obtenir le résultat recherché.
*
*   BUGS
*   FixFFT_Mono_C contrôlée conforme le 09.07.98
*
*****************************************************************************
*
*

        SECTION "_FixFFT_Mono_C:0",CODE

;void FixFFT_Mono_C(REAL *pd_FFTIn, REAL dSinCos[2][10], UWORD iFFTSize)

                XDEF    _FixFFT_Mono_C

_FixFFT_Mono_C

                COS_9:  EQU      9*4            ; Index des valeurs recherchées.
                SIN_9:  EQU     19*4            ; (Sin/Cos (-PI/512) )

                move.w  d0,d1
                move.l  a1,a3

        ;------ Préparer les pointeurs temporaires.

                asr.w   #1,d0                   ; iFFTLen = iFFTSize >> 1

                ;add.w   d1,d1                  ; pd_FFTIn2 = &pd_FFTIn[iFFTSize << 1]
                lea     0(a0,d1.w*8),a1
                move.l  a0,a2                   ; pd_FFTOrg = pd_FFTIn
                addq.w  #8,a0                   ; pd_FFTIn += 2

                fmove.s #0.5,fp5                ; dOneHalf

                fmove.s COS_9(a3),fp4           ; wr = wpr = cos(-pi/512)
                fmove.s SIN_9(a3),fp2           ; wi = wpi = sin(-pi/512)

                subq.w  #1,d0

        ;------ Boucle principale.

.MLoop          subq.w  #8,a1                   ; pd_FFTIn2 -= 2

                fmove.s $4(a0),fp0              ; h2r = dOneHalf * (pd_FFTIn[1] + pd_FFTIn2[1]);
                fadd.s  $4(a1),fp0
                fmul.x  fp5,fp0

                fmove.s (a1),fp1                ; h2i = dOneHalf * (pd_FFTIn2[0] - pd_FFTIn[0]);
                fsub.s  (a0),fp1
                fmul.x  fp5,fp1

                fmove.x fp4,fp3                 ; h2r = wr * h1r - wi * h2i
                fmul.x  fp0,fp3
                fmove.x fp2,fp6
                fmul.x  fp1,fp6
                fsub.x  fp6,fp3

                fmul.x  fp4,fp1                 ; h2i = wr * h2i + wi * h1r
                fmul.x  fp2,fp0
                fadd.x  fp0,fp1

                fmove.s (a0),fp0                ; h1r = dOneHalf * (pd_FFTIn[0] + pd_FFTIn2[0])
                fadd.s  (a1),fp0
                fmul.x  fp5,fp0

                fmove.s $4(a0),fp7              ; h1i = dOneHalf * (pd_FFTIn[1] - pd_FFTIn2[1])
                fsub.s  $4(a1),fp7
                fmul.x  fp5,fp7

                fmove.x fp3,fp6                 ; *pd_FFTIn++ = h2r + h1r
                fadd.x  fp0,fp6
                fmove.s fp6,(a0)+

                fmove.x fp1,fp6                 ; *pd_FFTIn++ = h2i + h1i
                fadd.x  fp7,fp6
                fmove.s fp6,(a0)+

                fsub.x  fp3,fp0                 ; pd_FFTIn2[0] = h1r - h2r
                fmove.s fp0,(a1)

                fsub.x  fp7,fp1                 ; pd_FFTIn2[1] = h2i - h1i
                fmove.s fp1,$4(a1)

                fmove.s COS_9(a3),fp3
                fmove.x fp4,fp0
                fmul.x  fp3,fp4                 ; wr = h1r * wpr - wi * wpi
                fmove.x fp2,fp1
                fmove.s SIN_9(a3),fp6
                fmul.x  fp6,fp1
                fsub.x  fp1,fp4

                fmul.x  fp3,fp2                 ; wi = wi * wpr + h1r * wpi
                fmul.x  fp6,fp0
                fadd.x  fp0,fp2

                dbra   d0,.MLoop

        ;------ Terminer la mise en forme.

                lea     0(a2,d1.w*8),a0         ; = pd_FFTOrg[iFFTSize]
                fmove.s (a2),fp0                ; pd_FFTOrg[iFFTSize] = pd_FFTOrg[0] - pd_FFTOrg[1]
                fmove.x fp0,fp1
                fmove.s $4(a2),fp2
                fsub.x  fp2,fp0
                fadd.x  fp2,fp1
                fmove.s fp0,(a0)+
                fmove.s fp1,(a2)+               ; pd_FFTOrg[0] += pd_FFTOrg[1]

                clr.l   (a0)                    ; pd_FFTOrg[0] = pd_FFTOrg[iFFTSize] = 0
                clr.l   (a2)
                rts
*///
*/// FixFFT_Mono_T (Version utilisant une table)
******* Misc_funcs/FixFFT_Mono **********************************************
*
*   NAME
*   PsychoC::FixFFT_Mono -- Calcule une FFT
*
*   SYNOPSIS
*   PsychoC::FixFFT_Mono_C(pd_FFTIn, dSinCos, iFFTSize)
*   PsychoC::FixFFT_Mono_T(pd_FFTIn, Cosin, iFFTSize)
*
*   void PsychoC::FixFFT_Mono_C(REAL *, REAL *, UWORD);
*   void PsychoC::FixFFT_Mono_T(REAL *, REAL *, UWORD);
*
*   FUNCTION
*   Calcule une FFT sur un groupe d'échantillons (fichier mono).
*
*   INPUTS
*   iFFTSize - Taille de la fenêtre FFT (est égale à la moitié du nombre d'
*       échantillons à analyser).
*   pd_FFTIn - Pointeur vers le tableaud d'entrée de la FFT.
*   dSinCos  - Valeurs angulaires (= intervalle)
*   Cosin    - Pointeur vers la table SinCos[]
*
*   NOTES
*   Les échantillons sont placés dans un ordre particulier afin de limiter
*   le nombre de calculs (échantillons d'index pair comme partie réelle,
*   échantillons d'index impair comme partie imaginaire).
*   Cette solution permet de limiter la taille de la fenêtre FFT à la moitié
*   de sa taille normale.
*   Il suffit de réordonner les nombres complexes en sortie de FFT pour
*   obtenir le résultat recherché.
*
*   BUGS
*   FixFFT_Mono_C contrôlée conforme le 09.07.98
*
*****************************************************************************
*
*

        SECTION "_FixFFT_Mono_T:0",CODE

;void FixFFT_Mono_T(REAL *pd_FFTIn, REAL *Cosin, UWORD iFFTSize)

                XDEF    _FixFFT_Mono_T

_FixFFT_Mono_T  move.w  d0,d1
                move.l  a1,a4

                asr.w   #1,d0                   ; iFFTLen = iFFTSize >> 1
                add.w   d1,d1                   ; pd_FFTIn2 = &pd_FFTIn[iFFTSize << 1]
                lea     0(a0,d1.w*4),a1
                move.l  a0,a2                   ; pd_FFTOrg = pd_FFTIn
                addq.w  #8,a0                   ; pd_FFTIn += 2

                addq.w  #4,a4                   ; Sauter la première valeur.
                lea     $400(a4),a3             ; Sinus = &Cosin[SINCOSSIZE / 3]
                fmove.s #0.5,fp4                ; dOneHalf = 0.5

                subq.w  #1,d0                   ; Initialiser l'indice de boucle (dbra)

        ;------ Boucle principale

.MLoop          subq.w  #8,a1                   ; pd_FFTIn2 -= 2

                fmove.s $4(a0),fp1              ; h2r = dOneHalf * (pd_FFTIn[1]  + pd_FFTIn2[1])
                fadd.s  $4(a1),fp1
                fmul.x  fp4,fp1

                fmove.s (a1),fp0                ; h2i = dOneHalf * (pd_FFTIn2[0] - pd_FFTIn[0])
                fsub.s  (a0),fp0
                fmul.x  fp4,fp0

                fmove.s (a4)+,fp5               ; wr = Cosin[delta]
                fmove.x fp5,fp2                 ; h2r = wr * h1r - wi * h2i
                fmul.x  fp1,fp2
                fmove.s (a3)+,fp3               ; wi = Sinus[delta]
                fmove.x fp3,fp6
                fmul.x  fp0,fp6
                fsub.x  fp6,fp2

                fmul.x  fp5,fp0                 ; h2i = wr * h2i + wi * h1r
                fmul.x  fp1,fp3
                fadd.x  fp3,fp0

                fmove.s (a0),fp1                ; h1r = dOneHalf * (pd_FFTIn[0]  + pd_FFTIn2[0])
                fadd.s  (a1),fp1
                fmul.x  fp4,fp1

                fmove.s $4(a0),fp3              ; h1i = dOneHalf * (pd_FFTIn[1]  - pd_FFTIn2[1])
                fsub.s  $4(a1),fp3
                fmul.x  fp4,fp3

                fmove.x fp2,fp5                 ; *pd_FFTIn++  = h2r + h1r
                fadd.x  fp1,fp5
                fmove.s fp5,(a0)+

                fmove.x fp0,fp5                 ; *pd_FFTIn++  = h2i + h1i
                fadd.x  fp3,fp5
                fmove.s fp5,(a0)+

                fsub.x  fp2,fp1                 ; pd_FFTIn2[0] = h1r - h2r
                fmove.s fp1,(a1)

                fsub.x  fp3,fp0                 ; pd_FFTIn2[1] = h2i - h1i
                fmove.s fp0,$4(a1)

                dbra    d0,.MLoop

                lea     0(a2,d1.w*4),a0         ; = pd_FFTOrg[iFFTSize]
                fmove.s (a2),fp0                ; pd_FFTOrg[iFFTSize] = pd_FFTOrg[0] - pd_FFTOrg[1]
                fmove.x fp0,fp1
                fmove.s $4(a2),fp2
                fsub.x  fp2,fp0
                fadd.x  fp2,fp1
                fmove.s fp0,(a0)+
                fmove.s fp1,(a2)+               ; pd_FFTOrg[0] += pd_FFTOrg[1]

                clr.l   (a0)                    ; pd_FFTOrg[0] = pd_FFTOrg[iFFTSize] = 0.0
                clr.l   (a2)
                rts
*///
*/// SubBandCoding_Stereo
******* Misc_funcs/SubBandCoding_Stereo *************************************
*
*   NAME
*   CoderC::SubBandCoding_Stereo -- Prétraitement des échantillons.
*
*   SYNOPSIS
*   CoderC::SubBandCoding_Stereo(pdSample, pActualPtr, pAnaFilter)
*
*   void CoderC::SubBandCoding_Stereo(T_SubBandSmplStereo *, WORD **, REAL *)
*   void CoderC::SubBandCoding_Mono(T_SubBandSmplMono *, WORD **, REAL *,
*
*   FUNCTION
*   Filtre la bande courante.
*
*   INPUTS
*   - pdSample   = Pointeur vers le tableau a initialiser.
*   - pActualPtr = Pointeur vers le tableau d'échantillons.
*   - pAnaFilter = Pointeur vers le tableau des filtres.
*
*   NOTES
*   Cette fonction est constituée de plusieurs sous-ensembles des sources
*   originaux (boucles, window_subband et filter_subband). L'intégration de
*   ces blocs dans une seule et unique fonction permet de supprimer les
*   différents appels de fonction, et autorise une meilleure gestion des
*   ressources.
*   Cette fonction est fortement optimisée. Toutefois, une re-écriture en
*   assembleur permettrait de gagner encore quelques secondes de traitement
*   sur un fichier stéréo de 3 minutes.
*
*   L'implémentation actuelle de l'algorithme est basée sur une optimisation
*   des accès mémoire. Elle n'est pas forcément la plus efficace lorsque l'
*   encodeur est utilisée sur une machine dépourvue de cache (68020).
*
*   BUGS
*
*****************************************************************************
*
*
        SECTION "_SubBandCoding_Stereo:0",CODE

;void _SubBandCoding_Stereo(REAL pdSample[2][12][32], WORD **pActualPtr, REAL *pAnaFilter)

        XDEF    _SubBandCoding_Stereo


_SubBandCoding_Stereo

                link    a5,#-$10C
                PUSH    d2-d7/a2-a4/a6,SBCoding_Stereo
                fmovem.x fp2/fp3/fp4/fp5,-(a7)

        ;------ Boucle principale (j).

                clr.l   -4(a5)

.MasterLoop
        ;------ Calculer y[0]

                movea.l #_a_dAnaWindow,a2

                movea.l $C(a5),a1
                movea.l (a1),a0                 ; p2 = *pActualPtr
                lea     $7C(a0),a1              ; p1 = &p2[31 * 2];
                adda.w  #$77C,a0                ; p2 = &p2[479 * 2];

                fmove.s #0.0,fp1                ; ysumL = ysumR = 0
                fmove.x fp1,fp2
                moveq   #2,d0

.Calc_Y0        fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                move.w  (a0),d1                 ; ysumL += wincoeff * ((LONG *p2 - (LONG) *p1)
                ext.l   d1
                move.w  (a1),d2
                ext.l   d2
                sub.l   d2,d1
                fmove.l d1,fp3
                fmul.x  fp0,fp3
                move.w  2(a0),d1                ; ysumR += wincoeff * ((long) p2[1] - (LONG) p1[1])
                ext.l   d1
                move.w  2(a1),d2
                fadd.x  fp3,fp1
                ext.l   d2
                sub.l   d2,d1
                fmul.l  d1,fp0
                adda.w  #$80,a1                 ; p1 += 32 * 2;
                suba.w  #$80,a0                 ; p2 += -(32 * 2);
                fadd.x  fp0,fp2

                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                move.w  (a0),d1                 ; ysumL += wincoeff * ((LONG) *p2 + (LONG) *p1)
                ext.l   d1
                move.w  (a1),d2
                ext.l   d2
                add.l   d2,d1
                fmove.l d1,fp3
                fmul.x  fp0,fp3
                move.w  2(a0),d1                ; ysumR += wincoeff * ((LONG) p2[1] + (LONG) p1[1])
                ext.l   d1
                move.w  2(a1),d2
                fadd.x  fp3,fp1
                ext.l   d2
                add.l   d2,d1
                fmul.l  d1,fp0
                adda.w  #$80,a1                 ; p1 += 32 * 2;
                suba.w  #$80,a0                 ; p2 += (-32 * 2);
                fadd.x  fp0,fp2
                dbra    d0,.Calc_Y0

                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                move.w  (a0),d0                 ; ysumL += wincoeff * ((LONG) *p2 - (LONG) *p1)
                ext.l   d0
                move.w  (a1),d1
                ext.l   d1
                sub.l   d1,d0
                fmove.l d0,fp3
                fmul.x  fp0,fp3
                move.w  2(a0),d0                ; ysumR += wincoeff * ((LONG) p2[1] - (LONG) p1[1])
                ext.l   d0
                move.w  2(a1),d1
                fadd.x  fp3,fp1
                ext.l   d1
                sub.l   d1,d0
                fmul.l  d0,fp0
                fadd.x  fp0,fp2

                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w $80(a1),fp3             ; yL[0] = ysumL + wincoeff * p1[32 * 2];
                fmul.x  fp0,fp3
                fadd.x  fp3,fp1
                fmove.s fp1,-$108(a5)
                fmul.w  $82(a1),fp0
                moveq   #$3C,d3                 ; stp = 30 * 2
                moveq   #$44,d2                 ; next = (64 - 30) * 2
                moveq   #0,d0                   ; n = 0
                fadd.x  fp0,fp2                 ; (yR[0] termination)
                fmove.s fp2,-$88(a5)

        ;------ Calculer y[1-15] et y[17-31]

.Calc_Yx        movea.l $C(a5),a1               ; p2 = enc_pSB_ActualPtr;
                move.l  d0,d1
                movea.l (a1),a0
                fmove.s #0.0,fp1                ; ysumL = ysumL2 = ysumR = ysumR2 = 0;
                neg.l   d1
                lea     (a0,d0.l*4),a1          ; p1 = &p2[n+n];
                fmove.x fp1,fp4
                fmove.x fp1,fp2
                lea     ($778.w,a0,d1.l*4),a0   ; p2 = &p2[478 * 2 - (n+n)];
                fmove.x fp1,fp3

                ; Boucle interne.

                moveq   #3,d1                   ; m

.Calc_Yx_1      fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w (a1),fp5                ; ysumL2 += wincoeff * p1[0];
                fmul.x  fp0,fp5
                fadd.x  fp5,fp3
                fmove.w 2(a1),fp5               ; ysumR2 += wincoeff * p1[1];
                fmul.x  fp0,fp5
                fadd.x  fp5,fp4
                fmove.w $80(a0),fp5             ; ysumL  += wincoeff * p2[32 * 2]
                fmul.x  fp0,fp5
                fadd.x  fp5,fp1
                fmul.w  $82(a0),fp0
                fadd.x  fp0,fp2

                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w (a0),fp5                ; ysumL2 += wincoeff * p2[0];
                fmul.x  fp0,fp5
                fadd.x  fp5,fp3
                fmove.w 2(a0),fp5               ; ysumR2 += wincoeff * p2[1];
                fmul.x  fp0,fp5
                fadd.x  fp5,fp4
                fmove.w $80(a1),fp5             ; ysumL  -= wincoeff * p1[32 * 2]
                fmul.x  fp0,fp5
                fsub.x  fp5,fp1
                move.l  d3,d4                   ; p2 = &p2[-stp];
                fmul.w  $82(a1),fp0
                neg.l   d4
                lea     (a1,d3.l*2),a1          ; p1 = &p1[stp];
                fsub.x  fp0,fp2
                lea     (a0,d4.l*2),a0

                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w (a1),fp5                ; ysumL2 -= wincoeff * p1[0];
                fmul.x  fp0,fp5
                fsub.x  fp5,fp3
                fmove.w 2(a1),fp5               ; ysumR2 -= wincoeff * p1[1];
                fmul.x  fp0,fp5
                fsub.x  fp5,fp4
                fmove.w $80(a0),fp5             ; ysumL  += wincoeff * p2[32 * 2]
                fmul.x  fp0,fp5
                fadd.x  fp5,fp1
                fmul.w  $82(a0),fp0
                fadd.x  fp0,fp2

                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w (a0),fp5                ; ysumL2 -= wincoeff * p2[0];
                fmul.x  fp0,fp5
                fsub.x  fp5,fp3
                fmove.w 2(a0),fp5               ; ysumR2 -= wincoeff * p2[1];
                fmul.x  fp0,fp5
                fsub.x  fp5,fp4
                fmove.w $80(a1),fp5             ; ysumL  -= wincoeff * p1[32 * 2]
                fmul.x  fp0,fp5
                fsub.x  fp5,fp1
                move.l  d2,d4
                fmul.w  $82(a1),fp0
                neg.l   d4
                lea     (a1,d2.l*2),a1          ; p1 = &p1[next];
                fsub.x  fp0,fp2
                lea     (a0,d4.l*2),a0          ; p2 = &p2[-next];
                dbra    d1,.Calc_Yx_1

                addq.l  #1,d0                   ; ++n;
                subq.l  #4,d3                   ; stp  -= 4;
                addq.l  #4,d2                   ; next += 4;
                lea     (-$108.w,a5,d0.l*4),a0
                fmove.s fp1,(a0)
                fmove.s fp2,$80(a0)
                fmove.s fp3,$3C(a0)
                fmove.s fp4,$BC(a0)

                cmpi.b   #15,d0
                blo     .Calc_Yx

        ;------ Calculer y[16]

                movea.l $C(a5),a1               ; pL = &enc_pSB_ActualPtr[47 * 2];
                fmove.s #0.0,fp1                ; ysumL = ysumR = 0;
                movea.l (a1),a0
                fmove.x fp1,fp2
                adda.w  #$BC,a0

                moveq   #3,d0                   ; n

.Calc_Y16       fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w (a0),fp3                ; ysumL -= wincoeff * *pL;
                fmul.x  fp0,fp3
                fsub.x  fp3,fp1
                fmul.w  2(a0),fp0
                fsub.x  fp0,fp2
                fmove.s (a2)+,fp0               ; wincoeff = *pAnaWindow++;
                fmove.w $400(a0),fp3            ; ysumL += wincoeff * pL[256 * 2];
                fmul.x  fp0,fp3
                fadd.x  fp3,fp1
                fmul.w  $402(a0),fp0
                adda.w  #$100,a0                ; pL += (64 * 2);
                fadd.x  fp0,fp2
                dbra    d0,.Calc_Y16

                ; a1 contient toujours "enc_pSB_ActualPtr"
                add.l   #$80,(a1)               ; enc_pSB_ActualPtr += (32 * 2);

        ;------ Convolution (algorithme évolué).

                move.l  -4(a5),d0               ; j
                movea.l 8(a5),a4                ; pSB_SampleL1 = &(*pdSample)[0][j][0];
                asl.l   #$8,d0
                adda.l  d0,a4
                lea     $C00(a4),a6             ; pSB_SampleR1 = &(*pdSample)[1][j][0]
                move.l  a4,-8(a5)               ; = pSB_SampleL1

                movea.l $10(a5),a2              ; pFilter = &(*enc_pdAnaFilter)[0]
                moveq   #4,d4                   ; max = 4
                moveq   #$10,d3                 ; lstep = 16
                moveq   #8,d6                   ; lpos = 8

                fmove.s -$108(a5),fp0           ; *pSB_SampleL1 = yL[0] * *pFilter;
                fmul.d  (a2),fp0
                fmove.d fp0,(a4)
                fmove.s -$88(a5),fp0            ; *pSB_SampleR1 = yR[0] * *pFilter;
                fmul.d  (a2),fp0
                fmove.d fp0,(a6)

                fmove.x fp1,fp0                 ; pSB_SampleL1[1] = ysumL - *pSB_SampleL1;
                fsub.d  (a4),fp0
                fmove.d fp0,8(a4)
                fmove.x fp2,fp0                 ; pSB_SampleR1[1] = ysumR - *pSB_SampleR1;
                fsub.d  (a6),fp0
                fmove.d fp0,8(a6)
                fadd.d  (a4),fp1                ; *pSB_SampleL1 += ysumL;
                fmove.d fp1,(a4)
                fadd.d  (a6),fp2                ; *pSB_SampleR1 += ysumR;
                fmove.d fp2,(a6)

        ;------ while (max <= 32)

.Filter_Outer   movea.l -8(a5),a4               ; pSB_SampleL1 = &(*pdSample)[0][j][0];
                moveq   #0,d7                   ; i32 = 0;
                ; pSB_SampleR1 = pSB_SampleL1 + $C00

                lea     (a4,d4.l*8),a6          ; pSB_SampleL2 = &pSB_SampleL1[max]
                ; pSB_SampleR2 = pSB_SampleR1 + $C00

                move.l  d6,d5                   ; i = lpos

.Filter_i       move.l  d5,d0                   ; fstep = i
                move.l  d0,d2                   ; fidx  = fstep - i32;
                sub.l   d7,d2
                andi.w  #$007F,d2
                add.l   #$20,d7                 ; i32 += 32;
                move.l  d0,d1                   ; fidx2 = fstep + i32;
                add.l   d7,d1
                add.l   d0,d0                   ; fstep += fstep;
                andi.w  #$007F,d1
                fmove.s #0.0,fp1                ; ysumL = ysumR = 0;
                lea     (-$108.w,a5,d6.l*4),a0  ; pyL = &yL[lpos]
                fmove.x fp1,fp2
                lea     -$C8(a5),a3             ; &yL[16]

.Filter_inner   fmove.d (a2,d2.w*8),fp5         ; filter[fidx]
                fmove.s (a0),fp0
                fmul.x  fp5,fp0
                fmove.d (a2,d1.w*8),fp4         ; filter[fidx2]
                fmove.s $3C(a0),fp3
                fmul.x  fp4,fp3
                fadd.x  fp3,fp0
                fadd.x  fp0,fp1                 ; ysumL += *pyL * f1 + pyL[15] * f2

                fmul.s  $80(a0),fp5
                add.l   d0,d2                   ; fidx  += fstep
                andi.w  #$007F,d2
                fmul.s  $BC(a0),fp4
                add.l   d0,d1                   ; fidx2 += fstep
                andi.w  #$007F,d1
                fadd.x  fp4,fp5
                lea     (a0,d3.l*4),a0          ; pyL += lstep
                fadd.x  fp5,fp2                 ; ysumR += *pyR * f1 + pyR[15] * f2
                cmp.l   a3,a0
                blo.b   .Filter_inner

                fmove.d (a4),fp0
                fsub.x  fp1,fp0
                fmove.d fp0,-(a6)               ; *--pSB_SampleL2 = *pSB_SampleL1 - ysumL

                fmove.d $C00(a4),fp0
                fsub.x  fp2,fp0
                fmove.d fp0,$C00(a6)            ; *pSB_SampleR2 = *pSB_SampleR1 - ysumR

                fadd.d  $C00(a4),fp2
                fmove.d fp2,$C00(a4)            ; *pSB_SampleR1 += ysumR
                fadd.d  (a4),fp1
                add.l   d3,d5                   ; i += lstep
                fmove.d fp1,(a4)+               ; *pSB_SampleL1++ += ysumL
                cmpi.b  #32,d5
                blo     .Filter_i

                sub.l   d6,d3                   ; lstep -= lpos
                lsr.l   #1,d6                   ; lpos >>= 1
                add.l   d4,d4                   ; max += max
                cmpi.b  #32,d4
                bls     .Filter_Outer

                addq.l  #1,-4(a5)
                move.l  -4(a5),d0
                cmpi.b   #12,d0
                blo     .MasterLoop

                fmovem.x (a7)+,fp2/fp3/fp4/fp5
                POP     SBCoding_Stereo
                unlk    a5
                rts

*///
*/// SubBandCoding_Mono

    SECTION "_SubBandCoding_Mono:0",CODE

;void _SubBandCoding_Mono(REAL pdSample[12][32], WORD **pActualPtr, REAL *pAnaFilter)

                XDEF    _SubBandCoding_Mono

_SubBandCoding_Mono

                link    a5,#-$94
                PUSH    d2-d7/a2-a4/a6,SubBandCoding_Mono
                fmovem.x fp2/fp3,-(a7)

        ;------ Boucle principale (j)

                clr.l   -4(a5)

.MasterLoop     movea.l #_a_dAnaWindow,a1       ; const T_ANAWINDOW *pAnaWindow = &a_dAnaWindow[0];
                movea.l 12(a5),a2               ; p2 = enc_pSB_ActualPtr
                movea.l (a2),a0
                lea     $3E(a0),a2              ; p1 = &p2[31]
                add.w   #$3BE,a0                ; p2 = &p2[479]
                fmove.s #0.0,fp1                ; ysum = 0
                moveq   #2,d1                   ; n

        ;------ Calculer Y[0]

.Calc_Y0        move.w  (a0),d0
                ext.l   d0
                move.w  (a2),d2
                fmove.s (a1)+,fp0
                ext.l   d2
                sub.l   d2,d0
                fmul.l  d0,fp0
                adda.w  #$40,a2                 ; p1 += 32
                suba.w  #$40,a0                 ; p2 -= 32
                fadd.x  fp0,fp1                 ; ysum += *pAnaWindow++ * ((LONG) *p2 - (LONG) *p1)

                move.w  (a0),d0
                ext.l   d0
                move.w  (a2),d2
                fmove.s (a1)+,fp0
                ext.l   d2
                add.l   d2,d0
                fmul.l  d0,fp0
                adda.w  #$40,a2                 ; p1 += 32
                suba.w  #$40,a0                 ; p2 -= 32
                fadd.x  fp0,fp1                 ; ysum += *pAnaWindow++ * ((LONG) *p2 + (LONG) *p1)
                dbra    d1,.Calc_Y0

                move.w  (a0),d0
                ext.l   d0
                move.w  (a2),d1
                fmove.s (a1)+,fp0
                ext.l   d1
                sub.l   d1,d0
                fmul.l  d0,fp0
                fadd.x  fp0,fp1                 ; ysum += *pAnaWindow++ * ((LONG) *p2 - (LONG) *p1)

                fmove.s (a1)+,fp0
                fmul.w  $40(a2),fp0
                fadd.x  fp0,fp1
                moveq   #$1E,d3                 ; stp = 30
                moveq   #$22,d2                 ; next = 64 - 30
                fmove.s fp1,-$8C(a5)            ; y[0] = ysum + *pAnaWindow++ * p1[32]
                moveq   #0,d1                   ; n = 0

        ;------ Calculer Yx[1;15] et Yx[17;31]

.Calc_Yx        move.l  12(a5),a2
                move.l  (a2),a0                 ; p2 = enc_pSB_ActualPtr
                fmove.s #0.0,fp1                ; ysum = 0
                lea     (a0,d1.l*2),a2          ; p1 = &p2[n]
                move.w  #$1DE,d0
                sub.w   d1,d0
                fmove.x fp1,fp2                 ; ysum2 = 0
                lea     (a0,d0.w*2),a0          ; p2 = &p2[478 - n]
                moveq   #3,d0                   ; m = 4

.Calc_Yx_1      fmove.s (a1)+,fp0               ; wincoeff = *pAnaWindow++
                fmove.w (a2),fp3
                fmul.x  fp0,fp3
                fadd.x  fp3,fp2                 ; ysum2 += wincoeff * p1[0]
                fmul.w  $40(a0),fp0
                fadd.x  fp0,fp1                 ; ysum += wincoeff * p2[32]

                fmove.s (a1)+,fp0               ; wincoeff = *pAnaWindow++
                fmove.w (a0),fp3
                fmul.x  fp0,fp3
                fadd.x  fp3,fp2                 ; ysum2 += wincoeff * p2[0]
                fmul.w  $40(a2),fp0
                move.l  d3,d4
                neg.l   d4
                lea     (a2,d3.l*2),a2          ; p1 = &p1[stp]
                fsub.x  fp0,fp1                 ; ysum -= wincoeff * p1[32]
                lea     (a0,d4.l*2),a0          ; p2 = &p2[-stp]

                fmove.s (a1)+,fp0               ; wincoeff = *pAnaWindow++
                fmove.w (a2),fp3
                fmul.x  fp0,fp3
                fsub.x  fp3,fp2                 ; ysum2 -= wincoeff * p1[0]
                fmul.w  $40(a0),fp0
                fadd.x  fp0,fp1                 ; ysum += wincoeff * p2[32]

                fmove.s (a1)+,fp0               ; wincoeff = *pAnaWindow++
                fmove.w (a0),fp3
                fmul.x  fp0,fp3
                fsub.x  fp3,fp2                 ; ysum2 -= wincoeff * p2[0]
                fmul.w  $40(a2),fp0
                move.l  d2,d4
                neg.l   d4
                lea     (a2,d2.l*2),a2          ; p1 = &p1[next]
                fsub.x  fp0,fp1                 ; ysum -= wincoeff * p1[32]
                lea     (a0,d4.l*2),a0          ; p2 = &p2[-next]
                dbra    d0,.Calc_Yx_1

                addq.l  #1,d1                   ; ++n
                subq.l  #2,d3                   ; stp -= 2
                addq.l  #2,d2                   ; next += 2
                lea     (-$8C.w,a5,d1.l*4),a0   ; py = &y[n]
                fmove.s fp1,(a0)                ; py[0] = ysum
                fmove.s fp2,$3C(a0)             ; py[15] = ysum2
                cmpi.b  #15,d1
                blo     .Calc_Yx

                move.l  12(a5),a2
                move.l  (a2),a0
                fmove.s #0.0,fp1                ; ysum = 0
                add.w   #$5E,a0                 ; p = &enc_pSB_ActualPtr[47]
                moveq   #3,d1                   ; n = 4

.Calc_Y16       fmove.s (a1)+,fp0
                fmul.w  (a0),fp0
                fsub.x  fp0,fp1                 ; ysum -= *pAnaWindow++ * p[0]
                fmove.s (a1)+,fp0
                fmul.w  $200(a0),fp0
                fadd.x  fp0,fp1                 ; ysum += *pAnaWindow++ * p[256]
                adda.w  #$80,a0                 ; p += 64
                dbra    d1,.Calc_Y16

                add.l   #$40,(a2)               ; enc_pSB_ActualPtr += 32

        ;------ Convolution (nouvel algo)

                move.l  -4(a5),d0
                asl.l   #$8,d0
                add.l   8(a5),d0
                move.l  d0,-$90(a5)             ; double *Sample = &(*pdSample)[j][0]
                movea.l d0,a3                   ; double *pSB_Sample1 = Sample
                move.l  $10(a5),a1              ; const REAL *pFilter = &(enc_pdAnaFilter)[0]
                fmove.s -$8C(a5),fp0
                fmul.d  (a1),fp0
                move.l  #4,d6                   ; ULONG max = 4
                moveq   #$10,d4                 ; ULONG lstep = 16
                move.l  #$8,d3                  ; ULONG lpos = 8
                fmove.d fp0,(a3)                ; pSB_Sample1[0] = y[0] * pFilter[0]
                fmove.x fp1,fp0
                fsub.d  (a3),fp0
                fmove.d fp0,$8(a3)              ; pSB_Sample1[1] = ysum - pSB_Sample1[0]
                fmove.d (a3),fp0
                fadd.x  fp1,fp0
                fmove.d fp0,(a3)                ; pSB_Sample1[0] = pSB_Sample1[0] + ysum

.Filter_outer   moveq   #0,d7                   ; i32 = 0
                move.l  -$90(a5),a3             ; pSB_Sample1 = Sample
                move.l  d6,d0
                asl.l   #3,d0
                add.l   a3,d0
                move.l  d0,a4                   ; pSB_Sample2 = &pSB_Sample1[max]
                move.l  d3,d5                   ; i = lpos

.Filter_i       move.l  d5,d0                   ; fstep = i
                move.l  d0,d2
                move.l  d0,d1
                sub.l   d7,d2                   ; fidx = fstep - i32
                add.l   #$20,d7                 ; i32 += 32
                andi.w  #$007F,d2
                add.l   d7,d1                   ; fidx2 = fstep + i32
                add.l   d0,d0                   ; fstep += fstep
                andi.w  #$007F,d1
                fmove.s #0.0,fp1                ; ysum = 0
                lea     (-$8C.w,a5,d3.l*4),a0   ; py = &y[lpos]

.Filter_inner   fmove.s (a0),fp0
                fmul.d  (a1,d2.w*8),fp0
                add.l   d0,d2                   ; fidx += fstep
                andi.w  #$007F,d2
                fmove.s $3C(a0),fp2
                fmul.d  (a1,d1.w*8),fp2
                add.l   d0,d1                   ; fidx2 += fstep
                andi.w  #$007F,d1
                fadd.x  fp2,fp0
                fadd.x  fp0,fp1                 ; ysum += py[0] * pFilter[fidx] + py[15] * pFilter[fidx2]
                lea     (a0,d4.l*4),a0
                lea     -$4C(a5),a2
                cmp.l   a2,a0
                blo.b   .Filter_inner

                fmove.d (a3),fp0
                fsub.x  fp1,fp0
                fmove.d fp0,-(a4)               ; *--pSB_Sample2 = *pSB_Sample1 - ysum
                fmove.d (a3),fp0
                fadd.x  fp1,fp0
                add.l   d4,d5
                fmove.d fp0,(a3)+               ; *pSB_Sample1++ = *pSB_Sample1 + ysum
                cmpi.b  #32,d5
                blo     .Filter_i

                sub.l   d3,d4                   ; lstep -= lpos
                lsr.l   #1,d3                   ; lpos >>= 1
                add.l   d6,d6                   ; max += max
                cmpi.b  #32,d6
                bls     .Filter_outer

                addq.l  #1,-4(a5)
                move.l  -4(a5),d0
                cmpi.b  #12,d0
                blo     .MasterLoop

                fmovem.x (a7)+,fp2/fp3
                POP     SubBandCoding_Mono
                unlk    a5
                rts
*///
*/// CalcGroupedValues
******* Misc_funcs/CalcGroupedValues ****************************************
*
*   NAME
*   PsychoC::CalcGroupedValues --
*
*   SYNOPSIS
*   CalcGroupedValues(wNew, GroupedValues, FFTOut, pEnergy, tmp, Part)
*
*   void CalcGroupedValues(UWORD, REAL [][], REAL *, REAL *, REAL *, UBYTE *);
*
*   FUNCTION
*   Calcule des vecteurs complexes à partir des données fournies par la FFT,
*   et les cumule par bandes de fréquences.
*
*   INPUTS
*   wNew          - Indice courant
*   GroupedValues - Tableau des sommes intermédiaires.
*   FFTOut        - Données en sortie de FFT.
*   pEnergy       - Tableau de sauvegarde de l'énergie.
*   tmp           - Tableau de sauvegarde locale
*   Part          - Tableau des indices de partitionnement.
*
*   NOTES
*
*   BUGS
*   Cette fonction n'est pas strictement conforme au source originale : L'
*   énergie du complexe C[512] est ici bornée (borne inférieure = 0.0005).
*
*   SEE ALSO
*
*****************************************************************************
*

        SECTION "_CalcGroupedValues:0",CODE


;void _CalcGroupedValues(UWORD wNew, REAL GroupedValues[][2], REAL *FFTOut, REAL *pEnergy, REAL *tmp, UBYTE *Part)

        XDEF    _CalcGroupedValues

_CalcGroupedValues

                link    a5,#-8                  ; cos_2phi
                PUSH    d2/d3/a2/a3/a6,CalcGroupedValues
                fmovem.x fp2/fp3/fp4/fp5/fp6/fp7,-(a7)
                move.w  $8(a5),d1
                move.l  $16(a5),a1
                move.l  $E(a5),a2

                moveq   #1,d0
                sub.w   d1,d0                   ; wOld = 1 - wNew

                move.l  $A(a5),a0               ; p = &GroupedValues[0][0]

        ;------ Initialiser la table des sommes intermédiaires.

                moveq   #$3F-1,d2

.ClrLoop        clr.l   (a0)+                   ; *p++ = 0.0
                clr.l   (a0)+
                clr.l   (a0)+                   ; *p++ = 0.0
                clr.l   (a0)+

                dbra    d2,.ClrLoop

        ;------ Initialiser les pointeurs pour la boucle principale.

                lea     (a1,d0.w*4),a6          ; pOld = &tmp[wOld]
                lea     (a1,d1.w*4),a3          ; pNew = &tmp[wNew]

        ;------ Boucle principale.

                moveq   #0,d2

.MasterLoop

        ;------ Calculer cos(phi_prime), sin(phi_prime) et r_prime.
        ; cos(2a) = 2.cos²(a) - 1
        ; sin(2a) = 2.cos(a).sin(a)
        ; cos(2a-b) = cos(2a).cos(b) + sin(2a).sin(b)
        ; sin(2a-b) = sin(2a).cos(b) - cos(2a).sin(b)

                fmove.s (a6),fp3                ; cos_phi  = pOld[COSINE]
                fmove.x fp3,fp7                 ; cos_phi_X2 = cos_phi + cos_phi
                fadd.x  fp3,fp7
                fmove.x fp7,fp2                 ; cos_2phi = cos_phi_X2 * cos_phi - 1
                fmul.x  fp3,fp2
                fsub.s  #1.0,fp2
                fmul.s  $08(a6),fp7             ; sin_2phi = pOld[SINE] * cos_phi_X2
                fmove.s (a3),fp3                ; cos_teta  = pOldest[COSINE]
                fmove.x fp3,fp4                 ; cos_phi' = cos_teta * cos_2phi  (Part #1)
                fmul.x  fp2,fp4
                fmove.x fp7,fp0                 ; cos_phi'  += sin_teta * sin_2phi  (Part #2)
                fmul.x  fp3,fp7                 ; sin_phi' = sin_2phi * cos_teta - cos_2phi * sin_teta
                fmove.s $08(a3),fp5             ; sin_teta  = pOldest[SINE]
                fmul.x  fp5,fp0
                fadd.x  fp0,fp4
                fmul.x  fp5,fp2
                fsub.x  fp2,fp7
                fmove.d fp4,-$8(a5)             ; = cos_phi'
                fmove.s $10(a6),fp6             ; r_prime = pOld[ENERGY]
                fadd.x  fp6,fp6                 ; r_prime += r_prime - pOldest[ENERGY]
                fsub.s  $10(a3),fp6

                ; r_prime  = fp6
                ; cos_phi' = -$8(a5)
                ; sin_phi' = fp7

        ;------ Calculer l'énergie

                fmove.s (a2)+,fp3               ; cos_phi = *p++
                fmove.x fp3,fp4                 ; energy  = cos_phi * cos_phi
                fmul.x  fp3,fp4
                fmove.s #0.0005,fp2
                fmove.s (a2)+,fp5               ; sin_phi = *p++
                fmove.x fp5,fp0                 ; energy += sin_phi * sin_phi
                fmul.x  fp5,fp0
                fadd.x  fp0,fp4

                ; r_prime  = fp6
                ; cos_phi' = -$8(a5)
                ; sin_phi' = fp7
                ; cos_phi  = fp3
                ; sin_phi  = fp5
                ; energy   = fp4
                ; r        = fp2

        ;------ Limiter la valeur minimale de l'énergie.

                fcmp.x  fp2,fp4                 ; if (energy <= r)
                fbogt.w .NoFix

                fmove.x fp2,fp4                 ; energy = r
                fmove.d #$3F96E5B7D1665A3B,fp2  ; r = SQRT(0.0005)
                fmove.x fp2,fp3                 ; cos_phi = SQRT(0.0005)
                fmove.s #0.0,fp5                ; sin_phi = 0
                bra.b   .SaveNRJ

.NoFix          fsqrt.x fp4,fp2                 ; r = SQRT(energy)

                ; Cette partie n'utilise que l'IU pendant que le FPU calcule la racine carrée.

.SaveNRJ        movea.l $1A(a5),a0              ; part = Part[j]
                moveq   #0,d0
                move.b  0(a0,d2.w),d0
                asl.l   #4,d0                   ; Grp  = &GroupedValues[part][0]
                add.l   $A(a5),d0
                move.l  d0,a1

        IFNE CPU_TYPE>68030
                move.l  (a1),d0                 ; Précharger le cache (FPU occupé).
        ENDC

                move.w  d2,d0
                move.l  $12(a5),a0              ; = pEnergy
                asr.w   #4,d0                   ; idx = j >> 4
                move.w  d2,d1
                lea     0(a0,d0.w*8),a0
                and.w   #$F,d1                  ; part = j & 15
                bne.b   .AddEnergy              ; if (part)

                cmp.w   #$20,d0
                beq.b   .ChkEnds                ; if (idx != 32)

        IFNE CPU_TYPE>68030
                move.l  (a0),d1                 ; Précharger le cache (FPU encore occupé)
        ENDC

                fmove.d fp4,(a0)                ; pEnergy[idx] = energy

.ChkEnds        subq.w  #1,d0                   ; if (idx--)
                bmi.b   .Continue

                subq.w  #8,a0                   ; Ajuster le pointeur.

.AddEnergy
        IFNE CPU_TYPE>68030
                move.l  (a0),d1                 ; Précharger le cache (FPU encore occupé).
        ENDC
                fmove.d (a0),fp0                ; pEnergy[idx] += energy
                fadd.x  fp4,fp0
                fmove.d fp0,(a0)

        ;------ Mémoriser les données courantes.

.Continue       fmove.s fp2,$10(a3)             ; pNew[ENERGY] = r
                fmove.s #1.0,fp1                ; inv_r = 1.0 / r
                fdiv.x  fp2,fp1
                fmove.x fp3,fp0                 ; pNew[COSINE] = cos_phi * inv_r
                fmul.x  fp1,fp0
                fmove.s fp0,(a3)
                fmul.x  fp5,fp1                 ; pNew[SINE]   = sin_phi * inv_r
                fmove.s fp1,$08(a3)

        ;------ Mettre à jour les sommes intermédiaires.

                ; r_prime  = fp6
                ; cos_phi' = -$8(a5)
                ; sin_phi' = fp7
                ; cos_phi  = fp3
                ; sin_phi  = fp5
                ; energy   = fp4
                ; r        = fp2

                fabs.x  fp6,fp0                 ; r = r + fabs(r_prime)
                fadd.x  fp0,fp2

                fmove.x fp6,fp0                 ; cos_phi -= r_prime * cos_2phi
                fmul.d  -$8(a5),fp0
                fsub.x  fp0,fp3

                fmul.x  fp7,fp6                 ; sin_phi -= r_prime * sin_2phi
                fsub.x  fp6,fp5

                fmul.x  fp3,fp3                 ; cos_phi  = cos_phi * cos_phi + sin_phi * sin_phi
                fmul.x  fp5,fp5
                fadd.x  fp5,fp3

                fmove.d (a1),fp0                ; Grp[0] += energy
                fadd.x  fp4,fp0
                fmove.d fp0,(a1)+

                fsqrt.x fp3,fp0                 ; Grp[1] += energy * sqrt(cos_phi) / r

                ; Profiter du fait que le FPU soit occupé pour faire travailler l'IU

                moveq   #$18,d0
                add.w   d0,a3                   ; pNew += NEXT_OFFSET
                addq.w  #1,d2
                add.w   d0,a6                   ; pOld += NEXT_OFFSET

        IFNE CPU_TYPE>68030
                move.l  (a6),d0                 ; Précharger le cache pour le
                move.l  $10(a6),d0              ; prochain passage.
                move.l  (a2),d0
        ENDC

                fmul.x  fp0,fp4
                fdiv.x  fp2,fp4

        IFNE CPU_TYPE>68030
                move.l  (a1),d0                 ; Précharger le cache (FPU occupé).
        ENDC

                fadd.d  (a1),fp4
                fmove.d fp4,(a1)

                cmp.w   #$201,d2
                blo .MasterLoop

                fmovem.x (a7)+,fp2/fp3/fp4/fp5/fp6/fp7
                POP     CalcGroupedValues
                unlk    a5
                rts
*///
*///FastFFT_C
******* Misc_funcs/FastFFT **************************************************
*
*   NAME
*   FastFFTC::FastFFT -- Calculer la transformée de Fourier.
*
*   SYNOPSIS
*   FastFFTC::FastFFT(pdFFTIn, dSinCos, iFFTSize)
*
*   void FastFFTC::FastFFT(REAL *, REAL *, UWORD);
*
*   FUNCTION
*   Calcule la transformée de Fourier sur un ensemble d'échantillons.
*
*   INPUTS
*   pdFFTIn  - Tableau contenant les échantillons (série de nombres complexes
*       dans l'ordre : [partie réelle][partie imaginaire].
*   dSinCos  - Tableau des valeurs angulaires.
*   iFFTSize - Nombre d'échantillons à traiter.
*
*   NOTES
*   Cette fonction a été fortement optimisée en tirant partie de quelques
*   angles particuliers. Elle est capable de calculer une FFT sur un ensemble
*   de 1024 échantillons au maximum.
*
*   BUGS
*   Fonction contrôlée conforme le 20.06.98
*
*   SEE ALSO
*   FastFFTC::ComputeFastFFT_Stereo()
*
*****************************************************************************
*

        SECTION "_FastFFT_C:0",CODE


;void _FastFFT_C(REAL *pdFFTIn, REAL dSinCos[2][10], UWORD iFFTSize)

        XDEF    _FastFFT_C

_FastFFT_C      move.w  d0,-(sp)
                move.l  a0,a4
                move.l  a1,a6
                move.w  d0,d6

                move.w  #$100,d3                ; iBandSize = MIN(iFFTSize,MAX_FFT_BLOCK)
                cmp.w   d3,d6
                bhs.b   .UseDefautSize

                move.w  d6,d3

.UseDefautSize

        ;------ Boucle principale.

                sub.w   d3,d6

.MasterLoop     moveq   #1,d5                   ; BlockEnd = 1
                moveq   #0,d7                   ; delta = 0

                ;------ Boucle interne (BlockSize)

                moveq   #2,d2

.BlkSizeLoop    move.l  d2,d1
                asl.l   #2+1,d1                 ; n = BlockSize * 2 * 4

                move.w  d6,d0                   ; pd_J = pd_J2 = &pdFFTIn[k + k]
                add.w   d0,d0
                lea     0(a4,d0.w*4),a0
                move.l  a0,a3
                lea     0(a0,d2.l*4),a1         ; pd_K = pd_K2 = &pd_J2[BlockSize]
                move.l  a1,a2

                ;------ Boucle interne (i)

                moveq   #0,d0

.i_Loop         fmove.s (a0),fp1                ; ti = pd_J[0]
                fmove.x fp1,fp2
                fmove.s (a1),fp0                ; tr = pd_K[0]
                fsub.x  fp0,fp2
                fmove.s fp2,(a1)                ; pd_K[0] = ti - tr
                fadd.x  fp0,fp1
                fmove.s fp1,(a0)                ; pd_J[0] = ti + tr

                fmove.s $4(a0),fp0              ; tr = pd_J[1]
                fmove.x fp0,fp2
                fmove.s $4(a1),fp1              ; ti = pd_K[1]
                fsub.x  fp1,fp2
                fmove.s fp2,$4(a1)              ; pd_K[1] = tr - ti
                fadd.x  fp1,fp0
                add.l   d1,a1                   ; pd_K += n
                add.l   d2,d0
                fmove.s fp0,$4(a0)              ; pd_J[1] = tr + ti
                add.l   d1,a0                   ; pd_J += n
                cmp.w   d3,d0
                blo.b   .i_Loop

                addq.w  #8,a3                   ; pd_J2 += 2
                addq.w  #8,a2                   ; pd_K2 += 2

                ;------ BlockEnd > 4

                cmp.w   #4,d5
                beq     .BlkEnd_4
                bls     .BlkEnd_2

                fmove.d 0(a6,d7.l*8),fp7        ; cos_alpha = dCosAlpha[delta]
                fmove.x fp7,fp2                 ; ar = cos_alpha
                fmove.d $50(a6,d7.l*8),fp5      ; sin_alpha = dSinAlpha[delta]
                fmove.x fp5,fp4                 ; ai = sin_alpha

                ;------ Boucle J (BlockEnd > 4)

                moveq   #1,d4

.Case1_J        move.l  a3,a0                   ; pd_J = pd_J2
                move.l  a2,a1                   ; pd_K = pd_K2

                ;------ Boucle I (BlockEnd > 4)

                moveq   #0,d0

.Case1_I        fmove.s (a1),fp1                ; ti = pd_K[0]
                fmove.x fp2,fp0
                fmul.x  fp1,fp0
                fmove.s $4(a1),fp3              ; pd_K[1]
                fmul.x  fp4,fp3
                fsub.x  fp3,fp0                 ; tr = ar * ti - ai * pd_K[1]
                fmove.s $4(a1),fp3              ; pd_K[1]
                fmul.x  fp2,fp3
                fmul.x  fp4,fp1
                fadd.x  fp3,fp1                 ; ti = ar * pd_K[1] + ai * ti

                fmove.s (a0),fp3                ; pd_J[0]
                fsub.x  fp0,fp3
                fmove.s fp3,(a1)                ; pd_K[0] = pd_J[0] - tr
                fadd.s  (a0),fp0
                fmove.s fp0,(a0)                ; pd_J[0] = pd_J[0] + tr

                fmove.s $4(a0),fp0              ; tr = pd_J[1]
                fmove.x fp0,fp3
                fsub.x  fp1,fp3
                fmove.s fp3,$4(a1)              ; pd_K[1] = tr - ti
                fadd.x  fp1,fp0
                add.w   d1,a1                   ; pd_K += n
                add.l   d2,d0
                fmove.s fp0,$4(a0)              ; pd_J[1] = tr + ti
                add.w   d1,a0                   ; pd_J += n
                cmp.w   d3,d0
                blo.b   .Case1_I

                fmove.x fp2,fp0                 ; tr = ar
                fmul.x  fp7,fp2
                addq.w  #8,a3                   ; pd_J2 += 2;
                addq.w  #8,a2                   ; pd_K2 += 2;
                fmove.x fp4,fp1
                fmul.x  fp5,fp1
                fsub.x  fp1,fp2                 ; ar = ar * cos_alpha - ai * sin_alpha

                fmul.x  fp5,fp0
                fmul.x  fp7,fp4
                addq.l  #1,d4
                fadd.x  fp0,fp4                 ; ai = tr * sin_alpha + ai * cos_alpha
                cmp.l   d5,d4
                blo     .Case1_J
                bra     .EndMaster

                ;------ BlockEnd == 2

.BlkEnd_2       move.l  a3,a0                   ; pd_J = pd_J2;
                move.l  a2,a1                   ; pd_K = pd_K2;

                cmp.w   #2,d5
                bne     .EndMaster

                ;------ Boucle I (BlockEnd == 2)

                moveq   #0,d0

.Case2_I        fmove.s (a0),fp2                ; pd_J[0]
                fmove.x fp2,fp5
                fmove.s $4(a1),fp1              ; ti = pd_K[1]
                fadd.x  fp1,fp5
                fmove.s fp5,(a0)                ; pd_J[0] = pd_J[0] + ti
                fsub.x  fp1,fp2
                fmove.s (a1),fp0                ; tr = pd_K[0]
                fmove.s fp2,(a1)                ; pd_K[0] = pd_J[0] - ti

                fmove.s $4(a0),fp1              ; ti = pd_J[1]
                fmove.x fp1,fp2
                fadd.x  fp0,fp2
                fmove.s fp2,$4(a1)              ; pd_K[1] = ti + tr
                fsub.x  fp0,fp1
                add.w   #$20,a1                 ; pd_K += 8
                addq.l  #4,d0
                fmove.s fp1,$4(a0)              ; pd_J[1] = ti - tr
                add.w   #$20,a0                 ; pd_J += 8
                cmp.w   d3,d0
                blo.b   .Case2_I
                bra     .EndMaster

                ;------ BlockEnd == 4

.BlkEnd_4       fmove.d 0(a6,d7.l*8),fp2        ; ar = dCosAlpha[delta]
                move.l  a3,a0                   ; pd_J = pd_J2;
                move.l  a2,a1                   ; pd_K = pd_K2;

                ;------ Boucle I

                moveq   #0,d0

.Case3_I        fmove.s (a1),fp3                ; ti = pd_K[0]
                fmove.s $4(a1),fp1              ; pd_K[1]
                fmove.x fp1,fp0
                fadd.x  fp3,fp0
                fmul.x  fp2,fp0                 ; tr = ar * (ti + pd_K[1])

                fsub.x  fp3,fp1
                fmul.x  fp2,fp1                 ; ti = ar * (pd_K[1] - ti)

                fmove.s (a0),fp5                ; pd_J[0]
                fmove.x fp5,fp3
                fsub.x  fp0,fp3
                fmove.s fp3,(a1)                ; pd_K[0] = pd_J[0] - tr

                fadd.x  fp5,fp0
                fmove.s fp0,(a0)                ; pd_J[0] = pd_J[0] + tr

                fmove.s $4(a0),fp0              ; tr = pd_J[1]
                fmove.x fp0,fp3
                fsub.x  fp1,fp3
                fmove.s fp3,$4(a1)              ; pd_K[1] = tr - ti

                fadd.x  fp1,fp0
                fmove.s fp0,$4(a0)              ; pd_J[1] = tr + ti

                fmove.s $8(a0),fp5              ; pd_J[2]
                fmove.x fp5,fp3
                fmove.s $0C(a1),fp1             ; ti = pd_K[3]
                fsub.x  fp1,fp3
                fmove.s $08(a1),fp0             ; tr = pd_K[2]
                fmove.s fp3,$08(a1)             ; pd_K[2] = pd_J[2] - ti

                fadd.x  fp5,fp1
                fmove.s fp1,$08(a0)             ; pd_J[2] = pd_J[2] + ti

                fmove.s $0C(a0),fp1             ; ti = pd_J[3]
                fmove.x fp1,fp3
                fadd.x  fp0,fp3
                fmove.s fp3,$0C(a1)             ; pd_K[3] = ti + tr

                fsub.x  fp0,fp1
                fmove.s fp1,$0C(a0)             ; pd_J[3] = ti - tr

                fmove.s $10(a1),fp1             ; ti = pd_K[4]
                fmove.x fp1,fp0
                fmove.s $14(a1),fp5             ; pd_K[5]
                fsub.x  fp5,fp0
                fmul.x  fp2,fp0                 ; tr = ar * (ti - pd_K[5])

                fadd.x  fp5,fp1
                fmul.x  fp2,fp1                 ; ti = ar * (pd_K[5] + ti)

                fmove.s $10(a0),fp5             ; pd_J[4]
                fmove.x fp5,fp3
                fsub.x  fp0,fp3
                fmove.s fp3,$10(a0)             ; pd_J[4] = pd_J[4] - tr

                fadd.x  fp0,fp5
                fmove.s fp5,$10(a1)             ; pd_K[4] = pd_J[4] + tr

                fmove.s $14(a0),fp0             ; tr = pd_J[5]
                fmove.x fp0,fp3
                fadd.x  fp1,fp3
                fmove.s fp3,$14(a1)             ; pd_K[5] = tr + ti

                fsub.x  fp1,fp0
                add.w   #$40,a1                 ; pd_K += 16
                addq.l  #$8,d0
                fmove.s fp0,$14(a0)             ; pd_J[5] = tr - ti
                add.w   #$40,a0                 ; pd_J += 16
                cmp.w   d3,d0
                blo     .Case3_I

        ;------ Dernière passe.

.EndMaster      move.l  d2,d5                   ; BlockEnd = BlockSize
                add.l   d2,d2
                addq.l  #1,d7                   ; ++delta
                cmp.w   d3,d2
                bls     .BlkSizeLoop

                sub.w   d3,d6
                bpl     .MasterLoop

                move.w  (sp)+,d3
                bra     .End

.LastLoop       move.l  a4,a0                   ; pd_J = &pdFFTIn[0]
                fmove.d 0(a6,d7.l*8),fp7        ; cos_alpha = dCosAlpha[delta]
                fmove.s #1.0,fp2                ; ar = 1.0
                fmove.d $50(a6,d7.l*8),fp5      ; sin_alpha = dSinAlpha[delta]
                fmove.s #0.0,fp4                ; ai = 1.0
                lea     0(a0,d2.l*4),a1         ; pd_K = &pdFFTIn[BlockSize]

                lea     $1004(a0),a2            ; pd_J[1025]
                lea     $1004(a1),a3            ; pd_K[1025]

                ;------ Boucle J

                moveq   #0,d4

.JLoop          cmp.w   #$100,d5                ; BlockEnd = 256 ?
                bne.b   .DoFirstHalf

                cmp.w   #$400,d3                ; iFFTSize = 1024 ?
                bne.b   .DoFirstHalf

                ; Cas spécial : BlockEnd = 256 et iFFTSize = 1024

                fmove.s $1000(a1),fp0           ; ti = pd_K[1024]
                fmove.x fp0,fp1
                fmul.x  fp2,fp0
                fmove.s (a3),fp3
                fmul.x  fp4,fp3
                fsub.x  fp3,fp0                 ; tr = ar * ti - ai * pd_K[1025]

                fmove.s (a3),fp3
                fmul.x  fp2,fp3
                fmul.x  fp4,fp1
                fadd.x  fp3,fp1                 ; ti = ar * pd_K[1025] + ai * ti

                fmove.s (a2),fp3
                fsub.x  fp1,fp3
                fmove.s fp3,(a3)                ; pd_K[1025] = pd_J[1025] - ti
                fadd.s  (a2),fp1
                fmove.s fp1,(a2)                ; pd_J[1025] = pd_J[1025] + ti

                fmove.s $1000(a0),fp1           ; ti = pd_J[1024]
                fmove.x fp1,fp3
                fsub.x  fp0,fp3
                addq.w  #$08,a2
                fmove.s fp3,$1000(a1)           ; pd_K[1024] = ti - tr
                fadd.x  fp0,fp1
                addq.w  #$08,a3
                fmove.s fp1,$1000(a0)           ; pd_J[1024] = ti + tr

.DoFirstHalf    fmove.s (a1),fp0                ; ti = pd_K[0]
                fmove.x fp0,fp1
                fmul.x  fp2,fp0
                fmove.s $4(a1),fp3
                fmul.x  fp4,fp3
                fsub.x  fp3,fp0                 ; tr = ar * ti - ai * pd_K[1]

                fmove.s $4(a1),fp3
                fmul.x  fp2,fp3
                fmul.x  fp4,fp1
                fadd.x  fp3,fp1                 ; ti = ar * pd_K[1] + ai * ti

                fmove.s (a0),fp3
                fsub.x  fp0,fp3
                fmove.s fp3,(a1)                ; pd_K[0] = pd_J[0] - tr
                fadd.s  (a0),fp0
                fmove.s fp0,(a0)                ; pd_J[0] = pd_J[0] + tr

                fmove.s $4(a0),fp3
                fmove.x fp3,fp0
                fsub.x  fp1,fp3
                fmove.s fp3,$4(a1)              ; pd_K[1] = pd_J[1] - ti
                fadd.x  fp0,fp1
                fmove.s fp1,$4(a0)              ; pd_J[1] = pd_J[1] + ti

                fmove.x fp2,fp0                 ; tr = ar
                fmul.x  fp7,fp2
                fmove.x fp4,fp1
                fmul.x  fp5,fp1
                fsub.x  fp1,fp2                 ; ar = ar * cos_alpha - ai * sin_alpha

                fmul.x  fp5,fp0
                fmul.x  fp7,fp4
                addq.w  #$08,a0
                fadd.x  fp0,fp4                 ; ai = tr * sin_alpha + ai * cos_alpha
                addq.l  #1,d4
                addq.w  #$08,a1
                cmp.l   d5,d4
                blo     .JLoop

                move.l  d2,d5                   ; BlockEnd = BlockSize
                add.l   d2,d2
                addq.l  #1,d7                   ; ++delta

.End            cmp.w   d3,d2
                bls     .LastLoop

                rts
*///
*///FastFFT_T (Version utilisant une LoopUp Table)
******* Misc_funcs/FastFFT **************************************************
*
*   NAME
*   FastFFTC::FastFFT -- Calculer la transformée de Fourier.
*
*   SYNOPSIS
*   FastFFTC::FastFFT(pdFFTIn, dSinCos, iFFTSize)
*
*   void FastFFTC::FastFFT(REAL *, REAL *, UWORD);
*
*   FUNCTION
*   Calcule la transformée de Fourier sur un ensemble d'échantillons.
*
*   INPUTS
*   pdFFTIn  - Tableau contenant les échantillons (série de nombres complexes
*       dans l'ordre : [partie réelle][partie imaginaire].
*   dSinCos  - Tableau des valeurs angulaires.
*   iFFTSize - Nombre d'échantillons à traiter.
*
*   NOTES
*   Cette fonction a été fortement optimisée en tirant partie de quelques
*   angles particuliers. Elle est capable de calculer une FFT sur un ensemble
*   de 1024 échantillons au maximum.
*
*   BUGS
*   Fonction contrôlée conforme le 20.06.98
*
*   SEE ALSO
*   FastFFTC::ComputeFastFFT_Stereo()
*
*****************************************************************************
*

        SECTION "_FastFFT_T:0",CODE


;void FastFFT_T(REAL *pdFFTIn, REAL dSinCos[], UWORD iFFTSize)

        XDEF    _FastFFT_T

_FastFFT_T      move.w  d0,-(sp)
                move.w  d0,d6
                move.l  a0,a4
                move.l  a1,a6

                move.w  #$100,d3
                cmp.w   d3,d6
                bhs.b   .UseDefaultSize

                move.w   d6,d3

.UseDefaultSize

        ;====== Boucle principale (k)

                sub.w   d3,d6

.MasterLoop     moveq   #1,d7                   ; BlockEnd = 1
                move.w  #$200,d5                ; step = 512

        ;------ Boucle interne (BlockSize)

                moveq   #2,d2

.InnerLoop      move.w  d6,d0                   ; k
                move.l  d2,d1
                add.w   d0,d0
                moveq   #0,d4                   ; delta = 0
                lea     0(a4,d0.w*4),a1
                move.l  a1,a3                   ; pd_J = pd_J2 = &pdFFTIn[k + k]
                asl.l   #2+1,d1                 ; n = BlockSize * 2 * 4
                lea     0(a3,d2.l*4),a0
                move.l  a0,a2                   ; pd_K = pd_K2 = &pd_J2[BlockSize]

                ;------ Boucle interne (i)

                moveq   #0,d0

.InitLoop       fmove.s (a1),fp1                ; ti = pd_J[0]
                fmove.x fp1,fp0
                fmove.s (a0),fp2                ; tr = pd_K[0]
                fsub.x  fp2,fp0
                fmove.s fp0,(a0)                ; pd_K[0] = ti - tr
                fadd.x  fp2,fp1
                fmove.s fp1,(a1)                ; pd_J[0] = ti + tr

                fmove.s $4(a1),fp2              ; tr = pd_J[1]
                fmove.x fp2,fp0
                fmove.s $4(a0),fp1              ; ti = pd_K[1]
                fsub.x  fp1,fp0
                fmove.s fp0,$4(a0)              ; pd_K[1] = tr - ti
                fadd.x  fp1,fp2
                add.w   d1,a0                   ; pd_K += n
                add.l   d2,d0
                fmove.s fp2,$4(a1)              ; pd_J[1] = tr + ti
                add.w   d1,a1                   ; pd_J += n
                cmp.w   d3,d0
                blo.b   .InitLoop

                addq.w  #$08,a3                 ; pd_J2 += 2
                addq.w  #$08,a2                 ; pd_K2 += 2

                cmp.w   #4,d7
                beq     .BlkSize_4
                bls     .BlkSize_2

                ;====== BlockEnd > 4

                moveq   #1,d0

                ;------ Boucle interne (j)

.Pass1_j        move.l  a3,a1                   ; pd_J = pd_J2
                move.l  a2,a0                   ; pd_K = pd_K2
                add.w   d5,d4                   ; delta += step

                fmove.s 0(a6,d4.w*4),fp4        ; ar = dSinCos[delta]
                fmove.s ($400.w,a6,d4.w*4),fp3  ; ai = dSinCos[delta + (SINCOSSIZE / 3)]

                swap    d5                      ; Sauvegarder la valeur "step"
                clr.w   d5

                ;------ Boucle interne (i)

.Pass1_i        fmove.s (a0),fp1                ; ti = pd_K[0]
                fmove.x fp4,fp2
                fmul.x  fp1,fp2
                fmove.x fp3,fp5
                fmove.s $4(a0),fp0              ; t  = pd_K[1]
                fmul.x  fp0,fp5
                fsub.x  fp5,fp2                 ; tr = ar * ti - ai * t

                fmul.x  fp4,fp0
                fmul.x  fp3,fp1
                fadd.x  fp0,fp1                 ; ti = ar * t + ai * ti

                fmove.s (a1),fp0                ; t = pd_J[0]
                fmove.x fp0,fp5
                fsub.x  fp2,fp5
                fmove.s fp5,(a0)                ; pd_K[0] = t - tr
                fadd.x  fp2,fp0
                fmove.s fp0,(a1)                ; pd_J[0] = t + tr

                fmove.s $4(a1),fp0              ; t = pd_J[1]
                fmove.x fp0,fp2
                fsub.x  fp1,fp2
                fmove.s fp2,$4(a0)              ; pd_K[1] = t - ti
                fadd.x  fp1,fp0
                add.w   d1,a0                   ; pd_K += n
                add.l   d2,d5
                fmove.s fp0,$4(a1)              ; pd_J[1] = t + ti
                add.w   d1,a1                   ; pd_J += n
                cmp.w   d3,d5
                blo.b   .Pass1_i

                swap    d5                      ; Récupérer la valeur "step"
                addq.l  #1,d0
                addq.w  #$08,a3                 ; pd_J2 += 2
                addq.w  #$08,a2                 ; pd_K2 += 2
                cmp.l   d7,d0
                blo     .Pass1_j
                bra     .MasterEnd

                ;====== BlockSize = 2

.BlkSize_2      move.l  a3,a1                   ; pd_J = pd_J2
                move.l  a2,a0                   ; pd_K = pd_K2

                cmp.w   #2,d7
                bne     .MasterEnd

                ;------ Boucle interne (i)

                moveq   #0,d0

.Pass2_i        fmove.s (a1),fp0                ; t = pd_J[0]
                fmove.x fp0,fp3
                fmove.s $4(a0),fp1              ; ti = pd_K[1]
                fsub.x  fp1,fp3
                fmove.s (a0),fp2                ; tr = pd_K[0]
                fmove.s fp3,(a0)                ; pd_K[0] = t - ti
                fadd.x  fp1,fp0
                fmove.s fp0,(a1)                ; pd_J[0] = t + ti

                fmove.s $4(a1),fp0              ; t = pd_J[1]
                fmove.x fp0,fp1
                fadd.x  fp2,fp1
                fmove.s fp1,$4(a0)              ; pd_K[1] = t + tr
                fsub.x  fp2,fp0
                add.w   #$20,a0                 ; pd_K += 8
                addq.l  #4,d0
                fmove.s fp0,$4(a1)              ; pd_J[1] = t - tr
                add.w   #$20,a1                 ; pd_J += 8
                cmp.w   d3,d0
                blo.b   .Pass2_i
                bra     .MasterEnd

                ;====== BlockSize = 4

.BlkSize_4      move.l  a3,a1                   ; pd_J = pd_J2
                move.l  a2,a0                   ; pd_K = pd_K2
                fmove.s $200(a6),fp3            ; ar = dSinCos[SINCOSSIZE / 6]

                ;------ Boucle interne (i)

                moveq   #0,d0

.Pass3_i        fmove.s (a0),fp0                ; ti = pd_K[0]
                fmove.x fp0,fp2
                fmove.s $4(a0),fp1              ; t  = pd_K[1]
                fadd.x  fp1,fp2
                fmul.x  fp3,fp2                 ; tr = ar * (ti + t)
                fsub.x  fp0,fp1
                fmul.x  fp3,fp1                 ; ti = ar * (t - ti)

                fmove.s (a1),fp0                ; t = pd_J[0]
                fmove.x fp0,fp4
                fsub.x  fp2,fp4
                fmove.s fp4,(a0)                ; pd_K[0] = t - tr
                fadd.x  fp2,fp0
                fmove.s fp0,(a1)                ; pd_J[0] = t + tr

                fmove.s $4(a1),fp0              ; t = pd_J[1]
                fmove.x fp0,fp2
                fsub.x  fp1,fp2
                fmove.s fp2,$4(a0)              ; pd_K[1] = t - ti
                fadd.x  fp1,fp0
                fmove.s fp0,$4(a1)              ; pd_J[1] = t + ti

                fmove.s $08(a1),fp0             ; t  = pd_J[2]
                fmove.x fp0,fp4
                fmove.s $0C(a0),fp1             ; ti = pd_K[3]
                fsub.x  fp1,fp4
                fmove.s $08(a0),fp2             ; tr = pd_K[2]
                fmove.s fp4,$08(a0)             ; pd_K[2] = t - ti
                fadd.x  fp1,fp0
                fmove.s fp0,$08(a1)             ; pd_J[2] = t + ti

                fmove.s $0C(a1),fp0             ; t = pd_J[3]
                fmove.x fp0,fp1
                fadd.x  fp2,fp1
                fmove.s fp1,$0C(a0)             ; pd_K[3] = t + tr
                fsub.x  fp2,fp0
                fmove.s fp0,$0C(a1)             ; pd_J[3] = t - tr

                fmove.s $10(a0),fp1             ; ti = pd_K[4]
                fmove.x fp1,fp2
                fmove.s $14(a0),fp0             ; t  = pd_K[5]
                fsub.x  fp0,fp2
                fmul.x  fp3,fp2                 ; tr = ar * (ti - t)
                fadd.x  fp0,fp1
                fmul.x  fp3,fp1                 ; ti = ar * (t + ti)

                fmove.s $10(a1),fp0             ; t = pd_J[4]
                fmove.x fp0,fp4
                fadd.x  fp2,fp4
                fmove.s fp4,$10(a0)             ; pd_K[4] = t + tr
                fsub.x  fp2,fp0
                fmove.s fp0,$10(a1)             ; pd_J[4] = t - tr

                fmove.s $14(a1),fp0             ; t = pd_J[5]
                fmove.x fp0,fp2
                fadd.x  fp1,fp2
                fmove.s fp2,$14(a0)             ; pd_K[5] = t + ti
                fsub.x  fp1,fp0
                add.w   #$40,a0                 ; pd_K += 16
                addq.l  #$8,d0
                fmove.s fp0,$14(a1)             ; pd_J[5] = t - ti
                add.w   #$40,a1                 ; pd_J += 16
                cmp.w   d3,d0
                blo     .Pass3_i

        ;====== Fin de la boucle principale.

.MasterEnd      move.l  d2,d7                   ; BlockEnd = BlockSize
                lsr.w   #1,d5                   ; step >>= 1
                add.l   d2,d2
                cmp.w   d3,d2
                bls     .InnerLoop

                sub.w   d3,d6
                bpl     .MasterLoop

        ;====== Dernière passe.

                move.w  (sp)+,d6
                bra     .LastLoopEnd

.LastLoop       move.l  a4,a1                   ; pd_J  = &pdFFTIn[0]
                moveq   #0,d4                   ; delta = 0
                fmove.s #1.0,fp4                ; ar = 1.0
                fmove.s #0.0,fp3                ; ai = 1.0
                lea     0(a1,d2.l*4),a0         ; pd_K  = &pdFFTIn[BlockSize]
                lea     $1000(a1),a3            ; pd_J2 = pd_J + 1024
                lea     $1000(a0),a2            ; pd_K2 = pd_K + 1024

        ;------ Boucle interne (j)

                moveq   #0,d3

.Pass4_j        cmp.w   #$100,d7
                bne.s   .DoFirstHalf            ; BlockEnd = 256 ?

                cmp.w   #$400,d6
                bne.s   .DoFirstHalf            ; iFFTSize = 1024 ?

                fmove.s (a2),fp1                ; ti = pd_K2[0]
                fmove.x fp4,fp2
                fmul.x  fp1,fp2
                fmove.x fp3,fp5
                fmove.s $4(a2),fp0              ; t  = pd_K2[1]
                fmul.x  fp0,fp5
                fsub.x  fp5,fp2                 ; tr = ar * ti - ai * t

                fmul.x  fp4,fp0
                fmul.x  fp3,fp1
                fadd.x  fp0,fp1                 ; ti = ar * t + ai * ti

                fmove.s (a3),fp0                ; t = pd_J2[0]
                fmove.x fp0,fp5
                fsub.x  fp2,fp5
                fmove.s fp5,(a2)                ; pd_K2[0] = t - tr
                fadd.x  fp2,fp0
                fmove.s fp0,(a3)                ; pd_J2[0] = t + tr

                fmove.s $4(a3),fp0              ; t = pd_J2[1]
                fmove.x fp0,fp2
                fsub.x  fp1,fp2
                fmove.s fp2,$4(a2)              ; pd_K2[1] = t - ti
                fadd.x  fp1,fp0
                addq.w  #$08,a2                 ; pd_K2 += 2
                addq.w  #$08,a3                 ; pd_J2 += 2
                fmove.s fp0,-4(a3)              ; pd_J2[1] = t + ti

.DoFirstHalf    fmove.s (a0),fp1                ; ti = pd_K[0]
                fmove.x fp4,fp2
                fmul.x  fp1,fp2
                fmove.x fp3,fp5
                fmove.s $4(a0),fp0              ; t  = pd_K[1]
                fmul.x  fp0,fp5
                fsub.x  fp5,fp2                 ; tr = ar * ti - ai * t

                fmul.x  fp4,fp0
                fmul.x  fp3,fp1
                fadd.x  fp0,fp1                 ; ti = ar * t + ai * ti

                fmove.s (a1),fp0                ; t = pd_J[0]
                fmove.x fp0,fp3
                fsub.x  fp2,fp3
                fmove.s fp3,(a0)                ; pd_K[0] = t - tr
                fadd.x  fp2,fp0
                fmove.s fp0,(a1)                ; pd_J[0] = t + tr

                fmove.s $4(a1),fp0              ; t = pd_J[1]
                fmove.x fp0,fp2
                fsub.x  fp1,fp2
                fmove.s fp2,$4(a0)              ; pd_K[1] = t - ti
                fadd.x  fp1,fp0
                addq.w  #$08,a0                 ; pd_K += 2
                addq.w  #$08,a1                 ; pd_J += 2
                fmove.s fp0,-4(a1)              ; pd_J[1] = t + ti

                add.w   d5,d4                   ; delta += step
                addq.l  #1,d3
                fmove.s 0(a6,d4.w*4),fp4        ; ar = dSinCos[delta]
                fmove.s ($400.w,a6,d4.w*4),fp3  ; ai = dSinCos[delta + (SINCOSSIZE / 3)]
                cmp.l   d7,d3
                blo     .Pass4_j

                move.l  d2,d7                   ; BlockEnd = BlockSize
                lsr.w   #1,d5                   ; step >>= 1
                add.l   d2,d2

.LastLoopEnd    cmp.w   d6,d2
                bls     .LastLoop

                rts
*///
*/// FastFFT_Global
        SECTION "_FastFFT_Stereo_T:0",CODE

;void FastFFT_Stereo_T(REAL *pdFFTIn, REAL dSinCos[], UWORD iFFTSize)

        XDEF    _FastFFT_Stereo_T
        XDEF    _FastFFT_Mono_T

_FastFFT_Stereo_T

                PUSH    d2-d7/a2-a4/a6,FastFFT_Stereo_T
                fmovem.x fp2/fp3/fp4/fp5/fp6/fp7,-(sp)

                DEFINE  FastFFT_Stereo_T
                LONG    FFT_FPU_REGS,6*3
                CPTR    FFT_pdFFTIn
                CPTR    FFT_dSinCos
                UWORD   FFT_iFFTSize

                move.l  FFT_pdFFTIn(sp),a0
                move.l  FFT_dSinCos(sp),a1
                move.w  FFT_iFFTSize(sp),d0
                jsr     _FastFFT_T

                move.l  FFT_pdFFTIn(sp),a0
                move.w  FFT_iFFTSize(sp),d0
                jsr     _FixFFT_Stereo

                fmovem.x (sp)+,fp2/fp3/fp4/fp5/fp6/fp7
                POP     FastFFT_Stereo_T
                rts

;void FastFFT_Mono_T(REAL *pdFFTIn, REAL dSinCos[], UWORD iFFTSize)

_FastFFT_Mono_T

                PUSH    d2-d7/a2-a4/a6,FastFFT_Mono_T
                fmovem.x fp2/fp3/fp4/fp5/fp6/fp7,-(sp)

                move.w  FFT_iFFTSize(sp),d0
                move.l  FFT_pdFFTIn(sp),a0
                lsr.w   #1,d0
                move.l  FFT_dSinCos(sp),a1
                jsr     _FastFFT_T

                move.w  FFT_iFFTSize(sp),d0
                move.l  FFT_pdFFTIn(sp),a0
                lsr.w   #1,d0
                move.l  FFT_dSinCos(sp),a1
                jsr     _FixFFT_Mono_T

                fmovem.x (sp)+,fp2/fp3/fp4/fp5/fp6/fp7
                POP     FastFFT_Mono_T
                rts


        SECTION "_FastFFT_Stereo_C:0",CODE

;void FastFFT_Stereo_C(REAL *pdFFTIn, REAL dSinCos[][], UWORD iFFTSize)

        XDEF    _FastFFT_Stereo_C
        XDEF    _FastFFT_Mono_C

_FastFFT_Stereo_C

                PUSH    d2-d7/a2-a4/a6,FastFFT_Stereo_C
                fmovem.x fp2/fp3/fp4/fp5/fp6/fp7,-(sp)

                move.l  FFT_pdFFTIn(sp),a0
                move.l  FFT_dSinCos(sp),a1
                move.w  FFT_iFFTSize(sp),d0
                jsr     _FastFFT_C

                move.l  FFT_pdFFTIn(sp),a0
                move.w  FFT_iFFTSize(sp),d0
                jsr     _FixFFT_Stereo

                fmovem.x (sp)+,fp2/fp3/fp4/fp5/fp6/fp7
                POP     FastFFT_Stereo_C
                rts


;void FastFFT_Mono_C(REAL *pdFFTIn, REAL dSinCos[][], UWORD iFFTSize)

_FastFFT_Mono_C

                PUSH    d2-d7/a2-a4/a6,FastFFT_Mono_C
                fmovem.x fp2/fp3/fp4/fp5/fp6/fp7,-(sp)

                move.w  FFT_iFFTSize(sp),d0
                move.l  FFT_pdFFTIn(sp),a0
                lsr.w   #1,d0
                move.l  FFT_dSinCos(sp),a1
                jsr     _FastFFT_C

                move.w  FFT_iFFTSize(sp),d0
                move.l  FFT_pdFFTIn(sp),a0
                lsr.w   #1,d0
                move.l  FFT_dSinCos(sp),a1
                jsr     _FixFFT_Mono_C

                fmovem.x (sp)+,fp2/fp3/fp4/fp5/fp6/fp7
                POP     FastFFT_Mono_C
                rts
*///
*/// ScaleFactorCalc_double

        SECTION "_ScaleFactorCalc_double:0",CODE

        XDEF    _ScaleFactorCalc_double


;void ScaleFactorCalc_double(UBYTE *pbScalar, REAL pdSample[12][32], ULONG iSBLimit)

_ScaleFactorCalc_double

                PUSH    d2/a2,ScaleFactorCalc_DBL

                DEFINE  ScaleFactorCalc_DBL
                ULONG   sfcD_pbScalar
                ULONG   sfcD_pdSample
                ULONG   sfcD_iSBLimit

                move.l  sfcD_iSBLimit(sp),d2    ; iSBLimit
                move.l  sfcD_pbScalar(sp),a0    ; pbScalar
                move.l  sfcD_pdSample(sp),a1    ; pdSample

                subq.w  #1,d2

        ;------ Boucle principale (i)

.i_loop         movea.l a1,a2
                fabs.d  (a1)+,fp0               ; ds = fabs(*pSamples)

        ;------ Boucle interne (j)

                moveq   #10,d0

.j_loop         adda.w  #32*8,a2                ; pSamples += SBLIMIT
                fabs.d  (a2),fp1                ; d = fabs(*pSamples)

        ;------ if (ds < d) ds = d;

                fcmp.x  fp1,fp0
                fboge   .j_end

                fmove.x fp1,fp0

.j_end          dbra    d0,.j_loop

                fmove.d fp0,-(sp)               ; u.f = real;

                move.w  (sp),d1
                andi.w  #$7FF0,d1
                move.w  #$400,d0
                lsr.w   #4,d1
                sub.w   d1,d0                   ; e = ( 1024 - ((u.s[0] & 0x7FF0) >> 4) ) * 3

        IFNE    CPU_TYPE=68060
                muls.w  #3,d0
        ELSE
                move.w  d0,d1
                add.w   d0,d0
                add.w   d1,d0                   ; d0 = 3.d0
        ENDC

                move.w  (sp),d1
                andi.w  #$F,d1
                ori.w   #$41D0,d1
                move.w  d1,(sp)                 ; u.s[0] = (u.s[0] & 0x000F) | NEW_EXP

                fmove.d (sp)+,fp0
                fmove.l fp0,d1                  ; m = (int) u.f

        ;------ if (m > 1704458901) e -= 3

                cmpi.l  #$6597FA95,d1
                bls.s   .Check_m2

                subq.l  #3,d0
                bra.s   .Adjust_exp

        ;------ else if (m > 1352829926) e -= 2

.Check_m2       cmpi.l  #$50A28BE6,d1
                bls.s   .Check_m3

                subq.l  #2,d0
                bra.s   .Adjust_exp

        ;------ else if (m > 1073741824) e -= 1

.Check_m3       cmpi.l  #$40000000,d1
                bls.s   .Adjust_exp

                subq.l  #1,d0

        ;------ if (e < 0) e = 0

.Adjust_exp     bpl.s   .Limit_exp

                moveq   #0,d0

        ;------ if (e > SCALE_RANGE - 2) e = SCALE_RANGE - 2

.Limit_exp      cmpi.l  #$3E,d0
                bls.s   .End

                moveq   #$3E,d0

.End            move.b  d0,(a0)+                ; *pbScalar++ = GetIndex(ds);

                dbra    d2,.i_loop

                POP     ScaleFactorCalc_DBL
                rts

*///

        ENDC

        IFEQ    USE_QUICK_PUTBITS
*/// PutBitsASM (C++)

        SECTION "PutBitsASM__CoderC__TP22s_OutputStream__CoderCUjUj:0",CODE

;void CoderC::PutBitsASM(s_OutputStream *pStreamDatas, ULONG iValue,ULONG iLength)

        XDEF    PutBitsASM__CoderC__TP22s_OutputStream__CoderCUjUj
        XREF    WriteBuffer__CoderC__T

    STRUCTURE   s_OutputStream
        ULONG   pOutputBuffer
        ULONG   iOB_BitIndex
        ULONG   iOB_TotalBits
        ULONG   iOB_BitsFree
        LONG    iOB_NoWriteError
    ENDSTRUCT   s_OutputStream

PutBitsASM__CoderC__TP22s_OutputStream__CoderCUjUj

                PUSH    d2-d4/a2,PutBitsASM

                DEFINE  PutBitsASM
                APTR    ClassBase
                APTR    pStreamDatas
                ULONG   iValue
                ULONG   iLength

                move.l  iValue(sp),d4
                move.l  iLength(sp),d2
                movea.l pStreamDatas(sp),a2

                move.l  d2,d3                   ; iFieldSize = iLength
                sub.l   iOB_BitsFree(a2),d3
                ble.s   .ResetReminder

        ;------ si iReminder > 0

                sub.l   d3,d2                   ; iFieldSize -= iReminder
                bra.s   .InsertFirst

.ResetReminder  moveq   #0,d3                   ; iReminder = 0;

.InsertFirst    move.l  d4,d0                   ; iValue
                move.l  iOB_BitIndex(a2),d1
                lsr.l   d3,d0                   ; iValue >> iReminder
                move.l  pOutputBuffer(a2),a0
                bfins   d0,(a0){d1:d2}          ; Insérer les nouveaux bits.

                add.l   d2,iOB_BitIndex(a2)     ; pStreamDatas->iOB_BitIndex += iFieldSize
                sub.l   d2,iOB_BitsFree(a2)     ; pStreamDatas->iOB_BitsFree -= iFieldSize
                bne.s   .DoReminder

        ;------ Tampon plein.

                move.l  ClassBase(sp),-(sp)
                jsr     WriteBuffer__CoderC__T
                addq.w  #4,a7

                clr.l   iOB_BitIndex(a2)
                move.l  iOB_TotalBits(a2),iOB_BitsFree(a2)

        ;------ Traiter le reste s'il existe.

.DoReminder     tst.l   d3
                beq.s   .End

                move.l  (a2),a0
                bfins   d4,(a0){0:d3}

                add.l   d3,iOB_BitIndex(a2)
                sub.l   d3,iOB_BitsFree(a2)

.End            POP     PutBitsASM
                rts

*///
        ELSE
*/// PutBitsASM2 (C)

        SECTION "PutBitsASM",CODE

;void CoderC::PutBitsASM2(s_OutputStream *pStreamDatas, UWORD *buffer, UWORD *lastpos)

        XDEF    PutBitsASM2__CoderC__TP22s_OutputStream__CoderCPUsPUs
        XREF    WriteBuffer__CoderC__T

    STRUCTURE   s_OutputStream
        ULONG   pOutputBuffer
        ULONG   iOB_BitIndex
        ULONG   iOB_TotalBits
        ULONG   iOB_BitsFree
        LONG    iOB_NoWriteError
    ENDSTRUCT   s_OutputStream

PutBitsASM2__CoderC__TP22s_OutputStream__CoderCPUsPUs

                PUSH    d2-d6/a2-a4/a6,PutBitsASM2

                DEFINE  PutBitsASM2
                APTR    ClassBase
                APTR    pStreamDatas
                APTR    pBuffer
                APTR    pLastPos

                ;move.l  iValue(sp),d4
                ;move.l  iLength(sp),d2
                movea.l pBuffer(sp),a3
                movea.l pLastPos(sp),a4
                movea.l pStreamDatas(sp),a2
                move.l  iOB_BitsFree(a2),d5
                move.l  iOB_BitIndex(a2),d6
                movea.l pOutputBuffer(a2),a6

.start          move.w  (a3)+,d2                ; Bitfield length
                ext.l   d2
                move.l  d2,d3                   ; iFieldSize = iLength
                move.w  (a3)+,d4                ; Value.
                ext.l   d4
                move.l  d4,d0
                sub.l   d5,d3
                ble.s   .Insert

        ;------ si iReminder > 0

                sub.l   d3,d2                   ; iFieldSize -= iReminder
                lsr.l   d3,d0                   ; iValue >> iReminder

.Insert         bfins   d0,(a6){d6:d2}          ; Insérer les nouveaux bits.
                add.l   d2,d6                   ; pStreamDatas->iOB_BitIndex += iFieldSize
                sub.l   d2,d5                   ; pStreamDatas->iOB_BitsFree -= iFieldSize
                bne.s   .DoReminder

        ;------ Tampon plein.

                move.l  d6,iOB_BitIndex(a2)

                move.l  ClassBase(sp),-(sp)
                jsr     WriteBuffer__CoderC__T
                addq.w  #4,sp

                clr.l   d6
                move.l  iOB_TotalBits(a2),d5

        ;------ Traiter le reste s'il existe.

.DoReminder     tst.l   d3
                ble.s   .EndLoop

                bfins   d4,(a6){0:d3}

                add.l   d3,d6
                sub.l   d3,d5

.EndLoop        cmpa.l  a4,a3
                bcs.s   .start

                move.l  d5,iOB_BitsFree(a2)
                move.l  d6,iOB_BitIndex(a2)

.End            POP     PutBitsASM2
                rts

*///
        ENDC

*/// UpdateCRC

        SECTION "_UpdateCRC:0",CODE

;UWORD UpdateCRC(ULONG iData, UWORD wLength, UWORD wCRC)

        XDEF    _UpdateCRC

_UpdateCRC      PUSH    d2-d4,UpdateCRC

; NOTE : Le prototype de la fonction permet au compilateur de placer les données requises
;        directement dans les bons registres.
;
;               d2  crc_Checksum
;               d1  crc_Length
;               d0  crc_Data

                ror.l   d1,d0                   ; Justifier "data" à gauche.
                subq.w  #1,d1

.CRCLoop        moveq   #0,d3
                asl.w   #1,d2                   ; wCRC <<= 1, sr[carry] placé.
                roxl.w  #1,d3                   ; iCarry = sr[carry]
                moveq   #0,d4
                asl.l   #1,d0                   ; sr[carry] = Bit suivant de "data"
                roxl.w  #1,d4                   ; Bit suivant de "data" (= sr[carry]
                eor.w   d4,d3
                beq.b   .EndLoop                ; !iCarry ^ !(iData & iMasking) == FALSE
                                                ; <==> iCarry ^ (idata & iMasking) == FALSE

                eori.w  #$8005,d2               ; wCRC ^= 0x8005

.EndLoop        dbra    d1,.CRCLoop

                move.w  d2,d0
                POP     UpdateCRC
                rts

*///

        END

