/*==================================================================================== EVS Codec 3GPP TS26.443 Jun 30, 2015. Version CR 26.443-0006 ====================================================================================*/ #define _USE_MATH_DEFINES #include #include #include #include "options.h" #include "prot.h" /************************************************************************************/ /* forward declarations for local functions, see implementation at end of this file */ /************************************************************************************/ static void CalcMDXT(TonalMDCTConcealPtr const self, char const type, float const * const timeSignal, float * const mdxtOutput); static void CalcPowerSpec(float const * mdctSpec, float const * mdstSpec, unsigned int nSamples, float floorPowerSpectrum, float * powerSpec); static void CalcPowerSpecAndDetectTonalComponents(TonalMDCTConcealPtr const self, float secondLastMDST[], float secondLastMDCT[], float const pitchLag); static void FindPhases(TonalMDCTConcealPtr const self, float const secondLastMDCT[], float const secondLastMDST[]); static void FindPhaseDifferences(TonalMDCTConcealPtr const self, float powerSpectrum[]); /*******************************************************/ /*-------------- public functions -------------------- */ /*******************************************************/ TONALMDCTCONCEAL_ERROR TonalMDCTConceal_Init( TonalMDCTConcealPtr self, unsigned int nSamples, unsigned int nSamplesCore, unsigned int nScaleFactors, TCX_config * tcx_cfg ) { if (nSamples > L_FRAME_MAX || nScaleFactors > FDNS_NPTS) { assert(nSamples <= L_FRAME_MAX); assert(nScaleFactors <= FDNS_NPTS); return TONALMDCTCONCEAL_NSAMPLES_LARGER_THAN_MAXBLOCKSIZE; } assert((self->nScaleFactors == nScaleFactors) || (self->nSamples != nSamples)); /* If nSamples doesn't change then also nScaleFactors must stay the same */ self->tcx_cfg = tcx_cfg; self->lastBlockData.spectralData = self->spectralDataBuffers[0]; self->secondLastBlockData.spectralData = self->spectralDataBuffers[1]; self->secondLastPowerSpectrum = self->secondLastBlockData.spectralData; self->lastBlockData.scaleFactors = self->scaleFactorsBuffers[0]; self->secondLastBlockData.scaleFactors = self->scaleFactorsBuffers[1]; self->lastBlockData.blockIsValid = 0; self->secondLastBlockData.blockIsValid = 0; self->nSamples = 0; self->nScaleFactors = 0; self->lastBlockData.blockIsConcealed = 0; self->secondLastBlockData.blockIsConcealed = 0; self->pTCI = (TonalComponentsInfo *)self->timeDataBuffer; self->lastPitchLag = 0; if (self->nSamples != nSamples) { self->secondLastBlockData.blockIsValid = 0; self->lastBlockData.blockIsValid = 0; } self->nSamples = nSamples; self->nSamplesCore = nSamplesCore; self->nScaleFactors = nScaleFactors; /* Offset the pointer to the end of buffer, so that pTCI is not destroyed when new time samples are stored in lastPcmOut */ /* just the second half of the second last pcm output is needed */ self->secondLastPcmOut = &self->timeDataBuffer[(3*L_FRAME_MAX)/2-(3*min(L_FRAME_MAX, nSamples))/2]; self->lastPcmOut = &self->timeDataBuffer[(3*L_FRAME_MAX)/2-min(L_FRAME_MAX, nSamples)]; /* If the second last frame was lost and concealed with tonal PLC, we reuse saved TonalComponentsInfo and don't update pcm buffers */ assert(sizeof(*self->pTCI) <= (self->lastPcmOut-self->timeDataBuffer)*sizeof(self->timeDataBuffer[0])); return TONALMDCTCONCEAL_OK; } TONALMDCTCONCEAL_ERROR TonalMDCTConceal_SaveFreqSignal( TonalMDCTConcealPtr self, float const *mdctSpectrum, unsigned int nNewSamples, unsigned int nNewSamplesCore, float const *scaleFactors ) { float * temp; int nOldSamples; assert(nNewSamples > 0 && nNewSamples <= 2*L_FRAME_MAX); /* Avoid overwriting self->secondLastPowerSpectrum stored in spectralData, because it is needed if the second last and the current frame are lost and concealed using the Tonal MDCT PLC */ if (!self->lastBlockData.tonalConcealmentActive || (self->lastBlockData.nSamples != nNewSamples)) { if (nNewSamples <= L_FRAME_MAX) { /* Shift the buffers */ temp = self->secondLastBlockData.spectralData; /* Save the pointer */ self->secondLastBlockData.spectralData = self->lastBlockData.spectralData; self->lastBlockData.spectralData = temp; temp = self->secondLastBlockData.scaleFactors; self->secondLastBlockData.scaleFactors = self->lastBlockData.scaleFactors; self->lastBlockData.scaleFactors = temp; } else { /* Order the buffers so that even transition frame can fit in if written into the first buffer */ self->lastBlockData.spectralData = self->spectralDataBuffers[0]; self->secondLastBlockData.spectralData = self->spectralDataBuffers[1]; self->lastBlockData.scaleFactors = self->scaleFactorsBuffers[0]; self->secondLastBlockData.scaleFactors = self->scaleFactorsBuffers[1]; } nOldSamples = self->lastBlockData.nSamples; self->lastBlockData.nSamples = nNewSamples; self->secondLastBlockData.nSamples = nOldSamples; nOldSamples = self->lastBlockData.nSamplesCore; self->lastBlockData.nSamplesCore = nNewSamplesCore; self->secondLastBlockData.nSamplesCore = nOldSamples; } if ((nNewSamples > 0) && (nNewSamples <= 2*L_FRAME_MAX)) { /* Store new data */ mvr2r(mdctSpectrum, self->lastBlockData.spectralData, nNewSamples); mvr2r(scaleFactors, self->lastBlockData.scaleFactors, self->nScaleFactors); } return TONALMDCTCONCEAL_OK; } TONALMDCTCONCEAL_ERROR TonalMDCTConceal_UpdateState(TonalMDCTConcealPtr self, int nNewSamples, float pitchLag, int badBlock, int tonalConcealmentActive ) { int newBlockIsValid; assert(!(!badBlock && tonalConcealmentActive)); if (badBlock) { newBlockIsValid = self->lastBlockData.blockIsValid; } else { newBlockIsValid = (nNewSamples <= 2*L_FRAME_MAX) && (nNewSamples > 0); } /* Shift old state */ self->secondLastBlockData.blockIsConcealed = self->lastBlockData.blockIsConcealed; self->secondLastBlockData.blockIsValid = self->lastBlockData.blockIsValid; self->secondLastBlockData.tonalConcealmentActive = self->lastBlockData.tonalConcealmentActive; /* Store new state */ self->lastBlockData.blockIsConcealed = badBlock; self->lastBlockData.blockIsValid = newBlockIsValid; self->lastBlockData.tonalConcealmentActive = tonalConcealmentActive; self->lastPitchLag = pitchLag; return TONALMDCTCONCEAL_OK; } static void FindPhases(TonalMDCTConcealPtr const self, float const secondLastMDCT[], float const secondLastMDST[]) { unsigned int i; int l; float * pCurrentPhase; pCurrentPhase = self->pTCI->phase_currentFramePredicted; /* for each index/index group */ for( i = 0; i < self->pTCI->numIndexes; i++) { for (l = self->pTCI->lowerIndex[i]; l <= self->pTCI->upperIndex[i]; l++) { *pCurrentPhase++ = (float)atan2(secondLastMDST[l], secondLastMDCT[l]); } } return; } static void FindPhaseDifferences(TonalMDCTConcealPtr const self, float powerSpectrum[]) { static float const bandwidth = 7.0f; float const m = (float)cos(EVS_PI/bandwidth); float const s = (float)cos((3*EVS_PI)/bandwidth); float const n = (float)sin(EVS_PI/bandwidth); float const j = (float)sin((3*EVS_PI)/bandwidth); static float const G = (float)(1.0/(2*1.36)); static float const maxRatio = 44.8f; /* Maximum ratio |ODFT[k-1]|/|ODFT[k+1]| is 16.5 dB, that is maximum ratio (for fractional = 0) is (cos(EVS_PI/bandwidth)/cos(3PI/bandwidth))^1.36 */ unsigned int i, k; float odft_left, odft_right; float * phaseDiff; float fractional; float Q, a; phaseDiff = self->pTCI->phaseDiff; for (i = 0; i < self->pTCI->numIndexes; i++) { k = self->pTCI->indexOfTonalPeak[i]; odft_left = powerSpectrum[k-1]; odft_right = powerSpectrum[k+1]; if (odft_left >= maxRatio*odft_right) { a = (float)tan(0.0f*EVS_PI/bandwidth); } else { if (odft_right >= maxRatio*odft_left) { a = (float)tan(2.0f*EVS_PI/bandwidth); } else { Q = (float)pow(odft_left/odft_right, G); a = (m - Q * s) / (n + Q * j); } } fractional = (float)atan(a) * (bandwidth/2.0f); assert((fractional >= 0) && (fractional <= EVS_PI + 1.192092896e-07F)); phaseDiff[i] = fractional + EVS_PI*(k%4); } return; } static void CalcPowerSpecAndDetectTonalComponents(TonalMDCTConcealPtr const self, float secondLastMDST[], float secondLastMDCT[], float const pitchLag) { unsigned int nSamples; unsigned int i; float floorPowerSpectrum; /* Minimum significant value of a spectral line in the power spectrum */ float powerSpectrum[L_FRAME_MAX]; /* 32 bits are required */ float invScaleFactors[FDNS_NPTS]; nSamples = self->nNonZeroSamples; /* It is taken into account that the MDCT is not normalized. */ floorPowerSpectrum = self->nSamples*self->nSamples/400.0f; CalcPowerSpec(secondLastMDCT, secondLastMDST, nSamples, floorPowerSpectrum, powerSpectrum ); /* This setting to minimal level is required because the power spectrum is used in the threshold adaptation using the pitch up to self->nSamples. */ set_f(powerSpectrum+nSamples, floorPowerSpectrum, self->nSamples-nSamples); /* this setting to zero is needed since the FDNS needs to be called with self->nSamplesCore; it relevant only for nb; it has no effect to the output, but memory checker may complain otherwise due to the usage of uninitialized values */ if (self->nSamplesCore > self->nSamples) { set_zero(powerSpectrum+self->nSamples, self->nSamplesCore-self->nSamples); } DetectTonalComponents(self->pTCI->indexOfTonalPeak, self->pTCI->lowerIndex, self->pTCI->upperIndex, &self->pTCI->numIndexes, self->lastPitchLag, pitchLag, self->lastBlockData.spectralData, self->lastBlockData.scaleFactors, powerSpectrum, nSamples, self->nSamplesCore, floorPowerSpectrum ); FindPhases(self, secondLastMDCT, secondLastMDST); FindPhaseDifferences(self, powerSpectrum); if (self->pTCI->numIndexes > 0) { self->secondLastPowerSpectrum = self->secondLastBlockData.spectralData; for ( i=0; inScaleFactors; i++) { invScaleFactors[i] = 1.0f/self->secondLastBlockData.scaleFactors[i]; } mdct_noiseShaping(powerSpectrum, self->nSamplesCore, invScaleFactors); v_multc( powerSpectrum + self->nSamplesCore, invScaleFactors[FDNS_NPTS-1], powerSpectrum + self->nSamplesCore, self->nSamples - self->nSamplesCore); mvr2r( powerSpectrum, self->secondLastPowerSpectrum, self->nSamples); /* 16 bits are now enough for storing the power spectrum */ } return; } static void CalcMDXT(TonalMDCTConcealPtr const self, char const type, float const * const timeSignal, float * const mdxtOutput) { float windowedTimeSignal[L_FRAME_PLUS+2*L_MDCT_OVLP_MAX]; int left_overlap, right_overlap, L_frame; L_frame = self->nSamples; WindowSignal( self->tcx_cfg, self->tcx_cfg->tcx_offsetFB, FULL_OVERLAP, FULL_OVERLAP, &left_overlap, &right_overlap, timeSignal, &L_frame, windowedTimeSignal, 1 ); if (type == 'S') { TCX_MDST( windowedTimeSignal, mdxtOutput, left_overlap, L_frame - (left_overlap+right_overlap)/2, right_overlap ); } else { TCX_MDCT( windowedTimeSignal, mdxtOutput, left_overlap, L_frame - (left_overlap+right_overlap)/2, right_overlap ); } return; } TONALMDCTCONCEAL_ERROR TonalMDCTConceal_Detect( TonalMDCTConcealPtr const self, float const pitchLag, int * const numIndices) { float secondLastMDST[L_FRAME_MAX]; /* 32 bits are required */ float secondLastMDCT[L_FRAME_MAX]; /* 32 bits are required */ float * powerSpectrum = secondLastMDST; unsigned int nSamples; unsigned int i; nSamples = self->nSamples; if (self->lastBlockData.blockIsValid && self->secondLastBlockData.blockIsValid && (self->lastBlockData.nSamples == nSamples) && (self->secondLastBlockData.nSamples == nSamples) && (!self->secondLastBlockData.blockIsConcealed || self->secondLastBlockData.tonalConcealmentActive || (pitchLag != 0)) /* Safety if the second last frame was concealed and tonal concealment was inactive */ ) { if (!self->lastBlockData.blockIsConcealed) { if (!self->secondLastBlockData.tonalConcealmentActive) { CalcMDXT(self, 'S', self->secondLastPcmOut, secondLastMDST); CalcMDXT(self, 'C', self->secondLastPcmOut, secondLastMDCT); self->nNonZeroSamples = 0; for (i = 0; i < self->nSamples; i++) { if (self->secondLastBlockData.spectralData[i] != 0) { self->nNonZeroSamples = i; } } /* 23 is the maximum length of the MA filter in getEnvelope */ self->nNonZeroSamples = min(self->nSamples, self->nNonZeroSamples+23); ; CalcPowerSpecAndDetectTonalComponents(self, secondLastMDST, secondLastMDCT, pitchLag); } else { /* If the second last frame was also lost, it is expected that pastTimeSignal could hold a bit different signal (e.g. including fade-out) from the one stored in TonalMDCTConceal_SaveTimeSignal. */ /* That is why we reuse the already stored information about the concealed spectrum in the second last frame */ nSamples = self->nNonZeroSamples; mvr2r(self->secondLastPowerSpectrum, powerSpectrum, nSamples); /* Convert from 16 bits to 32 bits */ mdct_noiseShaping(powerSpectrum, self->nSamplesCore, self->secondLastBlockData.scaleFactors); v_multc(powerSpectrum + self->nSamplesCore, self->secondLastBlockData.scaleFactors[FDNS_NPTS-1], powerSpectrum + self->nSamplesCore, nSamples - self->nSamplesCore); v_mult(powerSpectrum, powerSpectrum, powerSpectrum, nSamples); RefineTonalComponents(self->pTCI->indexOfTonalPeak, self->pTCI->lowerIndex, self->pTCI->upperIndex, self->pTCI->phaseDiff, self->pTCI->phase_currentFramePredicted, &self->pTCI->numIndexes, self->lastPitchLag, pitchLag, self->lastBlockData.spectralData, self->lastBlockData.scaleFactors, powerSpectrum, nSamples, self->nSamplesCore, self->nSamples*self->nSamples/400.0f /* floorPowerSpectrum */ ); } } } else { self->pTCI->numIndexes = 0; } *numIndices = self->pTCI->numIndexes; return TONALMDCTCONCEAL_OK; } TONALMDCTCONCEAL_ERROR TonalMDCTConceal_InsertNoise( TonalMDCTConcealPtr self, /*IN */ float* mdctSpectrum, /*OUT*/ int tonalConcealmentActive, short* pSeed, float tiltCompFactor, float crossfadeGain, int crossOverFreq) { unsigned int i; Word16 rnd; float g, nrgNoiseInLastFrame, nrgWhiteNoise, tiltFactor, tilt; g = 1.0f-crossfadeGain; if (!self->lastBlockData.blockIsConcealed) { rnd = 1977; } else { rnd = *pSeed; } if (!self->lastBlockData.blockIsValid) { /* may just become active if the very first frame is lost */ set_f( mdctSpectrum, 0.0f, self->nSamples); } else { /* based on what is done in tcx_noise_filling() */ tiltFactor = (float)pow(max(0.375f, tiltCompFactor), 1.0f/self->lastBlockData.nSamples); tilt = 1.0f; nrgNoiseInLastFrame = nrgWhiteNoise = 0.0f; if (!tonalConcealmentActive) { for (i = 0; i < (unsigned int)crossOverFreq; i++) { float const x = self->lastBlockData.spectralData[i]; float y; rnd = (Word16) (rnd * 31821L + 13849L); y = tilt*rnd; nrgNoiseInLastFrame += x*x; nrgWhiteNoise += y*y; mdctSpectrum[i] = y; tilt *= tiltFactor; } if (nrgWhiteNoise > 0) { g *= (float)sqrt(nrgNoiseInLastFrame/nrgWhiteNoise); } for (i = 0; i < (unsigned int)crossOverFreq; i++) { float const x = self->lastBlockData.spectralData[i]; float const y = mdctSpectrum[i]; if (y > 0) { mdctSpectrum[i] = g*y + crossfadeGain*x; } else { mdctSpectrum[i] = g*y - crossfadeGain*x; } } for (i = (unsigned int)crossOverFreq; i < self->lastBlockData.nSamples; i++) { mdctSpectrum[i] = self->lastBlockData.spectralData[i]; } } else { unsigned int l; assert(self->pTCI->numIndexes > 0); for (l = 0; l < self->pTCI->lowerIndex[0]; l++) { float const x = self->lastBlockData.spectralData[l]; float y; rnd = (Word16) (rnd * 31821L + 13849L); y = tilt*rnd; nrgNoiseInLastFrame += x*x; nrgWhiteNoise += y*y; mdctSpectrum[l] = y; tilt *= tiltFactor; } for (i = 1; i < self->pTCI->numIndexes; i++) { tilt *= (float)pow(tiltFactor, self->pTCI->upperIndex[i-1]-self->pTCI->lowerIndex[i-1]+1); for (l = self->pTCI->upperIndex[i-1]+1; l < self->pTCI->lowerIndex[i]; l++) { float const x = self->lastBlockData.spectralData[l]; float y; rnd = (Word16) (rnd * 31821L + 13849L); y = tilt*rnd; nrgNoiseInLastFrame += x*x; nrgWhiteNoise += y*y; mdctSpectrum[l] = y; tilt *= tiltFactor; } } tilt *= (float)pow(tiltFactor, self->pTCI->upperIndex[self->pTCI->numIndexes-1]-self->pTCI->lowerIndex[self->pTCI->numIndexes-1]+1); for (l = self->pTCI->upperIndex[self->pTCI->numIndexes-1]+1; l < (unsigned int)crossOverFreq; l++) { float const x = self->lastBlockData.spectralData[l]; float y; rnd = (Word16) (rnd * 31821L + 13849L); y = tilt*rnd; nrgNoiseInLastFrame += x*x; nrgWhiteNoise += y*y; mdctSpectrum[l] = y; tilt *= tiltFactor; } if (nrgWhiteNoise > 0) { g *= (float)sqrt(nrgNoiseInLastFrame/nrgWhiteNoise); } for (l = 0; l < self->pTCI->lowerIndex[0]; l++) { float const x = self->lastBlockData.spectralData[l]; float const y = mdctSpectrum[l]; if (y > 0) { mdctSpectrum[l] = g*y + crossfadeGain*x; } else { mdctSpectrum[l] = g*y - crossfadeGain*x; } } for (i = 1; i < self->pTCI->numIndexes; i++) { for (l = self->pTCI->upperIndex[i-1]+1; l < self->pTCI->lowerIndex[i]; l++) { float const x = self->lastBlockData.spectralData[l]; float const y = mdctSpectrum[l]; if (y > 0) { mdctSpectrum[l] = g*y + crossfadeGain*x; } else { mdctSpectrum[l] = g*y - crossfadeGain*x; } } } /* initialize bins of tonal components with zero: basically not necessary, but currently the whole spectrum is rescaled in mdct_noiseShaping() and then there would be a processing of uninitialized values */ for (i = 0; i < self->pTCI->numIndexes; i++) { for (l = self->pTCI->lowerIndex[i]; l <= self->pTCI->upperIndex[i]; l++) { mdctSpectrum[l] = 0; } } for (l = self->pTCI->upperIndex[self->pTCI->numIndexes-1]+1; l < (unsigned int)crossOverFreq; l++) { float const x = self->lastBlockData.spectralData[l]; float const y = mdctSpectrum[l]; if (y > 0) { mdctSpectrum[l] = g*y + crossfadeGain*x; } else { mdctSpectrum[l] = g*y - crossfadeGain*x; } } for (l = (unsigned int)crossOverFreq; l < self->lastBlockData.nSamples; l++) { mdctSpectrum[l] = self->lastBlockData.spectralData[l]; } } } *pSeed = rnd; return TONALMDCTCONCEAL_OK; } TONALMDCTCONCEAL_ERROR TonalMDCTConceal_Apply(TonalMDCTConcealPtr self, /*IN */ float *mdctSpectrum /*OUT */ ) { unsigned int i, l; float * phaseDiff, * pCurrentPhase; float phaseToAdd; float powerSpectrum[L_FRAME_MAX]; unsigned int nSamples; if (self->lastBlockData.blockIsValid & self->secondLastBlockData.blockIsValid) { assert(self->pTCI->numIndexes > 0); nSamples = self->nNonZeroSamples; assert(self->pTCI->upperIndex[self->pTCI->numIndexes-1] < nSamples); mvr2r(self->secondLastPowerSpectrum, powerSpectrum, nSamples); /* Convert from 16 bits to 32 bits */ mdct_noiseShaping(powerSpectrum, self->nSamplesCore, self->secondLastBlockData.scaleFactors); v_multc( powerSpectrum + self->nSamplesCore, self->secondLastBlockData.scaleFactors[FDNS_NPTS-1], powerSpectrum + self->nSamplesCore, nSamples - self->nSamplesCore ); phaseDiff = self->pTCI->phaseDiff; /* if multiple frame loss occurs use the phase from the last frame and continue rotating */ pCurrentPhase = self->pTCI->phase_currentFramePredicted; if (!self->lastBlockData.blockIsConcealed) { if (self->secondLastBlockData.tonalConcealmentActive) { self->nFramesLost += 1; } else { self->nFramesLost = 1.5; } } /* for each index group */ for (i = 0; i < self->pTCI->numIndexes; i++) { phaseToAdd = self->nFramesLost*phaseDiff[i]; /* Move phaseToAdd to range -EVS_PI..EVS_PI */ while (phaseToAdd > EVS_PI) { phaseToAdd -= 2*EVS_PI; } while (phaseToAdd < -EVS_PI) { /* should never occur in flt - kept for safety reasons */ phaseToAdd += 2*EVS_PI; } for (l = self->pTCI->lowerIndex[i]; l <= self->pTCI->upperIndex[i]; l++) { float const currentPhase = (*pCurrentPhase++) + phaseToAdd; /* *pCurrentPhase and phaseToAdd are in range -EVS_PI..EVS_PI */ mdctSpectrum[l] = (float)cos(currentPhase) * powerSpectrum[l]; } } } self->nFramesLost++; return TONALMDCTCONCEAL_OK; } TONALMDCTCONCEAL_ERROR TonalMDCTConceal_SaveTimeSignal( TonalMDCTConcealPtr self, float* timeSignal, unsigned int nNewSamples ) { if (nNewSamples == self->nSamples) { assert(nNewSamples <= L_FRAME_MAX); if (!self->secondLastBlockData.tonalConcealmentActive) { mvr2r(self->lastPcmOut + self->nSamples/2, self->secondLastPcmOut, self->nSamples/2); } mvr2r(timeSignal, self->lastPcmOut, self->nSamples); } return TONALMDCTCONCEAL_OK; } static void CalcPowerSpec(float const * mdctSpec, float const * mdstSpec, unsigned int nSamples, float floorPowerSpectrum, float * powerSpec) { unsigned int k; float x; for (k = 1; k <= nSamples-2; k++) { x = mdctSpec[k] * mdctSpec[k] + mdstSpec[k] * mdstSpec[k]; powerSpec[k] = max(floorPowerSpectrum, x); } powerSpec[0] = 0.5f*powerSpec[1]; powerSpec[nSamples-1] = 0.5f*powerSpec[nSamples-2]; return; }