1 2 /* ----------------------------------------------------------------------------------------------------------- 3 Software License for The Fraunhofer FDK AAC Codec Library for Android 4 5 Copyright 1995 - 2015 Fraunhofer-Gesellschaft zur Frderung der angewandten Forschung e.V. 6 All rights reserved. 7 8 1. INTRODUCTION 9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements 10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. 11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices. 12 13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual 14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by 15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part 16 of the MPEG specifications. 17 18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) 19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners 20 individually for the purpose of encoding or decoding bit streams in products that are compliant with 21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license 22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec 23 software may already be covered under those patent licenses when it is used for those licensed purposes only. 24 25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, 26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional 27 applications information and documentation. 28 29 2. COPYRIGHT LICENSE 30 31 Redistribution and use in source and binary forms, with or without modification, are permitted without 32 payment of copyright license fees provided that you satisfy the following conditions: 33 34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or 35 your modifications thereto in source code form. 36 37 You must retain the complete text of this software license in the documentation and/or other materials 38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. 39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your 40 modifications thereto to recipients of copies in binary form. 41 42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without 43 prior written permission. 44 45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec 46 software or your modifications thereto. 47 48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software 49 and the date of any change. For modified versions of the FDK AAC Codec, the term 50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term 51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." 52 53 3. NO PATENT LICENSE 54 55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, 56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with 57 respect to this software. 58 59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized 60 by appropriate patent licenses. 61 62 4. DISCLAIMER 63 64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors 65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties 66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, 68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits, 69 or business interruption, however caused and on any theory of liability, whether in contract, strict 70 liability, or tort (including negligence), arising in any way out of the use of this software, even if 71 advised of the possibility of such damage. 72 73 5. CONTACT INFORMATION 74 75 Fraunhofer Institute for Integrated Circuits IIS 76 Attention: Audio and Multimedia Departments - FDK AAC LL 77 Am Wolfsmantel 33 78 91058 Erlangen, Germany 79 80 www.iis.fraunhofer.de/amm 81 amm-info (at) iis.fraunhofer.de 82 ----------------------------------------------------------------------------------------------------------- */ 83 84 #include "tran_det.h" 85 86 #include "fram_gen.h" 87 #include "sbr_ram.h" 88 #include "sbr_misc.h" 89 90 #include "genericStds.h" 91 92 #define NORM_QMF_ENERGY 9.31322574615479E-10 /* 2^-30 */ 93 94 /* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 * NORM_QMF_ENERGY), (FIXP_DBL)1) Minimum threshold for detecting changes */ 95 #define ABS_THRES ((FIXP_DBL)16) 96 97 /******************************************************************************* 98 Functionname: spectralChange 99 ******************************************************************************* 100 \brief Calculates a measure for the spectral change within the frame 101 102 The function says how good it would be to split the frame at the given border 103 position into 2 envelopes. 104 105 The return value delta_sum is scaled with the factor 1/64 106 107 \return calculated value 108 *******************************************************************************/ 109 #define NRG_SHIFT 3 /* for energy summation */ 110 111 static FIXP_DBL spectralChange(FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], 112 INT *scaleEnergies, 113 FIXP_DBL EnergyTotal, 114 INT nSfb, 115 INT start, 116 INT border, 117 INT YBufferWriteOffset, 118 INT stop, 119 INT *result_e) 120 { 121 INT i,j; 122 INT len1,len2; 123 SCHAR energies_e_diff[NUMBER_TIME_SLOTS_2304], energies_e, energyTotal_e=19, energies_e_add; 124 SCHAR prevEnergies_e_diff, newEnergies_e_diff; 125 FIXP_DBL tmp0,tmp1; 126 FIXP_DBL accu1,accu2,accu1_init,accu2_init; 127 FIXP_DBL delta, delta_sum; 128 INT accu_e, tmp_e; 129 130 delta_sum = FL2FXCONST_DBL(0.0f); 131 *result_e = 0; 132 133 len1 = border-start; 134 len2 = stop-border; 135 136 /* prefer borders near the middle of the frame */ 137 FIXP_DBL pos_weight; 138 pos_weight = FL2FXCONST_DBL(0.5f) - (len1*GetInvInt(len1+len2)); 139 pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL - (fMult(pos_weight, pos_weight)<<2); 140 141 /*** Calc scaling for energies ***/ 142 FDK_ASSERT(scaleEnergies[0] >= 0); 143 FDK_ASSERT(scaleEnergies[1] >= 0); 144 145 energies_e = 19 - FDKmin(scaleEnergies[0], scaleEnergies[1]); 146 147 /* limit shift for energy accumulation, energies_e can be -10 min. */ 148 if (energies_e < -10) { 149 energies_e_add = -10 - energies_e; 150 energies_e = -10; 151 } else if (energies_e > 17) { 152 energies_e_add = energies_e - 17; 153 energies_e = 17; 154 } else { 155 energies_e_add = 0; 156 } 157 158 /* compensate scaling differences between scaleEnergies[0] and scaleEnergies[1] */ 159 prevEnergies_e_diff = scaleEnergies[0] - FDKmin(scaleEnergies[0], scaleEnergies[1]) + energies_e_add + NRG_SHIFT; 160 newEnergies_e_diff = scaleEnergies[1] - FDKmin(scaleEnergies[0], scaleEnergies[1]) + energies_e_add + NRG_SHIFT; 161 162 prevEnergies_e_diff = fMin(prevEnergies_e_diff, DFRACT_BITS-1); 163 newEnergies_e_diff = fMin(newEnergies_e_diff, DFRACT_BITS-1); 164 165 for (i=start; i<YBufferWriteOffset; i++) { 166 energies_e_diff[i] = prevEnergies_e_diff; 167 } 168 for (i=YBufferWriteOffset; i<stop; i++) { 169 energies_e_diff[i] = newEnergies_e_diff; 170 } 171 172 /* Sum up energies of all QMF-timeslots for both halfs */ 173 FDK_ASSERT(len1<=8); /* otherwise an overflow is possible */ 174 FDK_ASSERT(len2<=8); /* otherwise an overflow is possible */ 175 /* init with some energy to prevent division by zero 176 and to prevent splitting for very low levels */ 177 accu1_init = scaleValue((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY))),-energies_e); 178 accu2_init = scaleValue((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY))),-energies_e); 179 accu1_init = fMult(accu1_init, (FIXP_DBL)len1<<((DFRACT_BITS-1)-NRG_SHIFT-1))<<1; 180 accu2_init = fMult(accu2_init, (FIXP_DBL)len2<<((DFRACT_BITS-1)-NRG_SHIFT-1))<<1; 181 182 for (j=0; j<nSfb; j++) { 183 184 accu1 = accu1_init; 185 accu2 = accu2_init; 186 accu_e = energies_e+3; 187 188 /* Sum up energies in first half */ 189 for (i=start; i<border; i++) { 190 accu1 += scaleValue(Energies[i][j], -energies_e_diff[i]); 191 } 192 193 /* Sum up energies in second half */ 194 for (i=border; i<stop; i++) { 195 accu2 += scaleValue(Energies[i][j], -energies_e_diff[i]); 196 } 197 198 /* Energy change in current band */ 199 #define LN2 FL2FXCONST_DBL(0.6931471806f) /* ln(2) */ 200 tmp0 = fLog2(accu2, accu_e) - fLog2(accu1, accu_e); 201 tmp1 = fLog2((FIXP_DBL)len1, 31) - fLog2((FIXP_DBL)len2, 31); 202 delta = fMult(LN2, (tmp0 + tmp1)); 203 delta = (FIXP_DBL)FDKabs( delta ); 204 205 /* Weighting with amplitude ratio of this band */ 206 accu_e++; 207 accu1>>=1; 208 accu2>>=1; 209 if (accu_e & 1) { 210 accu_e++; 211 accu1>>=1; 212 accu2>>=1; 213 } 214 215 delta_sum += fMult(sqrtFixp(accu1+accu2), delta); 216 *result_e = ((accu_e>>1) + LD_DATA_SHIFT); 217 } 218 219 energyTotal_e+=1; /* for a defined square result exponent, the exponent has to be even */ 220 EnergyTotal<<=1; 221 delta_sum = fMult(delta_sum, invSqrtNorm2(EnergyTotal, &tmp_e)); 222 *result_e = *result_e + (tmp_e-(energyTotal_e>>1)); 223 224 return fMult(delta_sum, pos_weight); 225 226 } 227 228 229 /******************************************************************************* 230 Functionname: addLowbandEnergies 231 ******************************************************************************* 232 \brief Calculates total lowband energy 233 234 The input values Energies[0] (low-band) are scaled by the factor 235 2^(14-*scaleEnergies[0]) 236 The input values Energies[1] (high-band) are scaled by the factor 237 2^(14-*scaleEnergies[1]) 238 239 \return total energy in the lowband, scaled by the factor 2^19 240 *******************************************************************************/ 241 static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, 242 int *scaleEnergies, 243 int YBufferWriteOffset, 244 int nrgSzShift, 245 int tran_off, 246 UCHAR *freqBandTable, 247 int slots) 248 { 249 FIXP_DBL nrgTotal; 250 FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f); 251 FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f); 252 int tran_offdiv2 = tran_off>>nrgSzShift; 253 int ts,k; 254 255 /* Sum up lowband energy from one frame at offset tran_off */ 256 /* freqBandTable[LORES] has MAX_FREQ_COEFFS/2 +1 coeefs max. */ 257 for (ts=tran_offdiv2; ts<YBufferWriteOffset; ts++) { 258 for (k = 0; k < freqBandTable[0]; k++) { 259 accu1 += Energies[ts][k] >> 6; 260 } 261 } 262 for (; ts<tran_offdiv2+(slots>>nrgSzShift); ts++) { 263 for (k = 0; k < freqBandTable[0]; k++) { 264 accu2 += Energies[ts][k] >> 9; 265 } 266 } 267 268 nrgTotal = ( scaleValueSaturate(accu1, 1-scaleEnergies[0]) ) 269 + ( scaleValueSaturate(accu2, 4-scaleEnergies[1]) ); 270 271 return(nrgTotal); 272 } 273 274 275 /******************************************************************************* 276 Functionname: addHighbandEnergies 277 ******************************************************************************* 278 \brief Add highband energies 279 280 Highband energies are mapped to an array with smaller dimension: 281 Its time resolution is only 1 SBR-timeslot and its frequency resolution 282 is 1 SBR-band. Therefore the data to be fed into the spectralChange 283 function is reduced. 284 285 The values EnergiesM are scaled by the factor (2^19-scaleEnergies[0]) for 286 slots<YBufferWriteOffset and by the factor (2^19-scaleEnergies[1]) for 287 slots>=YBufferWriteOffset. 288 289 \return total energy in the highband, scaled by factor 2^19 290 *******************************************************************************/ 291 292 static FIXP_DBL addHighbandEnergies(FIXP_DBL **RESTRICT Energies, /*!< input */ 293 INT *scaleEnergies, 294 INT YBufferWriteOffset, 295 FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], /*!< Combined output */ 296 UCHAR *RESTRICT freqBandTable, 297 INT nSfb, 298 INT sbrSlots, 299 INT timeStep) 300 { 301 INT i,j,k,slotIn,slotOut,scale[2]; 302 INT li,ui; 303 FIXP_DBL nrgTotal; 304 FIXP_DBL accu = FL2FXCONST_DBL(0.0f); 305 306 /* Combine QMF-timeslots to SBR-timeslots, 307 combine QMF-bands to SBR-bands, 308 combine Left and Right channel */ 309 for (slotOut=0; slotOut<sbrSlots; slotOut++) { 310 slotIn = timeStep*slotOut; 311 312 for (j=0; j<nSfb; j++) { 313 accu = FL2FXCONST_DBL(0.0f); 314 315 li = freqBandTable[j]; 316 ui = freqBandTable[j + 1]; 317 318 for (k=li; k<ui; k++) { 319 for (i=0; i<timeStep; i++) { 320 accu += (Energies[(slotIn+i)>>1][k] >> 5); 321 } 322 } 323 EnergiesM[slotOut][j] = accu; 324 } 325 } 326 327 /* scale energies down before add up */ 328 scale[0] = fixMin(8,scaleEnergies[0]); 329 scale[1] = fixMin(8,scaleEnergies[1]); 330 331 if ((scaleEnergies[0]-scale[0]) > (DFRACT_BITS-1) || (scaleEnergies[1]-scale[0]) > (DFRACT_BITS-1)) 332 nrgTotal = FL2FXCONST_DBL(0.0f); 333 else { 334 /* Now add all energies */ 335 accu = FL2FXCONST_DBL(0.0f); 336 337 for (slotOut=0; slotOut<YBufferWriteOffset; slotOut++) { 338 for (j=0; j<nSfb; j++) { 339 accu += (EnergiesM[slotOut][j] >> scale[0]); 340 } 341 } 342 nrgTotal = accu >> (scaleEnergies[0]-scale[0]); 343 344 for (slotOut=YBufferWriteOffset; slotOut<sbrSlots; slotOut++) { 345 for (j=0; j<nSfb; j++) { 346 accu += (EnergiesM[slotOut][j] >> scale[0]); 347 } 348 } 349 nrgTotal = accu >> (scaleEnergies[1]-scale[1]); 350 } 351 352 return(nrgTotal); 353 } 354 355 356 /******************************************************************************* 357 Functionname: FDKsbrEnc_frameSplitter 358 ******************************************************************************* 359 \brief Decides if a FIXFIX-frame shall be splitted into 2 envelopes 360 361 If no transient has been detected before, the frame can still be splitted 362 into 2 envelopes. 363 *******************************************************************************/ 364 void 365 FDKsbrEnc_frameSplitter(FIXP_DBL **Energies, 366 INT *scaleEnergies, 367 HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, 368 UCHAR *freqBandTable, 369 UCHAR *tran_vector, 370 int YBufferWriteOffset, 371 int YBufferSzShift, 372 int nSfb, 373 int timeStep, 374 int no_cols, 375 FIXP_DBL* tonality) 376 { 377 if (tran_vector[1]==0) /* no transient was detected */ 378 { 379 FIXP_DBL delta; 380 INT delta_e; 381 FIXP_DBL (*EnergiesM)[MAX_FREQ_COEFFS]; 382 FIXP_DBL EnergyTotal,newLowbandEnergy,newHighbandEnergy; 383 INT border; 384 INT sbrSlots = fMultI(GetInvInt(timeStep),no_cols); 385 C_ALLOC_SCRATCH_START(_EnergiesM, FIXP_DBL, NUMBER_TIME_SLOTS_2304*MAX_FREQ_COEFFS) 386 387 FDK_ASSERT( sbrSlots * timeStep == no_cols ); 388 389 EnergiesM = (FIXP_DBL(*)[MAX_FREQ_COEFFS])_EnergiesM; 390 391 /* 392 Get Lowband-energy over a range of 2 frames (Look half a frame back and ahead). 393 */ 394 newLowbandEnergy = addLowbandEnergies(Energies, 395 scaleEnergies, 396 YBufferWriteOffset, 397 YBufferSzShift, 398 h_sbrTransientDetector->tran_off, 399 freqBandTable, 400 no_cols); 401 402 newHighbandEnergy = addHighbandEnergies(Energies, 403 scaleEnergies, 404 YBufferWriteOffset, 405 EnergiesM, 406 freqBandTable, 407 nSfb, 408 sbrSlots, 409 timeStep); 410 411 { 412 /* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame look-behind 413 newLowbandEnergy: Corresponds to 1 frame, starting in the middle of the current frame */ 414 EnergyTotal = (newLowbandEnergy + h_sbrTransientDetector->prevLowBandEnergy) >> 1; 415 EnergyTotal += newHighbandEnergy; 416 /* The below border should specify the same position as the middle border 417 of a FIXFIX-frame with 2 envelopes. */ 418 border = (sbrSlots+1) >> 1; 419 420 if ( (INT)EnergyTotal&0xffffffe0 && (scaleEnergies[0]<32 || scaleEnergies[1]<32) ) /* i.e. > 31 */ { 421 delta = spectralChange(EnergiesM, 422 scaleEnergies, 423 EnergyTotal, 424 nSfb, 425 0, 426 border, 427 YBufferWriteOffset, 428 sbrSlots, 429 &delta_e 430 ); 431 } else { 432 delta = FL2FXCONST_DBL(0.0f); 433 delta_e = 0; 434 435 /* set tonality to 0 when energy is very low, since the amplitude 436 resolution should then be low as well */ 437 *tonality = FL2FXCONST_DBL(0.0f); 438 } 439 440 441 if ( fIsLessThan(h_sbrTransientDetector->split_thr_m, h_sbrTransientDetector->split_thr_e, delta, delta_e) ) { 442 tran_vector[0] = 1; /* Set flag for splitting */ 443 } else { 444 tran_vector[0] = 0; 445 } 446 447 } 448 449 /* Update prevLowBandEnergy */ 450 h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy; 451 h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy; 452 C_ALLOC_SCRATCH_END(_EnergiesM, FIXP_DBL, NUMBER_TIME_SLOTS_2304*MAX_FREQ_COEFFS) 453 } 454 } 455 456 /* 457 * Calculate transient energy threshold for each QMF band 458 */ 459 static void 460 calculateThresholds(FIXP_DBL **RESTRICT Energies, 461 INT *RESTRICT scaleEnergies, 462 FIXP_DBL *RESTRICT thresholds, 463 int YBufferWriteOffset, 464 int YBufferSzShift, 465 int noCols, 466 int noRows, 467 int tran_off) 468 { 469 FIXP_DBL mean_val,std_val,temp; 470 FIXP_DBL i_noCols; 471 FIXP_DBL i_noCols1; 472 FIXP_DBL accu,accu0,accu1; 473 int scaleFactor0,scaleFactor1,commonScale; 474 int i,j; 475 476 i_noCols = GetInvInt(noCols + tran_off ) << YBufferSzShift; 477 i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift; 478 479 /* calc minimum scale of energies of previous and current frame */ 480 commonScale = fixMin(scaleEnergies[0],scaleEnergies[1]); 481 482 /* calc scalefactors to adapt energies to common scale */ 483 scaleFactor0 = fixMin((scaleEnergies[0]-commonScale), (DFRACT_BITS-1)); 484 scaleFactor1 = fixMin((scaleEnergies[1]-commonScale), (DFRACT_BITS-1)); 485 486 FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0)); 487 488 /* calculate standard deviation in every subband */ 489 for (i=0; i<noRows; i++) 490 { 491 int startEnergy = (tran_off>>YBufferSzShift); 492 int endEnergy = ((noCols>>YBufferSzShift)+tran_off); 493 int shift; 494 495 /* calculate mean value over decimated energy values (downsampled by 2). */ 496 accu0 = accu1 = FL2FXCONST_DBL(0.0f); 497 498 for (j=startEnergy; j<YBufferWriteOffset; j++) 499 accu0 += fMult(Energies[j][i], i_noCols); 500 for (; j<endEnergy; j++) 501 accu1 += fMult(Energies[j][i], i_noCols); 502 503 mean_val = (accu0 >> scaleFactor0) + (accu1 >> scaleFactor1); /* average */ 504 shift = fixMax(0,CountLeadingBits(mean_val)-6); /* -6 to keep room for accumulating upto N = 24 values */ 505 506 /* calculate standard deviation */ 507 accu = FL2FXCONST_DBL(0.0f); 508 509 /* summe { ((mean_val-nrg)^2) * i_noCols1 } */ 510 for (j=startEnergy; j<YBufferWriteOffset; j++) { 511 temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor0))<<shift; 512 temp = fPow2(temp); 513 temp = fMult(temp, i_noCols1); 514 accu += temp; 515 } 516 for (; j<endEnergy; j++) { 517 temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1))<<shift; 518 temp = fPow2(temp); 519 temp = fMult(temp, i_noCols1); 520 accu += temp; 521 } 522 523 std_val = sqrtFixp(accu)>>shift; /* standard deviation */ 524 525 /* 526 Take new threshold as average of calculated standard deviation ratio 527 and old threshold if greater than absolute threshold 528 */ 529 temp = ( commonScale<=(DFRACT_BITS-1) ) 530 ? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) + (fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale) 531 : (FIXP_DBL) 0; 532 533 thresholds[i] = fixMax(ABS_THRES,temp); 534 535 FDK_ASSERT(commonScale >= 0); 536 } 537 } 538 539 /* 540 * Calculate transient levels for each QMF time slot. 541 */ 542 static void 543 extractTransientCandidates(FIXP_DBL **RESTRICT Energies, 544 INT *RESTRICT scaleEnergies, 545 FIXP_DBL *RESTRICT thresholds, 546 FIXP_DBL *RESTRICT transients, 547 int YBufferWriteOffset, 548 int YBufferSzShift, 549 int noCols, 550 int start_band, 551 int stop_band, 552 int tran_off, 553 int addPrevSamples) 554 { 555 FIXP_DBL i_thres; 556 C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS); 557 FIXP_DBL *RESTRICT pEnergiesTemp = EnergiesTemp; 558 int tmpScaleEnergies0, tmpScaleEnergies1; 559 int endCond; 560 int startEnerg,endEnerg; 561 int i,j,jIndex,jpBM; 562 563 tmpScaleEnergies0 = scaleEnergies[0]; 564 tmpScaleEnergies1 = scaleEnergies[1]; 565 566 /* Scale value for first energies, upto YBufferWriteOffset */ 567 tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL); 568 /* Scale value for first energies, from YBufferWriteOffset upwards */ 569 tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL); 570 571 FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0)); 572 573 /* Keep addPrevSamples extra previous transient candidates. */ 574 FDKmemmove(transients, transients + noCols - addPrevSamples, (tran_off+addPrevSamples) * sizeof (FIXP_DBL)); 575 FDKmemclear(transients + tran_off + addPrevSamples, noCols * sizeof (FIXP_DBL)); 576 577 endCond = noCols; /* Amount of new transient values to be calculated. */ 578 startEnerg = (tran_off-3)>>YBufferSzShift; /* >>YBufferSzShift because of amount of energy values. -3 because of neighbors being watched. */ 579 endEnerg = ((noCols+ (YBufferWriteOffset<<YBufferSzShift))-1)>>YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */ 580 581 /* Compute differential values with two different weightings in every subband */ 582 for (i=start_band; i<stop_band; i++) 583 { 584 FIXP_DBL thres = thresholds[i]; 585 586 if((LONG)thresholds[i]>=256) 587 i_thres = (LONG)( (LONG)MAXVAL_DBL / ((((LONG)thresholds[i]))+1) )<<(32-24); 588 else 589 i_thres = (LONG)MAXVAL_DBL; 590 591 /* Copy one timeslot and de-scale and de-squish */ 592 if (YBufferSzShift == 1) { 593 for(j=startEnerg; j<YBufferWriteOffset; j++) { 594 FIXP_DBL tmp = Energies[j][i]; 595 EnergiesTemp[(j<<1)+1] = EnergiesTemp[j<<1] = tmp>>tmpScaleEnergies0; 596 } 597 for(; j<=endEnerg; j++) { 598 FIXP_DBL tmp = Energies[j][i]; 599 EnergiesTemp[(j<<1)+1] = EnergiesTemp[j<<1] = tmp>>tmpScaleEnergies1; 600 } 601 } else { 602 for(j=startEnerg; j<YBufferWriteOffset; j++) { 603 FIXP_DBL tmp = Energies[j][i]; 604 EnergiesTemp[j] = tmp>>tmpScaleEnergies0; 605 } 606 for(; j<=endEnerg; j++) { 607 FIXP_DBL tmp = Energies[j][i]; 608 EnergiesTemp[j] = tmp>>tmpScaleEnergies1; 609 } 610 } 611 612 /* Detect peaks in energy values. */ 613 614 jIndex = tran_off; 615 jpBM = jIndex+addPrevSamples; 616 617 for (j=endCond; j--; jIndex++, jpBM++) 618 { 619 620 FIXP_DBL delta, tran; 621 int d; 622 623 delta = (FIXP_DBL)0; 624 tran = (FIXP_DBL)0; 625 626 for (d=1; d<4; d++) { 627 delta += pEnergiesTemp[jIndex+d]; /* R */ 628 delta -= pEnergiesTemp[jIndex-d]; /* L */ 629 delta -= thres; 630 631 if ( delta > (FIXP_DBL)0 ) { 632 tran += fMult(i_thres, delta); 633 } 634 } 635 transients[jpBM] += tran; 636 } 637 } 638 C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS); 639 } 640 641 void 642 FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran, 643 FIXP_DBL **Energies, 644 INT *scaleEnergies, 645 UCHAR *transient_info, 646 int YBufferWriteOffset, 647 int YBufferSzShift, 648 int timeStep, 649 int frameMiddleBorder) 650 { 651 int no_cols = h_sbrTran->no_cols; 652 int qmfStartSample; 653 int addPrevSamples; 654 int timeStepShift=0; 655 int i, cond; 656 657 /* Where to start looking for transients in the transient candidate buffer */ 658 qmfStartSample = timeStep * frameMiddleBorder; 659 /* We need to look one value backwards in the transients, so we might need one more previous value. */ 660 addPrevSamples = (qmfStartSample > 0) ? 0: 1; 661 662 switch (timeStep) { 663 case 1: timeStepShift = 0; break; 664 case 2: timeStepShift = 1; break; 665 case 4: timeStepShift = 2; break; 666 } 667 668 calculateThresholds(Energies, 669 scaleEnergies, 670 h_sbrTran->thresholds, 671 YBufferWriteOffset, 672 YBufferSzShift, 673 h_sbrTran->no_cols, 674 h_sbrTran->no_rows, 675 h_sbrTran->tran_off); 676 677 extractTransientCandidates(Energies, 678 scaleEnergies, 679 h_sbrTran->thresholds, 680 h_sbrTran->transients, 681 YBufferWriteOffset, 682 YBufferSzShift, 683 h_sbrTran->no_cols, 684 0, 685 h_sbrTran->no_rows, 686 h_sbrTran->tran_off, 687 addPrevSamples ); 688 689 transient_info[0] = 0; 690 transient_info[1] = 0; 691 transient_info[2] = 0; 692 693 /* Offset by the amount of additional previous transient candidates being kept. */ 694 qmfStartSample += addPrevSamples; 695 696 /* Check for transients in second granule (pick the last value of subsequent values) */ 697 for (i=qmfStartSample; i<qmfStartSample + no_cols; i++) { 698 cond = (h_sbrTran->transients[i] < fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1]) ) 699 && (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); 700 701 if (cond) { 702 transient_info[0] = (i - qmfStartSample)>>timeStepShift; 703 transient_info[1] = 1; 704 break; 705 } 706 } 707 708 if ( h_sbrTran->frameShift != 0) { 709 /* transient prediction for LDSBR */ 710 /* Check for transients in first <frameShift> qmf-slots of second frame */ 711 for (i=qmfStartSample+no_cols; i<qmfStartSample + no_cols+h_sbrTran->frameShift; i++) { 712 713 cond = (h_sbrTran->transients[i] < fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1]) ) 714 && (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); 715 716 if (cond) { 717 int pos = (int) ( (i - qmfStartSample-no_cols) >> timeStepShift ); 718 if ((pos < 3) && (transient_info[1]==0)) { 719 transient_info[2] = 1; 720 } 721 break; 722 } 723 } 724 } 725 } 726 727 int 728 FDKsbrEnc_InitSbrTransientDetector(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, 729 UINT sbrSyntaxFlags, /* SBR syntax flags derived from AOT. */ 730 INT frameSize, 731 INT sampleFreq, 732 sbrConfigurationPtr params, 733 int tran_fc, 734 int no_cols, 735 int no_rows, 736 int YBufferWriteOffset, 737 int YBufferSzShift, 738 int frameShift, 739 int tran_off) 740 { 741 INT totalBitrate = params->codecSettings.standardBitrate * params->codecSettings.nChannels; 742 INT codecBitrate = params->codecSettings.bitRate; 743 FIXP_DBL bitrateFactor_m, framedur_fix; 744 INT bitrateFactor_e, tmp_e; 745 746 FDKmemclear(h_sbrTransientDetector,sizeof(SBR_TRANSIENT_DETECTOR)); 747 748 h_sbrTransientDetector->frameShift = frameShift; 749 h_sbrTransientDetector->tran_off = tran_off; 750 751 if(codecBitrate) { 752 bitrateFactor_m = fDivNorm((FIXP_DBL)totalBitrate, (FIXP_DBL)(codecBitrate<<2),&bitrateFactor_e); 753 bitrateFactor_e += 2; 754 } 755 else { 756 bitrateFactor_m = FL2FXCONST_DBL(1.0/4.0); 757 bitrateFactor_e = 2; 758 } 759 760 framedur_fix = fDivNorm(frameSize, sampleFreq); 761 762 /* The longer the frames, the more often should the FIXFIX- 763 case transmit 2 envelopes instead of 1. 764 Frame durations below 10 ms produce the highest threshold 765 so that practically always only 1 env is transmitted. */ 766 FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010); 767 768 tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001)); 769 tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &tmp_e); 770 771 bitrateFactor_e = (tmp_e + bitrateFactor_e); 772 773 if(sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { 774 bitrateFactor_e--; /* divide by 2 */ 775 } 776 777 FDK_ASSERT(no_cols <= QMF_MAX_TIME_SLOTS); 778 FDK_ASSERT(no_rows <= QMF_CHANNELS); 779 780 h_sbrTransientDetector->no_cols = no_cols; 781 h_sbrTransientDetector->tran_thr = (FIXP_DBL)((params->tran_thr << (32-24-1)) / no_rows); 782 h_sbrTransientDetector->tran_fc = tran_fc; 783 h_sbrTransientDetector->split_thr_m = fMult(tmp, bitrateFactor_m); 784 h_sbrTransientDetector->split_thr_e = bitrateFactor_e; 785 h_sbrTransientDetector->no_rows = no_rows; 786 h_sbrTransientDetector->mode = params->tran_det_mode; 787 h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f); 788 789 return (0); 790 } 791 792 793 #define ENERGY_SCALING_SIZE 32 794 795 INT FDKsbrEnc_InitSbrFastTransientDetector( 796 HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector, 797 const INT time_slots_per_frame, 798 const INT bandwidth_qmf_slot, 799 const INT no_qmf_channels, 800 const INT sbr_qmf_1st_band 801 ) 802 { 803 804 int i, e; 805 int buff_size; 806 FIXP_DBL myExp; 807 FIXP_DBL myExpSlot; 808 809 h_sbrFastTransientDetector->lookahead = TRAN_DET_LOOKAHEAD; 810 h_sbrFastTransientDetector->nTimeSlots = time_slots_per_frame; 811 812 buff_size = h_sbrFastTransientDetector->nTimeSlots + h_sbrFastTransientDetector->lookahead; 813 814 for(i=0; i< buff_size; i++) { 815 h_sbrFastTransientDetector->delta_energy[i] = FL2FXCONST_DBL(0.0f); 816 h_sbrFastTransientDetector->energy_timeSlots[i] = FL2FXCONST_DBL(0.0f); 817 h_sbrFastTransientDetector->lowpass_energy[i] = FL2FXCONST_DBL(0.0f); 818 h_sbrFastTransientDetector->transientCandidates[i] = 0; 819 } 820 821 FDK_ASSERT(bandwidth_qmf_slot > 0.f); 822 h_sbrFastTransientDetector->stopBand = fMin(TRAN_DET_STOP_FREQ/bandwidth_qmf_slot, no_qmf_channels); 823 h_sbrFastTransientDetector->startBand = fMin(sbr_qmf_1st_band, h_sbrFastTransientDetector->stopBand - TRAN_DET_MIN_QMFBANDS); 824 825 FDK_ASSERT(h_sbrFastTransientDetector->startBand < no_qmf_channels); 826 FDK_ASSERT(h_sbrFastTransientDetector->startBand < h_sbrFastTransientDetector->stopBand); 827 FDK_ASSERT(h_sbrFastTransientDetector->startBand > 1); 828 FDK_ASSERT(h_sbrFastTransientDetector->stopBand > 1); 829 830 /* the energy weighting and adding up has a headroom of 6 Bits, 831 so up to 64 bands can be added without potential overflow. */ 832 FDK_ASSERT(h_sbrFastTransientDetector->stopBand - h_sbrFastTransientDetector->startBand <= 64); 833 834 /* QMF_HP_dB_SLOPE_FIX says that we want a 20 dB per 16 kHz HP filter. 835 The following lines map this to the QMF bandwidth. */ 836 #define EXP_E 7 /* QMF_CHANNELS (=64) multiplications max, max. allowed sum is 0.5 */ 837 myExp = fMultNorm(QMF_HP_dBd_SLOPE_FIX, (FIXP_DBL)bandwidth_qmf_slot, &e); 838 myExp = scaleValueSaturate(myExp, e+0+DFRACT_BITS-1-EXP_E); 839 myExpSlot = myExp; 840 841 for(i=0; i<QMF_CHANNELS; i++){ 842 /* Calculate dBf over all qmf bands: 843 dBf = (10^(0.002266f/10*bw(slot)))^(band) = 844 = 2^(log2(10)*0.002266f/10*bw(slot)*band) = 845 = 2^(0.00075275f*bw(slot)*band) */ 846 847 FIXP_DBL dBf_m; /* dBf mantissa */ 848 INT dBf_e; /* dBf exponent */ 849 INT tmp; 850 851 INT dBf_int; /* dBf integer part */ 852 FIXP_DBL dBf_fract; /* dBf fractional part */ 853 854 /* myExp*(i+1) = myExp_int - myExp_fract 855 myExp*(i+1) is split up here for better accuracy of CalcInvLdData(), 856 for its result can be split up into an integer and a fractional part */ 857 858 /* Round up to next integer */ 859 FIXP_DBL myExp_int = (myExpSlot & (FIXP_DBL)0xfe000000) + (FIXP_DBL)0x02000000; 860 861 /* This is the fractional part that needs to be substracted */ 862 FIXP_DBL myExp_fract = myExp_int - myExpSlot; 863 864 /* Calc integer part */ 865 dBf_int = CalcInvLdData(myExp_int); 866 /* The result needs to be re-scaled. The ld(myExp_int) had been scaled by EXP_E, 867 the CalcInvLdData expects the operand to be scaled by LD_DATA_SHIFT. 868 Therefore, the correctly scaled result is dBf_int^(2^(EXP_E-LD_DATA_SHIFT)), 869 which is dBf_int^2 */ 870 dBf_int *= dBf_int; 871 872 /* Calc fractional part */ 873 dBf_fract = CalcInvLdData(-myExp_fract); 874 /* The result needs to be re-scaled. The ld(myExp_fract) had been scaled by EXP_E, 875 the CalcInvLdData expects the operand to be scaled by LD_DATA_SHIFT. 876 Therefore, the correctly scaled result is dBf_fract^(2^(EXP_E-LD_DATA_SHIFT)), 877 which is dBf_fract^2 */ 878 dBf_fract = fMultNorm(dBf_fract, dBf_fract, &tmp); 879 880 /* Get worst case scaling of multiplication result */ 881 dBf_e = (DFRACT_BITS-1 - tmp) - CountLeadingBits(dBf_int); 882 883 /* Now multiply integer with fractional part of the result, thus resulting 884 in the overall accurate fractional result */ 885 dBf_m = fMultNorm(dBf_int, dBf_fract, &e); 886 dBf_m = scaleValueSaturate(dBf_m, e+DFRACT_BITS-1+tmp-dBf_e); 887 myExpSlot += myExp; 888 889 /* Keep the results */ 890 h_sbrFastTransientDetector->dBf_m[i] = dBf_m; 891 h_sbrFastTransientDetector->dBf_e[i] = dBf_e; 892 893 } 894 895 /* Make sure that dBf is greater than 1.0 (because it should be a highpass) */ 896 /* ... */ 897 898 return 0; 899 } 900 901 void FDKsbrEnc_fastTransientDetect( 902 const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector, 903 const FIXP_DBL *const *Energies, 904 const int *const scaleEnergies, 905 const INT YBufferWriteOffset, 906 UCHAR *const tran_vector 907 ) 908 { 909 int timeSlot, band; 910 911 FIXP_DBL max_delta_energy; /* helper to store maximum energy ratio */ 912 int max_delta_energy_scale; /* helper to store scale of maximum energy ratio */ 913 int ind_max = 0; /* helper to store index of maximum energy ratio */ 914 int isTransientInFrame = 0; 915 916 const int nTimeSlots = h_sbrFastTransientDetector->nTimeSlots; 917 const int lookahead = h_sbrFastTransientDetector->lookahead; 918 const int startBand = h_sbrFastTransientDetector->startBand; 919 const int stopBand = h_sbrFastTransientDetector->stopBand; 920 921 int * transientCandidates = h_sbrFastTransientDetector->transientCandidates; 922 923 FIXP_DBL * energy_timeSlots = h_sbrFastTransientDetector->energy_timeSlots; 924 int * energy_timeSlots_scale = h_sbrFastTransientDetector->energy_timeSlots_scale; 925 926 FIXP_DBL * delta_energy = h_sbrFastTransientDetector->delta_energy; 927 int * delta_energy_scale = h_sbrFastTransientDetector->delta_energy_scale; 928 929 const FIXP_DBL thr = TRAN_DET_THRSHLD; 930 const INT thr_scale = TRAN_DET_THRSHLD_SCALE; 931 932 /*reset transient info*/ 933 tran_vector[2] = 0; 934 935 /* reset transient candidates */ 936 FDKmemclear(transientCandidates+lookahead, nTimeSlots*sizeof(int)); 937 938 for(timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) { 939 int i, norm; 940 FIXP_DBL tmpE = FL2FXCONST_DBL(0.0f); 941 int headroomEnSlot = DFRACT_BITS-1; 942 943 FIXP_DBL smallNRG = FL2FXCONST_DBL(1e-2f); 944 FIXP_DBL denominator; 945 INT denominator_scale; 946 947 /* determine minimum headroom of energy values for this timeslot */ 948 for(band = startBand; band < stopBand; band++) { 949 int tmp_headroom = fNormz(Energies[timeSlot][band])-1; 950 if(tmp_headroom < headroomEnSlot){ 951 headroomEnSlot = tmp_headroom; 952 } 953 } 954 955 for(i = 0, band = startBand; band < stopBand; band++, i++) { 956 /* energy is weighted by weightingfactor stored in dBf_m array */ 957 /* dBf_m index runs from 0 to stopBand-startband */ 958 /* energy shifted by calculated headroom for maximum precision */ 959 FIXP_DBL weightedEnergy = fMult(Energies[timeSlot][band]<<headroomEnSlot, h_sbrFastTransientDetector->dBf_m[i]); 960 961 /* energy is added up */ 962 /* shift by 6 to have a headroom for maximum 64 additions */ 963 /* shift by dBf_e to handle weighting factor dependent scale factors */ 964 tmpE += weightedEnergy >> (6 + (10 - h_sbrFastTransientDetector->dBf_e[i])); 965 } 966 967 /* store calculated energy for timeslot */ 968 energy_timeSlots[timeSlot] = tmpE; 969 970 /* calculate overall scale factor for energy of this timeslot */ 971 /* = original scale factor of energies (-scaleEnergies[0]+2*QMF_SCALE_OFFSET or -scaleEnergies[1]+2*QMF_SCALE_OFFSET */ 972 /* depending on YBufferWriteOffset) */ 973 /* + weighting factor scale (10) */ 974 /* + adding up scale factor ( 6) */ 975 /* - headroom of energy value (headroomEnSlot) */ 976 if(timeSlot < YBufferWriteOffset){ 977 energy_timeSlots_scale[timeSlot] = (-scaleEnergies[0]+2*QMF_SCALE_OFFSET) + (10+6) - headroomEnSlot; 978 } else { 979 energy_timeSlots_scale[timeSlot] = (-scaleEnergies[1]+2*QMF_SCALE_OFFSET) + (10+6) - headroomEnSlot; 980 } 981 982 /* Add a small energy to the denominator, thus making the transient 983 detection energy-dependent. Loud transients are being detected, 984 silent ones not. */ 985 986 /* make sure that smallNRG does not overflow */ 987 if ( -energy_timeSlots_scale[timeSlot-1] + 1 > 5 ) 988 { 989 denominator = smallNRG; 990 denominator_scale = 0; 991 } else { 992 /* Leave an additional headroom of 1 bit for this addition. */ 993 smallNRG = scaleValue(smallNRG, -(energy_timeSlots_scale[timeSlot-1] + 1)); 994 denominator = (energy_timeSlots[timeSlot-1]>>1) + smallNRG; 995 denominator_scale = energy_timeSlots_scale[timeSlot-1]+1; 996 } 997 998 delta_energy[timeSlot] = fDivNorm(energy_timeSlots[timeSlot], denominator, &norm); 999 delta_energy_scale[timeSlot] = energy_timeSlots_scale[timeSlot] - denominator_scale + norm; 1000 } 1001 1002 /*get transient candidates*/ 1003 /* For every timeslot, check if delta(E) exceeds the threshold. If it did, 1004 it could potentially be marked as a transient candidate. However, the 2 1005 slots before the current one must not be transients with an energy higher 1006 than 1.4*E(current). If both aren't transients or if the energy of the 1007 current timesolot is more than 1.4 times higher than the energy in the 1008 last or the one before the last slot, it is marked as a transient.*/ 1009 1010 FDK_ASSERT(lookahead >= 2); 1011 for(timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) { 1012 FIXP_DBL energy_cur_slot_weighted = fMult(energy_timeSlots[timeSlot],FL2FXCONST_DBL(1.0f/1.4f)); 1013 if( !fIsLessThan(delta_energy[timeSlot], delta_energy_scale[timeSlot], thr, thr_scale) && 1014 ( ((transientCandidates[timeSlot-2]==0) && (transientCandidates[timeSlot-1]==0)) || 1015 !fIsLessThan(energy_cur_slot_weighted, energy_timeSlots_scale[timeSlot], energy_timeSlots[timeSlot-1], energy_timeSlots_scale[timeSlot-1] ) || 1016 !fIsLessThan(energy_cur_slot_weighted, energy_timeSlots_scale[timeSlot], energy_timeSlots[timeSlot-2], energy_timeSlots_scale[timeSlot-2] ) 1017 ) 1018 ) 1019 { 1020 /* in case of strong transients, subsequent 1021 * qmf slots might be recognized as transients. */ 1022 transientCandidates[timeSlot] = 1; 1023 } 1024 } 1025 1026 /*get transient with max energy*/ 1027 max_delta_energy = FL2FXCONST_DBL(0.0f); 1028 max_delta_energy_scale = 0; 1029 ind_max = 0; 1030 isTransientInFrame = 0; 1031 for(timeSlot = 0; timeSlot < nTimeSlots; timeSlot++) { 1032 int scale = fMax(delta_energy_scale[timeSlot], max_delta_energy_scale); 1033 if(transientCandidates[timeSlot] && ( (delta_energy[timeSlot] >> (scale - delta_energy_scale[timeSlot])) > (max_delta_energy >> (scale - max_delta_energy_scale)) ) ) { 1034 max_delta_energy = delta_energy[timeSlot]; 1035 max_delta_energy_scale = scale; 1036 ind_max = timeSlot; 1037 isTransientInFrame = 1; 1038 } 1039 } 1040 1041 /*from all transient candidates take the one with the biggest energy*/ 1042 if(isTransientInFrame) { 1043 tran_vector[0] = ind_max; 1044 tran_vector[1] = 1; 1045 } else { 1046 /*reset transient info*/ 1047 tran_vector[0] = tran_vector[1] = 0; 1048 } 1049 1050 /*check for transients in lookahead*/ 1051 for(timeSlot = nTimeSlots; timeSlot < nTimeSlots + lookahead; timeSlot++) { 1052 if(transientCandidates[timeSlot]) { 1053 tran_vector[2] = 1; 1054 } 1055 } 1056 1057 /*update buffers*/ 1058 for(timeSlot = 0; timeSlot < lookahead; timeSlot++) { 1059 transientCandidates[timeSlot] = transientCandidates[nTimeSlots + timeSlot]; 1060 1061 /* fixpoint stuff */ 1062 energy_timeSlots[timeSlot] = energy_timeSlots[nTimeSlots + timeSlot]; 1063 energy_timeSlots_scale[timeSlot] = energy_timeSlots_scale[nTimeSlots + timeSlot]; 1064 1065 delta_energy[timeSlot] = delta_energy[nTimeSlots + timeSlot]; 1066 delta_energy_scale[timeSlot] = delta_energy_scale[nTimeSlots + timeSlot]; 1067 } 1068 } 1069 1070