home *** CD-ROM | disk | FTP | other *** search
- /*
- **
- ** CoderC.cpp
- **
- ** $VER: CoderC.cpp 1.0 (05.06.99)
- **
- ** $Revision: 1.5 $
- ** $State: Exp $
- ** $Date: 1998/08/16 19:03:39 $
- **
- ** $Log: CoderC.cpp $
- ** Revision 1.5 1998/08/16 19:03:39 kakace
- ** Version Beta3+
- **
- ** Revision 1.4 1998/08/02 15:17:05 kakace
- ** Fonctionnement OK (Layer 1/2 + Stereo/JStereo)
- **
- ** Revision 1.3 1998/08/02 02:13:45 kakace
- ** Modes stereo Ok (?)
- **
- */
-
-
- //----------------------------------------------------------------------------------------------------
-
- /// 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
-
- ///
-
-
- //----------------------------------------------------------------------------------------------------
- //====================================== 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 (128 kbits/s)/
- *
- * INPUTS
- * wBitRate - Taux de sortie souhaité (kbits/s)
- *
- *****************************************************************************
- *
- */
-
-
- void EncoderConfigC::SetBitRate(UWORD wBitRate)
- {
- static UWORD a_wBitrate[3][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
- {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320} // Layer III
- };
-
- 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 == 0)
- {
- 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 = 160;
-
- if (iLayer == LAYER_I) ecfg_sModes.bitrate = 4;
- else if (iLayer == LAYER_II) ecfg_sModes.bitrate = 8;
- else ecfg_sModes.bitrate = 9;
- }
- }
- }
- ///
- /// 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_bStereo = (GetEncodingMode() == MONO) ? 1 : 2;
- enc_bSBLimit = SBLIMIT;
-
- enc_iMinNeededBits = (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;
-
- // Fermer le fichier à encoder.
-
- if (enc_pInputHandle)
- {
- enc_pInputHandle->FreeStreamBuffer();
- enc_pInputHandle->CloseStream();
- delete enc_pInputHandle; // Fermer le flux d'entrée.
- }
- }
- ///
-
-
- //----------------------------------------------------------------------------------------------------
- //=========================== 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().
- *
- *****************************************************************************
- *
- */
-
-
- 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;
- 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;
- 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)) )
- {
- 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 != 0)
- {
- ::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 == 0) 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 != 0)
- {
- 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_wFrameSize)) )
- {
- // 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_wFrameSize;
- char temp;
-
- for (int i = 0; i < FrameSize; i++)
- {
- temp = *p;
- *p++ = *(p+1);
- *p++ = temp;
- }
- }
-
- // Ajouter un slot si nécessaire.
-
- if (enc_wSPF_Reminder)
- {
- if (enc_wSlotFree >= ecfg_wSampling)
- {
- // Le dernier slot utilisé peut contenir les données.
- enc_wSlotFree -= ecfg_wSampling;
- enc_iAvgDataBits = 0;
- enc_BSHeader.sBSHeader.bsh_Padding = 0;
- }
- else
- {
- // Slot partiel (non entièrement rempli).
- enc_wSlotFree += enc_wSPF_Reminder; // Calculer la place restante dans ce slot.
- enc_iAvgDataBits = enc_bBitsPerSlot;
- enc_BSHeader.sBSHeader.bsh_Padding = 1;
- }
- }
-
- enc_iAvgDataBits += enc_wSlotsPerFrame << enc_bBitsPerSlotN;
- ++enc_iFrameNumber;
-
- return TRUE;
- }
-
- return FALSE;
- }
- ///
-
- // Fonctions protégées.
-
- ///CoderC::InitSlotsPerFrame()
- /****** Class CoderC/InitSlotsPerFrame **************************************
- *
- * NAME
- * CoderC::InitSlotsPerFrame --
- *
- * SYNOPSIS
- * CoderC::InitSlotsPerFrame(wSamplesPerFrame, wNumBitsN)
- *
- * void CoderC::InitSlotsPerFrame(UWORD, UWORD);
- *
- * 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(UWORD wSamplesPerFrame, UWORD wNumBitsN)
- {
- enc_wSamplesPerFrame = wSamplesPerFrame;
- enc_bBitsPerSlot = 1 << wNumBitsN;
- enc_bBitsPerSlotN = wNumBitsN;
- enc_wFrameSize = enc_roFileInfos.GetNumChannels() * wSamplesPerFrame;
-
- div_t t = div( (enc_wSamplesPerFrame >> enc_bBitsPerSlotN) * 1000 * ecfg_wBitrate, ecfg_wSampling);
- enc_wSlotsPerFrame = t.quot;
- enc_wSPF_Reminder = enc_wSlotFree = ecfg_wSampling - t.rem;
-
- enc_iAvgDataBits = enc_wSlotsPerFrame << enc_bBitsPerSlotN;
- }
- ///
- ///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 _USE_ASM_FCT_ == 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 // _USE_ASM_FCT_
- ///
- /// CoderC::SubBandCoding_Mono() (ASM)
-
- #if _USE_ASM_FCT_ == 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 // _USE_ASM_FCT_
- ///
- /// CoderC::ScaleFactor()
- /****** 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.
- *
- * 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 de chaque canal.
-
- inline void CoderC::ScaleFactor(CoderC::T_ScaleStereo *pScalar, CoderC::T_SubBandSmplStereo *pSample)
- {
- for (ULONG k = 0; k < enc_bStereo; k++)
- {
- ScaleFactorCalc(&(*pScalar)[k][0], (T_SubBandSmplMono *) &(*pSample)[k][0][0]);
- }
- }
- ///
- /// CoderC::ScaleFactorCalc() (ASM)
- // Rechercher le facteur d'échelle du canal.
-
- #if _USE_ASM_FCT_ == 1
-
- extern "C"{
- void ScaleFactorCalc_double(UBYTE *pbScalar, REAL pdSample[12][32], ULONG iSBLimit);
- }
-
- void CoderC::ScaleFactorCalc(UBYTE *pbScalar, CoderC::T_SubBandSmplMono *pdSample)
- {
- ::ScaleFactorCalc_double(pbScalar, *pdSample, enc_bSBLimit);
- }
-
- #else
-
- void CoderC::ScaleFactorCalc(UBYTE *pbScalar, CoderC::T_SubBandSmplMono *pdSample)
- {
- LONG i, j;
- REAL ds, d, *pSamples;
-
- for (i = 0; i < enc_bSBLimit; 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
- ///
- /// 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_bSBLimit; // Layer I : offset = 0
-
- // 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_bSBLimit; 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_bJSBound = enc_bSBLimit;
-
- if (BitsForNoNoise() > enc_iAvgDataBits)
- {
- ULONG mode_ext = 4;
- enc_BSHeader.sBSHeader.bsh_Mode = JOINTSTEREO;
-
- do
- {
- SetJSBound(--mode_ext);
- } while (BitsForNoNoise() > enc_iAvgDataBits && 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 _USE_ASM_FCT_ == 1 || _CPUMODEL_ == 68020
-
- 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
- ///
- /// 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.
- *
- *****************************************************************************
- *
- */
-
- #ifndef USE_QUICK_PUTBITS
- #if _USE_ASM_FCT_ == 1 || _CPUMODEL_ == 68020
- inline void CoderC::PutBits(ULONG iSource, ULONG iLength)
- {
- PutBitsASM(&enc_sOutputStreamDatas, iSource, iLength);
- }
-
- #else
-
- void CoderC::PutBits(ULONG source, ULONG length)
- {
- UWORD *output = (UWORD *) enc_sOutputStreamDatas.pOutputBuffer;
- ULONG bit_index = enc_sOutputStreamDatas.iOB_BitIndex;
- LONG bits_free = enc_sOutputStreamDatas.iOB_BitsFree;
- ULONG offset = bit_index >> 4;
- LONG remaining_bits;
- ULONG bit_field;
-
- remaining_bits = 32 - (bit_index & 15) - length; // E [1;31]
- bit_field = (output[offset] * 65536) | (source << remaining_bits);
-
- output[offset] = bit_field >> 16;
- 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;
- bit_index += length;
- }
-
- enc_sOutputStreamDatas.iOB_BitIndex = bit_index;
- enc_sOutputStreamDatas.iOB_BitsFree = bits_free;
- }
- #endif
- #endif // USE_QUICK_PUTBITS
- ///
- /// CoderC::FillFrame()
- void CoderC::FillFrame()
- {
- while (enc_iAvgDataBits >= 16)
- {
- PutBits(0, 16);
- enc_iAvgDataBits -= 16;
- }
-
- if (enc_iAvgDataBits)
- {
- PutBits(0, enc_iAvgDataBits);
- }
-
- #ifdef USE_QUICK_PUTBITS
- #if _USE_ASM_FCT_ == 1 || _CPUMODEL_ == 68020
- PutBitsASM2(&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
- #endif
- }
- ///
-
- //----------------------------------------------------------------------------------------------------
- //========================================= 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_bJSBound = enc_bSBLimit;
-
- if (iInitError != FALSE || enc_poPsychoC->CheckPsychoStatus() != FALSE)
- {
- 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_bStereo == 2)
- {
- 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, k;
- ULONG jsbound = enc_bJSBound;
- ULONG req_bits = REQBITS + (jsbound * 4);
-
- LONG LTMin;
-
- for (i = 0; i < jsbound; i++)
- {
- for (j = 0; j < 2; j++)
- {
- for (k = 0, LTMin = enc_LTMin[j][i]; snr[k] < LTMin && k < 14; k++) ;
-
- if (k) req_bits += 6 * (k + k + 3); // NB : (k + 1) × SCALE_BLOCK + 6 = 6 × (2k + 3)
- }
- }
-
- LONG *p1 = &enc_LTMin[0][i];
- LONG *p2 = &enc_LTMin[1][i];
-
- for ( /*i = jsbound,*/ ; i < SBLIMIT; i++)
- {
- for (k = 0, LTMin = *p1; snr[k] < LTMin && k < 14; k++) ;
- for ( LTMin = *p2; snr[k] < LTMin && k < 14; k++) ;
-
- ++p1; ++p2;
-
- if (k) req_bits += 6 * (k + k + 4); // NB : (k + 1) × SCALE_BLOCK + 12 = 6 × (2k + 4)
- }
-
- return 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;
-
- enc_iAvgDataBits -= enc_iMinNeededBits + 4 * (SBLIMIT + ( (enc_bStereo == 2) ? enc_bJSBound : 0) );
-
- // 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_bStereo; 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_bStereo - 1; k >= 0; --k)
- {
- 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;
-
- 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;
-
- if (min_sb >= enc_bJSBound && enc_bStereo == 2)
- {
- smpl_bits = 24 + 12;
- }
- }
-
- smpl_bits += numbits;
-
- if (enc_iAvgDataBits >= 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 (min_sb >= enc_bJSBound && enc_bStereo == 2)
- {
- ULONG oth_ch = SBLIMIT - (min_ch * SBLIMIT) + min_sb;
-
- pBitAlloc[oth_ch] = pBitAlloc[offset];
- used[oth_ch] = used[offset];
- MinNR[oth_ch] = snr[pBitAlloc[offset]] - pLTMin[oth_ch];
- }
- }
-
- } while (min_sb >= 0);
-
- enc_iAvgDataBits -= 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();
-
- #ifdef USE_QUICK_PUTBITS
- InitBitBuffer();
- #endif
-
- 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_bStereo == 2) 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_bStereo - 1;
- ULONG jsbound = enc_bJSBound;
-
- 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_bStereo - 1;
- ULONG jsbound = enc_bJSBound;
-
- // 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
- *
- *****************************************************************************
- *
- */
-
-
- void CoderL1C::EncodeSamples()
- {
- int i, j, k, n;
- ULONG jsbound = enc_bJSBound;
- ULONG sign;
- double d;
- double 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_bStereo * SBLIMIT) : SBLIMIT); k += SBLIMIT)
- {
- if ( (n = pBitAlloc[k]) )
- {
- if (i >= jsbound && enc_bStereo == 2)
- {
- 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;
- }
- }
- }
- ///
-
-
- //----------------------------------------------------------------------------------------------------
- //========================================= Classe CoderL2C ==========================================
- //----------------------------------------------------------------------------------------------------
-
- // 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.
-
- UWORD iSampleFreq = GetSampleFreq();
- UWORD iBitRate = GetBitRate();
- UWORD iTable;
-
- if (enc_bStereo == 2) 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_bSBLimit = 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_bJSBound = enc_bSBLimit;
-
- if (!enc_poPsychoC->InitPsychoAnalyzer(enc_bSBLimit))
- 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_bStereo == 2) ? 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_bJSBound;
- ULONG req_bits;
- LONG maxAlloc;
- s_SBAlloc *pAlloc;
- LONG LTMin;
-
- req_bits = 0;
-
- for (sb = 0; sb < jsbound; sb++)
- {
- req_bits += (*enc_psAllocTable)[sb][0].bBits;
- }
-
- req_bits += req_bits;
-
- for ( ; sb < enc_bSBLimit; sb++)
- {
- req_bits += (*enc_psAllocTable)[sb][0].bBits;
- }
-
- req_bits += enc_iMinNeededBits;
-
- 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_bSBLimit; 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++) ;
-
- ++p1; ++p2;
-
- 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;
-
- UBYTE 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_bStereo - 1; min_ch >= 0; --min_ch)
- {
- for (min_sb = enc_bSBLimit, offset = min_ch * SBLIMIT; min_sb > 0; --min_sb, ++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 = 0;
- pAlloc = &(*enc_psAllocTable)[0][0];
-
- for (min_sb = 0; min_sb < enc_bJSBound; ++min_sb)
- {
- // numbits += (*enc_psAllocTable)[min_sb][0].bBits;
- numbits += pAlloc->bBits;
- pAlloc += MAX_ALLOC_COLS;
- }
-
- if (enc_bStereo == 2) numbits += numbits;
-
- for ( ; min_sb < enc_bSBLimit; ++min_sb)
- {
- // numbits += (*enc_psAllocTable)[min_sb][0].bBits;
- numbits += pAlloc->bBits;
- pAlloc += MAX_ALLOC_COLS;
- }
-
- enc_iAvgDataBits -= numbits + enc_iMinNeededBits;
-
- // Localiser la sous-bande ayant le SMR minimum.
-
- numbits = 0;
-
- do
- {
- min_sb = -1;
-
- {
- LONG i, k;
- LONG small = 999999;
-
- for (k = enc_bStereo - 1; k >= 0; --k)
- {
- offset = k * SBLIMIT;
-
- for (i = enc_bSBLimit; i > 0; --i, ++offset)
- {
- if (small > MinNR[offset] && used[offset] != 2)
- {
- small = MinNR[offset];
- min_sb = enc_bSBLimit - i;
- min_ch = k;
- }
- }
- }
- }
-
- if (min_sb >= 0)
- {
- LONG oth_ch;
- ULONG ba, increment;
-
- LONG *pLTMin;
-
- offset = (min_ch * SBLIMIT);
- oth_ch = 32 - 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_bJSBound && enc_bStereo == 2)
- {
- increment += sfsPerScfsi[pSCFSI[oth_ch]];
- }
- }
-
- increment += numbits;
-
- if (enc_iAvgDataBits >= 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] = 2;
- }
- else used[offset] = 2;
-
- if (min_sb >= enc_bJSBound && enc_bStereo == 2)
- {
- 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_iAvgDataBits -= 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();
-
- #ifdef USE_QUICK_PUTBITS
- InitBitBuffer();
- #endif
-
- 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];
- T_SubBandSmplMono *pJ_Samples = (T_SubBandSmplMono *) &(*enc_pdJ_Samples)[iFrame][0][0];
-
- if (enc_bStereo == 2) SubBandCoding_Stereo(pSB_Samples);
- else SubBandCoding_Mono( (T_SubBandSmplMono *) pSB_Samples);
-
- ScaleFactor( (T_ScaleStereo *) &enc_bScalar[iFrame][0][0], pSB_Samples);
-
- if (GetEncodingMode() == JOINTSTEREO)
- {
- 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]
-
- UBYTE CoderL2C::InitAllocTables(CoderL2C::T_AllocTable *paTable, UBYTE 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, },
- };
-
-
- UBYTE bNumEntries = a_bAllocEntries[iTable];
- UBYTE bLine, bSubTable, bCol, bEntry;
- 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;
- }
- }
- 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;
- const int SC_xxx = CODE2; // Code spécial.
-
- // 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_xxx, 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_bStereo; 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_bSBLimit; i++)
- {
- class0 = *scalar0 - *scalar1;
- class1 = *scalar1 - *scalar2;
-
- if (class0 <= -3) class0 = 0 * 5;
- else if (class0 < 0) class0 = 1 * 5;
- else if (class0 == 0) class0 = 2 * 5;
- else if (class0 < 3) class0 = 3 * 5;
- else class0 = 4 * 5;
-
- if (class1 > -3)
- {
- if (class1 < 0) class0 += 1;
- else if (class1 == 0) class0 += 2;
- else if (class1 < 3) class0 += 3;
- else class0 += 4;
- }
-
- 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 if (class1 == SC_333) *scalar0 = *scalar1 = *scalar2;
- else if (*scalar0 > *scalar2) *scalar1 = *scalar0 = *scalar2;
- else *scalar1 = *scalar2 = *scalar0;
- }
- 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_bSBLimit;
- ULONG jsbound = enc_bJSBound;
- ULONG stereo = enc_bStereo - 1;
-
- 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_bStereo - 1) * SBLIMIT;
- ULONG sblimit = enc_bSBLimit;
- ULONG jsbound = enc_bJSBound;
-
- 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] == 0)
- {
- 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
- *
- *****************************************************************************
- *
- */
-
-
- void CoderL2C::EncodeSamples()
- {
- int f, i, j, k, n, n2, j2;
- ULONG jsbound = enc_bJSBound;
- ULONG sign;
- double d;
- const float one = 1.0;
-
- UWORD sbband[3][2*32];
-
- UBYTE *pBitAlloc;
- UBYTE *pJScale;
- UBYTE *pSScale;
- REAL *pSSamples;
- REAL *pJSamples;
- s_SBAlloc *pAlloc;
-
- for (f = 0; f < 3; f++)
- {
- for (j = 0, j2 = 0; j < SCALE_BLOCK; j++, j2++)
- {
- pSSamples = &(*enc_pdSB_Samples)[f][0][j][0];
- pJSamples = &(*enc_pdJ_Samples)[f][j][0];
-
- pBitAlloc = &enc_bBitAlloc[0][0];
- pJScale = &enc_bJScale[f][0];
- pSScale = &enc_bScalar[f][0][0];
-
- if (j2 == 3) j2 = 0;
-
- for (i = 0; i < enc_bSBLimit; i++)
- {
- //pAlloc = &(*enc_psAllocTable)[i][0];
-
- for (k = 0; k < ( (i < jsbound) ? (enc_bStereo * SBLIMIT) : SBLIMIT); k += SBLIMIT)
- {
- if ( (n = pBitAlloc[k]) )
- {
- pAlloc = &(*enc_psAllocTable)[i][n];
- if (i >= jsbound && enc_bStereo == 2) {
- d = *pJSamples * enc_adMultiples[*pJScale];
- }
- else {
- d = pSSamples[k * SCALE_BLOCK] * enc_adMultiples[pSScale[k]];
- }
-
- d = (d + one) * quant_a[pAlloc->wQuant] - one;
- n2 = pAlloc->wStepMask;
-
- if (d < 0) {
- sign = 0;
- d += one;
- }
- else {
- sign = n2;
- }
-
- {
- UWORD *pSBBand = &sbband[0][k + i];
-
- #ifndef USE_OLD_MATHLIB
- pSBBand[j2*64] = ((ULONG) (d * n2)) | sign;
- #else
- pSBBand[j2*64] = ( (ULONG) floor(d * n2) ) | sign;
- #endif
- if (j2 == 2) {
- if (pAlloc->bGroup) { // == 3)
- n = pAlloc->bBits;
- for (int x = 0; x < 3 * 64; x += 64)
- PutBits(pSBBand[x], n);
- }
- else {
- int y = pAlloc->wSteps;
- int x = pSBBand[0 * 64] + y * (pSBBand[1 * 64] + y * pSBBand[2 * 64]);
-
- PutBits(x, pAlloc->bBits);
- }
- }
- }
- }
- }
- ++pBitAlloc; ++pJSamples; ++pSSamples; ++pJScale; ++pSScale;
- }
- }
- }
- }
- ///
-
- //----------------------------------------------------------------------------------------------------
-
-
-