/src/aac/libSBRenc/src/mh_det.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* ----------------------------------------------------------------------------- |
2 | | Software License for The Fraunhofer FDK AAC Codec Library for Android |
3 | | |
4 | | © Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten |
5 | | Forschung e.V. All rights reserved. |
6 | | |
7 | | 1. INTRODUCTION |
8 | | The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software |
9 | | that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding |
10 | | scheme for digital audio. This FDK AAC Codec software is intended to be used on |
11 | | a wide variety of Android devices. |
12 | | |
13 | | AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient |
14 | | general perceptual audio codecs. AAC-ELD is considered the best-performing |
15 | | full-bandwidth communications codec by independent studies and is widely |
16 | | deployed. AAC has been standardized by ISO and IEC as part of the MPEG |
17 | | specifications. |
18 | | |
19 | | Patent licenses for necessary patent claims for the FDK AAC Codec (including |
20 | | those of Fraunhofer) may be obtained through Via Licensing |
21 | | (www.vialicensing.com) or through the respective patent owners individually for |
22 | | the purpose of encoding or decoding bit streams in products that are compliant |
23 | | with the ISO/IEC MPEG audio standards. Please note that most manufacturers of |
24 | | Android devices already license these patent claims through Via Licensing or |
25 | | directly from the patent owners, and therefore FDK AAC Codec software may |
26 | | already be covered under those patent licenses when it is used for those |
27 | | licensed purposes only. |
28 | | |
29 | | Commercially-licensed AAC software libraries, including floating-point versions |
30 | | with enhanced sound quality, are also available from Fraunhofer. Users are |
31 | | encouraged to check the Fraunhofer website for additional applications |
32 | | information and documentation. |
33 | | |
34 | | 2. COPYRIGHT LICENSE |
35 | | |
36 | | Redistribution and use in source and binary forms, with or without modification, |
37 | | are permitted without payment of copyright license fees provided that you |
38 | | satisfy the following conditions: |
39 | | |
40 | | You must retain the complete text of this software license in redistributions of |
41 | | the FDK AAC Codec or your modifications thereto in source code form. |
42 | | |
43 | | You must retain the complete text of this software license in the documentation |
44 | | and/or other materials provided with redistributions of the FDK AAC Codec or |
45 | | your modifications thereto in binary form. You must make available free of |
46 | | charge copies of the complete source code of the FDK AAC Codec and your |
47 | | modifications thereto to recipients of copies in binary form. |
48 | | |
49 | | The name of Fraunhofer may not be used to endorse or promote products derived |
50 | | from this library without prior written permission. |
51 | | |
52 | | You may not charge copyright license fees for anyone to use, copy or distribute |
53 | | the FDK AAC Codec software or your modifications thereto. |
54 | | |
55 | | Your modified versions of the FDK AAC Codec must carry prominent notices stating |
56 | | that you changed the software and the date of any change. For modified versions |
57 | | of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" |
58 | | must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK |
59 | | AAC Codec Library for Android." |
60 | | |
61 | | 3. NO PATENT LICENSE |
62 | | |
63 | | NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without |
64 | | limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. |
65 | | Fraunhofer provides no warranty of patent non-infringement with respect to this |
66 | | software. |
67 | | |
68 | | You may use this FDK AAC Codec software or modifications thereto only for |
69 | | purposes that are authorized by appropriate patent licenses. |
70 | | |
71 | | 4. DISCLAIMER |
72 | | |
73 | | This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright |
74 | | holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, |
75 | | including but not limited to the implied warranties of merchantability and |
76 | | fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
77 | | CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, |
78 | | or consequential damages, including but not limited to procurement of substitute |
79 | | goods or services; loss of use, data, or profits, or business interruption, |
80 | | however caused and on any theory of liability, whether in contract, strict |
81 | | liability, or tort (including negligence), arising in any way out of the use of |
82 | | this software, even if advised of the possibility of such damage. |
83 | | |
84 | | 5. CONTACT INFORMATION |
85 | | |
86 | | Fraunhofer Institute for Integrated Circuits IIS |
87 | | Attention: Audio and Multimedia Departments - FDK AAC LL |
88 | | Am Wolfsmantel 33 |
89 | | 91058 Erlangen, Germany |
90 | | |
91 | | www.iis.fraunhofer.de/amm |
92 | | amm-info@iis.fraunhofer.de |
93 | | ----------------------------------------------------------------------------- */ |
94 | | |
95 | | /**************************** SBR encoder library ****************************** |
96 | | |
97 | | Author(s): |
98 | | |
99 | | Description: |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | #include "mh_det.h" |
104 | | |
105 | | #include "sbrenc_ram.h" |
106 | | #include "sbr_misc.h" |
107 | | |
108 | | #include "genericStds.h" |
109 | | |
110 | 0 | #define SFM_SHIFT 2 /* Attention: SFM_SCALE depends on SFM_SHIFT */ |
111 | 0 | #define SFM_SCALE (MAXVAL_DBL >> SFM_SHIFT) /* 1.0 >> SFM_SHIFT */ |
112 | | |
113 | | /*!< Detector Parameters for AAC core codec. */ |
114 | | static const DETECTOR_PARAMETERS_MH paramsAac = { |
115 | | 9, /*!< deltaTime */ |
116 | | { |
117 | | FL2FXCONST_DBL(20.0f * RELAXATION_FLOAT), /*!< thresHoldDiff */ |
118 | | FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldDiffGuide */ |
119 | | FL2FXCONST_DBL(15.0f * RELAXATION_FLOAT), /*!< thresHoldTone */ |
120 | | FL2FXCONST_DBL((1.0f / 15.0f) * |
121 | | RELAXATION_FLOAT), /*!< invThresHoldTone */ |
122 | | FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldToneGuide */ |
123 | | FL2FXCONST_DBL(0.3f) >> SFM_SHIFT, /*!< sfmThresSbr */ |
124 | | FL2FXCONST_DBL(0.1f) >> SFM_SHIFT, /*!< sfmThresOrig */ |
125 | | FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ |
126 | | FL2FXCONST_DBL(0.5f), /*!< decayGuideDiff */ |
127 | | FL2FXCONST_DBL(-0.000112993269), |
128 | | /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ |
129 | | FL2FXCONST_DBL(-0.000112993269), |
130 | | /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ |
131 | | FL2FXCONST_DBL( |
132 | | -0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< |
133 | | derivThresAboveLD64 |
134 | | */ |
135 | | }, |
136 | | 50 /*!< maxComp */ |
137 | | }; |
138 | | |
139 | | /*!< Detector Parameters for AAC LD core codec. */ |
140 | | static const DETECTOR_PARAMETERS_MH paramsAacLd = { |
141 | | 16, /*!< Delta time. */ |
142 | | { |
143 | | FL2FXCONST_DBL(25.0f * RELAXATION_FLOAT), /*!< thresHoldDiff */ |
144 | | FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< tresHoldDiffGuide */ |
145 | | FL2FXCONST_DBL(15.0f * RELAXATION_FLOAT), /*!< thresHoldTone */ |
146 | | FL2FXCONST_DBL((1.0f / 15.0f) * |
147 | | RELAXATION_FLOAT), /*!< invThresHoldTone */ |
148 | | FL2FXCONST_DBL(1.26f * RELAXATION_FLOAT), /*!< thresHoldToneGuide */ |
149 | | FL2FXCONST_DBL(0.3f) >> SFM_SHIFT, /*!< sfmThresSbr */ |
150 | | FL2FXCONST_DBL(0.1f) >> SFM_SHIFT, /*!< sfmThresOrig */ |
151 | | FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ |
152 | | FL2FXCONST_DBL(0.2f), /*!< decayGuideDiff */ |
153 | | FL2FXCONST_DBL(-0.000112993269), |
154 | | /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ |
155 | | FL2FXCONST_DBL(-0.000112993269), |
156 | | /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ |
157 | | FL2FXCONST_DBL( |
158 | | -0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< |
159 | | derivThresAboveLD64 |
160 | | */ |
161 | | }, |
162 | | 50 /*!< maxComp */ |
163 | | }; |
164 | | |
165 | | /**************************************************************************/ |
166 | | /*! |
167 | | \brief Calculates the difference in tonality between original and SBR |
168 | | for a given time and frequency region. |
169 | | |
170 | | The values for pDiffMapped2Scfb are scaled by RELAXATION |
171 | | |
172 | | \return none. |
173 | | |
174 | | */ |
175 | | /**************************************************************************/ |
176 | | static void diff(FIXP_DBL *RESTRICT pTonalityOrig, FIXP_DBL *pDiffMapped2Scfb, |
177 | | const UCHAR *RESTRICT pFreqBandTable, INT nScfb, |
178 | 0 | SCHAR *indexVector) { |
179 | 0 | UCHAR i, ll, lu, k; |
180 | 0 | FIXP_DBL maxValOrig, maxValSbr, tmp; |
181 | 0 | INT scale; |
182 | |
|
183 | 0 | for (i = 0; i < nScfb; i++) { |
184 | 0 | ll = pFreqBandTable[i]; |
185 | 0 | lu = pFreqBandTable[i + 1]; |
186 | |
|
187 | 0 | maxValOrig = FL2FXCONST_DBL(0.0f); |
188 | 0 | maxValSbr = FL2FXCONST_DBL(0.0f); |
189 | |
|
190 | 0 | for (k = ll; k < lu; k++) { |
191 | 0 | maxValOrig = fixMax(maxValOrig, pTonalityOrig[k]); |
192 | 0 | maxValSbr = fixMax(maxValSbr, pTonalityOrig[indexVector[k]]); |
193 | 0 | } |
194 | |
|
195 | 0 | if ((maxValSbr >= RELAXATION)) { |
196 | 0 | tmp = fDivNorm(maxValOrig, maxValSbr, &scale); |
197 | 0 | pDiffMapped2Scfb[i] = |
198 | 0 | scaleValue(fMult(tmp, RELAXATION_FRACT), |
199 | 0 | fixMax(-(DFRACT_BITS - 1), (scale - RELAXATION_SHIFT))); |
200 | 0 | } else { |
201 | 0 | pDiffMapped2Scfb[i] = maxValOrig; |
202 | 0 | } |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | | /**************************************************************************/ |
207 | | /*! |
208 | | \brief Calculates a flatness measure of the tonality measures. |
209 | | |
210 | | Calculation of the power function and using scalefactor for basis: |
211 | | Using log2: |
212 | | z = (2^k * x)^y; |
213 | | z' = CalcLd(z) = y*CalcLd(x) + y*k; |
214 | | z = CalcInvLd(z'); |
215 | | |
216 | | Using ld64: |
217 | | z = (2^k * x)^y; |
218 | | z' = CalcLd64(z) = y*CalcLd64(x)/64 + y*k/64; |
219 | | z = CalcInvLd64(z'); |
220 | | |
221 | | The values pSfmOrigVec and pSfmSbrVec are scaled by the factor 1/4.0 |
222 | | |
223 | | \return none. |
224 | | |
225 | | */ |
226 | | /**************************************************************************/ |
227 | | static void calculateFlatnessMeasure(FIXP_DBL *pQuotaBuffer, SCHAR *indexVector, |
228 | | FIXP_DBL *pSfmOrigVec, |
229 | | FIXP_DBL *pSfmSbrVec, |
230 | 0 | const UCHAR *pFreqBandTable, INT nSfb) { |
231 | 0 | INT i, j; |
232 | 0 | FIXP_DBL invBands, tmp1, tmp2; |
233 | 0 | INT shiftFac0, shiftFacSum0; |
234 | 0 | INT shiftFac1, shiftFacSum1; |
235 | 0 | FIXP_DBL accu; |
236 | |
|
237 | 0 | for (i = 0; i < nSfb; i++) { |
238 | 0 | INT ll = pFreqBandTable[i]; |
239 | 0 | INT lu = pFreqBandTable[i + 1]; |
240 | 0 | pSfmOrigVec[i] = (FIXP_DBL)(MAXVAL_DBL >> 2); |
241 | 0 | pSfmSbrVec[i] = (FIXP_DBL)(MAXVAL_DBL >> 2); |
242 | |
|
243 | 0 | if (lu - ll > 1) { |
244 | 0 | FIXP_DBL amOrig, amTransp, gmOrig, gmTransp, sfmOrig, sfmTransp; |
245 | 0 | invBands = GetInvInt(lu - ll); |
246 | 0 | shiftFacSum0 = 0; |
247 | 0 | shiftFacSum1 = 0; |
248 | 0 | amOrig = amTransp = FL2FXCONST_DBL(0.0f); |
249 | 0 | gmOrig = gmTransp = (FIXP_DBL)MAXVAL_DBL; |
250 | |
|
251 | 0 | for (j = ll; j < lu; j++) { |
252 | 0 | sfmOrig = pQuotaBuffer[j]; |
253 | 0 | sfmTransp = pQuotaBuffer[indexVector[j]]; |
254 | |
|
255 | 0 | amOrig += fMult(sfmOrig, invBands); |
256 | 0 | amTransp += fMult(sfmTransp, invBands); |
257 | |
|
258 | 0 | shiftFac0 = CountLeadingBits(sfmOrig); |
259 | 0 | shiftFac1 = CountLeadingBits(sfmTransp); |
260 | |
|
261 | 0 | gmOrig = fMult(gmOrig, sfmOrig << shiftFac0); |
262 | 0 | gmTransp = fMult(gmTransp, sfmTransp << shiftFac1); |
263 | |
|
264 | 0 | shiftFacSum0 += shiftFac0; |
265 | 0 | shiftFacSum1 += shiftFac1; |
266 | 0 | } |
267 | |
|
268 | 0 | if (gmOrig > FL2FXCONST_DBL(0.0f)) { |
269 | 0 | tmp1 = CalcLdData(gmOrig); /* CalcLd64(x)/64 */ |
270 | 0 | tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ |
271 | | |
272 | | /* y*k/64 */ |
273 | 0 | accu = (FIXP_DBL)-shiftFacSum0 << (DFRACT_BITS - 1 - 8); |
274 | 0 | tmp2 = fMultDiv2(invBands, accu) << (2 + 1); |
275 | |
|
276 | 0 | tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ |
277 | 0 | gmOrig = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ |
278 | 0 | } else { |
279 | 0 | gmOrig = FL2FXCONST_DBL(0.0f); |
280 | 0 | } |
281 | |
|
282 | 0 | if (gmTransp > FL2FXCONST_DBL(0.0f)) { |
283 | 0 | tmp1 = CalcLdData(gmTransp); /* CalcLd64(x)/64 */ |
284 | 0 | tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ |
285 | | |
286 | | /* y*k/64 */ |
287 | 0 | accu = (FIXP_DBL)-shiftFacSum1 << (DFRACT_BITS - 1 - 8); |
288 | 0 | tmp2 = fMultDiv2(invBands, accu) << (2 + 1); |
289 | |
|
290 | 0 | tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ |
291 | 0 | gmTransp = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ |
292 | 0 | } else { |
293 | 0 | gmTransp = FL2FXCONST_DBL(0.0f); |
294 | 0 | } |
295 | 0 | if (amOrig != FL2FXCONST_DBL(0.0f)) |
296 | 0 | pSfmOrigVec[i] = |
297 | 0 | FDKsbrEnc_LSI_divide_scale_fract(gmOrig, amOrig, SFM_SCALE); |
298 | |
|
299 | 0 | if (amTransp != FL2FXCONST_DBL(0.0f)) |
300 | 0 | pSfmSbrVec[i] = |
301 | 0 | FDKsbrEnc_LSI_divide_scale_fract(gmTransp, amTransp, SFM_SCALE); |
302 | 0 | } |
303 | 0 | } |
304 | 0 | } |
305 | | |
306 | | /**************************************************************************/ |
307 | | /*! |
308 | | \brief Calculates the input to the missing harmonics detection. |
309 | | |
310 | | |
311 | | \return none. |
312 | | |
313 | | */ |
314 | | /**************************************************************************/ |
315 | | static void calculateDetectorInput( |
316 | | FIXP_DBL **RESTRICT pQuotaBuffer, /*!< Pointer to tonality matrix. */ |
317 | | SCHAR *RESTRICT indexVector, FIXP_DBL **RESTRICT tonalityDiff, |
318 | | FIXP_DBL **RESTRICT pSfmOrig, FIXP_DBL **RESTRICT pSfmSbr, |
319 | 0 | const UCHAR *freqBandTable, INT nSfb, INT noEstPerFrame, INT move) { |
320 | 0 | INT est; |
321 | | |
322 | | /* |
323 | | New estimate. |
324 | | */ |
325 | 0 | for (est = 0; est < noEstPerFrame; est++) { |
326 | 0 | diff(pQuotaBuffer[est + move], tonalityDiff[est + move], freqBandTable, |
327 | 0 | nSfb, indexVector); |
328 | |
|
329 | 0 | calculateFlatnessMeasure(pQuotaBuffer[est + move], indexVector, |
330 | 0 | pSfmOrig[est + move], pSfmSbr[est + move], |
331 | 0 | freqBandTable, nSfb); |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | | /**************************************************************************/ |
336 | | /*! |
337 | | \brief Checks that the detection is not due to a LP filter |
338 | | |
339 | | This function determines if a newly detected missing harmonics is not |
340 | | in fact just a low-pass filtere input signal. If so, the detection is |
341 | | removed. |
342 | | |
343 | | \return none. |
344 | | |
345 | | */ |
346 | | /**************************************************************************/ |
347 | | static void removeLowPassDetection(UCHAR *RESTRICT pAddHarmSfb, |
348 | | UCHAR **RESTRICT pDetectionVectors, |
349 | | INT start, INT stop, INT nSfb, |
350 | | const UCHAR *RESTRICT pFreqBandTable, |
351 | | FIXP_DBL *RESTRICT pNrgVector, |
352 | | THRES_HOLDS mhThresh) |
353 | | |
354 | 0 | { |
355 | 0 | INT i, est; |
356 | 0 | INT maxDerivPos = pFreqBandTable[nSfb]; |
357 | 0 | INT numBands = pFreqBandTable[nSfb]; |
358 | 0 | FIXP_DBL nrgLow, nrgHigh; |
359 | 0 | FIXP_DBL nrgLD64, nrgLowLD64, nrgHighLD64, nrgDiffLD64; |
360 | 0 | FIXP_DBL valLD64, maxValLD64, maxValAboveLD64; |
361 | 0 | INT bLPsignal = 0; |
362 | |
|
363 | 0 | maxValLD64 = FL2FXCONST_DBL(-1.0f); |
364 | 0 | for (i = numBands - 1 - 2; i > pFreqBandTable[0]; i--) { |
365 | 0 | nrgLow = pNrgVector[i]; |
366 | 0 | nrgHigh = pNrgVector[i + 2]; |
367 | |
|
368 | 0 | if (nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh) { |
369 | 0 | nrgLowLD64 = CalcLdData(nrgLow >> 1); |
370 | 0 | nrgDiffLD64 = CalcLdData((nrgLow >> 1) - (nrgHigh >> 1)); |
371 | 0 | valLD64 = nrgDiffLD64 - nrgLowLD64; |
372 | 0 | if (valLD64 > maxValLD64) { |
373 | 0 | maxDerivPos = i; |
374 | 0 | maxValLD64 = valLD64; |
375 | 0 | } |
376 | 0 | if (maxValLD64 > mhThresh.derivThresMaxLD64) { |
377 | 0 | break; |
378 | 0 | } |
379 | 0 | } |
380 | 0 | } |
381 | | |
382 | | /* Find the largest "gradient" above. (should be relatively flat, hence we |
383 | | expect a low value if the signal is LP.*/ |
384 | 0 | maxValAboveLD64 = FL2FXCONST_DBL(-1.0f); |
385 | 0 | for (i = numBands - 1 - 2; i > maxDerivPos + 2; i--) { |
386 | 0 | nrgLow = pNrgVector[i]; |
387 | 0 | nrgHigh = pNrgVector[i + 2]; |
388 | |
|
389 | 0 | if (nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh) { |
390 | 0 | nrgLowLD64 = CalcLdData(nrgLow >> 1); |
391 | 0 | nrgDiffLD64 = CalcLdData((nrgLow >> 1) - (nrgHigh >> 1)); |
392 | 0 | valLD64 = nrgDiffLD64 - nrgLowLD64; |
393 | 0 | if (valLD64 > maxValAboveLD64) { |
394 | 0 | maxValAboveLD64 = valLD64; |
395 | 0 | } |
396 | 0 | } else { |
397 | 0 | if (nrgHigh != FL2FXCONST_DBL(0.0f) && nrgHigh > nrgLow) { |
398 | 0 | nrgHighLD64 = CalcLdData(nrgHigh >> 1); |
399 | 0 | nrgDiffLD64 = CalcLdData((nrgHigh >> 1) - (nrgLow >> 1)); |
400 | 0 | valLD64 = nrgDiffLD64 - nrgHighLD64; |
401 | 0 | if (valLD64 > maxValAboveLD64) { |
402 | 0 | maxValAboveLD64 = valLD64; |
403 | 0 | } |
404 | 0 | } |
405 | 0 | } |
406 | 0 | } |
407 | |
|
408 | 0 | if (maxValLD64 > mhThresh.derivThresMaxLD64 && |
409 | 0 | maxValAboveLD64 < mhThresh.derivThresAboveLD64) { |
410 | 0 | bLPsignal = 1; |
411 | |
|
412 | 0 | for (i = maxDerivPos - 1; i > maxDerivPos - 5 && i >= 0; i--) { |
413 | 0 | if (pNrgVector[i] != FL2FXCONST_DBL(0.0f) && |
414 | 0 | pNrgVector[i] > pNrgVector[maxDerivPos + 2]) { |
415 | 0 | nrgDiffLD64 = CalcLdData((pNrgVector[i] >> 1) - |
416 | 0 | (pNrgVector[maxDerivPos + 2] >> 1)); |
417 | 0 | nrgLD64 = CalcLdData(pNrgVector[i] >> 1); |
418 | 0 | valLD64 = nrgDiffLD64 - nrgLD64; |
419 | 0 | if (valLD64 < mhThresh.derivThresBelowLD64) { |
420 | 0 | bLPsignal = 0; |
421 | 0 | break; |
422 | 0 | } |
423 | 0 | } else { |
424 | 0 | bLPsignal = 0; |
425 | 0 | break; |
426 | 0 | } |
427 | 0 | } |
428 | 0 | } |
429 | |
|
430 | 0 | if (bLPsignal) { |
431 | 0 | for (i = 0; i < nSfb; i++) { |
432 | 0 | if (maxDerivPos >= pFreqBandTable[i] && |
433 | 0 | maxDerivPos < pFreqBandTable[i + 1]) |
434 | 0 | break; |
435 | 0 | } |
436 | |
|
437 | 0 | if (pAddHarmSfb[i]) { |
438 | 0 | pAddHarmSfb[i] = 0; |
439 | 0 | for (est = start; est < stop; est++) { |
440 | 0 | pDetectionVectors[est][i] = 0; |
441 | 0 | } |
442 | 0 | } |
443 | 0 | } |
444 | 0 | } |
445 | | |
446 | | /**************************************************************************/ |
447 | | /*! |
448 | | \brief Checks if it is allowed to detect a missing tone, that wasn't |
449 | | detected previously. |
450 | | |
451 | | |
452 | | \return newDetectionAllowed flag. |
453 | | |
454 | | */ |
455 | | /**************************************************************************/ |
456 | | static INT isDetectionOfNewToneAllowed( |
457 | | const SBR_FRAME_INFO *pFrameInfo, INT *pDetectionStartPos, |
458 | | INT noEstPerFrame, INT prevTransientFrame, INT prevTransientPos, |
459 | | INT prevTransientFlag, INT transientPosOffset, INT transientFlag, |
460 | | INT transientPos, INT deltaTime, |
461 | 0 | HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector) { |
462 | 0 | INT transientFrame, newDetectionAllowed; |
463 | | |
464 | | /* Determine if this is a frame where a transient starts... |
465 | | * If the transient flag was set the previous frame but not the |
466 | | * transient frame flag, the transient frame flag is set in the current frame. |
467 | | *****************************************************************************/ |
468 | 0 | transientFrame = 0; |
469 | 0 | if (transientFlag) { |
470 | 0 | if (transientPos + transientPosOffset < |
471 | 0 | pFrameInfo->borders[pFrameInfo->nEnvelopes]) { |
472 | 0 | transientFrame = 1; |
473 | 0 | if (noEstPerFrame > 1) { |
474 | 0 | if (transientPos + transientPosOffset > |
475 | 0 | h_sbrMissingHarmonicsDetector->timeSlots >> 1) { |
476 | 0 | *pDetectionStartPos = noEstPerFrame; |
477 | 0 | } else { |
478 | 0 | *pDetectionStartPos = noEstPerFrame >> 1; |
479 | 0 | } |
480 | |
|
481 | 0 | } else { |
482 | 0 | *pDetectionStartPos = noEstPerFrame; |
483 | 0 | } |
484 | 0 | } |
485 | 0 | } else { |
486 | 0 | if (prevTransientFlag && !prevTransientFrame) { |
487 | 0 | transientFrame = 1; |
488 | 0 | *pDetectionStartPos = 0; |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | | /* |
493 | | * Determine if detection of new missing harmonics are allowed. |
494 | | * If the frame contains a transient it's ok. If the previous |
495 | | * frame contained a transient it needs to be sufficiently close |
496 | | * to the start of the current frame. |
497 | | ****************************************************************/ |
498 | 0 | newDetectionAllowed = 0; |
499 | 0 | if (transientFrame) { |
500 | 0 | newDetectionAllowed = 1; |
501 | 0 | } else { |
502 | 0 | if (prevTransientFrame && |
503 | 0 | fixp_abs(pFrameInfo->borders[0] - |
504 | 0 | (prevTransientPos + transientPosOffset - |
505 | 0 | h_sbrMissingHarmonicsDetector->timeSlots)) < deltaTime) { |
506 | 0 | newDetectionAllowed = 1; |
507 | 0 | *pDetectionStartPos = 0; |
508 | 0 | } |
509 | 0 | } |
510 | |
|
511 | 0 | h_sbrMissingHarmonicsDetector->previousTransientFlag = transientFlag; |
512 | 0 | h_sbrMissingHarmonicsDetector->previousTransientFrame = transientFrame; |
513 | 0 | h_sbrMissingHarmonicsDetector->previousTransientPos = transientPos; |
514 | |
|
515 | 0 | return (newDetectionAllowed); |
516 | 0 | } |
517 | | |
518 | | /**************************************************************************/ |
519 | | /*! |
520 | | \brief Cleans up the detection after a transient. |
521 | | |
522 | | |
523 | | \return none. |
524 | | |
525 | | */ |
526 | | /**************************************************************************/ |
527 | | static void transientCleanUp(FIXP_DBL **quotaBuffer, INT nSfb, |
528 | | UCHAR **detectionVectors, UCHAR *pAddHarmSfb, |
529 | | UCHAR *pPrevAddHarmSfb, INT **signBuffer, |
530 | | const UCHAR *pFreqBandTable, INT start, INT stop, |
531 | | INT newDetectionAllowed, FIXP_DBL *pNrgVector, |
532 | 0 | THRES_HOLDS mhThresh) { |
533 | 0 | INT i, j, est; |
534 | |
|
535 | 0 | for (est = start; est < stop; est++) { |
536 | 0 | for (i = 0; i < nSfb; i++) { |
537 | 0 | pAddHarmSfb[i] = pAddHarmSfb[i] || detectionVectors[est][i]; |
538 | 0 | } |
539 | 0 | } |
540 | |
|
541 | 0 | if (newDetectionAllowed == 1) { |
542 | | /* |
543 | | * Check for duplication of sines located |
544 | | * on the border of two scf-bands. |
545 | | *************************************************/ |
546 | 0 | for (i = 0; i < nSfb - 1; i++) { |
547 | | /* detection in adjacent channels.*/ |
548 | 0 | if (pAddHarmSfb[i] && pAddHarmSfb[i + 1]) { |
549 | 0 | FIXP_DBL maxVal1, maxVal2; |
550 | 0 | INT maxPos1, maxPos2, maxPosTime1, maxPosTime2; |
551 | |
|
552 | 0 | INT li = pFreqBandTable[i]; |
553 | 0 | INT ui = pFreqBandTable[i + 1]; |
554 | | |
555 | | /* Find maximum tonality in the the two scf bands.*/ |
556 | 0 | maxPosTime1 = start; |
557 | 0 | maxPos1 = li; |
558 | 0 | maxVal1 = quotaBuffer[start][li]; |
559 | 0 | for (est = start; est < stop; est++) { |
560 | 0 | for (j = li; j < ui; j++) { |
561 | 0 | if (quotaBuffer[est][j] > maxVal1) { |
562 | 0 | maxVal1 = quotaBuffer[est][j]; |
563 | 0 | maxPos1 = j; |
564 | 0 | maxPosTime1 = est; |
565 | 0 | } |
566 | 0 | } |
567 | 0 | } |
568 | |
|
569 | 0 | li = pFreqBandTable[i + 1]; |
570 | 0 | ui = pFreqBandTable[i + 2]; |
571 | | |
572 | | /* Find maximum tonality in the the two scf bands.*/ |
573 | 0 | maxPosTime2 = start; |
574 | 0 | maxPos2 = li; |
575 | 0 | maxVal2 = quotaBuffer[start][li]; |
576 | 0 | for (est = start; est < stop; est++) { |
577 | 0 | for (j = li; j < ui; j++) { |
578 | 0 | if (quotaBuffer[est][j] > maxVal2) { |
579 | 0 | maxVal2 = quotaBuffer[est][j]; |
580 | 0 | maxPos2 = j; |
581 | 0 | maxPosTime2 = est; |
582 | 0 | } |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | /* If the maximum values are in adjacent QMF-channels, we need to remove |
587 | | the lowest of the two.*/ |
588 | 0 | if (maxPos2 - maxPos1 < 2) { |
589 | 0 | if (pPrevAddHarmSfb[i] == 1 && pPrevAddHarmSfb[i + 1] == 0) { |
590 | | /* Keep the lower, remove the upper.*/ |
591 | 0 | pAddHarmSfb[i + 1] = 0; |
592 | 0 | for (est = start; est < stop; est++) { |
593 | 0 | detectionVectors[est][i + 1] = 0; |
594 | 0 | } |
595 | 0 | } else { |
596 | 0 | if (pPrevAddHarmSfb[i] == 0 && pPrevAddHarmSfb[i + 1] == 1) { |
597 | | /* Keep the upper, remove the lower.*/ |
598 | 0 | pAddHarmSfb[i] = 0; |
599 | 0 | for (est = start; est < stop; est++) { |
600 | 0 | detectionVectors[est][i] = 0; |
601 | 0 | } |
602 | 0 | } else { |
603 | | /* If the maximum values are in adjacent QMF-channels, and if the |
604 | | signs indicate that it is the same sine, we need to remove the |
605 | | lowest of the two.*/ |
606 | 0 | if (maxVal1 > maxVal2) { |
607 | 0 | if (signBuffer[maxPosTime1][maxPos2] < 0 && |
608 | 0 | signBuffer[maxPosTime1][maxPos1] > 0) { |
609 | | /* Keep the lower, remove the upper.*/ |
610 | 0 | pAddHarmSfb[i + 1] = 0; |
611 | 0 | for (est = start; est < stop; est++) { |
612 | 0 | detectionVectors[est][i + 1] = 0; |
613 | 0 | } |
614 | 0 | } |
615 | 0 | } else { |
616 | 0 | if (signBuffer[maxPosTime2][maxPos2] < 0 && |
617 | 0 | signBuffer[maxPosTime2][maxPos1] > 0) { |
618 | | /* Keep the upper, remove the lower.*/ |
619 | 0 | pAddHarmSfb[i] = 0; |
620 | 0 | for (est = start; est < stop; est++) { |
621 | 0 | detectionVectors[est][i] = 0; |
622 | 0 | } |
623 | 0 | } |
624 | 0 | } |
625 | 0 | } |
626 | 0 | } |
627 | 0 | } |
628 | 0 | } |
629 | 0 | } |
630 | | |
631 | | /* Make sure that the detection is not the cut-off of a low pass filter. */ |
632 | 0 | removeLowPassDetection(pAddHarmSfb, detectionVectors, start, stop, nSfb, |
633 | 0 | pFreqBandTable, pNrgVector, mhThresh); |
634 | 0 | } else { |
635 | | /* |
636 | | * If a missing harmonic wasn't missing the previous frame |
637 | | * the transient-flag needs to be set in order to be allowed to detect it. |
638 | | *************************************************************************/ |
639 | 0 | for (i = 0; i < nSfb; i++) { |
640 | 0 | if (pAddHarmSfb[i] - pPrevAddHarmSfb[i] > 0) pAddHarmSfb[i] = 0; |
641 | 0 | } |
642 | 0 | } |
643 | 0 | } |
644 | | |
645 | | /*****************************************************************************/ |
646 | | /*! |
647 | | \brief Detection for one tonality estimate. |
648 | | |
649 | | This is the actual missing harmonics detection, using information from the |
650 | | previous detection. |
651 | | |
652 | | If a missing harmonic was detected (in a previous frame) due to too high |
653 | | tonality differences, but there was not enough tonality difference in the |
654 | | current frame, the detection algorithm still continues to trace the strongest |
655 | | tone in the scalefactor band (assuming that this is the tone that is going to |
656 | | be replaced in the decoder). This is done to avoid abrupt endings of sines |
657 | | fading out (e.g. in the glockenspiel). |
658 | | |
659 | | The function also tries to estimate where one sine is going to be replaced |
660 | | with multiple sines (due to the patching). This is done by comparing the |
661 | | tonality flatness measure of the original and the SBR signal. |
662 | | |
663 | | The function also tries to estimate (for the scalefactor bands only |
664 | | containing one qmf subband) when a strong tone in the original will be |
665 | | replaced by a strong tone in the adjacent QMF subband. |
666 | | |
667 | | \return none. |
668 | | |
669 | | */ |
670 | | /**************************************************************************/ |
671 | | static void detection(FIXP_DBL *quotaBuffer, FIXP_DBL *pDiffVecScfb, INT nSfb, |
672 | | UCHAR *pHarmVec, const UCHAR *pFreqBandTable, |
673 | | FIXP_DBL *sfmOrig, FIXP_DBL *sfmSbr, |
674 | | GUIDE_VECTORS guideVectors, GUIDE_VECTORS newGuideVectors, |
675 | 0 | THRES_HOLDS mhThresh) { |
676 | 0 | INT i, j, ll, lu; |
677 | 0 | FIXP_DBL thresTemp, thresOrig; |
678 | | |
679 | | /* |
680 | | * Do detection on the difference vector, i.e. the difference between |
681 | | * the original and the transposed. |
682 | | *********************************************************************/ |
683 | 0 | for (i = 0; i < nSfb; i++) { |
684 | 0 | thresTemp = (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) |
685 | 0 | ? fMax(fMult(mhThresh.decayGuideDiff, |
686 | 0 | guideVectors.guideVectorDiff[i]), |
687 | 0 | mhThresh.thresHoldDiffGuide) |
688 | 0 | : mhThresh.thresHoldDiff; |
689 | |
|
690 | 0 | thresTemp = fMin(thresTemp, mhThresh.thresHoldDiff); |
691 | |
|
692 | 0 | if (pDiffVecScfb[i] > thresTemp) { |
693 | 0 | pHarmVec[i] = 1; |
694 | 0 | newGuideVectors.guideVectorDiff[i] = pDiffVecScfb[i]; |
695 | 0 | } else { |
696 | | /* If the guide wasn't zero, but the current level is to low, |
697 | | start tracking the decay on the tone in the original rather |
698 | | than the difference.*/ |
699 | 0 | if (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) { |
700 | 0 | guideVectors.guideVectorOrig[i] = mhThresh.thresHoldToneGuide; |
701 | 0 | } |
702 | 0 | } |
703 | 0 | } |
704 | | |
705 | | /* |
706 | | * Trace tones in the original signal that at one point |
707 | | * have been detected because they will be replaced by |
708 | | * multiple tones in the sbr signal. |
709 | | ****************************************************/ |
710 | |
|
711 | 0 | for (i = 0; i < nSfb; i++) { |
712 | 0 | ll = pFreqBandTable[i]; |
713 | 0 | lu = pFreqBandTable[i + 1]; |
714 | |
|
715 | 0 | thresOrig = |
716 | 0 | fixMax(fMult(guideVectors.guideVectorOrig[i], mhThresh.decayGuideOrig), |
717 | 0 | mhThresh.thresHoldToneGuide); |
718 | 0 | thresOrig = fixMin(thresOrig, mhThresh.thresHoldTone); |
719 | |
|
720 | 0 | if (guideVectors.guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)) { |
721 | 0 | for (j = ll; j < lu; j++) { |
722 | 0 | if (quotaBuffer[j] > thresOrig) { |
723 | 0 | pHarmVec[i] = 1; |
724 | 0 | newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; |
725 | 0 | } |
726 | 0 | } |
727 | 0 | } |
728 | 0 | } |
729 | | |
730 | | /* |
731 | | * Check for multiple sines in the transposed signal, |
732 | | * where there is only one in the original. |
733 | | ****************************************************/ |
734 | 0 | thresOrig = mhThresh.thresHoldTone; |
735 | |
|
736 | 0 | for (i = 0; i < nSfb; i++) { |
737 | 0 | ll = pFreqBandTable[i]; |
738 | 0 | lu = pFreqBandTable[i + 1]; |
739 | |
|
740 | 0 | if (pHarmVec[i] == 0) { |
741 | 0 | if (lu - ll > 1) { |
742 | 0 | for (j = ll; j < lu; j++) { |
743 | 0 | if (quotaBuffer[j] > thresOrig && |
744 | 0 | (sfmSbr[i] > mhThresh.sfmThresSbr && |
745 | 0 | sfmOrig[i] < mhThresh.sfmThresOrig)) { |
746 | 0 | pHarmVec[i] = 1; |
747 | 0 | newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; |
748 | 0 | } |
749 | 0 | } |
750 | 0 | } else { |
751 | 0 | if (i < nSfb - 1) { |
752 | 0 | ll = pFreqBandTable[i]; |
753 | |
|
754 | 0 | if (i > 0) { |
755 | 0 | if (quotaBuffer[ll] > mhThresh.thresHoldTone && |
756 | 0 | (pDiffVecScfb[i + 1] < mhThresh.invThresHoldTone || |
757 | 0 | pDiffVecScfb[i - 1] < mhThresh.invThresHoldTone)) { |
758 | 0 | pHarmVec[i] = 1; |
759 | 0 | newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; |
760 | 0 | } |
761 | 0 | } else { |
762 | 0 | if (quotaBuffer[ll] > mhThresh.thresHoldTone && |
763 | 0 | pDiffVecScfb[i + 1] < mhThresh.invThresHoldTone) { |
764 | 0 | pHarmVec[i] = 1; |
765 | 0 | newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; |
766 | 0 | } |
767 | 0 | } |
768 | 0 | } |
769 | 0 | } |
770 | 0 | } |
771 | 0 | } |
772 | 0 | } |
773 | | |
774 | | /**************************************************************************/ |
775 | | /*! |
776 | | \brief Do detection for every tonality estimate, using forward prediction. |
777 | | |
778 | | |
779 | | \return none. |
780 | | |
781 | | */ |
782 | | /**************************************************************************/ |
783 | | static void detectionWithPrediction( |
784 | | FIXP_DBL **quotaBuffer, FIXP_DBL **pDiffVecScfb, INT **signBuffer, INT nSfb, |
785 | | const UCHAR *pFreqBandTable, FIXP_DBL **sfmOrig, FIXP_DBL **sfmSbr, |
786 | | UCHAR **detectionVectors, UCHAR *pPrevAddHarmSfb, |
787 | | GUIDE_VECTORS *guideVectors, INT noEstPerFrame, INT detectionStart, |
788 | | INT totNoEst, INT newDetectionAllowed, INT *pAddHarmFlag, |
789 | | UCHAR *pAddHarmSfb, FIXP_DBL *pNrgVector, |
790 | 0 | const DETECTOR_PARAMETERS_MH *mhParams) { |
791 | 0 | INT est = 0, i; |
792 | 0 | INT start; |
793 | |
|
794 | 0 | FDKmemclear(pAddHarmSfb, nSfb * sizeof(UCHAR)); |
795 | |
|
796 | 0 | if (newDetectionAllowed) { |
797 | | /* Since we don't want to use the transient region for detection (since the |
798 | | tonality values tend to be a bit unreliable for this region) the |
799 | | guide-values are copied to the current starting point. */ |
800 | 0 | if (totNoEst > 1) { |
801 | 0 | start = detectionStart + 1; |
802 | |
|
803 | 0 | if (start != 0) { |
804 | 0 | FDKmemcpy(guideVectors[start].guideVectorDiff, |
805 | 0 | guideVectors[0].guideVectorDiff, nSfb * sizeof(FIXP_DBL)); |
806 | 0 | FDKmemcpy(guideVectors[start].guideVectorOrig, |
807 | 0 | guideVectors[0].guideVectorOrig, nSfb * sizeof(FIXP_DBL)); |
808 | 0 | FDKmemclear(guideVectors[start - 1].guideVectorDetected, |
809 | 0 | nSfb * sizeof(UCHAR)); |
810 | 0 | } |
811 | 0 | } else { |
812 | 0 | start = 0; |
813 | 0 | } |
814 | 0 | } else { |
815 | 0 | start = 0; |
816 | 0 | } |
817 | |
|
818 | 0 | for (est = start; est < totNoEst; est++) { |
819 | | /* |
820 | | * Do detection on the current frame using |
821 | | * guide-info from the previous. |
822 | | *******************************************/ |
823 | 0 | if (est > 0) { |
824 | 0 | FDKmemcpy(guideVectors[est].guideVectorDetected, |
825 | 0 | detectionVectors[est - 1], nSfb * sizeof(UCHAR)); |
826 | 0 | } |
827 | |
|
828 | 0 | FDKmemclear(detectionVectors[est], nSfb * sizeof(UCHAR)); |
829 | |
|
830 | 0 | if (est < totNoEst - 1) { |
831 | 0 | FDKmemclear(guideVectors[est + 1].guideVectorDiff, |
832 | 0 | nSfb * sizeof(FIXP_DBL)); |
833 | 0 | FDKmemclear(guideVectors[est + 1].guideVectorOrig, |
834 | 0 | nSfb * sizeof(FIXP_DBL)); |
835 | 0 | FDKmemclear(guideVectors[est + 1].guideVectorDetected, |
836 | 0 | nSfb * sizeof(UCHAR)); |
837 | |
|
838 | 0 | detection(quotaBuffer[est], pDiffVecScfb[est], nSfb, |
839 | 0 | detectionVectors[est], pFreqBandTable, sfmOrig[est], |
840 | 0 | sfmSbr[est], guideVectors[est], guideVectors[est + 1], |
841 | 0 | mhParams->thresHolds); |
842 | 0 | } else { |
843 | 0 | FDKmemclear(guideVectors[est].guideVectorDiff, nSfb * sizeof(FIXP_DBL)); |
844 | 0 | FDKmemclear(guideVectors[est].guideVectorOrig, nSfb * sizeof(FIXP_DBL)); |
845 | 0 | FDKmemclear(guideVectors[est].guideVectorDetected, nSfb * sizeof(UCHAR)); |
846 | |
|
847 | 0 | detection(quotaBuffer[est], pDiffVecScfb[est], nSfb, |
848 | 0 | detectionVectors[est], pFreqBandTable, sfmOrig[est], |
849 | 0 | sfmSbr[est], guideVectors[est], guideVectors[est], |
850 | 0 | mhParams->thresHolds); |
851 | 0 | } |
852 | 0 | } |
853 | | |
854 | | /* Clean up the detection.*/ |
855 | 0 | transientCleanUp(quotaBuffer, nSfb, detectionVectors, pAddHarmSfb, |
856 | 0 | pPrevAddHarmSfb, signBuffer, pFreqBandTable, start, totNoEst, |
857 | 0 | newDetectionAllowed, pNrgVector, mhParams->thresHolds); |
858 | | |
859 | | /* Set flag... */ |
860 | 0 | *pAddHarmFlag = 0; |
861 | 0 | for (i = 0; i < nSfb; i++) { |
862 | 0 | if (pAddHarmSfb[i]) { |
863 | 0 | *pAddHarmFlag = 1; |
864 | 0 | break; |
865 | 0 | } |
866 | 0 | } |
867 | |
|
868 | 0 | FDKmemcpy(pPrevAddHarmSfb, pAddHarmSfb, nSfb * sizeof(UCHAR)); |
869 | 0 | FDKmemcpy(guideVectors[0].guideVectorDetected, pAddHarmSfb, |
870 | 0 | nSfb * sizeof(INT)); |
871 | |
|
872 | 0 | for (i = 0; i < nSfb; i++) { |
873 | 0 | guideVectors[0].guideVectorDiff[i] = FL2FXCONST_DBL(0.0f); |
874 | 0 | guideVectors[0].guideVectorOrig[i] = FL2FXCONST_DBL(0.0f); |
875 | |
|
876 | 0 | if (pAddHarmSfb[i] == 1) { |
877 | | /* If we had a detection use the guide-value in the next frame from the |
878 | | last estimate were the detection was done.*/ |
879 | 0 | for (est = start; est < totNoEst; est++) { |
880 | 0 | if (guideVectors[est].guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) { |
881 | 0 | guideVectors[0].guideVectorDiff[i] = |
882 | 0 | guideVectors[est].guideVectorDiff[i]; |
883 | 0 | } |
884 | 0 | if (guideVectors[est].guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)) { |
885 | 0 | guideVectors[0].guideVectorOrig[i] = |
886 | 0 | guideVectors[est].guideVectorOrig[i]; |
887 | 0 | } |
888 | 0 | } |
889 | 0 | } |
890 | 0 | } |
891 | 0 | } |
892 | | |
893 | | /**************************************************************************/ |
894 | | /*! |
895 | | \brief Calculates a compensation vector for the energy data. |
896 | | |
897 | | This function calculates a compensation vector for the energy data (i.e. |
898 | | envelope data) that is calculated elsewhere. This is since, one sine on |
899 | | the border of two scalefactor bands, will be replace by one sine in the |
900 | | middle of either scalefactor band. However, since the sine that is replaced |
901 | | will influence the energy estimate in both scalefactor bands (in the envelops |
902 | | calculation function) a compensation value is required in order to avoid |
903 | | noise substitution in the decoder next to the synthetic sine. |
904 | | |
905 | | \return none. |
906 | | |
907 | | */ |
908 | | /**************************************************************************/ |
909 | | static void calculateCompVector(UCHAR *pAddHarmSfb, FIXP_DBL **pTonalityMatrix, |
910 | | INT **pSignMatrix, UCHAR *pEnvComp, INT nSfb, |
911 | | const UCHAR *freqBandTable, INT totNoEst, |
912 | | INT maxComp, UCHAR *pPrevEnvComp, |
913 | 0 | INT newDetectionAllowed) { |
914 | 0 | INT scfBand, est, l, ll, lu, maxPosF, maxPosT; |
915 | 0 | FIXP_DBL maxVal; |
916 | 0 | INT compValue; |
917 | 0 | FIXP_DBL tmp; |
918 | |
|
919 | 0 | FDKmemclear(pEnvComp, nSfb * sizeof(UCHAR)); |
920 | |
|
921 | 0 | for (scfBand = 0; scfBand < nSfb; scfBand++) { |
922 | 0 | if (pAddHarmSfb[scfBand]) { /* A missing sine was detected */ |
923 | 0 | ll = freqBandTable[scfBand]; |
924 | 0 | lu = freqBandTable[scfBand + 1]; |
925 | |
|
926 | 0 | maxPosF = 0; /* First find the maximum*/ |
927 | 0 | maxPosT = 0; |
928 | 0 | maxVal = FL2FXCONST_DBL(0.0f); |
929 | |
|
930 | 0 | for (est = 0; est < totNoEst; est++) { |
931 | 0 | for (l = ll; l < lu; l++) { |
932 | 0 | if (pTonalityMatrix[est][l] > maxVal) { |
933 | 0 | maxVal = pTonalityMatrix[est][l]; |
934 | 0 | maxPosF = l; |
935 | 0 | maxPosT = est; |
936 | 0 | } |
937 | 0 | } |
938 | 0 | } |
939 | | |
940 | | /* |
941 | | * If the maximum tonality is at the lower border of the |
942 | | * scalefactor band, we check the sign of the adjacent channels |
943 | | * to see if this sine is shared by the lower channel. If so, the |
944 | | * energy of the single sine will be present in two scalefactor bands |
945 | | * in the SBR data, which will cause problems in the decoder, when we |
946 | | * add a sine to just one of the channels. |
947 | | *********************************************************************/ |
948 | 0 | if (maxPosF == ll && scfBand) { |
949 | 0 | if (!pAddHarmSfb[scfBand - 1]) { /* No detection below*/ |
950 | 0 | if (pSignMatrix[maxPosT][maxPosF - 1] > 0 && |
951 | 0 | pSignMatrix[maxPosT][maxPosF] < 0) { |
952 | | /* The comp value is calulated as the tonallity value, i.e we want |
953 | | to reduce the envelope data for this channel with as much as the |
954 | | tonality that is spread from the channel above. (ld64(RELAXATION) |
955 | | = 0.31143075889) */ |
956 | 0 | tmp = fixp_abs( |
957 | 0 | (FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF - 1]) + |
958 | 0 | RELAXATION_LD64); |
959 | 0 | tmp = (tmp >> (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1)) + |
960 | 0 | (FIXP_DBL)1; /* shift one bit less for rounding */ |
961 | 0 | compValue = ((INT)(LONG)tmp) >> 1; |
962 | | |
963 | | /* limit the comp-value*/ |
964 | 0 | if (compValue > maxComp) compValue = maxComp; |
965 | |
|
966 | 0 | pEnvComp[scfBand - 1] = compValue; |
967 | 0 | } |
968 | 0 | } |
969 | 0 | } |
970 | | |
971 | | /* |
972 | | * Same as above, but for the upper end of the scalefactor-band. |
973 | | ***************************************************************/ |
974 | 0 | if (maxPosF == lu - 1 && scfBand + 1 < nSfb) { /* Upper border*/ |
975 | 0 | if (!pAddHarmSfb[scfBand + 1]) { |
976 | 0 | if (pSignMatrix[maxPosT][maxPosF] > 0 && |
977 | 0 | pSignMatrix[maxPosT][maxPosF + 1] < 0) { |
978 | 0 | tmp = fixp_abs( |
979 | 0 | (FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF + 1]) + |
980 | 0 | RELAXATION_LD64); |
981 | 0 | tmp = (tmp >> (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1)) + |
982 | 0 | (FIXP_DBL)1; /* shift one bit less for rounding */ |
983 | 0 | compValue = ((INT)(LONG)tmp) >> 1; |
984 | |
|
985 | 0 | if (compValue > maxComp) compValue = maxComp; |
986 | |
|
987 | 0 | pEnvComp[scfBand + 1] = compValue; |
988 | 0 | } |
989 | 0 | } |
990 | 0 | } |
991 | 0 | } |
992 | 0 | } |
993 | |
|
994 | 0 | if (newDetectionAllowed == 0) { |
995 | 0 | for (scfBand = 0; scfBand < nSfb; scfBand++) { |
996 | 0 | if (pEnvComp[scfBand] != 0 && pPrevEnvComp[scfBand] == 0) |
997 | 0 | pEnvComp[scfBand] = 0; |
998 | 0 | } |
999 | 0 | } |
1000 | | |
1001 | | /* remember the value for the next frame.*/ |
1002 | 0 | FDKmemcpy(pPrevEnvComp, pEnvComp, nSfb * sizeof(UCHAR)); |
1003 | 0 | } |
1004 | | |
1005 | | /**************************************************************************/ |
1006 | | /*! |
1007 | | \brief Detects where strong tonal components will be missing after |
1008 | | HFR in the decoder. |
1009 | | |
1010 | | |
1011 | | \return none. |
1012 | | |
1013 | | */ |
1014 | | /**************************************************************************/ |
1015 | | void FDKsbrEnc_SbrMissingHarmonicsDetectorQmf( |
1016 | | HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMHDet, FIXP_DBL **pQuotaBuffer, |
1017 | | INT **pSignBuffer, SCHAR *indexVector, const SBR_FRAME_INFO *pFrameInfo, |
1018 | | const UCHAR *pTranInfo, INT *pAddHarmonicsFlag, |
1019 | | UCHAR *pAddHarmonicsScaleFactorBands, const UCHAR *freqBandTable, INT nSfb, |
1020 | 0 | UCHAR *envelopeCompensation, FIXP_DBL *pNrgVector) { |
1021 | 0 | INT transientFlag = pTranInfo[1]; |
1022 | 0 | INT transientPos = pTranInfo[0]; |
1023 | 0 | INT newDetectionAllowed; |
1024 | 0 | INT transientDetStart = 0; |
1025 | |
|
1026 | 0 | UCHAR **detectionVectors = h_sbrMHDet->detectionVectors; |
1027 | 0 | INT move = h_sbrMHDet->move; |
1028 | 0 | INT noEstPerFrame = h_sbrMHDet->noEstPerFrame; |
1029 | 0 | INT totNoEst = h_sbrMHDet->totNoEst; |
1030 | 0 | INT prevTransientFlag = h_sbrMHDet->previousTransientFlag; |
1031 | 0 | INT prevTransientFrame = h_sbrMHDet->previousTransientFrame; |
1032 | 0 | INT transientPosOffset = h_sbrMHDet->transientPosOffset; |
1033 | 0 | INT prevTransientPos = h_sbrMHDet->previousTransientPos; |
1034 | 0 | GUIDE_VECTORS *guideVectors = h_sbrMHDet->guideVectors; |
1035 | 0 | INT deltaTime = h_sbrMHDet->mhParams->deltaTime; |
1036 | 0 | INT maxComp = h_sbrMHDet->mhParams->maxComp; |
1037 | |
|
1038 | 0 | int est; |
1039 | | |
1040 | | /* |
1041 | | Buffer values. |
1042 | | */ |
1043 | 0 | FDK_ASSERT(move <= (MAX_NO_OF_ESTIMATES >> 1)); |
1044 | 0 | FDK_ASSERT(noEstPerFrame <= (MAX_NO_OF_ESTIMATES >> 1)); |
1045 | | |
1046 | 0 | FIXP_DBL *sfmSbr[MAX_NO_OF_ESTIMATES]; |
1047 | 0 | FIXP_DBL *sfmOrig[MAX_NO_OF_ESTIMATES]; |
1048 | 0 | FIXP_DBL *tonalityDiff[MAX_NO_OF_ESTIMATES]; |
1049 | |
|
1050 | 0 | for (est = 0; est < MAX_NO_OF_ESTIMATES / 2; est++) { |
1051 | 0 | sfmSbr[est] = h_sbrMHDet->sfmSbr[est]; |
1052 | 0 | sfmOrig[est] = h_sbrMHDet->sfmOrig[est]; |
1053 | 0 | tonalityDiff[est] = h_sbrMHDet->tonalityDiff[est]; |
1054 | 0 | } |
1055 | |
|
1056 | 0 | C_ALLOC_SCRATCH_START(_scratch, FIXP_DBL, |
1057 | 0 | 3 * MAX_NO_OF_ESTIMATES / 2 * MAX_FREQ_COEFFS) |
1058 | 0 | FIXP_DBL *scratch = _scratch; |
1059 | 0 | for (; est < MAX_NO_OF_ESTIMATES; est++) { |
1060 | 0 | sfmSbr[est] = scratch; |
1061 | 0 | scratch += MAX_FREQ_COEFFS; |
1062 | 0 | sfmOrig[est] = scratch; |
1063 | 0 | scratch += MAX_FREQ_COEFFS; |
1064 | 0 | tonalityDiff[est] = scratch; |
1065 | 0 | scratch += MAX_FREQ_COEFFS; |
1066 | 0 | } |
1067 | | |
1068 | | /* Determine if we're allowed to detect "missing harmonics" that wasn't |
1069 | | detected before. In order to be allowed to do new detection, there must be |
1070 | | a transient in the current frame, or a transient in the previous frame |
1071 | | sufficiently close to the current frame. */ |
1072 | 0 | newDetectionAllowed = isDetectionOfNewToneAllowed( |
1073 | 0 | pFrameInfo, &transientDetStart, noEstPerFrame, prevTransientFrame, |
1074 | 0 | prevTransientPos, prevTransientFlag, transientPosOffset, transientFlag, |
1075 | 0 | transientPos, deltaTime, h_sbrMHDet); |
1076 | | |
1077 | | /* Calulate the variables that will be used subsequently for the actual |
1078 | | * detection */ |
1079 | 0 | calculateDetectorInput(pQuotaBuffer, indexVector, tonalityDiff, sfmOrig, |
1080 | 0 | sfmSbr, freqBandTable, nSfb, noEstPerFrame, move); |
1081 | | |
1082 | | /* Do the actual detection using information from previous detections */ |
1083 | 0 | detectionWithPrediction(pQuotaBuffer, tonalityDiff, pSignBuffer, nSfb, |
1084 | 0 | freqBandTable, sfmOrig, sfmSbr, detectionVectors, |
1085 | 0 | h_sbrMHDet->guideScfb, guideVectors, noEstPerFrame, |
1086 | 0 | transientDetStart, totNoEst, newDetectionAllowed, |
1087 | 0 | pAddHarmonicsFlag, pAddHarmonicsScaleFactorBands, |
1088 | 0 | pNrgVector, h_sbrMHDet->mhParams); |
1089 | | |
1090 | | /* Calculate the comp vector, so that the energy can be |
1091 | | compensated for a sine between two QMF-bands. */ |
1092 | 0 | calculateCompVector(pAddHarmonicsScaleFactorBands, pQuotaBuffer, pSignBuffer, |
1093 | 0 | envelopeCompensation, nSfb, freqBandTable, totNoEst, |
1094 | 0 | maxComp, h_sbrMHDet->prevEnvelopeCompensation, |
1095 | 0 | newDetectionAllowed); |
1096 | |
|
1097 | 0 | for (est = 0; est < move; est++) { |
1098 | 0 | FDKmemcpy(tonalityDiff[est], tonalityDiff[est + noEstPerFrame], |
1099 | 0 | sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1100 | 0 | FDKmemcpy(sfmOrig[est], sfmOrig[est + noEstPerFrame], |
1101 | 0 | sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1102 | 0 | FDKmemcpy(sfmSbr[est], sfmSbr[est + noEstPerFrame], |
1103 | 0 | sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1104 | 0 | } |
1105 | 0 | C_ALLOC_SCRATCH_END(_scratch, FIXP_DBL, |
1106 | 0 | 3 * MAX_NO_OF_ESTIMATES / 2 * MAX_FREQ_COEFFS) |
1107 | 0 | } |
1108 | | |
1109 | | /**************************************************************************/ |
1110 | | /*! |
1111 | | \brief Initialize an instance of the missing harmonics detector. |
1112 | | |
1113 | | |
1114 | | \return errorCode, noError if OK. |
1115 | | |
1116 | | */ |
1117 | | /**************************************************************************/ |
1118 | | INT FDKsbrEnc_CreateSbrMissingHarmonicsDetector( |
1119 | 0 | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT chan) { |
1120 | 0 | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; |
1121 | 0 | INT i; |
1122 | |
|
1123 | 0 | UCHAR *detectionVectors = GetRam_Sbr_detectionVectors(chan); |
1124 | 0 | UCHAR *guideVectorDetected = GetRam_Sbr_guideVectorDetected(chan); |
1125 | 0 | FIXP_DBL *guideVectorDiff = GetRam_Sbr_guideVectorDiff(chan); |
1126 | 0 | FIXP_DBL *guideVectorOrig = GetRam_Sbr_guideVectorOrig(chan); |
1127 | |
|
1128 | 0 | FDKmemclear(hs, sizeof(SBR_MISSING_HARMONICS_DETECTOR)); |
1129 | |
|
1130 | 0 | hs->prevEnvelopeCompensation = GetRam_Sbr_prevEnvelopeCompensation(chan); |
1131 | 0 | hs->guideScfb = GetRam_Sbr_guideScfb(chan); |
1132 | |
|
1133 | 0 | if ((NULL == detectionVectors) || (NULL == guideVectorDetected) || |
1134 | 0 | (NULL == guideVectorDiff) || (NULL == guideVectorOrig) || |
1135 | 0 | (NULL == hs->prevEnvelopeCompensation) || (NULL == hs->guideScfb)) { |
1136 | 0 | goto bail; |
1137 | 0 | } |
1138 | | |
1139 | 0 | for (i = 0; i < MAX_NO_OF_ESTIMATES; i++) { |
1140 | 0 | hs->guideVectors[i].guideVectorDiff = |
1141 | 0 | guideVectorDiff + (i * MAX_FREQ_COEFFS); |
1142 | 0 | hs->guideVectors[i].guideVectorOrig = |
1143 | 0 | guideVectorOrig + (i * MAX_FREQ_COEFFS); |
1144 | 0 | hs->detectionVectors[i] = detectionVectors + (i * MAX_FREQ_COEFFS); |
1145 | 0 | hs->guideVectors[i].guideVectorDetected = |
1146 | 0 | guideVectorDetected + (i * MAX_FREQ_COEFFS); |
1147 | 0 | } |
1148 | |
|
1149 | 0 | return 0; |
1150 | | |
1151 | 0 | bail: |
1152 | 0 | hs->guideVectors[0].guideVectorDiff = guideVectorDiff; |
1153 | 0 | hs->guideVectors[0].guideVectorOrig = guideVectorOrig; |
1154 | 0 | hs->detectionVectors[0] = detectionVectors; |
1155 | 0 | hs->guideVectors[0].guideVectorDetected = guideVectorDetected; |
1156 | |
|
1157 | 0 | FDKsbrEnc_DeleteSbrMissingHarmonicsDetector(hs); |
1158 | 0 | return -1; |
1159 | 0 | } |
1160 | | |
1161 | | /**************************************************************************/ |
1162 | | /*! |
1163 | | \brief Initialize an instance of the missing harmonics detector. |
1164 | | |
1165 | | |
1166 | | \return errorCode, noError if OK. |
1167 | | |
1168 | | */ |
1169 | | /**************************************************************************/ |
1170 | | INT FDKsbrEnc_InitSbrMissingHarmonicsDetector( |
1171 | | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, INT sampleFreq, |
1172 | | INT frameSize, INT nSfb, INT qmfNoChannels, INT totNoEst, INT move, |
1173 | 0 | INT noEstPerFrame, UINT sbrSyntaxFlags) { |
1174 | 0 | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; |
1175 | 0 | int i; |
1176 | |
|
1177 | 0 | FDK_ASSERT(totNoEst <= MAX_NO_OF_ESTIMATES); |
1178 | | |
1179 | 0 | if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { |
1180 | 0 | switch (frameSize) { |
1181 | 0 | case 1024: |
1182 | 0 | case 512: |
1183 | 0 | hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; |
1184 | 0 | hs->timeSlots = 16; |
1185 | 0 | break; |
1186 | 0 | case 960: |
1187 | 0 | case 480: |
1188 | 0 | hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; |
1189 | 0 | hs->timeSlots = 15; |
1190 | 0 | break; |
1191 | 0 | default: |
1192 | 0 | return -1; |
1193 | 0 | } |
1194 | 0 | } else { |
1195 | 0 | switch (frameSize) { |
1196 | 0 | case 2048: |
1197 | 0 | case 1024: |
1198 | 0 | hs->transientPosOffset = FRAME_MIDDLE_SLOT_2048; |
1199 | 0 | hs->timeSlots = NUMBER_TIME_SLOTS_2048; |
1200 | 0 | break; |
1201 | 0 | case 1920: |
1202 | 0 | case 960: |
1203 | 0 | hs->transientPosOffset = FRAME_MIDDLE_SLOT_1920; |
1204 | 0 | hs->timeSlots = NUMBER_TIME_SLOTS_1920; |
1205 | 0 | break; |
1206 | 0 | default: |
1207 | 0 | return -1; |
1208 | 0 | } |
1209 | 0 | } |
1210 | | |
1211 | 0 | if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { |
1212 | 0 | hs->mhParams = ¶msAacLd; |
1213 | 0 | } else |
1214 | 0 | hs->mhParams = ¶msAac; |
1215 | |
|
1216 | 0 | hs->qmfNoChannels = qmfNoChannels; |
1217 | 0 | hs->sampleFreq = sampleFreq; |
1218 | 0 | hs->nSfb = nSfb; |
1219 | |
|
1220 | 0 | hs->totNoEst = totNoEst; |
1221 | 0 | hs->move = move; |
1222 | 0 | hs->noEstPerFrame = noEstPerFrame; |
1223 | |
|
1224 | 0 | for (i = 0; i < totNoEst; i++) { |
1225 | 0 | FDKmemclear(hs->guideVectors[i].guideVectorDiff, |
1226 | 0 | sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1227 | 0 | FDKmemclear(hs->guideVectors[i].guideVectorOrig, |
1228 | 0 | sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1229 | 0 | FDKmemclear(hs->detectionVectors[i], sizeof(UCHAR) * MAX_FREQ_COEFFS); |
1230 | 0 | FDKmemclear(hs->guideVectors[i].guideVectorDetected, |
1231 | 0 | sizeof(UCHAR) * MAX_FREQ_COEFFS); |
1232 | 0 | } |
1233 | | |
1234 | | // for(i=0; i<totNoEst/2; i++) { |
1235 | 0 | for (i = 0; i < MAX_NO_OF_ESTIMATES / 2; i++) { |
1236 | 0 | FDKmemclear(hs->tonalityDiff[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1237 | 0 | FDKmemclear(hs->sfmOrig[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1238 | 0 | FDKmemclear(hs->sfmSbr[i], sizeof(FIXP_DBL) * MAX_FREQ_COEFFS); |
1239 | 0 | } |
1240 | |
|
1241 | 0 | FDKmemclear(hs->prevEnvelopeCompensation, sizeof(UCHAR) * MAX_FREQ_COEFFS); |
1242 | 0 | FDKmemclear(hs->guideScfb, sizeof(UCHAR) * MAX_FREQ_COEFFS); |
1243 | |
|
1244 | 0 | hs->previousTransientFlag = 0; |
1245 | 0 | hs->previousTransientFrame = 0; |
1246 | 0 | hs->previousTransientPos = 0; |
1247 | |
|
1248 | 0 | return (0); |
1249 | 0 | } |
1250 | | |
1251 | | /**************************************************************************/ |
1252 | | /*! |
1253 | | \brief Deletes an instance of the missing harmonics detector. |
1254 | | |
1255 | | |
1256 | | \return none. |
1257 | | |
1258 | | */ |
1259 | | /**************************************************************************/ |
1260 | | void FDKsbrEnc_DeleteSbrMissingHarmonicsDetector( |
1261 | 0 | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet) { |
1262 | 0 | if (hSbrMHDet) { |
1263 | 0 | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; |
1264 | |
|
1265 | 0 | FreeRam_Sbr_detectionVectors(&hs->detectionVectors[0]); |
1266 | 0 | FreeRam_Sbr_guideVectorDetected(&hs->guideVectors[0].guideVectorDetected); |
1267 | 0 | FreeRam_Sbr_guideVectorDiff(&hs->guideVectors[0].guideVectorDiff); |
1268 | 0 | FreeRam_Sbr_guideVectorOrig(&hs->guideVectors[0].guideVectorOrig); |
1269 | 0 | FreeRam_Sbr_prevEnvelopeCompensation(&hs->prevEnvelopeCompensation); |
1270 | 0 | FreeRam_Sbr_guideScfb(&hs->guideScfb); |
1271 | 0 | } |
1272 | 0 | } |
1273 | | |
1274 | | /**************************************************************************/ |
1275 | | /*! |
1276 | | \brief Resets an instance of the missing harmonics detector. |
1277 | | |
1278 | | |
1279 | | \return error code, noError if OK. |
1280 | | |
1281 | | */ |
1282 | | /**************************************************************************/ |
1283 | | INT FDKsbrEnc_ResetSbrMissingHarmonicsDetector( |
1284 | | HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, |
1285 | 0 | INT nSfb) { |
1286 | 0 | int i; |
1287 | 0 | FIXP_DBL tempGuide[MAX_FREQ_COEFFS]; |
1288 | 0 | UCHAR tempGuideInt[MAX_FREQ_COEFFS]; |
1289 | 0 | INT nSfbPrev; |
1290 | |
|
1291 | 0 | nSfbPrev = hSbrMissingHarmonicsDetector->nSfb; |
1292 | 0 | hSbrMissingHarmonicsDetector->nSfb = nSfb; |
1293 | |
|
1294 | 0 | FDKmemcpy(tempGuideInt, hSbrMissingHarmonicsDetector->guideScfb, |
1295 | 0 | nSfbPrev * sizeof(UCHAR)); |
1296 | |
|
1297 | 0 | if (nSfb > nSfbPrev) { |
1298 | 0 | for (i = 0; i < (nSfb - nSfbPrev); i++) { |
1299 | 0 | hSbrMissingHarmonicsDetector->guideScfb[i] = 0; |
1300 | 0 | } |
1301 | |
|
1302 | 0 | for (i = 0; i < nSfbPrev; i++) { |
1303 | 0 | hSbrMissingHarmonicsDetector->guideScfb[i + (nSfb - nSfbPrev)] = |
1304 | 0 | tempGuideInt[i]; |
1305 | 0 | } |
1306 | 0 | } else { |
1307 | 0 | for (i = 0; i < nSfb; i++) { |
1308 | 0 | hSbrMissingHarmonicsDetector->guideScfb[i] = |
1309 | 0 | tempGuideInt[i + (nSfbPrev - nSfb)]; |
1310 | 0 | } |
1311 | 0 | } |
1312 | |
|
1313 | 0 | FDKmemcpy(tempGuide, |
1314 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff, |
1315 | 0 | nSfbPrev * sizeof(FIXP_DBL)); |
1316 | |
|
1317 | 0 | if (nSfb > nSfbPrev) { |
1318 | 0 | for (i = 0; i < (nSfb - nSfbPrev); i++) { |
1319 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = |
1320 | 0 | FL2FXCONST_DBL(0.0f); |
1321 | 0 | } |
1322 | |
|
1323 | 0 | for (i = 0; i < nSfbPrev; i++) { |
1324 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0] |
1325 | 0 | .guideVectorDiff[i + (nSfb - nSfbPrev)] = tempGuide[i]; |
1326 | 0 | } |
1327 | 0 | } else { |
1328 | 0 | for (i = 0; i < nSfb; i++) { |
1329 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = |
1330 | 0 | tempGuide[i + (nSfbPrev - nSfb)]; |
1331 | 0 | } |
1332 | 0 | } |
1333 | |
|
1334 | 0 | FDKmemcpy(tempGuide, |
1335 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig, |
1336 | 0 | nSfbPrev * sizeof(FIXP_DBL)); |
1337 | |
|
1338 | 0 | if (nSfb > nSfbPrev) { |
1339 | 0 | for (i = 0; i < (nSfb - nSfbPrev); i++) { |
1340 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = |
1341 | 0 | FL2FXCONST_DBL(0.0f); |
1342 | 0 | } |
1343 | |
|
1344 | 0 | for (i = 0; i < nSfbPrev; i++) { |
1345 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0] |
1346 | 0 | .guideVectorOrig[i + (nSfb - nSfbPrev)] = tempGuide[i]; |
1347 | 0 | } |
1348 | 0 | } else { |
1349 | 0 | for (i = 0; i < nSfb; i++) { |
1350 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = |
1351 | 0 | tempGuide[i + (nSfbPrev - nSfb)]; |
1352 | 0 | } |
1353 | 0 | } |
1354 | |
|
1355 | 0 | FDKmemcpy(tempGuideInt, |
1356 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected, |
1357 | 0 | nSfbPrev * sizeof(UCHAR)); |
1358 | |
|
1359 | 0 | if (nSfb > nSfbPrev) { |
1360 | 0 | for (i = 0; i < (nSfb - nSfbPrev); i++) { |
1361 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = 0; |
1362 | 0 | } |
1363 | |
|
1364 | 0 | for (i = 0; i < nSfbPrev; i++) { |
1365 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0] |
1366 | 0 | .guideVectorDetected[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; |
1367 | 0 | } |
1368 | 0 | } else { |
1369 | 0 | for (i = 0; i < nSfb; i++) { |
1370 | 0 | hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = |
1371 | 0 | tempGuideInt[i + (nSfbPrev - nSfb)]; |
1372 | 0 | } |
1373 | 0 | } |
1374 | |
|
1375 | 0 | FDKmemcpy(tempGuideInt, |
1376 | 0 | hSbrMissingHarmonicsDetector->prevEnvelopeCompensation, |
1377 | 0 | nSfbPrev * sizeof(UCHAR)); |
1378 | |
|
1379 | 0 | if (nSfb > nSfbPrev) { |
1380 | 0 | for (i = 0; i < (nSfb - nSfbPrev); i++) { |
1381 | 0 | hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = 0; |
1382 | 0 | } |
1383 | |
|
1384 | 0 | for (i = 0; i < nSfbPrev; i++) { |
1385 | 0 | hSbrMissingHarmonicsDetector |
1386 | 0 | ->prevEnvelopeCompensation[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; |
1387 | 0 | } |
1388 | 0 | } else { |
1389 | 0 | for (i = 0; i < nSfb; i++) { |
1390 | 0 | hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = |
1391 | 0 | tempGuideInt[i + (nSfbPrev - nSfb)]; |
1392 | 0 | } |
1393 | 0 | } |
1394 | |
|
1395 | 0 | return 0; |
1396 | 0 | } |