LCOV - code coverage report
Current view: top level - lib_isar - isar_RMSEnvGrouping.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 0 198 0.0 %
Date: 2025-05-23 08:37:30 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : #include <stdlib.h>
      34             : #include "options.h"
      35             : #include <math.h>
      36             : #include "prot.h"
      37             : #include "isar_lcld_prot.h"
      38             : #include "isar_rom_lcld_tables.h"
      39             : #include "wmc_auto.h"
      40             : 
      41             : 
      42             : /*-------------------------------------------------------------------*
      43             :  * Local ROM tables
      44             :  *
      45             :  *
      46             :  *-------------------------------------------------------------------*/
      47             : 
      48             : static const float c_afThreshQuiet48[23] = {
      49             :     -8.40653699e+01f,
      50             :     -8.40653699e+01f,
      51             :     -8.40653699e+01f,
      52             :     -8.40653699e+01f,
      53             :     -8.40653699e+01f,
      54             :     -8.40653699e+01f,
      55             :     -8.40653699e+01f,
      56             :     -8.40653699e+01f,
      57             :     -8.38067304e+01f,
      58             :     -8.28409495e+01f,
      59             :     -8.17031225e+01f,
      60             :     -7.89799501e+01f,
      61             :     -7.70607916e+01f,
      62             :     -7.58484320e+01f,
      63             :     -7.47976303e+01f,
      64             :     -7.37491303e+01f,
      65             :     -7.13163746e+01f,
      66             :     -6.86144293e+01f,
      67             :     -6.56295695e+01f,
      68             :     -6.06521800e+01f,
      69             :     -3.15408065e+01f,
      70             :     -1.92542188e+01f,
      71             :     -1.88401753e+01f,
      72             : };
      73             : 
      74             : static const float c_fiDefaultTheta48[MAX_BANDS_48] = {
      75             :     0.4375,
      76             :     0.4375,
      77             :     0.375,
      78             :     0.3125,
      79             :     0.3125,
      80             :     0.25,
      81             :     0.25,
      82             :     0.25,
      83             :     0.25,
      84             :     0.25,
      85             :     0.25,
      86             :     0.25,
      87             :     0.25,
      88             :     0.25,
      89             :     0.25,
      90             :     0.25,
      91             :     0.25,
      92             :     0.25,
      93             :     0.25,
      94             :     0.25,
      95             :     0.25,
      96             :     0.25,
      97             :     0.25,
      98             : };
      99             : 
     100             : typedef struct GMNODE
     101             : {
     102             :     int32_t iGroupStart;
     103             :     int32_t iGroupLength;
     104             :     float *pfMergedEnergydB;
     105             :     int32_t *piQRMSEnvelope;
     106             : 
     107             :     int32_t iGroupRMSEnvelopeCost;
     108             :     float fGroupSNRPenalty;
     109             : 
     110             :     struct GMNODE *psNext;
     111             : } GMNode;
     112             : 
     113             : struct RMS_ENVELOPE_GROUPING
     114             : {
     115             :     int32_t iNumBlocks;
     116             :     int32_t iMaxGroups;
     117             :     float **ppfBandEnergy;
     118             :     float **ppfBandEnergydB;
     119             :     float **ppfWeight;
     120             :     GMNode *psGMNodes;
     121             : };
     122             : 
     123             : 
     124             : /*-------------------------------------------------------------------*
     125             :  * Function CreateRMSEnvelopeGrouping()
     126             :  *
     127             :  *
     128             :  *-------------------------------------------------------------------*/
     129             : 
     130           0 : RMSEnvelopeGrouping *CreateRMSEnvelopeGrouping(
     131             :     const int32_t iNumBlocks )
     132             : {
     133             :     int32_t n;
     134             : 
     135             :     RMSEnvelopeGrouping *psRMSEnvelopeGrouping;
     136             : 
     137           0 :     psRMSEnvelopeGrouping = (RMSEnvelopeGrouping *) malloc( sizeof( RMSEnvelopeGrouping ) );
     138           0 :     psRMSEnvelopeGrouping->iNumBlocks = iNumBlocks;
     139             : 
     140           0 :     psRMSEnvelopeGrouping->iMaxGroups = iNumBlocks >> 1;
     141             : 
     142           0 :     psRMSEnvelopeGrouping->ppfBandEnergy = (float **) malloc( psRMSEnvelopeGrouping->iNumBlocks * sizeof( float * ) );
     143           0 :     psRMSEnvelopeGrouping->ppfBandEnergydB = (float **) malloc( psRMSEnvelopeGrouping->iNumBlocks * sizeof( float * ) );
     144           0 :     psRMSEnvelopeGrouping->ppfWeight = (float **) malloc( psRMSEnvelopeGrouping->iNumBlocks * sizeof( float * ) );
     145           0 :     for ( n = 0; n < psRMSEnvelopeGrouping->iNumBlocks; n++ )
     146             :     {
     147           0 :         psRMSEnvelopeGrouping->ppfBandEnergy[n] = (float *) malloc( MAX_BANDS * 2 * sizeof( float ) ); /* 2 for stereo joint group calc */
     148           0 :         psRMSEnvelopeGrouping->ppfBandEnergydB[n] = (float *) malloc( MAX_BANDS * 2 * sizeof( float ) );
     149           0 :         psRMSEnvelopeGrouping->ppfWeight[n] = (float *) malloc( MAX_BANDS * 2 * sizeof( float ) );
     150             :     }
     151             : 
     152           0 :     psRMSEnvelopeGrouping->psGMNodes = (GMNode *) malloc( psRMSEnvelopeGrouping->iNumBlocks * sizeof( GMNode ) );
     153           0 :     for ( n = 0; n < psRMSEnvelopeGrouping->iNumBlocks; n++ )
     154             :     {
     155           0 :         psRMSEnvelopeGrouping->psGMNodes[n].pfMergedEnergydB = (float *) malloc( MAX_BANDS * 2 * sizeof( float ) );
     156           0 :         psRMSEnvelopeGrouping->psGMNodes[n].piQRMSEnvelope = (int32_t *) malloc( MAX_BANDS * 2 * sizeof( int32_t ) );
     157           0 :         psRMSEnvelopeGrouping->psGMNodes[n].iGroupRMSEnvelopeCost = -1;
     158           0 :         psRMSEnvelopeGrouping->psGMNodes[n].fGroupSNRPenalty = -1.0;
     159             :     }
     160             : 
     161           0 :     return psRMSEnvelopeGrouping;
     162             : }
     163             : 
     164             : 
     165             : /*-------------------------------------------------------------------*
     166             :  * Function DeleteRMSEnvelopeGrouping()
     167             :  *
     168             :  *
     169             :  *-------------------------------------------------------------------*/
     170             : 
     171           0 : void DeleteRMSEnvelopeGrouping(
     172             :     RMSEnvelopeGrouping *psRMSEnvelopeGrouping )
     173             : {
     174             :     int32_t n;
     175             : 
     176           0 :     for ( n = 0; n < psRMSEnvelopeGrouping->iNumBlocks; n++ )
     177             :     {
     178           0 :         free( psRMSEnvelopeGrouping->ppfBandEnergy[n] );
     179           0 :         free( psRMSEnvelopeGrouping->ppfBandEnergydB[n] );
     180           0 :         free( psRMSEnvelopeGrouping->ppfWeight[n] );
     181             :     }
     182           0 :     free( psRMSEnvelopeGrouping->ppfBandEnergy );
     183           0 :     free( psRMSEnvelopeGrouping->ppfBandEnergydB );
     184           0 :     free( psRMSEnvelopeGrouping->ppfWeight );
     185             : 
     186           0 :     for ( n = 0; n < psRMSEnvelopeGrouping->iNumBlocks; n++ )
     187             :     {
     188           0 :         free( psRMSEnvelopeGrouping->psGMNodes[n].pfMergedEnergydB );
     189           0 :         free( psRMSEnvelopeGrouping->psGMNodes[n].piQRMSEnvelope );
     190             :     }
     191           0 :     free( psRMSEnvelopeGrouping->psGMNodes );
     192             : 
     193           0 :     free( psRMSEnvelopeGrouping );
     194             : 
     195           0 :     return;
     196             : }
     197             : 
     198             : 
     199             : /*-------------------------------------------------------------------*
     200             :  * Function ComputeBandEnergy()
     201             :  *
     202             :  *
     203             :  *-------------------------------------------------------------------*/
     204             : 
     205           0 : static void ComputeBandEnergy(
     206             :     const int32_t iChannels,
     207             :     const int32_t iNumBlocks,
     208             :     const int32_t iNumBands,
     209             :     const int32_t *piBandwidths,
     210             :     float ***pppfReal,
     211             :     float ***pppfImag,
     212             :     float **ppfBandEnergy,
     213             :     float **ppfBandEnergydB,
     214             :     float **ppfWeight )
     215             : {
     216             :     int32_t n;
     217             : 
     218           0 :     for ( n = 0; n < iChannels; n++ )
     219             :     {
     220             :         int32_t k;
     221             :         int32_t iChanOffset;
     222             : 
     223           0 :         iChanOffset = n * iNumBands;
     224           0 :         for ( k = 0; k < iNumBlocks; k++ )
     225             :         {
     226             :             int32_t b;
     227             :             int32_t iFBOffset;
     228             :             float fMaxWeight;
     229             : 
     230           0 :             iFBOffset = 0;
     231           0 :             fMaxWeight = 0.0f;
     232           0 :             for ( b = 0; b < iNumBands; b++ )
     233             :             {
     234             :                 int32_t m;
     235           0 :                 float fEnergy = 1e-12f;
     236             :                 float fWeight;
     237             : 
     238           0 :                 for ( m = 0; m < piBandwidths[b]; m++ )
     239             :                 {
     240           0 :                     fEnergy += ( pppfReal[n][k][iFBOffset] * pppfReal[n][k][iFBOffset] + pppfImag[n][k][iFBOffset] * pppfImag[n][k][iFBOffset] );
     241           0 :                     iFBOffset++;
     242             :                 }
     243           0 :                 fEnergy /= (float) ( piBandwidths[b] ); /* Correction removed normalization by 2*/
     244           0 :                 ppfBandEnergy[k][iChanOffset + b] = fEnergy;
     245             : 
     246           0 :                 fWeight = 0.33f * powf( 10.0f, 0.0068f * ( 10.0f * log10f( fEnergy ) - c_afThreshQuiet48[b] ) );
     247           0 :                 fWeight = ( fWeight > 0.33f ) ? fWeight : 0.33f;
     248           0 :                 fWeight = ( fWeight < 1.0f ) ? fWeight : 1.0f;
     249           0 :                 fMaxWeight = ( fMaxWeight > fWeight ) ? fMaxWeight : fWeight;
     250           0 :                 ppfWeight[k][iChanOffset + b] = fWeight;
     251             : 
     252             : #ifdef APPLY_TEMPORAL_SMOOTHING
     253             :                 if ( k > 0 )
     254             :                 {
     255             :                     float fSmoothEnergy;
     256             :                     fSmoothEnergy = 0.7f * ppfBandEnergy[k - 1][iChanOffset + b] + 0.3f * fEnergy;
     257             : 
     258             :                     fEnergy = ( fEnergy > fSmoothEnergy ) ? fEnergy : fSmoothEnergy;
     259             :                 }
     260             : #endif
     261           0 :                 fEnergy = 10.0f * log10f( fEnergy );
     262           0 :                 ppfBandEnergydB[k][iChanOffset + b] = fEnergy;
     263             :             }
     264           0 :             for ( b = 0; b < iNumBands; b++ )
     265             :             {
     266           0 :                 ppfWeight[k][iChanOffset + b] /= fMaxWeight;
     267             :             }
     268             :         }
     269             :     }
     270             : 
     271           0 :     return;
     272             : }
     273             : 
     274             : /*-------------------------------------------------------------------*
     275             :  * Function ComputeMergeRMS()
     276             :  *
     277             :  *
     278             :  *-------------------------------------------------------------------*/
     279             : 
     280           0 : static void ComputeMergeRMS(
     281             :     const int32_t iNumBands,
     282             :     const int32_t iStartBlock,
     283             :     const int32_t iGroupLength,
     284             :     float **ppfBandEnergy,
     285             :     float *pfMergedEnergydB,
     286             :     int32_t *piQRMSEnvelope )
     287             : {
     288             :     int32_t b;
     289           0 :     float fInvGroupSize = 1.0f / (float) iGroupLength;
     290             : 
     291           0 :     for ( b = 0; b < iNumBands; b++ )
     292             :     {
     293             :         int32_t n;
     294             :         float fGroupEnergy;
     295             :         float fRMSEnvelope;
     296             :         int32_t iQRMSEnvelope;
     297             : 
     298           0 :         fGroupEnergy = 0.0;
     299           0 :         for ( n = iStartBlock; n < ( iStartBlock + iGroupLength ); n++ )
     300             :         {
     301           0 :             fGroupEnergy += ppfBandEnergy[n][b];
     302             :         }
     303           0 :         fGroupEnergy *= fInvGroupSize;
     304             : 
     305           0 :         fRMSEnvelope = log2f( fGroupEnergy );
     306           0 :         iQRMSEnvelope = ( fRMSEnvelope > 0.0 ) ? (int32_t) ( fRMSEnvelope + 0.5 ) : (int32_t) ( fRMSEnvelope - 0.5 );
     307             : 
     308           0 :         fGroupEnergy = 10.0f * log10f( fGroupEnergy ); /* Note epsilon was added when computing BandEnergy;*/
     309             : 
     310           0 :         pfMergedEnergydB[b] = fGroupEnergy;
     311           0 :         piQRMSEnvelope[b] = iQRMSEnvelope;
     312             :     }
     313             : 
     314           0 :     return;
     315             : }
     316             : 
     317             : 
     318             : /*-------------------------------------------------------------------*
     319             :  * Function ComputeRMSEnvelopeBits()
     320             :  *
     321             :  *
     322             :  *-------------------------------------------------------------------*/
     323             : 
     324           0 : static int32_t ComputeRMSEnvelopeBits(
     325             :     const int32_t iChannels,
     326             :     const int32_t iNumBands,
     327             :     const int32_t *piQRMSEnevelope )
     328             : {
     329             :     int32_t n;
     330           0 :     int32_t iRMSEnvelopeBits = 0;
     331           0 :     int32_t iChanOffset = 0;
     332             : 
     333           0 :     for ( n = 0; n < iChannels; n++ )
     334             :     {
     335             :         int32_t b;
     336             :         int32_t iLastRMSVal;
     337             : 
     338           0 :         iRMSEnvelopeBits += ENV0_BITS;
     339           0 :         iLastRMSVal = piQRMSEnevelope[iChanOffset];
     340           0 :         for ( b = 1; b < iNumBands; b++ )
     341             :         {
     342             :             int32_t iDelta;
     343             : 
     344           0 :             iDelta = piQRMSEnevelope[iChanOffset + b] - iLastRMSVal;
     345           0 :             iDelta = ( iDelta > ENV_DELTA_MIN ) ? iDelta : ENV_DELTA_MIN;
     346           0 :             iDelta = ( iDelta < ENV_DELTA_MAX ) ? iDelta : ENV_DELTA_MAX;
     347           0 :             iDelta -= ENV_DELTA_MIN;
     348           0 :             iRMSEnvelopeBits += c_aaiRMSEnvHuffEnc[iDelta][0];
     349             : 
     350           0 :             iLastRMSVal = piQRMSEnevelope[iChanOffset + b];
     351             :         }
     352             : 
     353           0 :         iChanOffset += iNumBands;
     354             :     }
     355             : 
     356           0 :     return iRMSEnvelopeBits;
     357             : }
     358             : 
     359             : 
     360             : /*-------------------------------------------------------------------*
     361             :  * Function ComputeSNRPenalty()
     362             :  *
     363             :  *
     364             :  *-------------------------------------------------------------------*/
     365             : 
     366           0 : static float ComputeSNRPenalty(
     367             :     const int32_t iChannels,
     368             :     const int32_t iNumBands,
     369             :     const int32_t *piBandwidths,
     370             :     const int32_t iStartBlock,
     371             :     const int32_t iGroupLength,
     372             :     float **ppfBandEnergydB,
     373             :     const int32_t *piRMSEnvelope )
     374             : {
     375             :     int32_t n;
     376             :     int32_t iChanOffset;
     377           0 :     float fSNRPenalty = 0.0;
     378             : 
     379           0 :     iChanOffset = 0;
     380           0 :     for ( n = 0; n < iChannels; n++ )
     381             :     {
     382             :         int32_t b;
     383           0 :         for ( b = 0; b < iNumBands; b++ )
     384             :         {
     385             :             int32_t k;
     386             :             float fRMSVal;
     387             : 
     388           0 :             fRMSVal = 3.0103f * (float) piRMSEnvelope[iChanOffset + b];
     389             : 
     390           0 :             for ( k = iStartBlock; k < ( iStartBlock + iGroupLength ); k++ )
     391             :             {
     392             :                 float fDeltadB;
     393             : 
     394           0 :                 fDeltadB = fRMSVal - ppfBandEnergydB[k][iChanOffset + b];
     395           0 :                 if ( fDeltadB < -9.0309f )
     396             :                 {
     397           0 :                     fSNRPenalty += 1e10f; /* Some large number to prevent clipping*/
     398             :                 }
     399             :                 else /*if(fDeltadB < 0.0)*/
     400             :                 {
     401           0 :                     fSNRPenalty += fabsf( c_fiDefaultTheta48[b] * fDeltadB - fDeltadB ) * 2.0f * (float) piBandwidths[b] / 6.0f;
     402             :                 }
     403             :             }
     404             :         }
     405             : 
     406           0 :         iChanOffset += iNumBands;
     407             :     }
     408             : 
     409           0 :     return fSNRPenalty;
     410             : }
     411             : 
     412             : 
     413             : /*-------------------------------------------------------------------*
     414             :  * Function TryMerge2()
     415             :  *
     416             :  *
     417             :  *-------------------------------------------------------------------*/
     418             : 
     419           0 : static float TryMerge2(
     420             :     const int32_t iChannels,
     421             :     const int32_t iNumBands,
     422             :     const int32_t *piBandwidths,
     423             :     float **ppfBandEnergy,
     424             :     float **ppfBandEnergydB,
     425             :     GMNode *psGMNode1,
     426             :     GMNode *psGMNode2 )
     427             : {
     428             :     int32_t iRMSEnvBits1;
     429             :     int32_t iRMSEnvBits2;
     430             :     int32_t iRMSEnvBitsMerged;
     431             :     float fSNRPenalty1;
     432             :     float fSNRPenalty2;
     433             :     float fSNRPenaltyMerged;
     434           0 :     float fMergedCost = 0.0;
     435             : 
     436             :     /* First compute current RMS Envelope for each group */
     437           0 :     if ( psGMNode1->iGroupRMSEnvelopeCost == -1 || psGMNode1->fGroupSNRPenalty == -1.0 )
     438             :     {
     439           0 :         ComputeMergeRMS( iNumBands * iChannels, psGMNode1->iGroupStart, psGMNode1->iGroupLength, ppfBandEnergy, psGMNode1->pfMergedEnergydB, psGMNode1->piQRMSEnvelope );
     440             : 
     441           0 :         iRMSEnvBits1 = ComputeRMSEnvelopeBits( iChannels, iNumBands, psGMNode1->piQRMSEnvelope );
     442             : 
     443           0 :         fSNRPenalty1 = ComputeSNRPenalty( iChannels, iNumBands, piBandwidths, psGMNode1->iGroupStart, psGMNode1->iGroupLength, ppfBandEnergydB, psGMNode1->piQRMSEnvelope );
     444             : 
     445           0 :         psGMNode1->iGroupRMSEnvelopeCost = iRMSEnvBits1;
     446           0 :         psGMNode1->fGroupSNRPenalty = fSNRPenalty1;
     447             :     }
     448             :     else
     449             :     {
     450           0 :         iRMSEnvBits1 = psGMNode1->iGroupRMSEnvelopeCost;
     451           0 :         fSNRPenalty1 = psGMNode1->fGroupSNRPenalty;
     452             :     }
     453             : 
     454           0 :     if ( psGMNode2->iGroupRMSEnvelopeCost == -1 || psGMNode2->fGroupSNRPenalty == -1.0 )
     455             :     {
     456           0 :         ComputeMergeRMS( iNumBands * iChannels, psGMNode2->iGroupStart, psGMNode2->iGroupLength, ppfBandEnergy, psGMNode2->pfMergedEnergydB, psGMNode2->piQRMSEnvelope );
     457             : 
     458           0 :         iRMSEnvBits2 = ComputeRMSEnvelopeBits( iChannels, iNumBands, psGMNode2->piQRMSEnvelope );
     459             : 
     460           0 :         fSNRPenalty2 = ComputeSNRPenalty( iChannels, iNumBands, piBandwidths, psGMNode2->iGroupStart, psGMNode2->iGroupLength, ppfBandEnergydB, psGMNode2->piQRMSEnvelope );
     461             : 
     462           0 :         psGMNode2->iGroupRMSEnvelopeCost = iRMSEnvBits2;
     463           0 :         psGMNode2->fGroupSNRPenalty = fSNRPenalty2;
     464             :     }
     465             :     else
     466             :     {
     467           0 :         iRMSEnvBits2 = psGMNode2->iGroupRMSEnvelopeCost;
     468           0 :         fSNRPenalty2 = psGMNode2->fGroupSNRPenalty;
     469             :     }
     470             : 
     471             :     /* Compute the merged group */
     472           0 :     ComputeMergeRMS( iNumBands * iChannels, psGMNode1->iGroupStart, psGMNode1->iGroupLength + psGMNode2->iGroupLength, ppfBandEnergy, psGMNode1->pfMergedEnergydB, psGMNode1->piQRMSEnvelope );
     473             : 
     474             :     /* Compute the RMS Envelope cost for merged group */
     475           0 :     iRMSEnvBitsMerged = ComputeRMSEnvelopeBits( iChannels, iNumBands, psGMNode1->piQRMSEnvelope );
     476             : 
     477             :     /* Compute an approximation of the bit cost based on SNR increase/decrease due to merging */
     478           0 :     fSNRPenaltyMerged = ComputeSNRPenalty( iChannels, iNumBands, piBandwidths, psGMNode1->iGroupStart, psGMNode1->iGroupLength + psGMNode2->iGroupLength, ppfBandEnergydB, psGMNode1->piQRMSEnvelope );
     479             : 
     480           0 :     fMergedCost = fSNRPenaltyMerged - fSNRPenalty1 - fSNRPenalty2 + (float) iRMSEnvBitsMerged - (float) iRMSEnvBits1 - (float) iRMSEnvBits2;
     481             : 
     482           0 :     return fMergedCost;
     483             : }
     484             : 
     485             : /*-------------------------------------------------------------------*
     486             :  * Function ComputeGreedyGroups3()
     487             :  *
     488             :  *
     489             :  *-------------------------------------------------------------------*/
     490             : 
     491           0 : static void ComputeGreedyGroups3(
     492             :     RMSEnvelopeGrouping *psRMSEnvelopeGrouping,
     493             :     const int32_t iChannels,
     494             :     const int32_t iNumBands,
     495             :     const int32_t *piBandwidths,
     496             :     const int32_t iMaxGroups )
     497             : {
     498             : 
     499           0 :     int32_t iDone = 0;
     500           0 :     int32_t iNumGroups = psRMSEnvelopeGrouping->iMaxGroups;
     501             : 
     502           0 :     while ( iDone == 0 )
     503             :     {
     504             :         GMNode *psGMNode;
     505             :         GMNode *psBestGMNode;
     506             :         float fBestMergeCost;
     507             : 
     508           0 :         fBestMergeCost = 1e20f;
     509           0 :         psGMNode = &psRMSEnvelopeGrouping->psGMNodes[0];
     510           0 :         psBestGMNode = NULL;
     511           0 :         while ( psGMNode->psNext != NULL )
     512             :         {
     513             :             float fMergeCost;
     514             : 
     515           0 :             fMergeCost = TryMerge2( iChannels, iNumBands, piBandwidths, psRMSEnvelopeGrouping->ppfBandEnergy, psRMSEnvelopeGrouping->ppfBandEnergydB, psGMNode, psGMNode->psNext );
     516             : 
     517           0 :             if ( fMergeCost < fBestMergeCost )
     518             :             {
     519           0 :                 fBestMergeCost = fMergeCost;
     520           0 :                 psBestGMNode = psGMNode;
     521             :             }
     522             : 
     523           0 :             psGMNode = psGMNode->psNext;
     524             :         }
     525             : 
     526           0 :         if ( fBestMergeCost > 0.0 && iNumGroups <= iMaxGroups )
     527             :         {
     528           0 :             iDone++;
     529             :         }
     530           0 :         else if ( psBestGMNode != NULL && psBestGMNode->psNext != NULL )
     531             :         {
     532           0 :             psBestGMNode->iGroupLength += psBestGMNode->psNext->iGroupLength;
     533           0 :             psBestGMNode->iGroupRMSEnvelopeCost = -1;
     534           0 :             psBestGMNode->fGroupSNRPenalty = -1.0;
     535           0 :             psBestGMNode->psNext = psBestGMNode->psNext->psNext;
     536           0 :             iNumGroups--;
     537             :         }
     538             :         else
     539             :         {
     540           0 :             iDone++; /* This only catches a problem*/
     541             :         }
     542             :     }
     543             : 
     544           0 :     return;
     545             : }
     546             : 
     547             : 
     548             : /*-------------------------------------------------------------------*
     549             :  * Function ComputeRMSEnvelope()
     550             :  *
     551             :  *
     552             :  *-------------------------------------------------------------------*/
     553             : 
     554           0 : static void ComputeRMSEnvelope(
     555             :     const int32_t iChannels,
     556             :     const int32_t iNumBands,
     557             :     const int32_t iNumGroups,
     558             :     const int32_t *piGroupLengths,
     559             :     float **ppfBandEnergy,
     560             :     int32_t ***pppiRMSEnvelope )
     561             : {
     562             :     int32_t n;
     563             : 
     564           0 :     for ( n = 0; n < iChannels; n++ )
     565             :     {
     566             :         int32_t b;
     567             :         int32_t iChanOffset;
     568             : 
     569           0 :         iChanOffset = n * iNumBands;
     570           0 :         for ( b = 0; b < iNumBands; b++ )
     571             :         {
     572             :             int32_t k;
     573             :             int32_t iBlockOffset;
     574             : 
     575           0 :             iBlockOffset = 0;
     576           0 :             for ( k = 0; k < iNumGroups; k++ )
     577             :             {
     578             :                 int32_t m;
     579             :                 float fGroupEnergy;
     580           0 :                 fGroupEnergy = 0.0;
     581           0 :                 for ( m = 0; m < piGroupLengths[k]; m++ )
     582             :                 {
     583           0 :                     fGroupEnergy += ppfBandEnergy[iBlockOffset][b + iChanOffset];
     584           0 :                     iBlockOffset++;
     585             :                 }
     586           0 :                 fGroupEnergy /= (float) piGroupLengths[k];
     587             : 
     588           0 :                 fGroupEnergy = log2f( fGroupEnergy );
     589           0 :                 pppiRMSEnvelope[n][k][b] = ( fGroupEnergy > 0.0 ) ? (int32_t) ( fGroupEnergy + 0.5 ) : (int32_t) ( fGroupEnergy - 0.5 );
     590           0 :                 pppiRMSEnvelope[n][k][b] = ( pppiRMSEnvelope[n][k][b] > ENV_MIN ) ? pppiRMSEnvelope[n][k][b] : ENV_MIN;
     591           0 :                 pppiRMSEnvelope[n][k][b] = ( pppiRMSEnvelope[n][k][b] < ENV_MAX ) ? pppiRMSEnvelope[n][k][b] : ENV_MAX;
     592             :             }
     593             :         }
     594             :     }
     595             : 
     596           0 :     return;
     597             : }
     598             : 
     599             : 
     600             : /*-------------------------------------------------------------------*
     601             :  * Function LimitRMSEnvelope()
     602             :  *
     603             :  *
     604             :  *-------------------------------------------------------------------*/
     605             : 
     606           0 : static void LimitRMSEnvelope(
     607             :     const int32_t iBandCount,
     608             :     const int32_t iRMSDeltaMax,
     609             :     const int32_t iRMSDeltaMin,
     610             :     int32_t *piRMSEnvelope )
     611             : {
     612             :     int32_t iBand;
     613             :     int32_t iLastSCF;
     614             : 
     615             :     /* Increase low envelope values to ensure that the scale factors traces the large values correctly (checking for max deltas) */
     616           0 :     iLastSCF = piRMSEnvelope[iBandCount - 1];
     617           0 :     for ( iBand = iBandCount - 2; iBand > -1; iBand-- )
     618             :     {
     619             :         int32_t iDelta;
     620             : 
     621           0 :         iDelta = iLastSCF - piRMSEnvelope[iBand];
     622             : 
     623           0 :         if ( iDelta > iRMSDeltaMax )
     624             :         {
     625             : #ifdef DEBUG_VERBOSE
     626             :             printf( "WARNING RMS envelope delta limited\n" );
     627             : #endif
     628           0 :             piRMSEnvelope[iBand] += ( iDelta - iRMSDeltaMax );
     629             :         }
     630             : 
     631           0 :         iLastSCF = piRMSEnvelope[iBand];
     632             :     }
     633             : 
     634             :     /* Increase low envelope values to ensure that the envelope traces the large values correctly (checking for min deltas)*/
     635           0 :     iLastSCF = piRMSEnvelope[0];
     636           0 :     for ( iBand = 1; iBand < iBandCount; iBand++ )
     637             :     {
     638             :         int32_t iDelta;
     639             : 
     640           0 :         iDelta = piRMSEnvelope[iBand] - iLastSCF;
     641             : 
     642           0 :         if ( iDelta < iRMSDeltaMin )
     643             :         {
     644             : #ifdef DEBUG_VERBOSE
     645             :             printf( "WARNING RMS envelope delta limited\n" );
     646             : #endif
     647           0 :             piRMSEnvelope[iBand] += ( iRMSDeltaMin - iDelta );
     648             :         }
     649             : 
     650           0 :         iLastSCF = piRMSEnvelope[iBand];
     651             :     }
     652             : 
     653           0 :     return;
     654             : }
     655             : 
     656             : 
     657             : /*-------------------------------------------------------------------*
     658             :  * Function ComputeEnvelopeGrouping()
     659             :  *
     660             :  *
     661             :  *-------------------------------------------------------------------*/
     662             : 
     663           0 : void ComputeEnvelopeGrouping(
     664             :     RMSEnvelopeGrouping *psRMSEnvelopeGrouping,
     665             :     const int32_t iChannels,
     666             :     const int32_t iNumBands,
     667             :     const int32_t *piBandwidths,
     668             :     float ***pppfReal,
     669             :     float ***pppfImag,
     670             :     int32_t *piNumGroups,
     671             :     int32_t *piGroupLengths,
     672             :     int32_t ***pppiRMSEnvelope )
     673             : {
     674             :     int32_t n;
     675             :     GMNode *psGMNode;
     676             : 
     677             :     /* Compute Band Energies */
     678           0 :     ComputeBandEnergy( iChannels, psRMSEnvelopeGrouping->iNumBlocks, iNumBands, piBandwidths, pppfReal, pppfImag, psRMSEnvelopeGrouping->ppfBandEnergy, psRMSEnvelopeGrouping->ppfBandEnergydB, psRMSEnvelopeGrouping->ppfWeight );
     679             : 
     680             :     /* Init GMNodes */
     681           0 :     psRMSEnvelopeGrouping->psGMNodes[0].iGroupStart = 0;
     682           0 :     psRMSEnvelopeGrouping->psGMNodes[0].iGroupLength = 2;
     683           0 :     psRMSEnvelopeGrouping->psGMNodes[0].psNext = NULL;
     684           0 :     psRMSEnvelopeGrouping->psGMNodes[0].iGroupRMSEnvelopeCost = -1;
     685           0 :     psRMSEnvelopeGrouping->psGMNodes[0].fGroupSNRPenalty = -1.0f;
     686             : 
     687           0 :     for ( n = 1; n < psRMSEnvelopeGrouping->iMaxGroups; n++ )
     688             :     {
     689           0 :         psRMSEnvelopeGrouping->psGMNodes[n - 1].psNext = &psRMSEnvelopeGrouping->psGMNodes[n];
     690           0 :         psRMSEnvelopeGrouping->psGMNodes[n].iGroupStart = n * 2;
     691           0 :         psRMSEnvelopeGrouping->psGMNodes[n].iGroupLength = 2;
     692           0 :         psRMSEnvelopeGrouping->psGMNodes[n].iGroupRMSEnvelopeCost = -1;
     693           0 :         psRMSEnvelopeGrouping->psGMNodes[n].fGroupSNRPenalty = -1.0;
     694           0 :         psRMSEnvelopeGrouping->psGMNodes[n].psNext = NULL;
     695             :     }
     696             : 
     697             :     /* Perform grouping via Greedy Merge */
     698             :     /* Allows control over max groups can call using 16 if want same as previous call */
     699           0 :     ComputeGreedyGroups3( psRMSEnvelopeGrouping, iChannels, iNumBands, piBandwidths, psRMSEnvelopeGrouping->iNumBlocks );
     700             : 
     701             :     /* Calc Groups from Merge Results */
     702           0 :     *piNumGroups = 0;
     703           0 :     psGMNode = &psRMSEnvelopeGrouping->psGMNodes[0];
     704           0 :     while ( psGMNode != NULL )
     705             :     {
     706           0 :         piGroupLengths[*piNumGroups] = psGMNode->iGroupLength;
     707           0 :         *piNumGroups += 1;
     708           0 :         psGMNode = psGMNode->psNext;
     709             :     }
     710             : 
     711             :     /* Compute RMS Envelope given group lengths */
     712           0 :     ComputeRMSEnvelope( iChannels, iNumBands, *piNumGroups, piGroupLengths, psRMSEnvelopeGrouping->ppfBandEnergy, pppiRMSEnvelope );
     713             : 
     714             :     /* Envelope Tenting */
     715           0 :     for ( n = 0; n < iChannels; n++ )
     716             :     {
     717             :         int32_t k;
     718           0 :         for ( k = 0; k < *piNumGroups; k++ )
     719             :         {
     720           0 :             LimitRMSEnvelope( iNumBands, ENV_DELTA_MAX, ENV_DELTA_MIN, pppiRMSEnvelope[n][k] );
     721             :         }
     722             :     }
     723             : 
     724           0 :     return;
     725             : }

Generated by: LCOV version 1.14