1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5� Copyright  1995 - 2015 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
6  All rights reserved.
7
8 1.    INTRODUCTION
9The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16of the MPEG specifications.
17
18Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20individually for the purpose of encoding or decoding bit streams in products that are compliant with
21the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27applications information and documentation.
28
292.    COPYRIGHT LICENSE
30
31Redistribution and use in source and binary forms, with or without modification, are permitted without
32payment of copyright license fees provided that you satisfy the following conditions:
33
34You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35your modifications thereto in source code form.
36
37You must retain the complete text of this software license in the documentation and/or other materials
38provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40modifications thereto to recipients of copies in binary form.
41
42The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43prior written permission.
44
45You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46software or your modifications thereto.
47
48Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49and 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
533.    NO PATENT LICENSE
54
55NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57respect to this software.
58
59You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60by appropriate patent licenses.
61
624.    DISCLAIMER
63
64This 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
66of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69or business interruption, however caused and on any theory of liability, whether in contract, strict
70liability, or tort (including negligence), arising in any way out of the use of this software, even if
71advised of the possibility of such damage.
72
735.    CONTACT INFORMATION
74
75Fraunhofer Institute for Integrated Circuits IIS
76Attention: Audio and Multimedia Departments - FDK AAC LL
77Am Wolfsmantel 33
7891058 Erlangen, Germany
79
80www.iis.fraunhofer.de/amm
81amm-info@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
111static 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*******************************************************************************/
241static 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
292static 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*******************************************************************************/
364void
365FDKsbrEnc_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 */
459static void
460calculateThresholds(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 */
542static void
543extractTransientCandidates(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
641void
642FDKsbrEnc_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
727int
728FDKsbrEnc_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
795INT 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
901void 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