summaryrefslogtreecommitdiffstats
path: root/libAACenc/src/aacenc_pns.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
commit2228e360595641dd906bf1773307f43d304f5b2e (patch)
tree57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libAACenc/src/aacenc_pns.cpp
downloadandroid_external_aac-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz
android_external_aac-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2
android_external_aac-2228e360595641dd906bf1773307f43d304f5b2e.zip
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libAACenc/src/aacenc_pns.cpp')
-rw-r--r--libAACenc/src/aacenc_pns.cpp591
1 files changed, 591 insertions, 0 deletions
diff --git a/libAACenc/src/aacenc_pns.cpp b/libAACenc/src/aacenc_pns.cpp
new file mode 100644
index 0000000..4d81268
--- /dev/null
+++ b/libAACenc/src/aacenc_pns.cpp
@@ -0,0 +1,591 @@
+
+/* -----------------------------------------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
+ All rights reserved.
+
+ 1. INTRODUCTION
+The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
+the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
+This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
+
+AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
+audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
+independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
+of the MPEG specifications.
+
+Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
+may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
+individually for the purpose of encoding or decoding bit streams in products that are compliant with
+the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
+these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
+software may already be covered under those patent licenses when it is used for those licensed purposes only.
+
+Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
+are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
+applications information and documentation.
+
+2. COPYRIGHT LICENSE
+
+Redistribution and use in source and binary forms, with or without modification, are permitted without
+payment of copyright license fees provided that you satisfy the following conditions:
+
+You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
+your modifications thereto in source code form.
+
+You must retain the complete text of this software license in the documentation and/or other materials
+provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
+You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
+modifications thereto to recipients of copies in binary form.
+
+The name of Fraunhofer may not be used to endorse or promote products derived from this library without
+prior written permission.
+
+You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
+software or your modifications thereto.
+
+Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
+and the date of any change. For modified versions of the FDK AAC Codec, the term
+"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
+"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
+
+3. NO PATENT LICENSE
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
+ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
+respect to this software.
+
+You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
+by appropriate patent licenses.
+
+4. DISCLAIMER
+
+This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
+"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
+of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
+including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
+or business interruption, however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence), arising in any way out of the use of this software, even if
+advised of the possibility of such damage.
+
+5. CONTACT INFORMATION
+
+Fraunhofer Institute for Integrated Circuits IIS
+Attention: Audio and Multimedia Departments - FDK AAC LL
+Am Wolfsmantel 33
+91058 Erlangen, Germany
+
+www.iis.fraunhofer.de/amm
+amm-info@iis.fraunhofer.de
+----------------------------------------------------------------------------------------------------------- */
+
+/******************************** MPEG Audio Encoder **************************
+
+ Initial author: M. Lohwasser
+ contents/description: pns.c
+
+******************************************************************************/
+
+#include "aacenc_pns.h"
+#include "psy_data.h"
+#include "pnsparam.h"
+#include "noisedet.h"
+#include "bit_cnt.h"
+#include "interface.h"
+
+
+/* minCorrelationEnergy = (1.0e-10f)^2 ~ 2^-67 = 2^-47 * 2^-20 */
+static const FIXP_DBL minCorrelationEnergy = FL2FXCONST_DBL(0.0); /* FL2FXCONST_DBL((float)FDKpow(2.0,-47)); */
+/* noiseCorrelationThresh = 0.6^2 */
+static const FIXP_DBL noiseCorrelationThresh = FL2FXCONST_DBL(0.36);
+
+static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT sfbActive,
+ const INT *sfbOffset,
+ INT tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality );
+
+static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive,
+ INT *pnsFlag,
+ FIXP_DBL *sfbEnergyLdData,
+ INT *noiseNrg );
+
+/*****************************************************************************
+
+ functionname: initPnsConfiguration
+ description: fill pnsConf with pns parameters
+ returns: error status
+ input: PNS Config struct (modified)
+ bitrate, samplerate, usePns,
+ number of sfb's, pointer to sfb offset
+ output: error code
+
+*****************************************************************************/
+
+AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf,
+ INT bitRate,
+ INT sampleRate,
+ INT usePns,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ const INT numChan,
+ const INT isLC)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+
+ /* init noise detection */
+ ErrorStatus = FDKaacEnc_GetPnsParam(&pnsConf->np,
+ bitRate,
+ sampleRate,
+ sfbCnt,
+ sfbOffset,
+ &usePns,
+ numChan,
+ isLC);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ pnsConf->minCorrelationEnergy = minCorrelationEnergy;
+ pnsConf->noiseCorrelationThresh = noiseCorrelationThresh;
+
+ pnsConf->usePns = usePns;
+
+ return AAC_ENC_OK;
+}
+
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_PnsDetect
+ description: do decision, if PNS shall used or not
+ returns:
+ input: pns config structure
+ pns data structure (modified),
+ lastWindowSequence (long or short blocks)
+ sfbActive
+ pointer to Sfb Energy, Threshold, Offset
+ pointer to mdct Spectrum
+ length of each group
+ pointer to tonality calculated in chaosmeasure
+ tns order and prediction gain
+ calculated noiseNrg at active PNS
+ output: pnsFlag in pns data structure
+
+*****************************************************************************/
+void FDKaacEnc_PnsDetect(PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT lastWindowSequence,
+ const INT sfbActive,
+ const INT maxSfbPerGroup,
+ FIXP_DBL *sfbThresholdLdData,
+ const INT *sfbOffset,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality,
+ INT tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *sfbEnergyLdData,
+ INT *noiseNrg )
+
+{
+ int sfb;
+ int startNoiseSfb;
+
+ if (pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) {
+ if ( (!pnsConf->usePns) || /* pns enabled? */
+ (lastWindowSequence == SHORT_WINDOW) ) /* currently only long blocks */
+ {
+ FDKmemclear(pnsData->pnsFlag, MAX_GROUPED_SFB*sizeof(INT)); /* clear all pnsFlags */
+ for (sfb=0; sfb<MAX_GROUPED_SFB; sfb++) {
+ noiseNrg[sfb] = NO_NOISE_PNS; /* clear nrg's of previous frame */
+ }
+ return;
+ }
+ }
+ else {
+ if(!pnsConf->usePns)
+ return;
+
+ /* PNS only for long Windows */
+ if (pnsConf->np.detectionAlgorithmFlags & JUST_LONG_WINDOW) {
+ if(lastWindowSequence != LONG_WINDOW) {
+ for (sfb = 0; sfb < sfbActive; sfb++) {
+ pnsData->pnsFlag[sfb] = 0; /* clear all pnsFlags */
+ }
+ return;
+ }
+ }
+ }
+ /*
+ call noise detection
+ */
+ FDKaacEnc_FDKaacEnc_noiseDetection( pnsConf,
+ pnsData,
+ sfbActive,
+ sfbOffset,
+ tnsOrder,
+ tnsPredictionGain,
+ tnsActive,
+ mdctSpectrum,
+ sfbMaxScaleSpec,
+ sfbtonality );
+
+ /* set startNoiseSfb (long) */
+ startNoiseSfb = pnsConf->np.startSfb;
+
+ /* Set noise substitution status */
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+
+ /* No PNS below startNoiseSfb */
+ if(sfb < startNoiseSfb){
+ pnsData->pnsFlag[sfb] = 0;
+ continue;
+ }
+
+ /*
+ do noise substitution if
+ fuzzy measure is high enough
+ sfb freq > minimum sfb freq
+ signal in coder band is not masked
+ */
+
+ if((pnsData->noiseFuzzyMeasure[sfb] > FL2FXCONST_SGL(0.5)) &&
+ ( (sfbThresholdLdData[sfb] + FL2FXCONST_DBL(0.5849625f/64.0f)) /* thr * 1.5 = thrLd +ld(1.5)/64 */
+ < sfbEnergyLdData[sfb] ) )
+ {
+ /*
+ mark in psyout flag array that we will code
+ this band with PNS
+ */
+ pnsData->pnsFlag[sfb] = 1; /* PNS_ON */
+ }
+ else{
+ pnsData->pnsFlag[sfb] = 0; /* PNS_OFF */
+ }
+
+ /* no PNS if LTP is active */
+ }
+
+ /* avoid PNS holes */
+ if((pnsData->noiseFuzzyMeasure[0]>FL2FXCONST_SGL(0.5f)) && (pnsData->pnsFlag[1])) {
+ pnsData->pnsFlag[0] = 1;
+ }
+
+ for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) {
+ if((pnsData->noiseFuzzyMeasure[sfb]>pnsConf->np.gapFillThr) &&
+ (pnsData->pnsFlag[sfb-1]) && (pnsData->pnsFlag[sfb+1])) {
+ pnsData->pnsFlag[sfb] = 1;
+ }
+ }
+
+ if(maxSfbPerGroup>0) {
+ /* avoid PNS hole */
+ if((pnsData->noiseFuzzyMeasure[maxSfbPerGroup-1]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[maxSfbPerGroup-2])) {
+ pnsData->pnsFlag[maxSfbPerGroup-1] = 1;
+ }
+ /* avoid single PNS band */
+ if(pnsData->pnsFlag[maxSfbPerGroup-2]==0) {
+ pnsData->pnsFlag[maxSfbPerGroup-1] = 0;
+ }
+ }
+
+ /* avoid single PNS bands */
+ if(pnsData->pnsFlag[1]==0) {
+ pnsData->pnsFlag[0] = 0;
+ }
+
+ for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) {
+ if((pnsData->pnsFlag[sfb-1]==0)&&(pnsData->pnsFlag[sfb+1]==0)) {
+ pnsData->pnsFlag[sfb] = 0;
+ }
+ }
+
+
+ /*
+ calculate noiseNrg's
+ */
+ FDKaacEnc_CalcNoiseNrgs( sfbActive,
+ pnsData->pnsFlag,
+ sfbEnergyLdData,
+ noiseNrg );
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_FDKaacEnc_noiseDetection
+ description: wrapper for noisedet.c
+ returns:
+ input: pns config structure
+ pns data structure (modified),
+ sfbActive
+ tns order and prediction gain
+ pointer to mdct Spectrumand Sfb Energy
+ pointer to Sfb tonality
+ output: noiseFuzzyMeasure in structure pnsData
+ flags tonal / nontonal
+
+*****************************************************************************/
+static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT sfbActive,
+ const INT *sfbOffset,
+ int tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality )
+{
+ INT condition = TRUE;
+ if ( !(pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) ) {
+ condition = (tnsOrder > 3);
+ }
+ /*
+ no PNS if heavy TNS activity
+ clear pnsData->noiseFuzzyMeasure
+ */
+ if((pnsConf->np.detectionAlgorithmFlags & USE_TNS_GAIN_THR) &&
+ (tnsPredictionGain >= pnsConf->np.tnsGainThreshold) && condition &&
+ !((pnsConf->np.detectionAlgorithmFlags & USE_TNS_PNS) && (tnsPredictionGain >= pnsConf->np.tnsPNSGainThreshold) && (tnsActive)) )
+ {
+ /* clear all noiseFuzzyMeasure */
+ FDKmemclear(pnsData->noiseFuzzyMeasure, sfbActive*sizeof(FIXP_SGL));
+ }
+ else
+ {
+ /*
+ call noise detection, output in pnsData->noiseFuzzyMeasure,
+ use real mdct spectral data
+ */
+ FDKaacEnc_noiseDetect( mdctSpectrum,
+ sfbMaxScaleSpec,
+ sfbActive,
+ sfbOffset,
+ pnsData->noiseFuzzyMeasure,
+ &pnsConf->np,
+ sfbtonality);
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_CalcNoiseNrgs
+ description: Calculate the NoiseNrg's
+ returns:
+ input: sfbActive
+ if pnsFlag calculate NoiseNrg
+ pointer to sfbEnergy and groupLen
+ pointer to noiseNrg (modified)
+ output: noiseNrg's in pnsFlaged sfb's
+
+*****************************************************************************/
+
+static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive,
+ INT *RESTRICT pnsFlag,
+ FIXP_DBL *RESTRICT sfbEnergyLdData,
+ INT *RESTRICT noiseNrg )
+{
+ int sfb;
+ INT tmp = (-LOG_NORM_PCM)<<2;
+
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+ if(pnsFlag[sfb]) {
+ INT nrg = (-sfbEnergyLdData[sfb]+FL2FXCONST_DBL(0.5f/64.0f))>>(DFRACT_BITS-1-7);
+ noiseNrg[sfb] = tmp - nrg;
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_CodePnsChannel
+ description: Execute pns decission
+ returns:
+ input: sfbActive
+ pns config structure
+ use PNS if pnsFlag
+ pointer to Sfb Energy, noiseNrg, Threshold
+ output: set sfbThreshold high to code pe with 0,
+ noiseNrg marks flag for pns coding
+
+*****************************************************************************/
+
+void FDKaacEnc_CodePnsChannel(const INT sfbActive,
+ PNS_CONFIG *pnsConf,
+ INT *RESTRICT pnsFlag,
+ FIXP_DBL *RESTRICT sfbEnergyLdData,
+ INT *RESTRICT noiseNrg,
+ FIXP_DBL *RESTRICT sfbThresholdLdData)
+{
+ INT sfb;
+ INT lastiNoiseEnergy = 0;
+ INT firstPNSband = 1; /* TRUE for first PNS-coded band */
+
+ /* no PNS */
+ if(!pnsConf->usePns) {
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+ /* no PNS coding */
+ noiseNrg[sfb] = NO_NOISE_PNS;
+ }
+ return;
+ }
+
+ /* code PNS */
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+ if(pnsFlag[sfb]) {
+ /* high sfbThreshold causes pe = 0 */
+ if(noiseNrg[sfb] != NO_NOISE_PNS)
+ sfbThresholdLdData[sfb] = sfbEnergyLdData[sfb] + FL2FXCONST_DBL(1.0f/LD_DATA_SCALING);
+
+ /* set noiseNrg in valid region */
+ if(!firstPNSband) {
+ INT deltaiNoiseEnergy = noiseNrg[sfb] - lastiNoiseEnergy;
+
+ if(deltaiNoiseEnergy > CODE_BOOK_PNS_LAV)
+ noiseNrg[sfb] -= deltaiNoiseEnergy - CODE_BOOK_PNS_LAV;
+ else if(deltaiNoiseEnergy < -CODE_BOOK_PNS_LAV)
+ noiseNrg[sfb] -= deltaiNoiseEnergy + CODE_BOOK_PNS_LAV;
+ }
+ else {
+ firstPNSband = 0;
+ }
+ lastiNoiseEnergy = noiseNrg[sfb];
+ }
+ else {
+ /* no PNS coding */
+ noiseNrg[sfb] = NO_NOISE_PNS;
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_PreProcessPnsChannelPair
+ description: Calculate the correlation of noise in a channel pair
+
+ returns:
+ input: sfbActive
+ pointer to sfb energies left, right and mid channel
+ pns config structure
+ pns data structure left and right (modified)
+
+ output: noiseEnergyCorrelation in pns data structure
+
+*****************************************************************************/
+
+void FDKaacEnc_PreProcessPnsChannelPair(const INT sfbActive,
+ FIXP_DBL *RESTRICT sfbEnergyLeft,
+ FIXP_DBL *RESTRICT sfbEnergyRight,
+ FIXP_DBL *RESTRICT sfbEnergyLeftLD,
+ FIXP_DBL *RESTRICT sfbEnergyRightLD,
+ FIXP_DBL *RESTRICT sfbEnergyMid,
+ PNS_CONFIG *RESTRICT pnsConf,
+ PNS_DATA *pnsDataLeft,
+ PNS_DATA *pnsDataRight)
+{
+ INT sfb;
+ FIXP_DBL ccf;
+
+ if(!pnsConf->usePns)
+ return;
+
+ FIXP_DBL *RESTRICT pNoiseEnergyCorrelationL = pnsDataLeft->noiseEnergyCorrelation;
+ FIXP_DBL *RESTRICT pNoiseEnergyCorrelationR = pnsDataRight->noiseEnergyCorrelation;
+
+ for(sfb=0;sfb< sfbActive;sfb++) {
+ FIXP_DBL quot = (sfbEnergyLeftLD[sfb]>>1) + (sfbEnergyRightLD[sfb]>>1);
+
+ if(quot < FL2FXCONST_DBL(-32.0f/(float)LD_DATA_SCALING))
+ ccf = FL2FXCONST_DBL(0.0f);
+ else {
+ FIXP_DBL accu = sfbEnergyMid[sfb]- (((sfbEnergyLeft[sfb]>>1)+(sfbEnergyRight[sfb]>>1))>>1);
+ INT sign = (accu < FL2FXCONST_DBL(0.0f)) ? 1 : 0 ;
+ accu = fixp_abs(accu);
+
+ ccf = CalcLdData(accu) + FL2FXCONST_DBL((float)1.0f/(float)LD_DATA_SCALING) - quot; /* ld(accu*2) = ld(accu) + 1 */
+ ccf = (ccf>=FL2FXCONST_DBL(0.0)) ? ((FIXP_DBL)MAXVAL_DBL) : (sign) ? -CalcInvLdData(ccf) : CalcInvLdData(ccf);
+ }
+
+ pNoiseEnergyCorrelationL[sfb] = ccf;
+ pNoiseEnergyCorrelationR[sfb] = ccf;
+ }
+}
+
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_PostProcessPnsChannelPair
+ description: if PNS used at left and right channel,
+ use msMask to flag correlation
+ returns:
+ input: sfbActive
+ pns config structure
+ pns data structure left and right (modified)
+ pointer to msMask, flags correlation by pns coding (modified)
+ Digest of MS coding
+ output: pnsFlag in pns data structure,
+ msFlag in msMask (flags correlation)
+
+*****************************************************************************/
+
+void FDKaacEnc_PostProcessPnsChannelPair(const INT sfbActive,
+ PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsDataLeft,
+ PNS_DATA *pnsDataRight,
+ INT *RESTRICT msMask,
+ INT *msDigest )
+{
+ INT sfb;
+
+ if(!pnsConf->usePns)
+ return;
+
+ for(sfb=0;sfb<sfbActive;sfb++) {
+ /*
+ MS post processing
+ */
+ if( msMask[sfb] ) {
+ if( (pnsDataLeft->pnsFlag[sfb]) &&
+ (pnsDataRight->pnsFlag[sfb]) ) {
+ /* AAC only: Standard */
+ /* do this to avoid ms flags in layers that should not have it */
+ if(pnsDataLeft->noiseEnergyCorrelation[sfb] <= pnsConf->noiseCorrelationThresh){
+ msMask[sfb] = 0;
+ *msDigest = MS_SOME;
+ }
+ }
+ else {
+ /*
+ No PNS coding
+ */
+ pnsDataLeft->pnsFlag[sfb] = 0;
+ pnsDataRight->pnsFlag[sfb] = 0;
+ }
+ }
+
+ /*
+ Use MS flag to signal noise correlation if
+ pns is active in both channels
+ */
+ if( (pnsDataLeft->pnsFlag[sfb]) && (pnsDataRight->pnsFlag[sfb]) ) {
+ if(pnsDataLeft->noiseEnergyCorrelation[sfb] > pnsConf->noiseCorrelationThresh) {
+ msMask[sfb] = 1;
+ *msDigest = MS_SOME;
+ }
+ }
+ }
+}