/*
**
** $VER: CoderC.cpp 1.10 (24.12.2001)
**
*/


//----------------------------------------------------------------------------------------------------

/// Includes

#ifndef  _INCLUDE_STDLIB_H
#include <stdlib.h>
#endif

#ifndef  _INCLUDE_MATH_H
#include <math.h>
#endif

#ifndef  _INCLUDE_IOSTREAM_H
#include <iostream.h>
#endif

#ifndef  CLIB_DOS_PROTOS_H
#include <clib/dos_protos.h>
#endif

#ifndef  _PEGASECOND_HPP
#include "PegaseCond.hpp"
#endif

#ifndef  _FILEINFOS_CLASS_HPP
#include "FileInfosC.hpp"
#endif

#ifndef  _INPUTSTREAM_CLASS_HPP
#include "InputStreamC.hpp"
#endif

#ifndef  _COMMON_HPP
#include "common.hpp"
#endif

#ifndef  _MEMORY_HPP
#include "Memory.hpp"
#endif

#ifndef  _CODER_CLASS_HPP
#include "CoderC.hpp"
#endif

#ifndef  _PSYCHO_CLASS_HPP
#include "PsychoC.hpp"
#endif

#ifndef  _ENCODERCONFIG_CLASS_HPP
#include "EncoderConfigC.hpp"
#endif

///


#define _ASM_SB_CODING_MONO_    _USE_ASM_FCT_
#define _ASM_SB_CODING_STEREO_  _USE_ASM_FCT_
#define _ASM_SCALEFACTOR_CALC_  _USE_ASM_FCT_
#define _ASM_UPDATECRC_         _USE_ASM_FCT_
#define _ASM_PUTBITS_           _USE_ASM_FCT_
#define _ASM_ENCODESAMPLES_     _USE_ASM_FCT_


//----------------------------------------------------------------------------------------------------
//====================================== Classe EncoderConfigC =======================================
//----------------------------------------------------------------------------------------------------

/// EncoderConfigC::COPY CONSTRUCTOR
/****** Class EncoderConfigC/COPY CONSTRUCTOR *******************************
*
*   NAME
*   EncoderConfigC::EncoderConfigC -- Constructeur de recopie
*
*   SYNOPSIS
*   EncoderConfigC::EncoderConfigC(roConfig)
*
*   EncoderConfigC::EncoderConfigC(const EncoderConfigC &);
*
*   FUNCTION
*   Recopie les réglages de l'encodeur.
*
*   INPUTS
*   roConfig - Réglages à recopier.
*
*   NOTES
*   Cette fonctionnalité est utilisée pour initialiser les réglages locaux
*   de l'encodeur pour chaque fichier, en partant des réglages par défaut.
*
*****************************************************************************
*
*/


EncoderConfigC::EncoderConfigC(const EncoderConfigC &roConfig)
{
    const EncoderConfigC *const poConfig = &roConfig;

    // Recopier les réglages par défaut.

    ecfg_iLayer       = poConfig->ecfg_iLayer;
    ecfg_wSampling    = poConfig->ecfg_wSampling;
    ecfg_wBitrate     = poConfig->ecfg_wBitrate;
    ecfg_sFlags       = poConfig->ecfg_sFlags;
    ecfg_sModes       = poConfig->ecfg_sModes;
    ecfg_wTargetType  = poConfig->ecfg_wTargetType;
    ecfg_iIntelFormat = poConfig->ecfg_iIntelFormat;
    ecfg_CDDAFmt      = poConfig->ecfg_CDDAFmt;

    SetOutputName(poConfig->GetOutputName());
}
///
/// EncoderConfigC::SetBitRate()
/****** Class EncoderConfigC/SetBitRate ****************************************
*
*   NAME
*   EncoderConfigC::SetBitRate -- Définir le taux de sortie de l'encodeur.
*
*   SYNOPSIS
*   EncoderConfigC::SetBitRate(wBitRate)
*
*   void EncoderConfigC::SetBitRate(UWORD);
*
*   FUNCTION
*   Mémorise le taux de sortie de l'encodeur, ainsi que l'index correspondant.
*   Si le taux de sortie demandé n'existe pas dans la table, la fonction sélec-
*   tionne la valeur inférieure la plus proche.
*   Si le taux de sortie demandé est inférieur à la plus petite valeur de la
*   table, la fonction sélectionne la valeur par défaut (160 kbits/s)/
*
*   INPUTS
*   wBitRate - Taux de sortie souhaité (kbits/s)
*
*****************************************************************************
*
*/


void EncoderConfigC::SetBitRate(UWORD wBitRate)
{
    static UWORD a_wBitrate[2][14] = {
          {32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, // Layer I
          {32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384}  // Layer II
    };

    int iBrate = 0;
    int ibr;
    int iLayer = ecfg_iLayer;
    ecfg_wBitrate = 0;

    // Utiliser le taux de sortie légal immédiatement inférieur à la valeur indiquée.

    while (wBitRate >= (ibr = a_wBitrate[iLayer][iBrate]) && iBrate < 14) {
        if (wBitRate == ibr) {
            ecfg_wBitrate = a_wBitrate[iLayer][iBrate];
            ecfg_sModes.bitrate = iBrate;
            break;
        }
        ++iBrate;
    }

    // Si le taux de sortie choisi n'a pas été trouvé, sélectionner la valeur inférieure
    // la plus proche, ou la valeur par défaut.

    if (!ecfg_wBitrate) {
        if (iBrate > 0 && iBrate < 14) {        // Prendre la valeur inférieure.
            ecfg_sModes.bitrate = --iBrate;
            ecfg_wBitrate       = a_wBitrate[iLayer][iBrate];
        }
        else {                                  // Prendre la valeur par défaut.
            ecfg_wBitrate = DEFAULT_BITRATE;
            ecfg_sModes.bitrate = (iLayer == LAYER_I) ? 4 : 8;
        }
    }
}
///
/// EncoderConfigC::SetSampleFreq()
/****** Class EncoderConfigC/SetSampleFreq *************************************
*
*   NAME
*   EncoderConfigC::SetSampleFreq -- Définir la fréquence d'échantillonage.
*
*   SYNOPSIS
*   success = EncoderConfigC::SetSampleFreq(wSampleFreq)
*
*   bool EncoderConfigC::SetSampleFreq(UWORD);
*
*   FUNCTION
*   Mémorise la fréquence d'échantillonage choisie par l'utilisateur ou
*   spécifiée par le fichier audio à encoder.
*   La tolérance pour cette fréquence d'échantillonage est de +/- 4% par
*   rapport aux valeurs autorisées (32 KHz, 44.1 KHz et 48 KHz). Toutes les
*   fréquences hors de ces limites sont rejetées.
*
*   INPUTS
*   wSampleFreq - Fréquence d'échantillonage à utiliser par défaut (Hz)
*
*   RESULT
*   success - FALSE si la fréquence est incorrecte.
*
*****************************************************************************
*
*/


int EncoderConfigC::SetSampleFreq(UWORD wSampleFreq)
{
    if (wSampleFreq >= 30720 && wSampleFreq <= 33280) {
        ecfg_wSampling = 32000;
        ecfg_sModes.sampfreq = F_32000;
    }
    else if (wSampleFreq >= 42336 && wSampleFreq <= 45864) {
        ecfg_wSampling = 44100;
        ecfg_sModes.sampfreq = F_44100;
    }
    else if (wSampleFreq >= 46080 && wSampleFreq <= 49920) {
        ecfg_wSampling = 48000;
        ecfg_sModes.sampfreq = F_48000;
    }
    else {
        ecfg_wSampling = 0;
        ecfg_sModes.sampfreq = F_ILLEGAL;
        return FALSE;
    }

    return TRUE;
}
///

//----------------------------------------------------------------------------------------------------
//========================================== Classe CoderC ===========================================
//----------------------------------------------------------------------------------------------------
//
//  CoderC est la classe de base, dérivée en classes spécialisées pour chaque Layer.
//  Les fonctions supportées par cette classe sont des fonctions générales, communes à chaque type
//  de layer (chaque classe spécialisée ayant la possibilité de re-définir en partie ces fonctions).

// Constructeur et destructeur.

/// CoderC::CoderC()
CoderC::CoderC(FileInfosC &roFileInfos, ULONG iReserved) : EncoderConfigC(roFileInfos), enc_roFileInfos(roFileInfos)
{
    int iInitError;

    SetErrorCodes(ESTAT_NOTREADY, ERR_NOT_INITIALIZED);     // Indiquer que l'encodeur n'est pas encore prêt.
    enc_pInputHandle   = NULL;

    SetOutputName(roFileInfos.GetOutputName());             // Récupérer le nom du fichier encodé.

    // Ouvrir le canal d'entrée (InputStream)

    if ( (enc_pInputHandle = CreateAudioC(roFileInfos)) ) {
        ULONG SpecialOffset = (GetEncodingMode() == MONO) ? iReserved : iReserved * 2;
        enc_pInputHandle->SetRollGap(SpecialOffset);

        if (enc_pInputHandle->OpenStream() == IOERR_NONE && enc_pInputHandle->AllocStreamBuffer() == IOERR_NONE) {
            iInitError  = !(enc_pdAnaFilter = (T_AnaFilter *) AllocAlignedBuffer(sizeof(T_AnaFilter)));
            iInitError |= !(enc_sOutputStreamDatas.pOutputBuffer = AllocAlignedBuffer(OUTPUT_BUFFSIZE));

            if (!iInitError) {
                SetErrorCodes(ESTAT_READY, ERR_NONE);

                enc_NumChannels = (GetEncodingMode() == MONO) ? 1 : 2;
                enc_isStereo = enc_NumChannels - 1;
                enc_SBLimit = SBLIMIT;

                enc_MinNeededBits = (sizeof(BSHeader) * 8) + (IsCRC() ? 16 : 0);
                enc_sOutputStreamDatas.iOB_BitIndex  = 0;
                enc_sOutputStreamDatas.iOB_TotalBits = enc_sOutputStreamDatas.iOB_BitsFree = OUTPUT_BUFFSIZE * 8;
                enc_bpOB_FileLock  = NULL;

                InitAnaFilter();
                InitWrite();            // Initialiser le fichier destination.

                // Initialiser le tableau "multiple" inverse (pour EncodeSamples()).

                REAL s = 1.25992104989487;          // = sqrt³(2)
                REAL old;
                enc_adMultiples[0] = old = 0.5;

                for (int i = 1; i < 63; i++)
                    old = enc_adMultiples[i] = old * s;

                enc_adMultiples[63] = 1e20;

                // Initialiser le bloc d'entête pour le fichier encodé.

                enc_BSHeader.sBSHeader.bsh_SyncWord  = 0xFFF;
                enc_BSHeader.sBSHeader.bsh_Version   = 1;        // MPEG-1
                enc_BSHeader.sBSHeader.bsh_CRC       = !IsCRC();
                enc_BSHeader.sBSHeader.bsh_Bitrate   = GetBitrateIndex() + 1;
                enc_BSHeader.sBSHeader.bsh_SmplFreq  = GetSmplFrqIndex();
                enc_BSHeader.sBSHeader.bsh_Padding   = 0;
                enc_BSHeader.sBSHeader.bsh_Extension = 0;
                enc_BSHeader.sBSHeader.bsh_Mode      = GetEncodingMode();
                enc_BSHeader.sBSHeader.bsh_ModeExt   = 0;
                enc_BSHeader.sBSHeader.bsh_Copyright = IsCopyrighted();
                enc_BSHeader.sBSHeader.bsh_Original  = IsOriginal();
                enc_BSHeader.sBSHeader.bsh_Emphasis  = GetDeemphasis();
            }
            else SetErrorCodes(ESTAT_NOMEMORY, ERR_INTERNAL_BUFFERS);
        }
        else SetErrorCodes(ESTAT_NOTREADY, ERR_ISTREAM_FAILURE);
    }
}
///
/// CoderC::~CoderC() (virtual)
CoderC::~CoderC()
{
    void *pOutBuffer = enc_sOutputStreamDatas.pOutputBuffer;

    if (enc_pdAnaFilter)
        FreeAlignedBuffer(enc_pdAnaFilter);

    if (pOutBuffer) {
        CleanupWrite();
        FreeAlignedBuffer(pOutBuffer);
    }

    if (enc_poPsychoC)
        delete enc_poPsychoC;

    CloseIStream();
}
///

void CoderC::CloseIStream()
{
    // Fermer le fichier à encoder.

    if (enc_pInputHandle) {
        enc_pInputHandle->FreeStreamBuffer();
        enc_pInputHandle->CloseStream();
        delete enc_pInputHandle;                      // Fermer le flux d'entrée.
        enc_pInputHandle = NULL;
    }
}



//----------------------------------------------------------------------------------------------------
//=========================== Parties communes à tous les types de Layers ============================
//----------------------------------------------------------------------------------------------------

// Fonctions privées.

/// CoderC::InitAnaFilter()
/****** Class CoderC/InitAnaFilter ******************************************
*
*   NAME
*   CoderC::InitAnaFilter -- Initialiser la table AnaFilter
*
*   SYNOPSIS
*   CoderC::InitAnaFilter()
*
*   void CoderC::InitAnaFilter();
*
*   FUNCTION
*   Initialise la table AnaFilter().
*
*   NOTES
*   Cette table est calculée en utilisant les formules de trigonométrie
*   classiques plutôt qu'en faisant appel de multiples fois à cos().
*
*****************************************************************************
*
*/

#ifndef PI
#define PI 3.141592653589797
#endif

void CoderC::InitAnaFilter()
{
    REAL sin_alpha, cos_alpha;
    REAL sin_delta, cos_delta;
    REAL t;

    t = PI / 64.0;
    sin_delta = sin(t);
    cos_delta = cos(t);

    sin_alpha = cos_alpha = sqrt(0.5);

    for (int i = 0; i < 128 ; i++) {
        t = cos_alpha * 1e9;
        (*enc_pdAnaFilter)[i] = 1e-9 * ( (t >= 0) ? floor(t + 0.5) : ceil(t - 0.5) );

        // Calculer les valeurs angulaires suivantes.
        t = cos_alpha;
        cos_alpha = t * cos_delta + sin_alpha * sin_delta;
        sin_alpha = sin_alpha * cos_delta - t * sin_delta;
    }
}
///
/// CoderC::GetIndex()   (double : ASM)
/****** Class CoderC/GetIndex ***********************************************
*
*   NAME
*   CoderC::GetIndex -- Retourne un index du tableau multiple[]
*
*   SYNOPSIS
*   Index = CoderC::GetIndex(real)
*
*   int CoderC::GetIndex(double);
*   int CoderC::GetIndex(float);
*
*   FUNCTION
*   Sépare la mantisse et l'exposant d'un nombre flottant, puis retourne
*   l'index du tableau multiple[] contenant la valeur immédiatement
*   supérieure.
*   Les deux variantes de la fonction permettent d'employer indifféremment
*   des "double" ou des "float".
*
*   INPUTS
*   real - Nombre flottant à traiter.
*   e    - Valeur de l'exposant.
*
*   RESULT
*   Mantisse - Valeur de la mantisse.
*
*   BUGS
*   La valeur retournée pour la mantisse ne prend pas en compte la totalité
*   des chiffres significatifs (6 chiffres en FLOAT, 9 chiffres en DOUBLE).
*
*   SEE ALSO
*   CoderC::ScaleFactor()
*
*****************************************************************************
*
* Le tableau "multiple[]" original est composé des 63 premiers termes d'une suite
* géométrique :
* U0 = 2, r = SQR³(1/2), U63 = 1e-20;
*
*  n   : Un                =>    exp        mantisse
* [00] : 2.00000000000000  => + 0x400   0x0000000000000
* [01] : 1.58740105196820  => + 0x3FF   0x965FEA53D6E3D
* [02] : 1.25992104989487  => + 0x3FF   0x428A2F98D728B
* [03] : 1.00000000000000  => + 0x3FF   0x0000000000000
* [04] : 0.79370052598410  => + 0x3FE   0x965FEA53D6E3D
* ...
*/


inline int CoderC::GetIndex(double real)
{
    // Format d'un "double" :
    // seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
    // Bias of biased exponent = 1023

    union lfloat {
        double f;
        short  s[4];
    } u;

    const int NEW_EXP = 0x3FF0 + (30 * 16);                // On n'utilise que 30 bits de la mantisse.
    int e, m;

    u.f = real;
    e = ( 1024 - ((u.s[0] & 0x7FF0) >> 4) ) * 3;            // Extraire l'exposant.
    u.s[0] = (u.s[0] & 0x000F) | NEW_EXP;                   // Modifier l'exposant.
    m = (int) u.f;                                          // Convertir la mantisse (flottante) en entier.

    if      (m >= 1704458901)  e -= 3;
    else if (m >= 1352829926)  e -= 2;
    else if (m >= 1073741824)  e -= 1;

    if (e < 0)
        e = 0;
    else if (e > SCALE_RANGE - 2)
        e = SCALE_RANGE - 2;

    return (e);
}


inline int CoderC::GetIndex(float real)
{
    // Format d'un "float" :
    // seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
    // Bias of biased exponent = 127

    union sfloat {
        float f;
        long  l;
    } u;

    int e, m;

    u.f = real;
    e = ( 128 - ((u.l & 0x7F800000) >> 23) ) * 3;           // Extraire l'exposant.
    m = u.l & 0x007FFFFF;

    if      (m >= 4927477)  e -= 3;
    else if (m >= 2180376)  e -= 2;
    else if (m >= 0)        e -= 1;

    if (e < 0)
        e = 0;
    else if (e > SCALE_RANGE - 2)
        e = SCALE_RANGE - 2;

    return (e);
}
///
/// CoderC::InitWrite()
/****** Class CoderC/InitWrite **********************************************
*
*   NAME
*   CoderC::InitWrite -- Initialiser le fichier de destination
*
*   SYNOPSIS
*   CoderC::InitWrite()
*
*   void CoderC::InitWrite();
*
*   FUNCTION
*   Initialise le fichier destination en l'effaçant s'il existe déjà.
*
*   NOTES
*   Il est nécessaire d'effacer ce fichier avant de commencer l'encodage, du
*   fait que la fonction WriteBuffer() ajoute les données au fur et à mesure
*   dans le fichier de sortie.
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderC::InitWrite()
{
    BPTR bpFileHandle;

    // Effacer le fichier, tout en le re-créant avec une taille de ZERO.

    if ( (bpFileHandle = ::Open(GetOutputName(), MODE_NEWFILE)) ) {
        // Création OK. Fermer le fichier (il doit maintenant avoir une taille de ZERO)

        if (::Close(bpFileHandle) != DOSFALSE) {
            if ( (enc_bpOB_FileLock = ::Lock(GetOutputName(), SHARED_LOCK)) ) {
                #if 0
                InfoData *idata;
                if ( (idata = new InfoData) && Info(enc_bpOB_FileLock, idata)) {
                    ULONG bitrate = GetBitRate() * (1000 / 8);
                    ULONG dstSize = enc_roFileInfos.GetNumFrames() / ecfg_wSampling * bitrate + bitrate;
                    LONG  freeBytes = (idata->id_NumBlocks - idata->id_NumBlocksUsed) * idata->id_BytesPerBlock;

                    if (dstSize > freeBytes)
                        SetErrorCodes(ESTAT_IOERROR, ERR_DISKFULL);

                }
                delete idata;
                #endif
                return;     // On a le Lock, donc poursuivre.
                            // Ce "lock" permettra de réouvrir ce fichier chaque fois qu'il
                            // faudra vider le tampon de sortie, et interdit en même temps
                            // la destruction du fichier tant que l'encodage n'est pas
                            // terminé.
            }
        }
    }

    SetErrorCodes(ESTAT_IOERROR, ERR_OPEN_OSTREAM);
}
///
/// CoderC::CleanupWrite()
/****** Class CoderC/CleanupWrite *******************************************
*
*   NAME
*   CoderC::CleanupWrite -- Fermer définitivement le fichier destination.
*
*   SYNOPSIS
*   CoderC::CleanupWrite()
*
*   void CoderC::CleanupWrite();
*
*   FUNCTION
*   Vide le tampon et ferme définitivement le fichier destination en libérant
*   le 'Lock' sur ce fichier.
*
*   NOTES
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderC::CleanupWrite()
{
    WriteBuffer();

    if (enc_bpOB_FileLock) {
        ::UnLock(enc_bpOB_FileLock);
        enc_bpOB_FileLock = 0;
    }
}
///
/// CoderC::WriteBuffer()
/****** Class CoderC/WriteBuffer ********************************************
*
*   NAME
*   CoderC::WriteBuffer -- Créer/compléter le fichier encodé.
*
*   SYNOPSIS
*   CoderC::WriteBuffer()
*
*   void CoderC::WriteBuffer();
*
*   FUNCTION
*   Ajoute le tampon de sortie au fichier encodé. Lors du premier appel, le
*   fichier est crée ou remplacé s'il existe déjà. Les appels suivants
*   ajoutent les données du tampon en fin de fichier.
*
*   NOTES
*   Le fichier est immédiatement refermé après avoir inscrit les nouvelles
*   données.
*
*   Lors du premier accès, le fichier est ouvert normalement, puis un 'Lock'
*   est obtenu sur ce fichier. Lorsque le fichier est refermé après avoir
*   inscrit les données, le 'Lock' est maintenu protégeant ainsi le fichier.
*   Lors des appels suivants, c'est ce 'Lock' qui est utilisé pour ouvrir
*   le fichier.
*
*   BUGS
*   Le mode READWRITE présentait l'avantage de créer un fichier vide s'il
*   n'existait pas, mais cette méthode semble poser des problèmes à AFS.
*   La méthode actuelle consiste donc à initialiser le fichier grâce au mode
*   NEWFILE, puis à obtenir directement un SHARED_LOCK après avoir fermé ce
*   fichier vide.
*
*****************************************************************************
*
*/

// La fonction Seek() ne fonctionne pas correctement avec le FileSystem v36/37.
// Voir les Autodocs pour le détail.

LONG NewSeek(BPTR file, LONG position, LONG offset);
// Fonction définie dans InputStream.cpp


void CoderC::WriteBuffer()
{
    BPTR  file_handle;
    ULONG num_bytes     = ((enc_sOutputStreamDatas.iOB_BitIndex + 7) >> 3);
    e_EncErrCodes error = ERR_NONE;

    // Avorter s'il y a eu une erreur, ou si le tampon est vide.

    if (enc_iEncoderStatus != ESTAT_READY || !num_bytes)
        return;

    // Ouvrir le fichier à partir du Lock obtenu à l'initialisation de l'encodeur.

    if (  (file_handle = ::OpenFromLock(enc_bpOB_FileLock)) && (enc_bpOB_FileLock = ::DupLockFromFH(file_handle)) ) {
        if (NewSeek(file_handle, 0, OFFSET_END) >= 0) {     // Se positionner en fin de fichier.
            BYTE *buffer = (BYTE *) enc_sOutputStreamDatas.pOutputBuffer;

            // Boucler sur l'écriture dans le fichier tant qu'il reste
            // des données dans le tampon.
            while (num_bytes) {
                LONG bytes_read = ::Write(file_handle, buffer, num_bytes);

                if (bytes_read == -1) {
                    error = ERR_WRITE_OSTREAM;              // Erreur d'écriture.
                    break;
                }

                num_bytes -= bytes_read;
                buffer    += bytes_read;
            }
        }
        else error = ERR_SEEK_OSTREAM;                      // Erreur de positionnement.

        if (::Close(file_handle) == DOSFALSE)
            error = ERR_CLOSE_OSTREAM;                      // Erreur de fermeture du fichier.
    }
    else error = ERR_OPEN_OSTREAM;                          // Erreur d'ouverture du fichier.

    // S'il y a eu une erreur, placer les indicateurs globaux.

    if (error != ERR_NONE)
        SetErrorCodes(ESTAT_IOERROR, error);
}
///

// Fonctions virtuelles.

/// CoderC::GetAudio()
/****** Class CoderC/GetAudio ***********************************************
*
*   NAME
*   CoderC::GetAudio -- Préparer la passe suivante de l'encodeur.
*
*   SYNOPSIS
*   Result = CoderC::GetAudio()
*
*   bool CoderC::GetAudio();
*
*   FUNCTION
*   Obtient l'adresse de la page suivante. Les échantillons au format Intel
*   sont convertis au format Motorola.
*
*   RESULT
*   Result - FALSE s'il y a eu une erreur pendant la lecture du tampon d'
*            entrée.
*
*****************************************************************************
*
*/


int CoderC::GetAudio()
{
    if ( (enc_pSamples = enc_pInputHandle->ReadSamples(enc_FrameSize)) ) {
        // Réordonner les échantillons si nécessaire (conversion Intel => Motorola).
        // (On converti la totalité du tampon de lecture).
        if (ecfg_iIntelFormat) {   // Format Intel ?
            char *p = (char *) enc_pSamples;
            ULONG FrameSize = enc_FrameSize;
            char  temp;

            for (int i = 0; i < FrameSize; i++) {
                temp = *p;
                *p++ = *(p+1);
                *p++ = temp;
            }
        }

        // Ajouter un slot si nécessaire.
        enc_AvgDataBits = 0;

        if (enc_SPF_Reminder) {
            if (enc_SlotLag >= enc_SlotRem) {
                enc_SlotLag -= enc_SlotRem;
                enc_AvgDataBits = enc_BitsPerSlot;
                enc_BSHeader.sBSHeader.bsh_Padding = 1;
            }
            else {
                enc_SlotLag += enc_SPF_Reminder;
                enc_BSHeader.sBSHeader.bsh_Padding = 0;
            }
        }

        enc_AvgDataBits += enc_SlotsPerFrame << enc_BitsPerSlotN;
        ++enc_FrameNumber;

        return TRUE;
    }

    return FALSE;
}
///

// Fonctions protégées.

///CoderC::InitSlotsPerFrame()
/****** Class CoderC/InitSlotsPerFrame **************************************
*
*   NAME
*   CoderC::InitSlotsPerFrame --
*
*   SYNOPSIS
*   CoderC::InitSlotsPerFrame(wSamplesPerFrame, wNumBitsN)
*
*   void CoderC::InitSlotsPerFrame(ULONG, ULONG);
*
*   FUNCTION
*
*   INPUTS
*   wSamplesPerFrame - Nombre d'échantillons par "page".
*   wNumBitsN        - Nombre de bits (Log2) par slot.
*
*   NOTES
*   L'encodeur original (Musicin) effectue ces calculs en flottant, ce qui
*   peut induire des erreurs d'arrondis par rapport aux calculs sur des
*   entiers comme c'est fait ici.
*   La différence de taille entre un fichier encodé avec Pegase et un fichier
*   encodé avec Musicin vient très probablement de là.
*
*****************************************************************************
*
*/


void CoderC::InitSlotsPerFrame(ULONG SamplesPerFrame, ULONG NumBitsN)
{
    enc_SamplesPerFrame = SamplesPerFrame;
    enc_BitsPerSlot     = 1 << NumBitsN;
    enc_BitsPerSlotN    = NumBitsN;
    enc_FrameSize       = enc_roFileInfos.GetNumChannels() * SamplesPerFrame;

    div_t t = div( (enc_SamplesPerFrame >> enc_BitsPerSlotN) * 1000 * ecfg_wBitrate, ecfg_wSampling);
    enc_SlotsPerFrame = t.quot;
    enc_SPF_Reminder = enc_SlotLag = t.rem;
    enc_SlotRem = ecfg_wSampling - t.rem;
    enc_AvgDataBits = enc_SlotsPerFrame << enc_BitsPerSlotN;
}
///
///CoderC::SubBandCoding_Stereo()  (ASM)
/****** Class CoderC/SubBandCoding_Stereo ***********************************
*
*   NAME
*   CoderC::SubBandCoding_Stereo -- Prétraitement des échantillons.
*
*   SYNOPSIS
*   CoderC::SubBandCoding_Stereo(pdSample)
*
*   void CoderC::SubBandCoding_Stereo(T_SubBandSmplStereo *);
*   void CoderC::SubBandCoding_Stereo(T_SubBandSmplMono *);
*
*   FUNCTION
*   Filtre la bande courante.
*
*   INPUTS
*   - pdSample = Pointeur vers le tableau a initialiser.
*
*   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.
*
*   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).
*
*****************************************************************************
*
*   22.06.98 :
*       · Modification du source entraînant une meilleure génération de code
*         du StormC.
*
*   10.09.98 :
*       · Nouvel algorithme plus performant. Les données sont systématiquement
*         utilisées dans tous les calculs dès la première lecture. De cette façon,
*         on ne modifie plus sans cesse le cache (tableaux y[]), et donc on
*         élimine un bon nombre de "flushes".
*
*   Combinaison des fonctions "window_subband" et "filter_subband" des Layers 1 et 2.
*
*   PROFILER :
*       Date        Fichier             Durée       Layer II (double)       Layer II (float)
*       ------------------------------------------------------------------------------------
*       09.05.98    Europe2.1           00:02           00:03.02                 00:02.82
*       12.05.98    07_AudioNormal      03:27           04:47
*       30.05.98    07_AudioNormal      03:27           04:17
*       14.06.98    07_AudioNormal      03:27           04:04
*       10.09.98    07_AudioNormal      03:27           03:13
*/

#if _ASM_SB_CODING_STEREO_ == 1

extern "C"{
void SubBandCoding_Stereo(REAL pdSample[2][12][32], WORD **pActualPtr, REAL *pAnaFilter);
}

inline void CoderC::SubBandCoding_Stereo(CoderC::T_SubBandSmplStereo *pdSample)
{
    ::SubBandCoding_Stereo(*pdSample, &enc_pSB_ActualPtr, &(*enc_pdAnaFilter)[0]);
}

#else

void CoderC::SubBandCoding_Stereo(CoderC::T_SubBandSmplStereo *pdSample)
{
    extern const T_ANAWINDOW a_dAnaWindow[];

    ULONG j, n, m;
    T_ANAWINDOW *py;
    T_ANAWINDOW y[SBLIMIT*2];
    T_ANAWINDOW  ysumL, ysumR;

    for (j = 0; j < SCALE_BLOCK; j++) {
        //-------------------------------------------------------------------
        //========== Collationnement et application des paramètres ==========
        //-------------------------------------------------------------------

        // Première partie : Calculer yx[0]

        const T_ANAWINDOW *pAnaWindow = &a_dAnaWindow[0];

        {
            T_ANAWINDOW wincoeff;
            WORD *p1, *p2;

            p2 = enc_pSB_ActualPtr;
            p1 = &p2[31 * 2];
            p2 = &p2[479 * 2];

            ysumL = ysumR = 0;

            for (n = 3; n > 0; --n) {
                wincoeff = *pAnaWindow++;
                ysumL += wincoeff * ((LONG) *p2    - (LONG) *p1);
                ysumR += wincoeff * ((LONG)  p2[1] - (LONG)  p1[1]);
                p1 += 32 * 2; p2 += -(32 * 2);

                wincoeff = *pAnaWindow++;
                ysumL += wincoeff * ((LONG) *p2    + (LONG) *p1);
                ysumR += wincoeff * ((LONG)  p2[1] + (LONG)  p1[1]);
                p1 += 32 * 2; p2 += -(32 * 2);
            }
            wincoeff = *pAnaWindow++;
            ysumL += wincoeff * ((LONG) *p2    - (LONG) *p1);
            ysumR += wincoeff * ((LONG)  p2[1] - (LONG)  p1[1]);

            wincoeff = *pAnaWindow++;
            y[0]  = ysumL + wincoeff * p1[32 * 2];
            y[32] = ysumR + wincoeff * p1[32 * 2 + 1];
        }

        // Deuxième partie : Calculer yx[1;15] et yx[17;31]

        {
            T_ANAWINDOW wincoeff;
            T_ANAWINDOW ysumL2, ysumR2;
            WORD *p1, *p2;

            ULONG stp  = 30 * 2;
            ULONG next = (64 - 30) * 2;

            n = 0;

            while (n < 15) {
                p2 = enc_pSB_ActualPtr;

                p1 = &p2[n+n];
                p2 = &p2[478 * 2 - (n+n)];

                ysumL = ysumL2 = ysumR = ysumR2 = 0;

                for (m = 4; m > 0; --m) {
                    wincoeff = *pAnaWindow++;
                    ysumL2 += wincoeff * p1[0];             // b4
                    ysumR2 += wincoeff * p1[1];
                    ysumL  += wincoeff * p2[32 * 2];        // a1
                    ysumR  += wincoeff * p2[32 * 2 + 1];

                    wincoeff = *pAnaWindow++;
                    ysumL2 += wincoeff * p2[0];             // b1
                    ysumR2 += wincoeff * p2[1];
                    ysumL  -= wincoeff * p1[32 * 2];        // a4
                    ysumR  -= wincoeff * p1[32 * 2 + 1];

                    p1 = &p1[stp]; p2 = &p2[-stp];

                    wincoeff = *pAnaWindow++;
                    ysumL2 -= wincoeff * p1[0];             // b3
                    ysumR2 -= wincoeff * p1[1];
                    ysumL  += wincoeff * p2[32 * 2];        // a2
                    ysumR  += wincoeff * p2[32 * 2 + 1];

                    wincoeff = *pAnaWindow++;
                    ysumL2 -= wincoeff * p2[0];             // b2
                    ysumR2 -= wincoeff * p2[1];
                    ysumL  -= wincoeff * p1[32 * 2];        // a3
                    ysumR  -= wincoeff * p1[32 * 2 + 1];

                    p1 = &p1[next]; p2 = &p2[-next];
                }

                stp  -= 4; next += 4;

                ++n; py = &y[n];

                py[0]  = ysumL;  py[32]  = ysumR;
                py[15] = ysumL2; py[47] = ysumR2;           // On continue à partir de y[16]
            }
        }

        // Dernière partie : Calculer yx[16]

        {
            T_ANAWINDOW wincoeff;
            WORD *pL = &enc_pSB_ActualPtr[47 * 2];

            ysumL = ysumR = 0;

            for (n = 4; n > 0; --n) {
                wincoeff = *pAnaWindow++;
                ysumL -= wincoeff * *pL;
                ysumR -= wincoeff *  pL[1];

                wincoeff = *pAnaWindow++;
                ysumL += wincoeff * pL[256 * 2];
                ysumR += wincoeff * pL[256 * 2 + 1];

                pL += (64 * 2);
            }
            // ysumL et ysumR contiennent les valeurs yR[16] et yL[16]
        }

        enc_pSB_ActualPtr += (32 * 2);                      // Pointer la sous-bande suivante.

        //---------------------------------------------
        //========== Application des filtres ==========
        //---------------------------------------------

        {
            double *SampleL1 = &(*pdSample)[0][j][0];
            double *pSB_SampleL1 = SampleL1;
            double *pSB_SampleL2;
            const  REAL *pFilter = &(*enc_pdAnaFilter)[0];

            #define K (32*12)       // Offset pour le second canal.

            ULONG max = 4, lstep = 16, lpos = 8;
            ULONG i, fidx, fidx2, fstep, i32;

            pSB_SampleL1[0]   = y[0]  * *pFilter;
            pSB_SampleL1[K]   = y[32] * *pFilter;
            pSB_SampleL1[1]   = ysumL - pSB_SampleL1[0];
            pSB_SampleL1[K+1] = ysumR - pSB_SampleL1[K];
            pSB_SampleL1[0] = pSB_SampleL1[0] + ysumL;
            pSB_SampleL1[K] = pSB_SampleL1[K] + ysumR;

            while (max <= 32) {
                i32 = 0;
                pSB_SampleL1 = SampleL1;
                pSB_SampleL2 = &pSB_SampleL1[max];

                for (i = lpos; i < 32; i += lstep) {
                    fstep = i;
                    fidx  = fstep - i32;
                    i32 += 32;
                    fidx2 = fstep + i32;

                    ysumL = ysumR = 0;
                    fstep += fstep;
                    py = &y[lpos];

                    while (py < &y[16]) {
                        double f1 = pFilter[fidx & 127];
                        double f2 = pFilter[fidx2 & 127];
                        ysumL += py[0]  * f1 + py[15] * f2;
                        ysumR += py[32] * f1 + py[47] * f2;
                        fidx += fstep; fidx2 += fstep; py += lstep;
                    }
                    *--pSB_SampleL2 = pSB_SampleL1[0] - ysumL;
                    pSB_SampleL2[K] = pSB_SampleL1[K] - ysumR;
                    pSB_SampleL1[K] = pSB_SampleL1[K] + ysumR;
                    *pSB_SampleL1++ = *pSB_SampleL1 + ysumL;
                }
                lstep -= lpos;
                lpos >>= 1;
                max += max;
            }
        }
    }
}

#endif  // _ASM_SB_CODING_STEREO_
///
/// CoderC::SubBandCoding_Mono()  (ASM)

#if _ASM_SB_CODING_MONO_ == 1

extern "C"{
void SubBandCoding_Mono(REAL pdSample[12][32], WORD **pActualPtr, REAL *pAnaFilter);
}

inline void CoderC::SubBandCoding_Mono(CoderC::T_SubBandSmplMono *pdSample)
{
    ::SubBandCoding_Mono(*pdSample, &enc_pSB_ActualPtr, &(*enc_pdAnaFilter)[0]);
}

#else

void CoderC::SubBandCoding_Mono(CoderC::T_SubBandSmplMono *pdSample)
{
    extern const T_ANAWINDOW a_dAnaWindow[];

    ULONG j, m, n;
    T_ANAWINDOW  y[SBLIMIT], *py;
    T_ANAWINDOW  ysum;

    for (j = 0; j < SCALE_BLOCK; j++) {
        //-------------------------------------------------------------------
        //========== Collationnement et application des paramètres ==========
        //-------------------------------------------------------------------

        // Première partie : Calculer yx[0]

        const T_ANAWINDOW *pAnaWindow = &a_dAnaWindow[0];

        {
            WORD *p1, *p2;

            p2 = enc_pSB_ActualPtr;
            p1 = &p2[31];
            p2 = &p2[479];

            ysum = 0;

            for (n = 3; n > 0; --n) {
                ysum += *pAnaWindow++ * ((LONG) *p2 - (LONG) *p1);
                p1 += 32; p2 += -32;

                ysum += *pAnaWindow++ * ((LONG) *p2 + (LONG) *p1);
                p1 += 32; p2 += -32;
            }
            ysum += *pAnaWindow++ * ((LONG) *p2 - (LONG) *p1);

            y[0] = ysum + *pAnaWindow++ * p1[32];
        }

        // Deuxième partie : Calculer yx[1;15] et yx[17;31]

        {
            T_ANAWINDOW ysum2, wincoeff;

            WORD  *p1, *p2;
            ULONG stp  = 30;
            ULONG next = 64 - 30;

            n = 0;

            while (n < 15) {
                p2 = enc_pSB_ActualPtr;

                p1 = &p2[n];
                p2 = &p2[478 - n];

                ysum = ysum2 = 0;

                for (m = 4; m > 0; --m) {
                    wincoeff = *pAnaWindow++;
                    ysum2 += wincoeff * p1[0];          // b4
                    ysum  += wincoeff * p2[32];         // a1

                    wincoeff = *pAnaWindow++;
                    ysum2 += wincoeff * p2[0];          // b1
                    ysum  -= wincoeff * p1[32];         // a4

                    p1 = &p1[stp]; p2 = &p2[-stp];

                    wincoeff = *pAnaWindow++;
                    ysum2 -= wincoeff * p1[0];          // b3
                    ysum  += wincoeff * p2[32];         // a2

                    wincoeff = *pAnaWindow++;
                    ysum2 -= wincoeff * p2[0];          // b2
                    ysum  -= wincoeff * p1[32];         // a3

                    p1 = &p1[next]; p2 = &p2[-next];
                }

                stp  -= 2; next += 2;

                ++n; py = &y[n];

                py[0] = ysum; py[15] = ysum2;           // On continue à partir de y[16]
            }
        }

        // Dernière partie : Calculer yx[16]

        {
            WORD *p = &enc_pSB_ActualPtr[47];

            ysum = 0;

            for (n = 4; n > 0; --n) {
                ysum -= *pAnaWindow++ * p[0];
                ysum += *pAnaWindow++ * p[256];

                p += 64;
            }
            // ysum contient la valeur y[16]
        }

        enc_pSB_ActualPtr += 32;                // Pointer la sous-bande suivante.

        //---------------------------------------------
        //========== Application des filtres ==========
        //---------------------------------------------

        {
            double *Sample = &(*pdSample)[j][0];
            double *pSB_Sample1 = Sample;
            double *pSB_Sample2;

            const REAL *pFilter = &(*enc_pdAnaFilter)[0];

            ULONG max = 4, lstep = 16, lpos = 8;
            ULONG i, fidx, fidx2, fstep, i32;

            pSB_Sample1[0] = y[0] * pFilter[0];
            pSB_Sample1[1] = ysum - pSB_Sample1[0];
            pSB_Sample1[0] = pSB_Sample1[0] + ysum;

            while (max <= 32) {
                i32 = 0;
                pSB_Sample1 = Sample;
                pSB_Sample2 = &pSB_Sample1[max];

                for (i = lpos; i < 32; i += lstep) {
                    fstep = i;
                    fidx  = fstep - i32;
                    i32 += 32;
                    fidx2 = fstep + i32;

                    ysum = 0;
                    fstep += fstep;
                    py = &y[lpos];

                    while (py < &y[16]) {
                        ysum += py[0] * pFilter[fidx & 127] + py[15] * pFilter[fidx2 & 127];
                        fidx += fstep; fidx2 += fstep; py += lstep;
                    }
                    *--pSB_Sample2 = *pSB_Sample1 - ysum;
                    *pSB_Sample1++ = *pSB_Sample1 + ysum;
                }
                lstep -= lpos;
                lpos >>= 1;
                max += max;
            }
        }
    }
}

#endif  // _ASM_SB_CODING_MONO_
///
/// CoderC::ScaleFactor()/ScaleFactorCalc()
/****** Class CoderC/ScaleFactor ********************************************
*
*   NAME
*   CoderC::ScaleFactor -- Rechercher le facteur d'échelle.
*
*   SYNOPSIS
*   CoderC::ScaleFactor(pScalar, pSample)
*   CoderC::ScaleFactorCalc(pbScalar, pdSample)
*
*   void CoderC::ScaleFactor(T_ScaleStereo *, T_SubBandSmplStereo *);
*   void CoderC::ScaleFactor(T_ScaleMono *, T_SubBandSmplMono *);
*
*   FUNCTION
*   Recherche le facteur d'échelle pour chaque sous-bande. ScaleFactorCalc()
*   est utilisée en mode joint-stéréo uniquement.
*
*   INPUTS
*   - pScalar : Tableau des index vers le tableau "Multiple[]"
*   - pSample : Tableau des bandes de filtres.
*
*   BUGS
*   La boucle originale ne prend pas en compte la valeur "multiple[63]", ce
*   qui semble curieux (cependant cette valeur est utilisée pour initialiser
*   le reste du tableau "scalar[]").
*   La méthode d'obtention de l'index n'est pas forcément strictement comp-
*   atible avec la méthode originale (du fait que le nombre de chiffres
*   significatifs utilisés pour la mantisse est peut-être trop faible...)
*
*   SEE ALSO
*   CoderC::GetIndex()
*
*****************************************************************************
*
*/

// Rechercher le facteur d'échelle du canal.

#if _ASM_SCALEFACTOR_CALC_ == 1

extern "C"{
void ScaleFactorCalc_double(UBYTE *pbScalar, REAL *pdSample, ULONG iSBLimit);
}

// Rechercher le facteur d'échelle de chaque canal.

inline void CoderC::ScaleFactor(CoderC::T_ScaleStereo *pScalar, CoderC::T_SubBandSmplStereo *pSample)
{
    ::ScaleFactorCalc_double((UBYTE *) pScalar, (REAL *) pSample, enc_SBLimit);
    if (enc_isStereo)
        ::ScaleFactorCalc_double( &(*pScalar)[1][0], &(*pSample)[1][0][0], enc_SBLimit);
}

inline void CoderC::ScaleFactorCalc(UBYTE *pbScalar, CoderC::T_SubBandSmplMono *pdSample)
{
    ::ScaleFactorCalc_double(pbScalar, (REAL *) pdSample, enc_SBLimit);
}

#else

// Rechercher le facteur d'échelle de chaque canal.

inline void CoderC::ScaleFactor(CoderC::T_ScaleStereo *pScalar, CoderC::T_SubBandSmplStereo *pSample)
{
    ScaleFactorCalc(&(*pScalar)[0][0], (T_SubBandSmplMono *) &(*pSample)[0][0][0]);
    if (enc_isStereo)
        ScaleFactorCalc(&(*pScalar)[1][0], (T_SubBandSmplMono *) &(*pSample)[1][0][0]);
}

void CoderC::ScaleFactorCalc(UBYTE *pbScalar, CoderC::T_SubBandSmplMono *pdSample)
{
    LONG  i, j;
    REAL  ds, d, *pSamples;

    for (i = 0; i < enc_SBLimit; i++) {
        pSamples = &(*pdSample)[0][i];
        ds = fabs(*pSamples);

        // Rechercher la valeur maximale dans chaque bande.
        for (j = 1; j < SCALE_BLOCK; j++) {
            pSamples += SBLIMIT;                // Passer à la bande suivante.
            d = fabs(*pSamples);
            if (ds < d) ds = d;
        }

        *pbScalar++ = GetIndex(ds);
    }
}

#endif  // _ASM_SCALEFACTOR_CALC_
///
/// CoderC::MixChannels()
/****** Class CoderC/MixChannels ********************************************
*
*   NAME
*   CoderC::MixChannels -- Mixe les canaux stéréo en un canal mono.
*
*   SYNOPSIS
*   CoderC::MixChannels()
*
*   void CoderC::MixChannels();
*
*   FUNCTION
*   Mélange les deux canaux stéréo en un canal mono (JOINTSTEREO)
*
*   NOTES
*   Le mixage s'effectue APRES le calcul des filtres. Il serait plus inter-
*   ressant (et plus rapide) de mixer les canaux stéréo AVANT de calculer
*   les filtres...
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderC::MixChannels(CoderC::T_SubBandSmplStereo *pSample, CoderC::T_SubBandSmplMono *pJSample)
{
    ULONG sb, smp, offset;
    REAL  *pSample0, *pSample1, *pJS;
    REAL  dOneHalf = 0.5;

    offset = SBLIMIT - enc_SBLimit;

    // Initialiser les pointeurs temporaires.

    pJS      = &(*pJSample)[0][0];
    pSample0 = &(*pSample)[0][0][0];
    pSample1 = &(*pSample)[1][0][0];

    for (smp = 0; smp < SCALE_BLOCK; smp++) {
        for (sb = 0; sb < enc_SBLimit; sb++)
            *pJS++ = dOneHalf * (*pSample0++ + *pSample1++);

        pJS      += offset;             // Adresser la "page" suivante.
        pSample0 += offset;             // (Le Layer II n'utilise pas toutes les pages)
        pSample1 += offset;
    }
}
///
/// CoderC::MainBitAllocation()
/****** Class CoderC/MainBitAllocation **************************************
*
*   NAME
*   CoderC::MainBitAllocation -- Traiter l'encodage en Joint-Stéréo.
*
*   SYNOPSIS
*   CoderC::MainBitAllocation()
*
*   void CoderC::MainBitAllocation();
*
*   FUNCTION
*   Détermine quel mode Joint-Stéréo (parmis les 4) utiliser pour l'encodage.
*   S'il y a assez de bits pour encoder en stéréo pure, l'encodeur utilise ce
*   mode plutôt que le Joint-Stéréo.
*
*   NOTES
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderC::MainBitAllocation()
{
    enc_BSHeader.sBSHeader.bsh_Mode    = STEREO;
    enc_BSHeader.sBSHeader.bsh_ModeExt = 0;
    enc_JSBound = enc_SBLimit;

    if (BitsForNoNoise() > enc_AvgDataBits) {
        ULONG mode_ext = 4;
        enc_BSHeader.sBSHeader.bsh_Mode = JOINTSTEREO;

        do {
            SetJSBound(--mode_ext);
        } while (BitsForNoNoise() > enc_AvgDataBits && mode_ext > 0);

        enc_BSHeader.sBSHeader.bsh_ModeExt = mode_ext;
    }
}
///
/// CoderC::UpdateCRC()  (ASM)
/****** Class CoderC/UpdateCRC **********************************************
*
*   NAME
*   CoderC::UpdateCRC -- Calcule la somme de contrôle.
*
*   SYNOPSIS
*   CoderC::UpdateCRC(iData, iLength)
*
*   void CoderC::UpdateCRC(ULONG, ULONG);
*
*   FUNCTION
*   Ajuste la somme de contrôle.
*
*   INPUTS
*   iData   - Donnée à prendre en charge.
*   iLength - Nombre de bits de cette donnée.
*
*   NOTES
*
*   BUGS
*
*****************************************************************************
*
*/


#if _ASM_UPDATECRC_ == 1

extern "C"{
UWORD UpdateCRC(register __d0 ULONG iData, register __d1 UWORD wLength, register __d2 UWORD wCRC);
}

inline void CoderC::UpdateCRC(ULONG iData, ULONG iLength)
{
    enc_wCRC = ::UpdateCRC(iData, iLength, enc_wCRC);
}

#else

void CoderC::UpdateCRC(ULONG iData, ULONG iLength)
{
    ULONG iMasking = 1 << iLength;
    ULONG iCarry;

    while (iMasking >>= 1) {
        iCarry = enc_wCRC & 0x8000;
        enc_wCRC *= 2;
        if (!iCarry ^ !(iData & iMasking))
            enc_wCRC ^= 0x8005;
    }
}
#endif  // _ASM_UPDATECRC_
///
/// CoderC::CRC_Calc()
/****** Class CoderC/CRC_Calc ***********************************************
*
*   NAME
*   CoderC::CRC_Calc -- Calcule le CRC du bloc d'entête.
*
*   SYNOPSIS
*   CoderC::CRC_Calc()
*
*   void CoderC::CRC_Calc();
*
*   FUNCTION
*   Initialise la somme de contrôle avec les informations du bloc d'entête.
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderC::CRC_Calc()
{
    enc_wCRC = 0xFFFF;

    UpdateCRC(GetBitrateIndex() + 1, 4);
    UpdateCRC(GetSmplFrqIndex(), 2);
    UpdateCRC(enc_BSHeader.sBSHeader.bsh_Padding, 1);
    UpdateCRC(enc_BSHeader.sBSHeader.bsh_Extension, 1);
    UpdateCRC(enc_BSHeader.sBSHeader.bsh_Mode, 2);
    UpdateCRC(enc_BSHeader.sBSHeader.bsh_ModeExt, 2);
    UpdateCRC((ULONG) IsCopyrighted(), 1);
    UpdateCRC((ULONG) IsOriginal(), 1);
    UpdateCRC(GetDeemphasis(), 2);
}
///
/// CoderC::PutBits()  (ASM)
/****** Class CoderC/PutBits ************************************************
*
*   NAME
*   CoderC::PutBits -- Placer un groupe de bits dans le tampon de sortie.
*
*   SYNOPSIS
*   CoderC::PutBits(iSource, iLength)
*
*   void CoderC::PutBits(ULONG, ULONG);
*
*   FUNCTION
*   Envoie le groupe de bits passé en argument vers le tampon de sortie.
*
*   INPUTS
*   iSource - Valeur à inscrire dans le tampon.
*   iLength - Nombre de bits significatifs.
*
*   BUGS
*   La fonction "SetBitField()" n'existe qu'en assembleur.
*
*****************************************************************************
*
*/

// Inlined code

///
/// CoderC::FillFrame()
void CoderC::FillFrame()
{
    ULONG i = enc_AvgDataBits;

    if (i) {
        PutBits(0, i & 15);
        i >>= 4;
        ++i;
        while (--i)
            PutBits(0, 16);
    }

    #if _ASM_PUTBITS_ == 1
        PutBitsASM(&enc_sOutputStreamDatas, &bit_buffer[0], BitBuffPtr);
    #else
    register UWORD *output = (UWORD *) enc_sOutputStreamDatas.pOutputBuffer;
    register UWORD *bitpos = &bit_buffer[0];

    ULONG bit_index = enc_sOutputStreamDatas.iOB_BitIndex;
    LONG  bits_free = enc_sOutputStreamDatas.iOB_BitsFree;
    ULONG offset;
    LONG  remaining_bits;
    ULONG bit_field;

    while (bitpos < BitBuffPtr) {
        ULONG length = *bitpos++;
        offset = bit_index >> 4;
        remaining_bits = 32 - (bit_index & 15) - length;     // E [1;31]
        bit_field      = (output[offset] * 65536) | (*bitpos++ << remaining_bits);

        output[offset] = bit_field >> 16;
        bit_index += length;
        bits_free -= length;

        // Si le tampon est plein, l'écrire sur disque.

        if (bits_free <= 0) {
            bits_free = enc_sOutputStreamDatas.iOB_TotalBits;
            enc_sOutputStreamDatas.iOB_BitIndex = bits_free;

            WriteBuffer();

            output[0] = bit_field;

            bit_index  = 16 - remaining_bits;
            bits_free -= bit_index;
        }
        else
            output[offset + 1] = bit_field;
    }
    enc_sOutputStreamDatas.iOB_BitIndex = bit_index;
    enc_sOutputStreamDatas.iOB_BitsFree = bits_free;
    #endif  // _ASM_PUTBITS_
}
///

//----------------------------------------------------------------------------------------------------
//========================================= Classe CoderL1C ==========================================
//----------------------------------------------------------------------------------------------------

// Constructeur et destructeur.

/// CoderL1C::CoderL1C()
CoderL1C::CoderL1C(FileInfosC &roFileInfos) : CoderC(roFileInfos, 576 + 64)
{
    if (enc_iEncoderStatus == ESTAT_READY) {
        int iInitError;

        // Initialiser l'encodeur.
        InitSlotsPerFrame(FRAME_SIZE, 5);
        iInitError = !(enc_poPsychoC = new Psycho_L1C(*this));
        iInitError |= !(enc_pdSB_Samples = (T_SubBandSmplStereo *) AllocAlignedBuffer(sizeof(T_SubBandSmplStereo)));
        iInitError |= !(enc_pdJ_Samples =  (T_SubBandSmplMono *) AllocAlignedBuffer(sizeof(T_SubBandSmplMono)));

        // A l'initialisation de l'encodeur, la variable "mode_ext" est soit
        // non définie, soit nulle. Voir les sources d'origine pour plus ample
        // information.
        enc_BSHeader.sBSHeader.bsh_Layer = 3;

        if (GetEncodingMode() == JOINTSTEREO)
            SetJSBound(0);
        else
            enc_JSBound = enc_SBLimit;

        if (iInitError || enc_poPsychoC->CheckPsychoStatus())
            SetErrorCodes(ESTAT_NOMEMORY, ERR_INTERNAL_BUFFERS);
        else if (!enc_poPsychoC->InitPsychoAnalyzer(SBLIMIT))
            SetErrorCodes(ESTAT_NOTSUPPORTED, ERR_BAD_FREQUENCY);
    }
}
///
/// CoderL1C::~CoderL1C()

CoderL1C::~CoderL1C()
{
    if (enc_pdSB_Samples)
        FreeAlignedBuffer(enc_pdSB_Samples);
    if (enc_pdJ_Samples)
        FreeAlignedBuffer(enc_pdJ_Samples);
}
///

// Fonctions virtuelles.

/// CoderL1C::GetAudio()
/****** Class CoderL1C/GetAudio *********************************************
*
*   NAME
*   CoderL1C::GetAudio -- Préparer l'analyse de la page suivante.
*
*   SYNOPSIS
*   Result = CoderL1C::GetAudio()
*
*   bool CoderL1C::GetAudio();
*
*   FUNCTION
*   Prépare l'analyse de la page suivante.
*
*   RESULT
*   Result - FALSE en cas d'erreur.
*
*   NOTES
*   Du fait que la fonction SubBandCoding() exploite les échantillons direc-
*   tement dans le tampon de lecture, le pointeur d'accès doit être adapté en
*   conséquence.
*   Même chose en ce qui concerne l'analyseur psycho-acoustique.
*
*   BUGS
*
*   SEE ALSO
*   CoderC::SubBandCoding_Stereo(), CoderC::SubBandCoding_Mono()
*
*****************************************************************************
*
*/


int CoderL1C::GetAudio()
{
    int success;
    ULONG iOffset1 = 576 + 64;
    ULONG iOffset2 = 64 + 480;

    if (enc_isStereo) {
        iOffset1 += iOffset1;
        iOffset2 += iOffset2;
    }

    if ( (success = CoderC::GetAudio()) ) {
        enc_pwSampleBuffer= enc_pSamples - iOffset1;
        enc_pSB_ActualPtr = enc_pSamples - iOffset2;
    }

    return success;
}
///
/// CoderL1C::BitsForNoNoise
/****** Class CoderL1C/BitsForNoNoise ***************************************
*
*   NAME
*   CoderL1C::BitsForNoNoise --
*
*   SYNOPSIS
*   NumBits = CoderL1C::BitsForNoNoise()
*
*   ULONG CoderL1C::BitsForNoNoise();
*
*   FUNCTION
*   Calcule le nombre de bits nécessaires à l'encodage des données avec les
*   réglages courants.
*
*   RESULT
*   NumBits - Nombre de bits nécessaires pour l'encodage.
*
*   NOTES
*   Cette fonction n'est appelée qu'en mode JOINT_STEREO. Par consequent,
*   il y a toujours 2 canaux à traiter.
*   La fonction a été modifiée en conséquence.
*
*   BUGS
*   A l'inverse des autres fonctions d'allocation, celle-ci n'alloue pas 16
*   bits supplémentaires lorsqu'on encode avec le CRC.
*   Ce n'est peut-être pas normal...
*
*****************************************************************************
*
*/


ULONG CoderL1C::BitsForNoNoise()
{
    const ULONG REQBITS = 32 + SBLIMIT * 4;

    ULONG i, j;
    ULONG jsbound  = enc_JSBound;
    ULONG req_bits = 0;

    LONG *p1 = &enc_LTMin[0][0];
    LONG *p2 = &enc_LTMin[1][0];

    LONG LTMin;

    for (i = 0; i < jsbound; i++) {
        for (j = 0, LTMin = *p1++; snr[j] < LTMin && j < 14; j++)
            ;
        if (j)
            req_bits += j * 2 + 3;
        for (j = 0, LTMin = *p2++; snr[j] < LTMin && j < 14; j++)
            ;
        if (j)
            req_bits += j * 2 + 3;
    }

    for ( /*i = jsbound,*/ ; i < SBLIMIT; i++) {
        for (j = 0, LTMin = *p1++; snr[j] < LTMin && j < 14; j++)
            ;
        for (LTMin = *p2++; snr[j] < LTMin && j < 14; j++)
            ;
        if (j)
            req_bits += j * 2 + 4;
    }

    return REQBITS + (jsbound * 4) + 6 * req_bits;
}
///
/// CoderL1C::OneBitAllocation()
/****** Class CoderL1C/OneBitAllocation *************************************
*
*   NAME
*   CoderL1C::OneBitAllocation --
*
*   SYNOPSIS
*   CoderL1C::OneBitAllocation()
*
*   void CoderL1C::OneBitAllocation();
*
*   FUNCTION
*   Adapte le nombre de bits nécessaire à l'encodage des données, bit à bit,
*   en augmentant progressivement la qualité jusqu'à ce que le nombre de bits
*   libres soit insuffisant.
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderL1C::OneBitAllocation()
{
    ULONG numbits, offset;
    LONG  min_sb, min_ch;
    UBYTE *pBitAlloc;

    UBYTE used[2 * SBLIMIT];
    LONG  MinNR[2 * SBLIMIT];
    LONG *pLTMin;

    numbits = SBLIMIT;
    if (enc_isStereo)
        numbits += enc_JSBound;
    enc_AvgDataBits -= enc_MinNeededBits + 4 * numbits;

    // Initialiser les tables intermédiaires.
    {
        LONG *pMNR;
        UBYTE *pUsed;

        pMNR      = &MinNR[0];
        pLTMin    = &enc_LTMin[0][0];
        pUsed     = &used[0];
        pBitAlloc = &enc_bBitAlloc[0][0];

        for (min_ch = enc_NumChannels; min_ch > 0; min_ch--) {
            for (min_sb = SBLIMIT; min_sb > 0; min_sb--) {
                *pMNR++      = - *pLTMin++;
                *pUsed++     = 0;
                *pBitAlloc++ = 0;
            }
        }
    }

    // Localiser la sous-bande ayant le SMR minimum.

    numbits = 0;

    do {
        min_sb = -1;
        {
            LONG i, k;
            LONG small  = MinNR[0] + 1;

            for (k = enc_NumChannels; --k >= 0; ) {
                for (i = SBLIMIT, offset = k * SBLIMIT; i > 0; --i, ++offset) {
                    if (small > MinNR[offset] && used[offset] != 2) {
                        small  = MinNR[offset];
                        min_sb = SBLIMIT - i;
                        min_ch = k;
                    }
                }
            }
        }

        if (min_sb >= 0) {
            ULONG smpl_bits;
            int jsmode = 0;

            if (min_sb >= enc_JSBound && enc_isStereo)
                jsmode = 6;

            offset = (min_ch * SBLIMIT) + min_sb;

            pLTMin    = &enc_LTMin[0][0];
            pBitAlloc = &enc_bBitAlloc[0][0];

            if (used[offset])
                smpl_bits  = SCALE_BLOCK;
            else
                smpl_bits  = (24 + 6) + jsmode;

            smpl_bits += numbits;
            if (enc_AvgDataBits >= smpl_bits) {
                numbits = smpl_bits;
                pBitAlloc[offset]++;
                used[offset] = 1;
                MinNR[offset] = snr[pBitAlloc[offset]] - pLTMin[offset];

                if (pBitAlloc[offset] == 14)
                    used[offset] = 2;
            }
            else used[offset] = 2;

            if (jsmode) {
                ULONG oth_ch = offset ^ SBLIMIT;
                pBitAlloc[oth_ch] = pBitAlloc[offset];
                used[oth_ch]      = used[offset];
                MinNR[oth_ch]     = snr[pBitAlloc[offset]] - pLTMin[oth_ch];
            }
        }
    } while (min_sb >= 0);

    enc_AvgDataBits -= numbits;
}
///
/// CoderL1C::Encode()
/****** Class CoderL1C/Encode ***********************************************
*
*   NAME
*   CoderL1C::Encode -- Fonction d'encodage principale.
*
*   SYNOPSIS
*   Success = CoderL1C::Encode()
*
*   bool CoderL1C::Encode();
*
*   FUNCTION
*   Cette fonction appelle toutes les autres fonctions nécessaires pour
*   encoder la portion actuelle du tampon d'entrée.
*
*   RESULT
*   Success - FALSE en cas d'erreur.
*
*   NOTES
*
*   BUGS
*
*****************************************************************************
*
*/


int CoderL1C::Encode()
{
    enc_poPsychoC->PsychoAnal(enc_LTMin);
    EncodeSubBand();

    if (GetEncodingMode() == JOINTSTEREO)
        MainBitAllocation();

    OneBitAllocation();
    InitBitBuffer();

    PutBits(enc_BSHeader.iBSHeader >> 16, 16);
    PutBits(enc_BSHeader.iBSHeader & 0xFFFF, 16);

    if (IsCRC()) {
        CRC_Calc();
        PutBits(enc_wCRC, 16);                      // encode_CRC()
    }

    EncodeScale();
    EncodeSamples();
    FillFrame();

    return (enc_iEncoderStatus == ESTAT_READY);
}
///

// Fonctions de gestion

/// CoderL1C::EncodeSubBand()
void CoderL1C::EncodeSubBand()
{
    if (enc_isStereo)
        SubBandCoding_Stereo(enc_pdSB_Samples);
    else
        SubBandCoding_Mono( (T_SubBandSmplMono *) enc_pdSB_Samples);

    ScaleFactor(&enc_bScalar, enc_pdSB_Samples);

    if (GetEncodingMode() == JOINTSTEREO) {
        MixChannels(enc_pdSB_Samples, enc_pdJ_Samples);
        ScaleFactorCalc(&enc_bJScale[0], enc_pdJ_Samples);
    }
}
///
/// CoderL1C::CRC_Calc()
/****** Class CoderL1C/CRC_Calc *********************************************
*
*   NAME
*   CoderL1C::CRC_Calc -- Ajuste la somme de contrôle.
*
*   SYNOPSIS
*   CoderL1C::CRC_Calc()
*
*   void CoderL1C::CRC_Calc();
*
*   FUNCTION
*   Initialise la somme de contrôle avec les données de l'entête et la table
*   d'allocation des bits.
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderL1C::CRC_Calc()
{
    int   i;
    ULONG stereo  = enc_isStereo;
    ULONG jsbound = enc_JSBound;

    UBYTE *pBitAlloc = &enc_bBitAlloc[0][0];

    CoderC::CRC_Calc();

    for (i = 0; i < SBLIMIT; i++) {
        UpdateCRC(*pBitAlloc, 4);

        if (stereo && (i < jsbound))
            UpdateCRC(pBitAlloc[SBLIMIT], 4);

         ++pBitAlloc;
    }
}
///
/// CoderL1C::EncodeScale()
/****** Class CoderL1C/EncodeScale ******************************************
*
*   NAME
*   CoderL1C::EncodeScale -- Encoder les informations de gestion.
*
*   SYNOPSIS
*   CoderL1C::EncodeScale()
*
*   void CoderL1C::EncodeScale();
*
*   FUNCTION
*   Encode les informations de gestion et les envoie dans le tampon de sortie
*
*   NOTES
*   Cumule les fonctions "encode_bit_alloc()" et "encode_scale()"
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderL1C::EncodeScale()
{
    int     i;
    UBYTE   *pBitAlloc = &enc_bBitAlloc[0][0];
    UBYTE   *pScalar   = &enc_bScalar[0][0];
    ULONG   stereo  = enc_isStereo;
    ULONG   jsbound = enc_JSBound;

    // encode_bit_alloc()

    for (i = 0; i < SBLIMIT; i++) {
        PutBits(*pBitAlloc, 4);

        if (stereo && (i < jsbound))
            PutBits(pBitAlloc[SBLIMIT], 4);

        ++pBitAlloc;
    }

    pBitAlloc = &enc_bBitAlloc[0][0];

    // encode_scale()

    for (i = 0; i < SBLIMIT; i++) {
        if (*pBitAlloc)
            PutBits(*pScalar, 6);
        if (stereo && pBitAlloc[SBLIMIT])
            PutBits(pScalar[SBLIMIT], 6);

        ++pBitAlloc; ++pScalar;
    }
}
///
/// CoderL1C::EncodeSamples()
/****** Class CoderL1C/EncodeSamples ****************************************
*
*   NAME
*   CoderL1C::EncodeSamples -- Encode les échantillons.
*
*   SYNOPSIS
*   CoderL1C::EncodeSamples()
*
*   void CoderL1C::EncodeSamples();
*
*   FUNCTION
*   Encode les échantillons et les envoies dans le tampon de sortie.
*
*   NOTES
*
*   BUGS
*
*****************************************************************************
*
*/

#if 1
void CoderL1C::EncodeSamples()
{
    int j, i, k, n, bits;
    ULONG sign;
    double d;

    register UWORD *buffptr = BitBuffPtr;
    register REAL  *pSSamples;
    register UBYTE *pSScale;
    UBYTE *pBitAlloc;

    pSSamples = &(*enc_pdSB_Samples)[0][0][0];
    pSScale   = &enc_bScalar[0][0];

    if (enc_JSBound != enc_SBLimit) {
        // L'encodage se fait en joint-stereo.
        // On recopie les informations joint-stereo (SubBandSamples et Scale)
        // à la place des informations stéréo.
        REAL *pJSamples = &(*enc_pdJ_Samples)[0][0];
        UBYTE *pJScale  = &enc_bJScale[0];

        for (i = enc_JSBound; i < enc_SBLimit; i++) {
            for (j = SCALE_BLOCK, k = i; j > 0; k += SBLIMIT, --j)
                pSSamples[k] = pJSamples[k];

            pSScale[i] = pJScale[i];
        }
    }

    // Maintenant, l'ensemble des échantillons se trouve dans enc_pdSB_Samples, et
    // les facteurs d'échelle sont dans enc_bScalar.


    for (j = 0; j < SCALE_BLOCK; j++) {
        int maxch = enc_NumChannels * SBLIMIT;

        pBitAlloc = &enc_bBitAlloc[0][0];
        pSScale   = &enc_bScalar[0][0];

        for (i = 0; i < SBLIMIT; i++) {
            if (i == enc_JSBound)
                maxch = SBLIMIT;

            for (k = 0; k < maxch; k += SBLIMIT) {
                if ( (bits = pBitAlloc[k]) ) {
                    d = pSSamples[k * SCALE_BLOCK] * enc_adMultiples[pSScale[k]] + 1.0;

                    d = d * quant_a[bits - 1] - 1.0;
                    sign = n = 1 << bits;

                    if (d < 0.0) {
                        d += 1.0;
                        sign = 0;
                    }

                #ifndef USE_OLD_MATHLIB
                    n = ( (ULONG) (d * n) ) | sign;
                #else
                    n = ( (ULONG) floor(d * n) ) | sign;
                #endif

                    *buffptr++ = bits + 1;
                    *buffptr++ = n;
                    // == PutBits(n, pBitAlloc[k] + 1);
                }
            }
            ++pBitAlloc; ++pSSamples; ++pSScale;
        }
    }

    BitBuffPtr = buffptr;
}
#else
void CoderL1C::EncodeSamples()
{
    int     i, j, k, n;
    ULONG   jsbound = enc_JSBound;
    ULONG   sign;
    double  d;
    const float one = 1.0;

    UBYTE *pBitAlloc;
    UBYTE *pJScale;
    UBYTE *pSScale;

    REAL  *pSSamples = &(*enc_pdSB_Samples)[0][0][0];
    REAL  *pJSamples = &(*enc_pdJ_Samples)[0][0];

    for (j = 0; j < SCALE_BLOCK; j++) {
        pBitAlloc = &enc_bBitAlloc[0][0];
        pJScale   = &enc_bJScale[0];
        pSScale   = &enc_bScalar[0][0];

        for (i = 0; i < SBLIMIT; i++) {
            for (k = 0; k < ( (i < jsbound) ? (enc_NumChannels * SBLIMIT) : SBLIMIT); k += SBLIMIT) {
                if ( (n = pBitAlloc[k]) ) {
                    if (i >= jsbound && enc_isStereo)
                        d = *pJSamples * enc_adMultiples[*pJScale];
                    else
                        d = pSSamples[k * SCALE_BLOCK] * enc_adMultiples[pSScale[k]];

                    d = (d + one) * quant_a[n - 1];
                    n = 1 << n;

                    if (d < one)
                        sign = 0;
                    else {
                        sign = n;
                        d -= one;
                    }

                #ifndef USE_OLD_MATHLIB
                    n = ( (ULONG) (d * n) ) | sign;
                #else
                    n = ( (ULONG) floor(d * n) ) | sign;
                #endif

                    PutBits(n, pBitAlloc[k] + 1);
                }
            }
            ++pBitAlloc; ++pJSamples; ++pSSamples; ++pJScale; ++pSScale;
        }
    }
}
#endif
///


//----------------------------------------------------------------------------------------------------
//========================================= Classe CoderL2C ==========================================
//----------------------------------------------------------------------------------------------------

#if _ASM_ENCODESAMPLES_ == 1
extern "C" EncodeSamplesL2(void *eDatas, void *L2Datas);

inline void CoderL2C::EncodeSamples()
{
    ::EncodeSamplesL2(&enc_SBLimit, &enc_psAllocTable);
}
#endif

// Constructeur et destructeur.

/// CoderL2C::CoderL2C()
CoderL2C::CoderL2C(FileInfosC &roFileInfos) : CoderC(roFileInfos, 480)
{
    if (enc_iEncoderStatus == ESTAT_READY) {
        int iInitError;

        // Initialiser l'encodeur.
        InitSlotsPerFrame(BIGGEST_FRAME, 3);

        // Allouer les tampons.
        iInitError = !(enc_poPsychoC = new Psycho_L2C(*this));
        iInitError |= !(enc_pdSB_Samples = (T_SB_Samples *) AllocAlignedBuffer(sizeof(T_SB_Samples)));
        iInitError |= !(enc_pdJ_Samples =  (T_J_Samples *) AllocAlignedBuffer(sizeof(T_J_Samples)));
        iInitError |= !(enc_psAllocTable = (T_AllocTable *) AllocBuffer(sizeof(T_AllocTable)));

        // Terminer l'initialisation de l'encodeur.

        enc_BSHeader.sBSHeader.bsh_Layer = 2;

        if (!iInitError && !enc_poPsychoC->CheckPsychoStatus()) {
            // Sélectionner le numéro de la table "Alloc_x" en fonction de la fréquence
            // d'échantillonage et du taux de sortie.

            ULONG iSampleFreq = GetSampleFreq();
            ULONG iBitRate    = GetBitRate();
            ULONG iTable;

            if (enc_isStereo)
                iBitRate >>= 1;   // Taux de sortie par canal.

            if ( iBitRate >= 56 && (iSampleFreq == 48000 || iBitRate <= 80) )   iTable = 0;
            else if (iSampleFreq != 48000 && iBitRate >= 96)                    iTable = 1;
            else if (iSampleFreq != 32000 && iBitRate <= 48)                    iTable = 2;
            else                                                                iTable = 3;

            enc_SBLimit = InitAllocTables(enc_psAllocTable, iTable);

            // A l'initialisation de l'encodeur, la variable "mode_ext" est soit
            // non définie, soit nulle. Voir les sources d'origine pour plus ample
            // information.

            if (GetEncodingMode() == JOINTSTEREO)
                SetJSBound(0);
            else
                enc_JSBound = enc_SBLimit;

            if (!enc_poPsychoC->InitPsychoAnalyzer(enc_SBLimit))
                SetErrorCodes(ESTAT_NOTSUPPORTED, ERR_BAD_FREQUENCY);
        }
        else SetErrorCodes(ESTAT_NOMEMORY, ERR_INTERNAL_BUFFERS);
    }
}
///
/// CoderL2C::~CoderL2C()
CoderL2C::~CoderL2C()
{
    if (enc_pdSB_Samples)   FreeAlignedBuffer(enc_pdSB_Samples);
    if (enc_pdJ_Samples)    FreeAlignedBuffer(enc_pdJ_Samples);
    if (enc_psAllocTable)   FreeBuffer(enc_psAllocTable);
}
///

// Fonctions virtuelles.

/// CoderL2C::GetAudio()
/****** Class CoderL2C/GetAudio *********************************************
*
*   NAME
*   CoderL2C::GetAudio -- Préparer l'analyse de la page suivante.
*
*   SYNOPSIS
*   Result = CoderL2C::GetAudio()
*
*   bool CoderL2C::GetAudio();
*
*   FUNCTION
*   Prépare l'analyse de la page suivante.
*
*   RESULT
*   Result - FALSE en cas d'erreur.
*
*   NOTES
*   Du fait que la fonction SubBandCoding() exploite les échantillons direc-
*   tement dans le tampon de lecture, le pointeur d'accès doit être adapté en
*   conséquence.
*   Même chose en ce qui concerne l'analyseur psycho-acoustique.
*
*   BUGS
*
*   SEE ALSO
*   CoderC::SubBandCoding_Stereo(), CoderC::SubBandCoding_Mono()
*
*****************************************************************************
*
*/


int CoderL2C::GetAudio()
{
    int  success;
    ULONG iOffset;

    iOffset = (enc_isStereo) ? 480 * 2 : 480;

    if ( (success = CoderC::GetAudio()) )
        enc_pSB_ActualPtr = enc_pwSampleBuffer = enc_pSamples - iOffset;

    return success;
}
///
/// CoderL2C::BitsForNoNoise()
/****** Class CoderL2C/BitsForNoNoise ***************************************
*
*   NAME
*   CoderL2C::BitsForNoNoise --
*
*   SYNOPSIS
*   NumBits = CoderL2C::BitsForNoNoise()
*
*   ULONG CoderL2C::BitsForNoNoise();
*
*   FUNCTION
*   Calcule le nombre de bits nécessaires pour encoder les données avec les
*   réglages courants.
*
*   RESULT
*   NumBits - Nombre de bits nécessaires.
*
*   NOTES
*   Cette fonction n'est appelée qu'en mode JOINT_STEREO. Par consequent,
*   il y a toujours 2 canaux à traiter.
*   La fonction a été modifiée en conséquence.
*
*   BUGS
*
*****************************************************************************
*
*/


ULONG CoderL2C::BitsForNoNoise()
{
    ULONG sb, ch, ba;
    ULONG jsbound = enc_JSBound;
    ULONG req_bits;
    LONG  maxAlloc;
    s_SBAlloc  *pAlloc;
    LONG LTMin;

    req_bits = enc_MinNeededBits + enc_BitSum[jsbound] + enc_BitSum[enc_SBLimit];

    for (sb = 0; sb < jsbound; sb++) {
        for (ch = 0; ch < 2; ch++) {
            pAlloc = &(*enc_psAllocTable)[sb][0];
            maxAlloc = pAlloc->iBitMask - 2;

            for (ba = 0, LTMin = enc_LTMin[ch][sb]; snr[pAlloc->wQuant + (ba ? 1 : 0)] < LTMin && ba < maxAlloc; ba++, pAlloc++)
                ;

            if (ba)
                req_bits += pAlloc->iTotalBits + sfsPerScfsi[enc_bScaleFactorInfo[ch][sb]];
        }
    }

    LONG *p1 = &enc_LTMin[0][sb];      // sb = jsbound
    LONG *p2 = &enc_LTMin[1][sb];

    for ( ; sb < enc_SBLimit; sb++) {
        pAlloc = &(*enc_psAllocTable)[sb][0];
        maxAlloc = pAlloc->iBitMask - 2;

        for (ba = 0, LTMin = *p1++; snr[pAlloc->wQuant + (ba ? 1 : 0)] < LTMin && ba < maxAlloc; ba++, pAlloc++)
            ;
        for ( LTMin = *p2++; snr[pAlloc->wQuant + (ba ? 1 : 0)] < LTMin && ba < maxAlloc; ba++, pAlloc++)
            ;

        if (ba)
            req_bits += pAlloc->iTotalBits + sfsPerScfsi[enc_bScaleFactorInfo[0][sb]] + sfsPerScfsi[enc_bScaleFactorInfo[1][sb]];
    }

    return req_bits;
}
///
/// CoderL2C::OneBitAllocation()
/****** Class CoderL2C/OneBitAllocation *************************************
*
*   NAME
*   CoderL2C::OneBitAllocation --
*
*   SYNOPSIS
*   CoderL2C::OneBitAllocation()
*
*   void CoderL2C::OneBitAllocation();
*
*   FUNCTION
*   Alloue un groupe de bits pour chacune des sous-bandes.
*   Le nombre de bit de chaque bande est incrémenté graduellement jusqu'à ce
*   qu'il n'y ait plus assez de bits libres.
*
*   NOTES
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderL2C::OneBitAllocation()
{
    ULONG numbits, offset;
    LONG  min_sb, min_ch;

    BYTE used[2 * SBLIMIT];
    UBYTE *pBitAlloc;

    LONG MinNR[2 * SBLIMIT];
    s_SBAlloc *pAlloc;

    // Initialiser les tables intermédiaires.

    {
        LONG *pLTMin;

        pLTMin    = &enc_LTMin[0][0];
        pBitAlloc = &enc_bBitAlloc[0][0];

        for (min_ch = enc_NumChannels; --min_ch >= 0; ) {
            min_sb = enc_SBLimit;
            offset = min_sb + min_ch * SBLIMIT;
            while (--min_sb >= 0) {
                --offset;
                MinNR[offset]     = - pLTMin[offset];
                used[offset]      = 0;
                pBitAlloc[offset] = 0;
            }
        }
    }

    // Calculer le nombre de bits nécessaire pour les tables de décodage.

    numbits = enc_isStereo ? enc_BitSum[enc_JSBound] : 0;
    enc_AvgDataBits -= enc_MinNeededBits + numbits + enc_BitSum[enc_SBLimit];

    // Localiser la sous-bande ayant le SMR minimum.
    numbits = 0;

    do {
        min_sb = -1;
        {
            LONG i, k;
            LONG small = 999999;

            for (k = enc_NumChannels; --k >= 0; ) {
                offset = k * SBLIMIT;
                for (i = enc_SBLimit; i > 0; --i, ++offset) {
                    if (small > MinNR[offset] && used[offset] >= 0) {
                        small  = MinNR[offset];
                        min_sb = enc_SBLimit - i;
                        min_ch = k;
                    }
                }
            }
        }

        if (min_sb >= 0) {
            LONG  oth_ch;
            ULONG ba, increment;

            LONG *pLTMin;

            offset = (min_ch * SBLIMIT);
            oth_ch = SBLIMIT - offset + min_sb;
            offset += min_sb;

            pBitAlloc = &enc_bBitAlloc[0][0];
            pAlloc    = &(*enc_psAllocTable)[min_sb][0];
            pLTMin    = &enc_LTMin[0][0];

            ba = pBitAlloc[offset];
            increment = pAlloc[ba + 1].iTotalBits;

            if (used[offset])
                increment -= pAlloc[ba].iTotalBits;
            else {
                UBYTE *pSCFSI = &enc_bScaleFactorInfo[0][0];

                increment += sfsPerScfsi[pSCFSI[offset]];

                if (min_sb >= enc_JSBound && enc_isStereo)
                    increment += sfsPerScfsi[pSCFSI[oth_ch]];
            }

            increment += numbits;

            if (enc_AvgDataBits >= increment) {
                ba = ++pBitAlloc[offset];
                numbits = increment;

                used[offset] = 1;
                MinNR[offset] = snr[pAlloc[ba].wQuant + 1] - pLTMin[offset];

                if (ba >= pAlloc[0].iBitMask)
                    used[offset] = -1;
            }
            else used[offset] = -1;

            if (min_sb >= enc_JSBound && enc_isStereo) {
                pBitAlloc[oth_ch] = ba;
                used[oth_ch]      = used[offset];
                MinNR[oth_ch]     = snr[pAlloc[ba].wQuant + 1] - pLTMin[oth_ch];
            }
        }

    } while (min_sb >= 0);

    enc_AvgDataBits -= numbits;
}
///
/// CoderL2C::Encode()
/****** Class CoderL2C/Encode ***********************************************
*
*   NAME
*   CoderL2C::Encode -- Fonction principale.
*
*   SYNOPSIS
*   success = CoderL2C::Encode()
*
*   bool CoderL2C::Encode();
*
*   FUNCTION
*   Cette fonction appelle toutes les fonctions nécessaires pour l'encodage
*   de la portion courante du tampon d'entrée.
*
*   RESULT
*   success - FALSE en cas d'erreur
*
*   BUGS
*
*****************************************************************************
*
*/


int CoderL2C::Encode()
{
    enc_poPsychoC->PsychoAnal(enc_LTMin);
    EncodeSubBand();

    TransmissionPattern();

    if (GetEncodingMode() == JOINTSTEREO)
        MainBitAllocation();

    OneBitAllocation();
    InitBitBuffer();

    PutBits(enc_BSHeader.iBSHeader >> 16, 16);
    PutBits(enc_BSHeader.iBSHeader & 0xFFFF, 16);

    if (IsCRC()) {
        CRC_Calc();
        PutBits(enc_wCRC, 16);                  // encode_CRC()
    }

    EncodeScale();
    EncodeSamples();
    FillFrame();

    return (enc_iEncoderStatus == ESTAT_READY);
}
///

// Fonctions de gestion.

/// CoderL2C::EncodeSubBand()
void CoderL2C::EncodeSubBand()
{
    int iFrame;

    for (iFrame = 0; iFrame < 3; iFrame++) {
        T_SubBandSmplStereo *pSB_Samples = (T_SubBandSmplStereo *) &(*enc_pdSB_Samples)[iFrame][0][0][0];

        if (enc_isStereo)
            SubBandCoding_Stereo(pSB_Samples);
        else
            SubBandCoding_Mono( (T_SubBandSmplMono *) pSB_Samples);

        ScaleFactor( (T_ScaleStereo *) &enc_bScalar[iFrame][0][0], pSB_Samples);

        if (GetEncodingMode() == JOINTSTEREO) {
            T_SubBandSmplMono *pJ_Samples  = (T_SubBandSmplMono *) &(*enc_pdJ_Samples)[iFrame][0][0];
            MixChannels(pSB_Samples, pJ_Samples);
            ScaleFactorCalc(&enc_bJScale[iFrame][0], pJ_Samples);
        }
    }
}
///
/// CoderL2C::InitAllocTables()
//----------------------------------------------------------------------------------------------------
//================================ Reconstruction des tables ALLOC_X =================================
//----------------------------------------------------------------------------------------------------
//
// TECHNIQUE :
//
//    Chacune des 4 tables contient 'L' lignes, 'L' étant donné par le tableau t_alloc_entries[].
//  Pour chacune de ces lignes, la table t_alloc_tables[][] donne l'index de la table de référence
//  à utiliser (t_ref_index[][]). Cette table de réference, associé au numéro de colonne, donne
//  l'index de la ligne d'information à entrer dans la table "alloc_x".
//
// => y = t_alloc_tables[x][line]
// => L = t_ref_index[y][col]
// => alloc_x[line][col] = t_ref_lines[L]

ULONG CoderL2C::InitAllocTables(CoderL2C::T_AllocTable *paTable, ULONG iTable)
{
    static const UBYTE a_bAllocEntries[] = {27, 30, 8, 12};

    // "Lignes" d'information utilisées.
                                                   // steps bits group quant
    static const struct s_InitTbl a_sRefLines[] = {  {    0,   2,    0,    0},    //  0
                                                     {    0,   3,    0,    0},    //  1
                                                     {    0,   4,    0,    0},    //  2
                                                     {    3,   5,    1,    0},    //  3
                                                     {    5,   7,    1,    1},    //  4
                                                     {    7,   3,    3,    2},    //  5
                                                     {    9,  10,    1,    3},    //  6
                                                     {   15,   4,    3,    4},    //  7
                                                     {   31,   5,    3,    5},    //  8
                                                     {   63,   6,    3,    6},    //  9
                                                     {  127,   7,    3,    7},    // 10
                                                     {  255,   8,    3,    8},    // 11
                                                     {  511,   9,    3,    9},    // 12
                                                     { 1023,  10,    3,   10},    // 13
                                                     { 2047,  11,    3,   11},    // 14
                                                     { 4095,  12,    3,   12},    // 15
                                                     { 8191,  13,    3,   13},    // 16
                                                     {16383,  14,    3,   14},    // 17
                                                     {32767,  15,    3,   15},    // 18
                                                     {65535,  16,    3,   16},    // 19
                                                  };


    // Index, pour chaque table de référence, des lignes à utiliser.

    static const UBYTE a_bRefIdx[][MAX_ALLOC_COLS] = {
                                              {2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19},   // 0
                                              {2, 3, 4, 5, 6, 7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 19},   // 1
                                              {1, 3, 4, 5, 6, 7,  8, 19, },                                 // 2
                                              {0, 3, 4, 19, },                                              // 3
                                              {2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18},    // 4
                                              {1, 3, 4, 6, 7, 8, 9, 10, },                                  // 5
                                            };


    // Index, pour chaque table, des tables de référence à utiliser.
    // Si les fonctions d'accès aux tables le permettent, il est possible de supprimer les tables
    // n° 0 et 2 en les remplaçant respectivement par les tables 1 et 3 (cela suppose que les fonctions
    // de gestion n'accèdent pas aux lignes non définies dans les tables d'origine).

    static const UBYTE a_bAllocTbl[][MAX_ALLOC_LINES] = {
                                                 {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, },
                                                 {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3},
                                                 {4, 4, 5, 5, 5, 5, 5, 5, },
                                                 {4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, },
                                               };


    ULONG  bNumEntries = a_bAllocEntries[iTable];
    ULONG  bLine, bSubTable, bCol, bEntry;
    UBYTE  bitsum = 0;
    struct s_SBAlloc *pTable;

    for (bLine = 0; bLine < bNumEntries; bLine++) {
        bSubTable = a_bAllocTbl[iTable][bLine];

        for (bCol = 0; bCol < MAX_ALLOC_COLS; bCol++) {
            bEntry = a_bRefIdx[bSubTable][bCol];
            pTable = & (*paTable)[bLine][bCol];

            // Initialiser la table.
            pTable->wSteps     = a_sRefLines[bEntry].wSteps;
            pTable->bBits      = a_sRefLines[bEntry].bBits;
            pTable->bGroup     = a_sRefLines[bEntry].bGroup;
            pTable->wQuant     = a_sRefLines[bEntry].bQuant;

            // Calculer des valeurs déduites des tables pour optimiser quelques fonctions.

            int n2 = 1;
            pTable->iTotalBits = SCALE_BLOCK * (pTable->bBits * pTable->bGroup);
            pTable->iBitMask   = (1 << pTable->bBits) - 1;

            while (n2 < pTable->wSteps && n2 < (1 << 16))
                n2 *= 2;

            pTable->wStepMask = n2 >> 1;

            // bGroup ne sert que de drapeau (EncodeSamples())
            pTable->bGroup = (pTable->bGroup == 3) ? 1 : 0;
        }
        bitsum = enc_BitSum[bLine + 1] = bitsum + (*paTable)[bLine][0].bBits;
    }
    return (bNumEntries);
}
///
/// CoderL2C::TransmissionPattern()
/****** Class CoderL2C/TransmissionPattern **********************************
*
*   NAME
*   CoderL2C::TransmissionPattern -- Déterminer les sous-bandes utiles.
*
*   SYNOPSIS
*   CoderL2C::TransmissionPattern()
*
*   void CoderL2C::TransmissionPattern();
*
*   FUNCTION
*   Pour une sous-bande donnée, détermine s'il faut envoyer 1, 2 ou les 3
*   valeurs ScaleFactor[], puis initialise le tableau de sélection en accord
*   avec cette analyse.
*
*   BUGS
*
*****************************************************************************
*
*  13.09.98 : Modification des patterns [3][0], [4][0] et [4][4].
*/

void CoderL2C::TransmissionPattern()
{
    int i, k;
    int class0, class1;
    UBYTE *scalar0, *scalar1, *scalar2;
    UBYTE *scfsi;

    // bits 0-2 : Masque. Un bit à 1 indique qu'il faut utiliser le facteur d'echelle.
    // bits 3-4 : Code scsfi.

    const int CODE0 = 0;    // Utiliser les trois facteurs d'echelle.
    const int CODE1 = 1;    // Utiliser deux fois le premier, puis le dernier.
    const int CODE2 = 2;    // Utiliser trois fois le même facteur d'echelle.
    const int CODE3 = 3;    // Utiliser le premier, puis deux fois le dernier.

    const int SC_1 =  4;
    const int SC_2 =  8;
    const int SC_3 = 16;

    const int SC_122 = CODE3 | SC_1 | SC_2;
    const int SC_133 = CODE3 | SC_1 | SC_3;
    const int SC_113 = CODE1 | SC_1 | SC_3;
    const int SC_223 = CODE1 | SC_2 | SC_3;
    const int SC_123 = CODE0 | SC_1 | SC_2 | SC_3;
    const int SC_111 = CODE2 | SC_1;
    const int SC_222 = CODE2 | SC_2;
    const int SC_333 = CODE2 | SC_3;

                            //  2 >> 3   2 > 3  2 == 3   2 < 3  2 << 3
    static UBYTE pattern[25] = {SC_123, SC_122, SC_122, SC_133, SC_123,     // 1 >> 2
                                SC_113, SC_111, SC_111, SC_111, SC_113,     // 1 > 2
                                SC_113, SC_111, SC_111, SC_333, SC_113,     // 1 == 2
                                SC_223, SC_222, SC_222, SC_333, SC_223,     // 1 < 2
                                SC_123, SC_122, SC_122, SC_133, SC_123};    // 1 << 2

    for (k = 0; k < enc_NumChannels; k++) {
        scalar0 = &enc_bScalar[0][k][0];
        scalar1 = scalar0 + SBLIMIT * 2;
        scalar2 = scalar0 + SBLIMIT * 4;

        scfsi = &enc_bScaleFactorInfo[k][0];

        for (i = 0; i < enc_SBLimit; i++) {
            class0 = *scalar0 - *scalar1;
            class1 = *scalar1 - *scalar2;

            if (class0 < 0) {
                if (class0 <= -3)   class0 = 0 * 5;
                else                class0 = 1 * 5;
            }
            else if (class0 == 0)   class0 = 2 * 5;
            else {
                if (class0 < 3)     class0 = 3 * 5;
                else                class0 = 4 * 5;
            }

            if (class1 < 0) {
                if (class1 > -3)    class0 += 1;
            }
            else if (class1 == 0)   class0 += 2;
            else {
                if (class1 < 3)     class0 += 3;
                else                class0 += 4;
            }

            // Modifiation 23.9.2000
            if (class0 == 6 && (*scalar2 - *scalar0) > 2)
                class1 = SC_113;
            else if (class0 == 18 && (*scalar0 - *scalar2) > 2)
                class1 = SC_223;
            else if (class0 == 8 && *scalar0 > *scalar2)
                class1 = SC_333;
            else
                class1 = pattern[class0];

            *scfsi++ = class0 = class1 & 3;

            // Mettre à jour les facteurs d'echelle (utilisés pour l'encodage des échantillons).

            if      (class0 == 1) {     // 2x le premier, puis le dernier.
                if (class1 == SC_113)   *scalar1 = *scalar0;    // SC_113
                else                    *scalar0 = *scalar1;    // SC_223
            }
            else if (class0 == 2) {     // 3x le premier.
                if      (class1 == SC_111) *scalar2 = *scalar1 = *scalar0;
                else if (class1 == SC_222) *scalar0 = *scalar2 = *scalar1;
                else                       *scalar0 = *scalar1 = *scalar2;
            }
            else if (class0 == 3) {     // 1x le premier, puis 2x le dernier.
                if (class1 == SC_122)   *scalar2 = *scalar1;    // SC_122
                else                    *scalar1 = *scalar2;    // SC_133
            }

            ++scalar0; ++scalar1; ++scalar2;
        }
    }
}
///
/// CoderL2C::CRC_Calc()
/****** Class CoderL2C/CRC_Calc *********************************************
*
*   NAME
*   CoderL2C::CRC_Calc -- Initialise la somme de contrôle.
*
*   SYNOPSIS
*   CoderL2C::CRC_Calc()
*
*   void CoderL2C::CRC_Calc();
*
*   FUNCTION
*   Initialise la somme de contrôle avec le bloc d'entête et les données de
*   gestion.
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderL2C::CRC_Calc()
{
    int   i;
    ULONG sblimit = enc_SBLimit;
    ULONG jsbound = enc_JSBound;
    ULONG stereo  = enc_isStereo;

    UBYTE *pBitAlloc = &enc_bBitAlloc[0][0];
    UBYTE *pSCFSI    = &enc_bScaleFactorInfo[0][0];

    CoderC::CRC_Calc();

    for (i = 0; i < sblimit; i++) {
        ULONG bits = (*enc_psAllocTable)[i][0].bBits;

        UpdateCRC(*pBitAlloc, bits);

        if (stereo && (i < jsbound))
            UpdateCRC(pBitAlloc[SBLIMIT], bits);

        ++pBitAlloc;
    }

    pBitAlloc = &enc_bBitAlloc[0][0];

    for (i = 0; i < sblimit; i++) {
        if (*pBitAlloc)
            UpdateCRC(*pSCFSI, 2);
        if (stereo && pBitAlloc[SBLIMIT])
            UpdateCRC(pSCFSI[SBLIMIT], 2);

        ++pSCFSI; ++pBitAlloc;
    }
}
///
/// CoderL2C::EncodeScale()
/****** Class CoderL2C/EncodeScale ******************************************
*
*   NAME
*   CoderL2C::EncodeScale -- Encoder les données de gestion.
*
*   SYNOPSIS
*   CoderL2C::EncodeScale()
*
*   void CoderL2C::EncodeScale();
*
*   FUNCTION
*   Encode les données de gestion et les envoies dans le tampon de sortie.
*   NOTES
*   Cumule les fonctions "encode_bit_alloc()" et "encode_scale()"
*
*   BUGS
*
*****************************************************************************
*
*/


void CoderL2C::EncodeScale()
{
    int     i, k;
    ULONG   stereo  = enc_isStereo ? SBLIMIT : 0;
    ULONG   sblimit = enc_SBLimit;
    ULONG   jsbound = enc_JSBound;

    UBYTE *pBitAlloc = &enc_bBitAlloc[0][0];

    // encode_bit_alloc()

    s_SBAlloc *pAlloc = &(*enc_psAllocTable)[0][0];

    for (i = 0; i < sblimit; i++) {
        k = pAlloc->bBits;
        PutBits(*pBitAlloc, k);
        if (stereo && (i < jsbound))
            PutBits(pBitAlloc[SBLIMIT], k);

        ++pBitAlloc; pAlloc += MAX_ALLOC_COLS;
    }

    // encode_scale()

    {
        UBYTE *pSCFSI    = &enc_bScaleFactorInfo[0][0];
        UBYTE *pScalar   = &enc_bScalar[0][0][0];

        pBitAlloc = &enc_bBitAlloc[0][0];

        for (i = 0; i < sblimit; i++) {
            for (k = 0; k <= stereo; k += SBLIMIT) {
                if (pBitAlloc[k])
                    PutBits(pSCFSI[k], 2);
            }
            ++pBitAlloc; ++pSCFSI;
        }

        pSCFSI    = &enc_bScaleFactorInfo[0][0];
        pBitAlloc = &enc_bBitAlloc[0][0];

        for (i = 0; i < sblimit; i++) {
            for (k = 0; k <= stereo; k += SBLIMIT) {
                if (pBitAlloc[k]) {
                    PutBits(pScalar[k], 6);

                    if (!pSCFSI[k])
                        PutBits(pScalar[k + SBLIMIT * 2], 6);

                    if (pSCFSI[k] != 2)
                        PutBits(pScalar[k + SBLIMIT * 4], 6);
                }
            }
            ++pSCFSI; ++pBitAlloc; ++pScalar;
        }
    }
}
///
/// CoderL2C::EncodeSamples()
/****** Class CoderL2C/EncodeSamples ****************************************
*
*   NAME
*   CoderL2C::EncodeSamples -- Encoder les échantillons.
*
*   SYNOPSIS
*   CoderL2C::EncodeSamples()
*
*   void CoderL2C::EncodeSamples();
*
*   FUNCTION
*   Encode les échantillons et les envoies dans le tampon de sortie.
*
*   NOTES
*   Cumule les fonctions "subband_quantization()" et "sample_encoding()"
*
*   BUGS
*
*****************************************************************************
*
*/

#if _ASM_ENCODESAMPLES_ == 0
void CoderL2C::EncodeSamples()
{
    int f, j, i, k, n;
    UWORD sbband[3];

    register UWORD *buffptr = BitBuffPtr;
    register REAL  *pSSamples;
    register UBYTE *pSScale;

    if (enc_JSBound != enc_SBLimit) {
        // L'encodage se fait en joint-stereo.
        // On recopie les informations joint-stereo (SubBandSamples et Scale)
        // à la place des informations stéréo.
        REAL *pJSamples = &(*enc_pdJ_Samples)[0][0][0];
        UBYTE *pJScale  = &enc_bJScale[0][0];

        pSSamples = &(*enc_pdSB_Samples)[0][0][0][0];
        pSScale   = &enc_bScalar[0][0][0];

        for (f = MAX_FRAMESETS; f > 0; --f) {
            for (i = enc_JSBound; i < enc_SBLimit; i++) {
                for (j = SCALE_BLOCK, k = i; j > 0; k += SBLIMIT, --j)
                    pSSamples[k] = pJSamples[k];

                pSScale[i] = pJScale[i];
            }
            pSSamples += SCALE_BLOCK * SBLIMIT * 2;
            pJSamples += SCALE_BLOCK * SBLIMIT;
            pSScale   += SBLIMIT * 2;
            pJScale   += SBLIMIT;
        }
    }

    // Maintenant, l'ensemble des échantillons se trouve dans enc_pdSB_Samples, et
    // les facteurs d'échelle sont dans enc_bScalar.

    pSSamples = &(*enc_pdSB_Samples)[0][0][0][0];
    pSScale   = &enc_bScalar[0][0][0];

    for (f = MAX_FRAMESETS; f > 0; --f) {
        for (j = 0; j < SCALE_BLOCK * SBLIMIT; j += 3 * SBLIMIT) {
            int maxch = enc_NumChannels;
            UBYTE *pBitAlloc = &enc_bBitAlloc[0][0];

            for (i = 0; i < enc_SBLimit; i++) {
                int z1, z2, z3;
                s_SBAlloc *pAlloc1 = &(*enc_psAllocTable)[i][0];

                if (i == enc_JSBound)
                    maxch = 1;

                for (k = 0, z1 = z2 = i; k < maxch; k++, z1 += SBLIMIT, z2 += SBLIMIT * SCALE_BLOCK) {
                    if ( (n = pBitAlloc[z1]) ) {
                        s_SBAlloc *pAlloc = &pAlloc1[n];
                        REAL multiple = enc_adMultiples[pSScale[z1]];
                        ULONG stepmask = pAlloc->wStepMask;
                        REAL  quant = quant_a[pAlloc->wQuant];

                        for (n = 0, z3 = z2 + j; n < 3; n++, z3 += SBLIMIT) {
                            ULONG sign;
                            REAL d = pSSamples[z3] * multiple + 1.0;

                            d = d * quant - 1.0;
                            sign = stepmask;

                            if (d < 0) {
                                sign = 0;
                                d += 1.0;
                            }

                            #ifndef USE_OLD_MATHLIB
                            sbband[n] = ((ULONG) (d * stepmask)) | sign;
                            #else
                            sbband[n] = ( (ULONG) floor(d * stepmask) ) | sign;
                            #endif
                        }
                        if (pAlloc->bGroup) {         //  == 3)
                            n = pAlloc->bBits;
                            *buffptr++ = n; *buffptr++ = sbband[0];     // == PutBits(sbband[0], n);
                            *buffptr++ = n; *buffptr++ = sbband[1];     // == PutBits(sbband[1], n);
                            *buffptr++ = n; *buffptr++ = sbband[2];     // == PutBits(sbband[2], n);
                        }
                        else {
                            int x;
                            n = pAlloc->wSteps;
                            x = sbband[0] + n * (sbband[1] + n * sbband[2]);
                            *buffptr++ = pAlloc->bBits; *buffptr++ = x;
                            // == PutBits(x, pAlloc->bBits);
                        }
                    }
                }
            }
        }
        pSSamples += SCALE_BLOCK * SBLIMIT * 2;
        pSScale   += SBLIMIT * 2;
    }

    BitBuffPtr = buffptr;
}
#endif
///

//----------------------------------------------------------------------------------------------------

/// const T_ANAWINDOW a_dAnaWindow[]

#define Z (32.0*32768.0*65536.0)

const T_ANAWINDOW a_dAnaWindow[256] = {
       -29.0/Z,    213.0/Z,   -459.0/Z,   2037.0/Z,  -5153.0/Z,   6574.0/Z, -37489.0/Z,  75038.0/Z,
        -1.0/Z,    -31.0/Z,    -26.0/Z,   -208.0/Z,    218.0/Z,   -519.0/Z,   -401.0/Z,  -2063.0/Z,
      2000.0/Z,  -5517.0/Z,  -4788.0/Z,  -7134.0/Z,   5959.0/Z, -39336.0/Z, -35640.0/Z, -74992.0/Z,
        -1.0/Z,    -35.0/Z,    -24.0/Z,   -202.0/Z,    222.0/Z,   -581.0/Z,   -347.0/Z,  -2080.0/Z,
      1952.0/Z,  -5879.0/Z,  -4425.0/Z,  -7640.0/Z,   5288.0/Z, -41176.0/Z, -33791.0/Z, -74856.0/Z,
        -1.0/Z,    -38.0/Z,    -21.0/Z,   -196.0/Z,    225.0/Z,   -645.0/Z,   -294.0/Z,  -2087.0/Z,
      1893.0/Z,  -6237.0/Z,  -4063.0/Z,  -8092.0/Z,   4561.0/Z, -43006.0/Z, -31947.0/Z, -74630.0/Z,
        -1.0/Z,    -41.0/Z,    -19.0/Z,   -190.0/Z,    227.0/Z,   -711.0/Z,   -244.0/Z,  -2085.0/Z,
      1822.0/Z,  -6589.0/Z,  -3705.0/Z,  -8492.0/Z,   3776.0/Z, -44821.0/Z, -30112.0/Z, -74313.0/Z,
        -1.0/Z,    -45.0/Z,    -17.0/Z,   -183.0/Z,    228.0/Z,   -779.0/Z,   -197.0/Z,  -2075.0/Z,
      1739.0/Z,  -6935.0/Z,  -3351.0/Z,  -8840.0/Z,   2935.0/Z, -46617.0/Z, -28289.0/Z, -73908.0/Z,
        -1.0/Z,    -49.0/Z,    -16.0/Z,   -176.0/Z,    228.0/Z,   -848.0/Z,   -153.0/Z,  -2057.0/Z,
      1644.0/Z,  -7271.0/Z,  -3004.0/Z,  -9139.0/Z,   2037.0/Z, -48390.0/Z, -26482.0/Z, -73415.0/Z,
        -2.0/Z,    -53.0/Z,    -14.0/Z,   -169.0/Z,    227.0/Z,   -919.0/Z,   -111.0/Z,  -2032.0/Z,
      1535.0/Z,  -7597.0/Z,  -2663.0/Z,  -9389.0/Z,   1082.0/Z, -50137.0/Z, -24694.0/Z, -72835.0/Z,
        -2.0/Z,    -58.0/Z,    -13.0/Z,   -161.0/Z,    224.0/Z,   -991.0/Z,    -72.0/Z,  -2001.0/Z,
      1414.0/Z,  -7910.0/Z,  -2330.0/Z,  -9592.0/Z,     70.0/Z, -51853.0/Z, -22929.0/Z, -72169.0/Z,
        -2.0/Z,    -63.0/Z,    -11.0/Z,   -154.0/Z,    221.0/Z,  -1064.0/Z,    -36.0/Z,  -1962.0/Z,
      1280.0/Z,  -8209.0/Z,  -2006.0/Z,  -9750.0/Z,   -998.0/Z, -53534.0/Z, -21189.0/Z, -71420.0/Z,
        -2.0/Z,    -68.0/Z,    -10.0/Z,   -147.0/Z,    215.0/Z,  -1137.0/Z,     -2.0/Z,  -1919.0/Z,
      1131.0/Z,  -8491.0/Z,  -1692.0/Z,  -9863.0/Z,  -2122.0/Z, -55178.0/Z, -19478.0/Z, -70590.0/Z,
        -3.0/Z,    -73.0/Z,     -9.0/Z,   -139.0/Z,    208.0/Z,  -1210.0/Z,     29.0/Z,  -1870.0/Z,
       970.0/Z,  -8755.0/Z,  -1388.0/Z,  -9935.0/Z,  -3300.0/Z, -56778.0/Z, -17799.0/Z, -69679.0/Z,
        -3.0/Z,    -79.0/Z,     -8.0/Z,   -132.0/Z,    200.0/Z,  -1283.0/Z,     57.0/Z,  -1817.0/Z,
       794.0/Z,  -8998.0/Z,  -1095.0/Z,  -9966.0/Z,  -4533.0/Z, -58333.0/Z, -16155.0/Z, -68692.0/Z,
        -4.0/Z,    -85.0/Z,     -7.0/Z,   -125.0/Z,    189.0/Z,  -1356.0/Z,     83.0/Z,  -1759.0/Z,
       605.0/Z,  -9219.0/Z,   -814.0/Z,  -9959.0/Z,  -5818.0/Z, -59838.0/Z, -14548.0/Z, -67629.0/Z,
        -4.0/Z,    -91.0/Z,     -7.0/Z,   -117.0/Z,    177.0/Z,  -1428.0/Z,    106.0/Z,  -1698.0/Z,
       402.0/Z,  -9416.0/Z,   -545.0/Z,  -9916.0/Z,  -7154.0/Z, -61289.0/Z, -12980.0/Z, -66494.0/Z,
        -5.0/Z,    -97.0/Z,     -6.0/Z,   -111.0/Z,    163.0/Z,  -1498.0/Z,    127.0/Z,  -1634.0/Z,
       185.0/Z,  -9585.0/Z,   -288.0/Z,  -9838.0/Z,  -8540.0/Z, -62684.0/Z, -11455.0/Z, -65290.0/Z,
      -104.0/Z,  -9975.0/Z,  -1567.0/Z,    -45.0/Z,  -9727.0/Z,    146.0/Z, -64019.0/Z,     -5.0/Z
};
///


