home *** CD-ROM | disk | FTP | other *** search
- /*
- **
- ** PsychoC.cpp
- **
- ** $VER: PsychoC.cpp 1.0 (01.06.98)
- **
- ** Analyseur psycho-acoustique
- **
- ** $Revision: 1.4 $
- ** $State: Exp $
- ** $Date: 1998/08/16 19:03:41 $
- **
- ** $Log: PsychoC.cpp $
- ** Revision 1.4 1998/08/16 19:03:41 kakace
- ** Version Beta3+
- **
- ** Revision 1.3 1998/07/27 14:13:05 kakace
- ** Validation de toutes les fonctions
- **
- ** Revision 1.2 1998/07/27 02:15:41 kakace
- ** Validation des fonctions (Layer II)
- **
- */
-
-
- //----------------------------------------------------------------------------------------------------
-
- /// Includes
- #ifndef _INCLUDE_ASSERT_H
- #include <assert.h>
- #endif
-
- #ifndef _INCLUDE_IOSTREAM_H
- #include <iostream.h>
- #endif
-
- #ifndef _INCLUDE_IOMANIP_H
- #include <iomanip.h>
- #endif
-
- #ifndef _INCLUDE_STDLIB_H
- #include <stdlib.h>
- #endif
-
- #ifndef _INCLUDE_MATH_H
- #include <math.h>
- #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 _PEGASECOND_HPP
- #include "PegaseCond.hpp"
- #endif
- ///
-
- #define MINTHRESHOLD 60802371420160.0;
-
-
- //----------------------------------------------------------------------------------------------------
- //========================================== Classe PsychoC ==========================================
- //----------------------------------------------------------------------------------------------------
-
- /// PsychoC::PsychoC()
- PsychoC::PsychoC(CoderC &roCoderC) : psy_roCoderC(roCoderC)
- {
- psy_MemoryError = FFT_MemoryError;
-
- // Allouer tous les tampons nécessaires.
-
- psy_MemoryError |= !(psy_pdSpreading = (T_FCBCB *) AllocAlignedBuffer(sizeof(T_FCBCB)));
- psy_MemoryError |= !(psy_pdTmpSave = (T_F2HBLK32 *) AllocAlignedBuffer(sizeof(T_F2HBLK32)));
- }
- ///
- /// PsychoC::~PsychoC() (virtual)
- PsychoC::~PsychoC()
- {
- if (psy_pdSpreading) FreeAlignedBuffer(psy_pdSpreading);
- if (psy_pdTmpSave) FreeAlignedBuffer(psy_pdTmpSave);
- }
- ///
-
- /// PsychoC::CalcPermissibleNoise()
- /****** Class PsychoC/CalcPermissibleNoise **********************************
- *
- * NAME
- * PsychoC::CalcPermissibleNoise --
- *
- * SYNOPSIS
- * PsychoC::CalcPermissibleNoise()
- *
- * void PsychoC::CalcPermissibleNoise()
- *
- * FUNCTION
- *
- * EXAMPLE
- *
- * NOTES
- * Fonction fortement modifiée pour optimiser la vitesse de traitement.
- * A contrôler.
- *
- * BUGS
- * Fonction contrôlée conforme le 26.07.98
- *
- *****************************************************************************
- *
- * Benchmarks (25 cycles par seconde) :
- * 14.06.98 : 1'05.63
- *
- * Estimation de temps de calcul (pour 31768 frames) :
- * · Log + Exp : 22 secondes
- * · Calcul initial "cb" et "ecb" : 30 secondes.
- */
-
-
- void PsychoC::CalcPermissibleNoise()
- {
- static float bmax[27] = {20.0, 20.0, 20.0, 20.0, 20.0, 17.0, 15.0,
- 10.0, 7.0, 4.4, 4.5, 4.5, 4.5, 4.5,
- 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5,
- 4.5, 4.5, 4.5, 3.5, 3.5, 3.5
- };
-
- // bmax_exp[n] = exp(-bmax[n] * LN_TO_LOG10)
-
- static REAL bmax_exp[27] = {0.01, 0.01, 0.01,
- 0.01, 0.01, 0.01995262314969,
- 0.03162277660168, 0.1, 0.19952623149689,
- 0.36307805477010, 0.35481338923358, 0.35481338923358,
- 0.35481338923358, 0.35481338923358, 0.35481338923358,
- 0.35481338923358, 0.35481338923358, 0.35481338923358,
- 0.35481338923358, 0.35481338923358, 0.35481338923358,
- 0.35481338923358, 0.35481338923358, 0.35481338923358,
- 0.44668359215096, 0.44668359215096, 0.44668359215096
- };
-
- //----------------------------------------------------------------------------------------------------
-
- #if 1
-
- register int j, k, l;
- register REAL cb, ecb, temp;
- register REAL *pSpreading;
-
- register REAL *pdTMN = psy_adToneMaskingNoise;
- register REAL *pdNB = psy_adNB;
- register BYTE *pbCB = &psy_abCBands[0][0];
-
- // NB : CBANDS a été remplacé par "psy_wCBands" pour tenir compte du fait qu'il n'y a pas
- // 63 bandes lorsqu'on encode en 32 KHz.
-
- for (j = 0; j <= psy_wCBands; j++)
- {
- REAL *pGrp;
- cb = ecb = 0.0;
-
- // La valeur "Spreading" est non nulle pour des indices bien particuliers. C'est pourquoi
- // le tableau "psy_abCBands" fournit l'indice de début et l'indice de fin des valeurs non
- // nulles, ce qui élimine un test inutile.
-
- l = pbCB[64];
- k = *pbCB++;
- pGrp = &psy_adGroupedValues[k][0];
- pSpreading = &(*psy_pdSpreading)[j][k];
-
- for (; k <= l; k++)
- {
- temp = *pSpreading++;
- ecb += temp * *pGrp++; // = grouped_e[]
- cb += temp * *pGrp++; // = grouped_c[]
- }
-
- if (ecb)
- {
- cb = cb / ecb;
- if (cb < 0.05) cb = LOG10_005 + LOG10_2; // = log10(0.05)
- else if (cb > 0.5) cb = LOG10_05 + LOG10_2; // = log10(0.5)
- else cb = log10(cb) + LOG10_2;
- }
- else cb = LOG10_005 + LOG10_2; // = log10(0.05)
-
- // Partie fortement modifiée par rapport à la version originale
- // (Les tables ont été modifiées pour prendre en compte encore plus
- // de données précalculées).
-
- cb = 5.5 - cb * *pdTMN++; // psy_adToneMaskingNoise[j];
- k = psy_abCenterBarkVal[j];
-
- if (cb < bmax[k]) cb = bmax_exp[k];
- else cb = exp(cb * (-LN_TO_LOG10));
-
- temp = psy_adRNorm[j];
-
- if (temp) *pdNB++ = ecb * cb * temp;
- else *pdNB++ = temp; // = 0.0
- }
-
- #else // Original code
-
- int j, k, l;
- REAL cb, ecb, temp;
- REAL *pSpreading;
-
- // NB : CBANDS a été remplacé par "psy_wCBands" pour tenir compte du fait qu'il n'y a pas
- // 63 bandes lorsqu'on encode en 32 KHz.
-
- for (j = 0; j <= psy_wCBands; j++)
- {
- REAL *pGrp;
- cb = ecb = 0.0;
-
- // La valeur "Spreading" est non nulle pour des indices bien particuliers. C'est pourquoi
- // le tableau "psy_abCBands" fournit l'indice de début et l'indice de fin des valeurs non
- // nulles, ce qui élimine un test inutile.
-
- k = psy_abCBands[0][j];
- l = psy_abCBands[1][j];
- pGrp = &psy_adGroupedValues[k][0];
- pSpreading = &(*psy_pdSpreading)[j][k];
-
- for (; k <= l; k++)
- {
- temp = *pSpreading++;
- ecb += temp * *pGrp++; // = grouped_e[]
- cb += temp * *pGrp++; // = grouped_c[]
- }
-
- if (ecb != 0.0)
- {
- cb = cb / ecb;
- if (cb < 0.05) cb = LOG10_005 + LOG10_2; // = log10(0.05)
- else if (cb > 0.5) cb = LOG10_05 + LOG10_2; // = log10(0.5)
- else cb = log10(cb) + LOG10_2;
- }
- else cb = LOG10_005 + LOG10_2; // = log10(0.05)
-
- // Partie fortement modifiée par rapport à la version originale
- // (Les tables ont été modifiées pour prendre en compte encore plus
- // de données précalculées).
-
- cb = 5.5 - cb * psy_adToneMaskingNoise[j];
- k = psy_abCenterBarkVal[j];
-
- if (cb < bmax[k]) cb = bmax_exp[k];
- else cb = exp(cb * (-LN_TO_LOG10));
-
- temp = psy_adRNorm[j];
-
- if (temp) psy_adNB[j] = ecb * cb * temp;
- else psy_adNB[j] = temp; // = 0.0
- }
- #endif
- }
- ///
- /// PsychoC::CalcGroupedValues()
- /****** Class PsychoC/CalcGroupedValues *************************************
- *
- * NAME
- * PsychoC::CalcGroupedValues --
- *
- * SYNOPSIS
- * PsychoC::CalcGroupedValues(wChannel, wNew)
- *
- * void PsychoC::CalcGroupedValues(UWORD, UWORD);
- *
- * FUNCTION
- * Calcule des vecteurs complexes à partir des données fournies par la FFT,
- * et les cumule par bandes de fréquences.
- *
- * INPUTS
- * wChannel - Numéro de canal.
- * wNew - Indice courant
- *
- * NOTES
- *
- * BUGS
- * Cette fonction n'est pas strictement conforme au source originale : L'
- * énergie du complexe C[512] est ici bornée (borne inférieure = 0.0005).
- *
- * Fonction validée le 26/07/98
- *
- * SEE ALSO
- *
- *****************************************************************************
- *
- * Benchmarks (3 cycles par seconde) :
- * 21.06.98 : 2'47.80
- *
- * NB : La clarté du code souffre un peu de l'entrelacement des calculs
- * destinés à occuper le FPU pendant que le cache termine (en principe)
- * la lecture d'une ligne.
- */
-
- #if _USE_ASM_FCT_ == 1
-
- extern "C"{
- void CalcGroupedValues(UWORD wNew, REAL *GroupedValues, T_FFTDATAS *FFTOut, REAL *Energy2, T_FFTDATAS *tmp, UBYTE *Part);
- }
-
- inline void PsychoC::CalcGroupedValues(UWORD wChannel, UWORD wNew)
- {
- ::CalcGroupedValues(wNew, (REAL *) psy_adGroupedValues, &(*FFT_pdWinSmplShuffled)[wChannel][0][0],
- psy_adEnergy2, &(*psy_pdTmpSave)[wChannel][0][0][0], psy_abPartition);
- }
-
- #else
-
- void PsychoC::CalcGroupedValues(UWORD wChannel, UWORD wNew)
- {
- #define pOldest pNew // Synonyme.
-
- const ULONG COSINE = 0; // Index d'accès aux données.
- const ULONG SINE = 2;
- const ULONG ENERGY = 4;
- const ULONG NEXT_OFFSET = 6; // {COSINE, SINE, ENERGY} × {NEW, OLD}
-
- UWORD wOld = 1 - wNew;
-
- int j, part, idx;
-
- double cos_phi, cos_2phi;
- double sin_phi, sin_2phi;
- double energy, r, r_prime;
-
- T_FFTDATAS *p;
- T_FFTDATAS *pNew, *pOld;
- REAL *Grp;
-
- // Initialiser les tableaux destinés à accueillir les sommes intermédiaires.
-
- {
- REAL *p = &psy_adGroupedValues[0][0];
-
- for (j = 0; j <= psy_wCBands; j++)
- {
- *p++ = 0.0; // Grouped_e[j]
- *p++ = 0.0; // Grouped_c[j]
- }
- }
-
- p = &(*FFT_pdWinSmplShuffled)[wChannel][0][0];
- pOld = &(*psy_pdTmpSave)[wChannel][0][0][wOld];
- pNew = &(*psy_pdTmpSave)[wChannel][0][0][wNew];
-
- for (j = 0; j < HBLKSIZE; j++)
- {
- // Initialiser les variables intermédiaires.
- // Les tables pOld et pNew se présentent sous la forme :
- // Cos_new, Cos_old, Sin_new, Sin_old, Nrj_new, Nrj_old, Cos_new...
- // NB : Cette partie s'efforce d'effectuer un maximum de calculs entre chaque
- // lecture dans une table de façon à ne pas être bloqué par un cache en
- // train de lire une ligne.
-
- cos_phi = pOld[COSINE]; // = cos(a)
- r = cos_phi + cos_phi; // = 2.cos(a)
- r_prime = r * cos_phi; // = 2.cos²(a)
- cos_phi = pOldest[COSINE]; // = cos(b)
-
- sin_2phi = pOld[SINE] * r; // = sin(2a) = 2.cos(a).sin(a)
- r = r_prime - 1.0; // = cos(2a) = 2.cos²(a) - 1
- energy = cos_phi * r; // Commencer le calcul de cos(2a-b) ( = cos(2a).cos(b))
- sin_phi = pOldest[SINE]; // = sin(b)
-
- r_prime = pOld[ENERGY];
- energy += sin_phi * sin_2phi; // cos(2a-b) = cos(2a).cos(b) + sin(2a).sin(b)
- sin_2phi = sin_2phi * cos_phi - r * sin_phi; // sin(2a-b) = sin(2a).cos(b) - cos(2a).sin(b)
- r_prime += r_prime - pOldest[ENERGY];
-
- cos_2phi = energy; // HINT : "energy" est dans un registre, ce qui
- // n'est pas le cas de "cos_2phi"
-
- // Récupérer les données en sortie de FFT (elle fournie gracieusement les
- // sin() et cos() voulus : inutile de passer par un angle intermédiaire).
-
- cos_phi = *p++; // (*FFT_pdWinSmplShuffled)[wChannel][j][0];
- energy = cos_phi * cos_phi;
- r = 0.0005;
- sin_phi = *p++; // (*FFT_pdWinSmplShuffled)[wChannel][j][1];
- energy += sin_phi * sin_phi;
-
- // Donner une valeur minimum à l'énergie.
- // NOTE : Dans le source d'origine, l'énergie n'est pas bornée (borne inférieure)
- // pour le complexe C[512].
-
- if (energy <= r)
- {
- energy = r; // energy = 0.0005
- r = SQRT_00005; // = sqrt(0.0005) = sqrt(5) / 100
- cos_phi = r; // => phi = 0
- sin_phi = 0.0;
- }
- else
- {
- r = sqrt(energy);
- }
-
- // Préparer la somme des énergies pour TranslateThreshold().
- // Par la même occasion, on occupe l'IU pendant que le FPU calcule SQRT().
-
- part = psy_abPartition[j];
- Grp = &psy_adGroupedValues[part][0];
-
- idx = j >> 4;
- part = j & 15;
-
- if (part) psy_adEnergy2[idx] += energy; // part != 0 : Ajouter l'énergie à la bande courante.
- else
- {
- if (idx != 32) psy_adEnergy2[idx] = energy; // part == 0 && idx != 32 : Initialiser la somme.
- if (idx--) psy_adEnergy2[idx] += energy; // part == 0 && idx != 0 : Ajouter à la bande précédente.
- }
-
- // Mémoriser les valeurs courantes pour la prochaine passe.
-
- pNew[ENERGY] = r; // r != 0 puisque l'énergie est bornée.
-
- r = 1.0 / r;
- pNew[COSINE] = cos_phi * r;
- pNew[SINE] = sin_phi * r;
-
- r = pNew[ENERGY] + fabs(r_prime); // r > 0 puisque l'energie est bornée.
-
- cos_phi -= r_prime * cos_2phi;
- sin_phi -= r_prime * sin_2phi;
- cos_phi = cos_phi * cos_phi + sin_phi * sin_phi;
- // = energy + r'² - 2.r.r'.cos(phi + phi')
-
- Grp[0] += energy;
- Grp[1] += energy * sqrt(cos_phi) / r;
-
- pNew += NEXT_OFFSET; // Ajuster les pointeurs.
- pOld += NEXT_OFFSET; // (pOldest = pNew)
- }
- }
-
- #endif // _USE_ASM_FCT_
- ///
- /// PsychoC::InitPsychoAnalyzer()
- /****** Class PsychoC/InitPsychoAnalyzer ************************************
- *
- * NAME
- * PsychoC::InitPsychoAnalyzer -- Initialiser l'analyseur psycho-acoustique.
- *
- * SYNOPSIS
- * result = PsychoC::InitPsychoAnalyzer(iSBLimit)
- *
- * bool PsychoC::InitPsychoAnalyzer(int);
- *
- * FUNCTION
- * Initialise l'analyseur psycho-acoustique en préparant les différentes
- * tables nécessaires à son fonctionnement.
- *
- * INPUTS
- * iSBLimit - Nombre de sous-bandes.
- *
- * RESULT
- * result = FALSE en cas d'erreur (tampons non alloués par exemple).
- *
- * NOTES
- * Une table SinCos() devrait aussi être initialisée afin d'améliorer la
- * vitesse des FFT lorsque le CPU utilisé est plus handicapé par une capa-
- * cité de traitement limitée que par ses accès mémoire (68020/68030).
- *
- * BUGS
- * Il n'existe pas de table AbsoluteThreshold pour le MPEG-2 !!!
- * Fonction contrôlée conforme le 27/07/98
- *
- * SEE ALSO
- *
- *****************************************************************************
- *
- */
-
-
- int PsychoC::InitPsychoAnalyzer(int iSBLimit)
- {
- extern const REAL a_dAbsoluteThresholds[3][HBLKSIZE];
-
- REAL adCenterBarkValue[CBANDS]; // (cbval[])
-
- int Result = TRUE;
- int i, j;
-
- // Initialiser les paramètres de l'analyseur psycho-acoustique selon le type de Layer.
-
- psy_wNew = 0;
- psy_wSBLimit = iSBLimit;
-
- // Adresser les tables des Thresholds en fonction de la fréquence d'échantillonage
-
- switch (psy_roCoderC.GetSampleFreq())
- {
- case 32000: psy_pdAbsThreshold = &a_dAbsoluteThresholds[0][0]; break;
- case 44100: psy_pdAbsThreshold = &a_dAbsoluteThresholds[1][0]; break;
- case 48000: psy_pdAbsThreshold = &a_dAbsoluteThresholds[2][0]; break;
- default:
- Result = FALSE;
- break;
- }
-
- // Initialiser les données pour le FFT.
-
- {
- static int crit_band[27] = { 0, 100, 200, 300, 400, 510, 630, 770,
- 920, 1080, 1270, 1480, 1720, 2000, 2320, 2700,
- 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000,
- 15500, 25000, 30000
- };
-
- const REAL INV_BLKSIZE = 1.0 / BLKSIZE;
- REAL t, cb, cb_pred;
- REAL bval_lo;
- int part, idx;
-
- REAL freq_mult = psy_roCoderC.GetSampleFreq() * INV_BLKSIZE;
-
- idx = 1;
- t = freq_mult;
- cb = crit_band[1];
- cb_pred = 0.0;
-
- bval_lo = 0.0; // Fréquence de départ de la bande courante.
- adCenterBarkValue[0] = 0.0;
- part = 0; // Numéro d'index de la bande courante.
- j = 1; // Nombre de fréquences dans la bande courante.
-
- for (i = 1; i < HBLKSIZE; i++, t += freq_mult)
- {
- REAL bval;
-
- if (t > cb)
- {
- idx++;
- cb_pred = cb;
- cb = crit_band[idx];
- }
-
- bval = idx - 1 + (t - cb_pred) / (cb - cb_pred);
-
- if ( (bval - bval_lo) > CB_FRACTION)
- {
- adCenterBarkValue[part] /= j; // Ajuster les infos de la bande précédente.
- psy_abNumLines[part] = j;
-
- psy_abPartition[i] = ++part; // Initialiser la bande suivante.
- adCenterBarkValue[part] = bval_lo = bval;
- j = 1;
- }
- else
- {
- psy_abPartition[i] = part; // Ajouter la fréquence dans la bande courante.
- adCenterBarkValue[part] += bval;
- j++;
- }
- }
-
- // Ajuster les informations de la dernière bande.
-
- psy_wCBands = part = psy_abPartition[HBLKSIZE-1];
- psy_abNumLines[part] = j;
- adCenterBarkValue[part] /= j;
- }
-
- // Calculer la fonction de "spreading"
-
- {
- const REAL cst = 17.5 * 1.106650803 - 3.555; // = 17.5 * sqrt(1.224676) - 3.555 = 15.811389
- REAL t1, t2, t3;
-
- // NB : CBANDS a été remplacé par "psy_wCBands" pour tenir compte du fait qu'il n'y a pas
- // 63 bandes lorsqu'on encode en 32 KHz.
-
- for (j = 0; j <= psy_wCBands; j++)
- {
- psy_abCBands[0][j] = psy_abCBands[1][j] = -1;
-
- for (i = 0; i <= psy_wCBands; i++)
- {
- t1 = (adCenterBarkValue[j] - adCenterBarkValue[i]) * 1.05;
-
- if (t1 >= 0.5 && t1 <= 2.5)
- {
- t2 = t1 - 0.5;
- t2 = 8.0 * t2 * (t2 - 2.0); // = 8.(t2.t2 - 2.t2)
- }
- else t2 = 0.0;
-
- t1 += 0.474;
- t3 = cst + 7.5 * t1 - 17.5 * sqrt(1.0 + t1 * t1);
-
- if (t3 <= -100.0) (*psy_pdSpreading)[j][i] = 0.0;
- else
- {
- if (psy_abCBands[0][j] < 0) psy_abCBands[0][j] = i;
- psy_abCBands[1][j] = i;
-
- t3 = (t2 + t3) * LN_TO_LOG10;
- (*psy_pdSpreading)[j][i] = exp(t3);
- }
- }
- }
- }
-
- // Calculer les valeurs "Tone Masking Noise"
-
- {
- REAL t1;
-
- // NB : CBANDS a été remplacé par "psy_wCBands" pour tenir compte du fait qu'il n'y a pas
- // 63 bandes lorsqu'on encode en 32 KHz.
-
- for (j = 0; j <= psy_wCBands; j++)
- {
- t1 = adCenterBarkValue[j];
- psy_abCenterBarkVal[j] = (UBYTE) ceil(t1);
-
- // Valeur précalculée pour CalcPersmissibleNoise()
- psy_adToneMaskingNoise[j] = (t1 > 9.0) ? (t1 + 10.0) : 19.0;
-
- t1 = (*psy_pdSpreading)[j][0];
-
- for (i = 1; i <= psy_wCBands; i++)
- {
- t1 += (*psy_pdSpreading)[j][i];
- }
-
- // Précalculer la valeur utilisée par CalcPermissibleNoise().
-
- t1 *= psy_abNumLines[j];
- if (t1 != 0.0) t1 = 1.0 / t1;
-
- psy_adRNorm[j] = t1;
- }
- }
-
- // Initialiser la table TmpSave[]
-
- for (j = 0; j < HBLKSIZE; j++)
- {
- (*psy_pdTmpSave)[0][j][0][0] = (*psy_pdTmpSave)[0][j][0][1] = 1;
- (*psy_pdTmpSave)[1][j][0][0] = (*psy_pdTmpSave)[1][j][0][1] = 1;
- }
-
- return Result;
- }
- ///
-
- //----------------------------------------------------------------------------------------------------
- //======================================== Classe Psycho_L1C =========================================
- //----------------------------------------------------------------------------------------------------
-
- /// Psycho_L1C::TranslateThreshold() (virtual)
- /****** Class Psycho_L1C/TranslateThreshold *********************************
- *
- * NAME
- * Psycho_L1C::TranslateThreshold --
- *
- * SYNOPSIS
- * Psycho_L1C::TranslateThreshold(wChannel)
- *
- * void Psycho_L1C::TranslateThreshold(UWORD);
- *
- * FUNCTION
- *
- * INPUTS
- * wChannel - Numéro de canal.
- *
- * NOTES
- *
- * BUGS
- * Fonction contrôlée conforme le 27/07/98
- *
- *****************************************************************************
- *
- */
-
- /*
- inline REAL Psycho_L1C::GetNoiseLevel(REAL dNoiseBand, REAL dThreshold, REAL *p_LThr)
- {
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- dThreshold = *p_LThr;
- *p_LThr = LXMIN * dNoiseBand; // = 32 * dNoiseBand
-
- if (dNoiseBand < dThreshold) dThreshold = dNoiseBand;
- dNoiseBand *= 0.00316;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- return dNoiseBand;
- }
- */
-
- void Psycho_L1C::TranslateThreshold(UWORD wChannel)
- {
- #if 1
-
- register int j, k;
- register REAL dNoiseBand, dThreshold, minthres;
- register ULONG SBLimit = psy_wSBLimit;
-
- register const REAL *pThreshold = psy_pdAbsThreshold;
- register REAL *pLThr = &(*psy_pdLThr)[wChannel][0];
- register REAL *pNB = psy_adNB;
- register UBYTE *pbPartition = &psy_abPartition[1];
- register REAL *pdEnergy2 = psy_adEnergy2;
- register REAL *pdSNR = psy_adSNRTemp;
-
- dNoiseBand = *pNB;
- dThreshold = *pThreshold++;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- dThreshold = *pLThr;
- *pLThr++ = LXMIN * dNoiseBand; // = 32 * dNoiseBand
-
- if (dNoiseBand < dThreshold) dThreshold = dNoiseBand;
- dNoiseBand *= 0.00316;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- for (j = 0; j < 13; j++)
- {
- minthres = MINTHRESHOLD;
- if (minthres > dNoiseBand) minthres = dNoiseBand;
-
- for (k = 16; k > 0; k--)
- {
- dNoiseBand = pNB[ *pbPartition++ ];
- dThreshold = *pThreshold++;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- dThreshold = *pLThr;
- *pLThr++ = LXMIN * dNoiseBand; // = 32 * dNoiseBand
-
- if (dNoiseBand < dThreshold) dThreshold = dNoiseBand;
- dNoiseBand *= 0.00316;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- if (minthres > dNoiseBand) minthres = dNoiseBand;
- }
- *pdSNR++ = *pdEnergy2++ / (minthres * 17.0);
- }
-
- for (j = 13; j < SBLimit; j++)
- {
- minthres = dNoiseBand;
-
- for (k = 16; k > 0; k--)
- {
- dNoiseBand = pNB[ *pbPartition++ ];
- dThreshold = *pThreshold++;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- dThreshold = *pLThr;
- *pLThr++ = LXMIN * dNoiseBand; // = 32 * dNoiseBand
-
- if (dNoiseBand < dThreshold) dThreshold = dNoiseBand;
- dNoiseBand *= 0.00316;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- minthres += dNoiseBand;
- }
- *pdSNR++ = *pdEnergy2++ / minthres;
- }
-
- #else // Original code.
-
- int j, k, idx;
- REAL dNoiseBand, dThreshold, minthres;
-
- const REAL *pThreshold = psy_pdAbsThreshold;
- REAL *pLThr = &(*psy_pdLThr)[wChannel][0];
- REAL *pNB = psy_adNB;
-
- dNoiseBand = GetNoiseLevel( pNB[0], pThreshold[0], pLThr);
-
- for (j = 0; j < 13; j++)
- {
- minthres = MINTHRESHOLD;
- if (minthres > dNoiseBand) minthres = dNoiseBand;
-
- for (k = 1, idx = (j * 16) + 1; k < 17; k++, idx++)
- {
- dNoiseBand = pNB[ psy_abPartition[idx] ];
- dThreshold = pThreshold[idx];
-
- dNoiseBand = GetNoiseLevel(dNoiseBand, dThreshold, &pLThr[idx]);
-
- if (minthres > dNoiseBand) minthres = dNoiseBand;
- }
- psy_adSNRTemp[j] = psy_adEnergy2[j] / (minthres * 17.0);
- }
-
- for (j = 13; j < psy_wSBLimit; j++)
- {
- minthres = dNoiseBand;
-
- for (k = 1, idx = (j * 16) + 1; k < 17; k++, idx++)
- {
- dNoiseBand = pNB[ psy_abPartition[idx] ];
- dThreshold = pThreshold[idx];
-
- dNoiseBand = GetNoiseLevel(dNoiseBand, dThreshold, &pLThr[idx]);
- minthres += dNoiseBand;
- }
- psy_adSNRTemp[j] = psy_adEnergy2[j] / minthres;
- }
- #endif
- }
- ///
- /// Psycho_L1C::PsychoAnal()
- /****** Class Psycho_L1C/PsychoAnal *****************************************
- *
- * NAME
- * Psycho_L1C::PsychoAnal -- Fonction principale.
- *
- * SYNOPSIS
- * Psycho_L1C::PsychoAnal(LTMin[2][32])
- *
- * void Psycho_L1C::PsychoAnal(LONG);
- *
- * FUNCTION
- * Effectue l'analyse psycho-acoustique.
- *
- * NOTES
- *
- * BUGS
- *
- *****************************************************************************
- *
- */
-
-
- void Psycho_L1C::PsychoAnal(LONG LTMin[MAX_CH][SBLIMIT])
- {
- const ULONG FLUSH = 384;
-
- ULONG j, k;
- UWORD wNumChannels = psy_roCoderC.GetNumChannels();
- WORD *pSamples = psy_roCoderC.GetSamplePtr();
-
- // Appliquer le filtre d'analyse (HANN window).
-
- SetupWinSamples_1024(pSamples, wNumChannels);
-
- // Calculer la transformée de Fourrier.
-
- if (wNumChannels == 2)
- {
- pSamples += FLUSH * 2;
- ComputeFastFFT_Stereo(BLKSIZE);
- }
- else
- {
- pSamples += FLUSH;
- ComputeFastFFT_Mono(BLKSIZE);
- }
-
- // Exploiter les résultats de la transformée de Fourrier pour chaque canal.
-
- for (k = 0, psy_wNew = 1 - psy_wNew; k < wNumChannels; k++)
- {
- CalcGroupedValues(k, psy_wNew);
- CalcPermissibleNoise();
- TranslateThreshold(k);
-
- for (j = 0; j < psy_wSBLimit; j++)
- {
- #ifndef USE_OLD_MATHLIB
- LTMin[k][j] = (LONG) ( (LOG10_TO_LN * 1000) * log(psy_adSNRTemp[j]) );
- #else
- LTMin[k][j] = (LONG) floor( (LOG10_TO_LN * 1000) * log(psy_adSNRTemp[j]) );
- #endif
- }
- }
- }
- ///
- /// Psycho_L1C::InitPsychoAnalyzer()
- //
- // Initialiser la table "psy_pdLThr", uniquement utilisée avec le Layer I
-
- int Psycho_L1C::InitPsychoAnalyzer(int iSBLimit)
- {
- // Initialiser la table des Threshold mini
-
- REAL *p1 = &(*psy_pdLThr)[0][0];
- REAL *p2 = &(*psy_pdLThr)[1][0];
- REAL d = MINTHRESHOLD;
-
- for (int i = 0; i < HBLKSIZE; i++)
- {
- *p1++ = *p2++ = d;
- }
-
- return PsychoC::InitPsychoAnalyzer(iSBLimit); // Initialisation générale.
- }
- ///
-
- //----------------------------------------------------------------------------------------------------
- //======================================== Classe Psycho_L2C =========================================
- //----------------------------------------------------------------------------------------------------
-
- /// Psycho_L2C::TranslateThreshold() (virtual)
- /****** Class Psycho_L2C/TranslateThreshold *********************************
- *
- * NAME
- * Psycho_L2C::TranslateThreshold --
- *
- * SYNOPSIS
- * Psycho_L2C::TranslateThreshold(pSNR)
- *
- * void Psycho_L2C::TranslateThreshold(REAL *);
- *
- * FUNCTION
- *
- * INPUTS
- *
- * NOTES
- *
- * BUGS
- *
- *****************************************************************************
- *
- */
-
-
- void Psycho_L2C::TranslateThreshold(REAL *pSNR)
- {
- #if 1
-
- register int j, k;
- register REAL dNoiseBand, dThreshold, minthres;
- register ULONG SBLimit = psy_wSBLimit;
-
- register const REAL *pThreshold = psy_pdAbsThreshold;
- register REAL *pNB = psy_adNB;
- register UBYTE *pbPartition = &psy_abPartition[1];
- register REAL *pdEnergy2 = psy_adEnergy2;
-
- dNoiseBand = *pNB;
- dThreshold = *pThreshold++;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- for (j = 0; j < 13; j++)
- {
- minthres = MINTHRESHOLD;
- if (minthres > dNoiseBand) minthres = dNoiseBand;
-
- for (k = 16; k > 0; k--)
- {
- dNoiseBand = pNB[ *pbPartition++ ];
- dThreshold = *pThreshold++;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- if (minthres > dNoiseBand) minthres = dNoiseBand;
- }
- *pSNR++ = *pdEnergy2++ / (minthres * 17.0);
- }
-
- for ( ; j < SBLimit; j++)
- {
- minthres = dNoiseBand;
-
- for (k = 16; k > 0; k--)
- {
- dNoiseBand = pNB[ *pbPartition++ ];
- dThreshold = *pThreshold++;
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- minthres += dNoiseBand;
- }
- *pSNR++ = *pdEnergy2++ / minthres;
- }
-
- #else // Original code.
-
- int j, k, idx;
- REAL dNoiseBand, dThreshold, minthres;
-
- const REAL *pThreshold = psy_pdAbsThreshold;
- REAL *pNB = psy_adNB;
-
- dNoiseBand = pNB[0];
- dThreshold = pThreshold[0];
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- for (j = 0; j < 13; j++)
- {
- minthres = MINTHRESHOLD;
- if (minthres > dNoiseBand) minthres = dNoiseBand;
-
- for (k = 1, idx = (j * 16) + 1; k < 17; k++, idx++)
- {
- dNoiseBand = pNB[ psy_abPartition[idx] ];
- dThreshold = pThreshold[idx];
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- if (minthres > dNoiseBand) minthres = dNoiseBand;
- }
- *pSNR++ = psy_adEnergy2[j] / (minthres * 17.0);
- }
-
- for (j = 13; j < psy_wSBLimit; j++)
- {
- minthres = dNoiseBand;
-
- for (k = 1, idx = (j * 16) + 1; k < 17; k++, idx++)
- {
- dNoiseBand = pNB[ psy_abPartition[idx] ];
- dThreshold = pThreshold[idx];
-
- if (dNoiseBand < dThreshold) dNoiseBand = dThreshold;
-
- minthres += dNoiseBand;
- }
- *pSNR++ = psy_adEnergy2[j] / minthres;
- }
- #endif
- }
- ///
- /// Psycho_L2C::PsychoAnal()
- /****** Class Psycho_L2C/PsychoAnal *****************************************
- *
- * NAME
- * Psycho_L2C::PsychoAnal -- Fonction principale.
- *
- * SYNOPSIS
- * Psycho_L2C::PsychoAnal(LTMin[2][32])
- *
- * void Psycho_L2C::PsychoAnal(LONG);
- *
- * FUNCTION
- * Effectue l'analyse psycho-acoustique.
- *
- * NOTES
- *
- * BUGS
- *
- *****************************************************************************
- *
- */
-
-
- void Psycho_L2C::PsychoAnal(LONG LTMin[MAX_CH][SBLIMIT])
- {
- const ULONG FLUSH = 576;
-
- ULONG i, j, k;
- UWORD wNumChannels = psy_roCoderC.GetNumChannels();
- WORD *pSamples = psy_roCoderC.GetSamplePtr();
-
- for (i = 0; i < 2; i++)
- {
- // Appliquer le filtre d'analyse (HANN window).
-
- SetupWinSamples_1024(pSamples, wNumChannels);
-
- // Calculer la transformée de Fourrier.
-
- if (wNumChannels == 2)
- {
- pSamples += FLUSH * 2;
- ComputeFastFFT_Stereo(BLKSIZE);
- }
- else
- {
- pSamples += FLUSH;
- ComputeFastFFT_Mono(BLKSIZE);
- }
-
- // Traiter le résultat de la transformée de Fourrier pour chaque canal.
-
- for (k = 0; k < wNumChannels; k++)
- {
- REAL *pSNR = &psy_adSNRTemp[k][0][0];
-
- psy_wNew = 1 - psy_wNew;
-
- CalcGroupedValues(k, psy_wNew);
- CalcPermissibleNoise();
-
- if (i)
- {
- LONG *pLTMin = <Min[k][0];
-
- TranslateThreshold(&pSNR[SBLIMIT]);
-
- for (j = 0; j < psy_wSBLimit; j++)
- {
- REAL snr_1 = pSNR[SBLIMIT];
- REAL snr_0 = *pSNR++;
-
- if (snr_1 > snr_0) snr_0 = snr_1;
-
- #ifndef USE_OLD_MATHLIB
- *pLTMin++ = (LONG) ( (LOG10_TO_LN * 1000) * log(snr_0) );
- #else
- *pLTMin++ = (LONG) floor( (LOG10_TO_LN * 1000) * log(snr_0) );
- #endif
- }
- }
- else TranslateThreshold(pSNR);
- }
- }
- }
- ///
-
- #if _USE_ASM_FCT_ == 1
- #if _CPUMODEL_ == 68020
- #error "Can't use ASM optimized version (No FPU available)!"
- #endif
- #endif
-
-