1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5� Copyright  1995 - 2013 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/*!
85  \file
86  \brief  frequency scale
87  \author Tobias Chalupka
88*/
89
90#include "sbrenc_freq_sca.h"
91#include "sbr_misc.h"
92
93#include "genericStds.h"
94
95/*  StartFreq */
96static INT getStartFreq(INT fsCore, const INT start_freq);
97
98/* StopFreq */
99static INT getStopFreq(INT fsCore, const INT stop_freq);
100
101static INT  numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor);
102static void CalcBands(INT * diff, INT start , INT stop , INT num_bands);
103static INT  modifyBands(INT max_band, INT * diff, INT length);
104static void cumSum(INT start_value, INT* diff, INT length, UCHAR  *start_adress);
105
106
107
108/*******************************************************************************
109 Functionname:  FDKsbrEnc_getSbrStartFreqRAW
110 *******************************************************************************
111 Description:
112
113 Arguments:
114
115 Return:
116 *******************************************************************************/
117
118INT
119FDKsbrEnc_getSbrStartFreqRAW (INT startFreq, INT fsCore)
120{
121  INT result;
122
123  if ( startFreq < 0 || startFreq > 15) {
124    return -1;
125  }
126  /* Update startFreq struct */
127  result = getStartFreq(fsCore, startFreq);
128
129  result = (result*(fsCore>>5)+1)>>1; /* (result*fsSBR/QMFbands+1)>>1; */
130
131  return (result);
132
133} /* End FDKsbrEnc_getSbrStartFreqRAW */
134
135
136/*******************************************************************************
137 Functionname:  getSbrStopFreq
138 *******************************************************************************
139 Description:
140
141 Arguments:
142
143 Return:
144 *******************************************************************************/
145INT FDKsbrEnc_getSbrStopFreqRAW  (INT stopFreq, INT fsCore)
146{
147  INT result;
148
149  if ( stopFreq < 0 || stopFreq > 13)
150    return -1;
151
152  /* Uppdate stopFreq struct */
153  result = getStopFreq(fsCore, stopFreq);
154  result = (result*(fsCore>>5)+1)>>1; /* (result*fsSBR/QMFbands+1)>>1; */
155
156  return (result);
157} /* End getSbrStopFreq */
158
159
160/*******************************************************************************
161 Functionname:  getStartFreq
162 *******************************************************************************
163 Description:
164
165 Arguments:  fsCore - core sampling rate
166
167
168 Return:
169 *******************************************************************************/
170static INT
171getStartFreq(INT fsCore, const INT start_freq)
172{
173  INT k0_min;
174
175  switch(fsCore){
176  case  8000: k0_min = 24; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */
177    break;
178  case 11025: k0_min = 17; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */
179    break;
180  case 12000: k0_min = 16; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */
181    break;
182  case 16000: k0_min = 16; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */
183    break;
184  case 22050: k0_min = 12; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */
185    break;
186  case 24000: k0_min = 11; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */
187    break;
188  case 32000: k0_min = 10; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
189    break;
190  case 44100: k0_min = 7;  /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
191    break;
192  case 48000: k0_min = 7;  /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
193    break;
194  case 96000: k0_min = 3;  /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
195    break;
196  default:
197    k0_min=11; /* illegal fs */
198  }
199
200
201  switch (fsCore) {
202
203  case  8000:
204    {
205      INT v_offset[]= {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7};
206      return (k0_min + v_offset[start_freq]);
207    }
208  case 11025:
209    {
210      INT v_offset[]= {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13};
211      return (k0_min + v_offset[start_freq]);
212    }
213  case 12000:
214    {
215      INT v_offset[]= {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16};
216      return (k0_min + v_offset[start_freq]);
217    }
218  case 16000:
219    {
220      INT v_offset[]= {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16};
221      return (k0_min + v_offset[start_freq]);
222    }
223  case 22050:
224  case 24000:
225  case 32000:
226    {
227      INT v_offset[]= {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20};
228      return (k0_min + v_offset[start_freq]);
229    }
230  case 44100:
231  case 48000:
232  case 96000:
233    {
234      INT v_offset[]= {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24};
235      return (k0_min + v_offset[start_freq]);
236    }
237  default:
238    {
239      INT v_offset[]= {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24, 28, 33};
240      return (k0_min + v_offset[start_freq]);
241    }
242  }
243} /* End getStartFreq */
244
245
246/*******************************************************************************
247 Functionname:  getStopFreq
248 *******************************************************************************
249 Description:
250
251 Arguments:
252
253 Return:
254 *******************************************************************************/
255 static INT
256getStopFreq(INT fsCore, const INT stop_freq)
257{
258  INT result,i;
259  INT k1_min;
260  INT v_dstop[13];
261
262  INT *v_stop_freq = NULL;
263  INT v_stop_freq_16[14] = {48,49,50,51,52,54,55,56,57,59,60,61,63,64};
264  INT v_stop_freq_22[14] = {35,37,38,40,42,44,46,48,51,53,56,58,61,64};
265  INT v_stop_freq_24[14] = {32,34,36,38,40,42,44,46,49,52,55,58,61,64};
266  INT v_stop_freq_32[14] = {32,34,36,38,40,42,44,46,49,52,55,58,61,64};
267  INT v_stop_freq_44[14] = {23,25,27,29,32,34,37,40,43,47,51,55,59,64};
268  INT v_stop_freq_48[14] = {21,23,25,27,30,32,35,38,42,45,49,54,59,64};
269  INT v_stop_freq_64[14] = {20,22,24,26,29,31,34,37,41,45,49,54,59,64};
270  INT v_stop_freq_88[14] = {15,17,19,21,23,26,29,33,37,41,46,51,57,64};
271  INT v_stop_freq_96[14] = {13,15,17,19,21,24,27,31,35,39,44,50,57,64};
272  INT v_stop_freq_192[14] = {7, 8,10,12,14,16,19,23,27,32,38,46,54,64};
273
274  switch(fsCore){
275  case  8000: k1_min = 48;
276              v_stop_freq =v_stop_freq_16;
277    break;
278  case 11025: k1_min = 35;
279              v_stop_freq =v_stop_freq_22;
280    break;
281  case 12000: k1_min = 32;
282              v_stop_freq =v_stop_freq_24;
283    break;
284  case 16000: k1_min = 32;
285              v_stop_freq =v_stop_freq_32;
286    break;
287  case 22050: k1_min = 23;
288              v_stop_freq =v_stop_freq_44;
289    break;
290  case 24000: k1_min = 21;
291              v_stop_freq =v_stop_freq_48;
292    break;
293  case 32000: k1_min = 20;
294              v_stop_freq =v_stop_freq_64;
295    break;
296  case 44100: k1_min = 15;
297              v_stop_freq =v_stop_freq_88;
298    break;
299  case 48000: k1_min = 13;
300              v_stop_freq =v_stop_freq_96;
301    break;
302  case 96000: k1_min =  7;
303              v_stop_freq =v_stop_freq_192;
304    break;
305  default:
306    k1_min = 21; /* illegal fs  */
307  }
308
309  /* if no valid core samplingrate is used this loop produces
310     a segfault, because v_stop_freq is not initialized */
311  /* Ensure increasing bandwidth */
312  for(i = 0; i <= 12; i++) {
313    v_dstop[i] = v_stop_freq[i+1] - v_stop_freq[i];
314  }
315
316  FDKsbrEnc_Shellsort_int(v_dstop, 13); /* Sort bandwidth changes */
317
318  result = k1_min;
319  for(i = 0; i < stop_freq; i++) {
320    result = result + v_dstop[i];
321  }
322
323  return(result);
324
325}/* End getStopFreq */
326
327
328/*******************************************************************************
329 Functionname:  FDKsbrEnc_FindStartAndStopBand
330 *******************************************************************************
331 Description:
332
333 Arguments:     srSbr            SBR sampling freqency
334                srCore           AAC core sampling freqency
335                noChannels       Number of QMF channels
336                startFreq        SBR start frequency in QMF bands
337                stopFreq         SBR start frequency in QMF bands
338
339               *k0               Output parameter
340               *k2               Output parameter
341
342 Return:       Error code (0 is OK)
343 *******************************************************************************/
344INT
345FDKsbrEnc_FindStartAndStopBand(
346        const INT srSbr,
347        const INT srCore,
348        const INT noChannels,
349        const INT startFreq,
350        const INT stopFreq,
351        INT *k0,
352        INT *k2
353        )
354{
355
356  /* Update startFreq struct */
357  *k0 = getStartFreq(srCore, startFreq);
358
359  /* Test if start freq is outside corecoder range */
360  if( srSbr*noChannels < *k0 * srCore ) {
361    return (1); /* raise the cross-over frequency and/or lower the number
362                   of target bands per octave (or lower the sampling frequency) */
363  }
364
365  /*Update stopFreq struct */
366  if ( stopFreq < 14 ) {
367    *k2 = getStopFreq(srCore, stopFreq);
368  } else if( stopFreq == 14 ) {
369    *k2 = 2 * *k0;
370  } else {
371    *k2 = 3 * *k0;
372  }
373
374  /* limit to Nyqvist */
375  if (*k2 > noChannels) {
376    *k2 = noChannels;
377  }
378
379
380
381  /* Test for invalid  k0 k2 combinations */
382  if ( (srCore == 22050) && ( (*k2 - *k0) > MAX_FREQ_COEFFS_FS44100 ) )
383    return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for fs=44.1kHz */
384
385  if ( (srCore >= 24000) && ( (*k2 - *k0) > MAX_FREQ_COEFFS_FS48000 ) )
386    return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for fs>=48kHz */
387
388  if ((*k2 - *k0) > MAX_FREQ_COEFFS)
389    return (1);/*Number of bands exceeds valid range of MAX_FREQ_COEFFS */
390
391  if ((*k2 - *k0) < 0)
392    return (1);/* Number of bands is negative */
393
394
395  return(0);
396}
397
398/*******************************************************************************
399 Functionname:  FDKsbrEnc_UpdateFreqScale
400 *******************************************************************************
401 Description:
402
403 Arguments:
404
405 Return:
406 *******************************************************************************/
407INT
408FDKsbrEnc_UpdateFreqScale(
409        UCHAR     *v_k_master,
410        INT       *h_num_bands,
411        const INT  k0,
412        const INT  k2,
413        const INT  freqScale,
414        const INT  alterScale
415        )
416
417{
418
419  INT     b_p_o = 0;        /* bands_per_octave */
420  FIXP_DBL warp = FL2FXCONST_DBL(0.0f);
421  INT     dk = 0;
422
423  /* Internal variables */
424  INT     k1 = 0, i;
425  INT     num_bands0;
426  INT     num_bands1;
427  INT     diff_tot[MAX_OCTAVE + MAX_SECOND_REGION];
428  INT     *diff0 = diff_tot;
429  INT     *diff1 = diff_tot+MAX_OCTAVE;
430  INT     k2_achived;
431  INT     k2_diff;
432  INT     incr = 0;
433
434  /* Init */
435  if (freqScale==1)  b_p_o = 12;
436  if (freqScale==2)  b_p_o = 10;
437  if (freqScale==3)  b_p_o = 8;
438
439
440  if(freqScale > 0) /*Bark*/
441    {
442      if(alterScale==0)
443        warp = FL2FXCONST_DBL(0.5f);        /* 1.0/(1.0*2.0) */
444      else
445        warp = FL2FXCONST_DBL(1.0f/2.6f);   /* 1.0/(1.3*2.0); */
446
447
448      if(4*k2 >= 9*k0)  /*two or more regions (how many times the basis band is copied)*/
449        {
450          k1=2*k0;
451
452          num_bands0=numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f));
453          num_bands1=numberOfBands(b_p_o, k1, k2, warp);
454
455          CalcBands(diff0, k0, k1, num_bands0);/*CalcBands1 => diff0 */
456          FDKsbrEnc_Shellsort_int( diff0, num_bands0);/*SortBands sort diff0 */
457
458          if (diff0[0] == 0) /* too wide FB bands for target tuning */
459          {
460            return (1);/* raise the cross-over frequency and/or lower the number
461                          of target bands per octave (or lower the sampling frequency */
462          }
463
464          cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */
465
466          CalcBands(diff1, k1, k2, num_bands1);     /* CalcBands2 => diff1 */
467          FDKsbrEnc_Shellsort_int( diff1, num_bands1);            /* SortBands sort diff1 */
468          if(diff0[num_bands0-1] > diff1[0])        /* max(1) > min(2) */
469            {
470              if(modifyBands(diff0[num_bands0-1],diff1, num_bands1))
471                return(1);
472            }
473
474          /* Add 2'nd region */
475          cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]);
476          *h_num_bands=num_bands0+num_bands1;     /* Output nr of bands */
477
478        }
479      else /* one region */
480        {
481          k1=k2;
482
483          num_bands0=numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f));
484          CalcBands(diff0, k0, k1, num_bands0);/* CalcBands1 => diff0 */
485          FDKsbrEnc_Shellsort_int( diff0, num_bands0);       /* SortBands sort diff0 */
486
487          if (diff0[0] == 0) /* too wide FB bands for target tuning */
488          {
489            return (1); /* raise the cross-over frequency and/or lower the number
490                           of target bands per octave (or lower the sampling frequency */
491          }
492
493          cumSum(k0, diff0, num_bands0, v_k_master);/* cumsum */
494          *h_num_bands=num_bands0;        /* Output nr of bands */
495
496        }
497    }
498  else /* Linear mode */
499    {
500      if (alterScale==0) {
501        dk = 1;
502        num_bands0 = 2 * ((k2 - k0)/2);         /* FLOOR to get to few number of bands*/
503      } else {
504        dk = 2;
505        num_bands0 = 2 * (((k2 - k0)/dk +1)/2); /* ROUND to get closest fit */
506      }
507
508      k2_achived = k0 + num_bands0*dk;
509      k2_diff = k2 - k2_achived;
510
511      for(i=0;i<num_bands0;i++)
512        diff_tot[i] = dk;
513
514      /* If linear scale wasn't achived */
515      /* and we got wide SBR are */
516      if (k2_diff < 0) {
517          incr = 1;
518          i = 0;
519      }
520
521      /* If linear scale wasn't achived */
522      /* and we got small SBR are */
523      if (k2_diff > 0) {
524          incr = -1;
525          i = num_bands0-1;
526      }
527
528      /* Adjust diff vector to get sepc. SBR range */
529      while (k2_diff != 0) {
530        diff_tot[i] = diff_tot[i] - incr;
531        i = i + incr;
532        k2_diff = k2_diff + incr;
533      }
534
535      cumSum(k0, diff_tot, num_bands0, v_k_master);/* cumsum */
536      *h_num_bands=num_bands0;        /* Output nr of bands */
537
538    }
539
540  if (*h_num_bands < 1)
541    return(1); /*To small sbr area */
542
543  return (0);
544}/* End FDKsbrEnc_UpdateFreqScale */
545
546static INT
547numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor)
548{
549  INT result=0;
550  /* result = 2* (INT) ( (double)b_p_o * (double)(FDKlog((double)stop/(double)start)/FDKlog((double)2)) * (double)FX_DBL2FL(warp_factor) + 0.5); */
551  result = ( ( b_p_o * fMult( (CalcLdInt(stop) - CalcLdInt(start)),  warp_factor) + (FL2FX_DBL(0.5f)>>LD_DATA_SHIFT)
552               ) >> ((DFRACT_BITS-1)-LD_DATA_SHIFT) ) << 1; /* do not optimize anymore (rounding!!) */
553
554  return(result);
555}
556
557
558static void
559CalcBands(INT * diff, INT start , INT stop , INT num_bands)
560{
561    INT i, qb, qe, qtmp;
562    INT previous;
563    INT current;
564    FIXP_DBL base, exp, tmp;
565
566    previous=start;
567    for(i=1; i<= num_bands; i++)
568    {
569        base = fDivNorm((FIXP_DBL)stop, (FIXP_DBL)start, &qb);
570        exp = fDivNorm((FIXP_DBL)i, (FIXP_DBL)num_bands, &qe);
571        tmp = fPow(base, qb, exp, qe, &qtmp);
572        tmp = fMult(tmp, (FIXP_DBL)(start<<24));
573        current   = (INT)scaleValue(tmp, qtmp-23);
574        current   = (current+1) >> 1; /* rounding*/
575        diff[i-1] = current-previous;
576        previous  = current;
577    }
578
579}/* End CalcBands */
580
581
582static void
583cumSum(INT start_value, INT* diff, INT length,  UCHAR *start_adress)
584{
585  INT i;
586  start_adress[0]=start_value;
587  for(i=1;i<=length;i++)
588    start_adress[i]=start_adress[i-1]+diff[i-1];
589} /* End cumSum */
590
591
592static INT
593modifyBands(INT max_band_previous, INT * diff, INT length)
594{
595  INT change=max_band_previous-diff[0];
596
597  /* Limit the change so that the last band cannot get narrower than the first one */
598  if ( change > (diff[length-1] - diff[0]) / 2 )
599    change = (diff[length-1] - diff[0]) / 2;
600
601  diff[0] += change;
602  diff[length-1] -= change;
603  FDKsbrEnc_Shellsort_int(diff, length);
604
605  return(0);
606}/* End modifyBands */
607
608
609/*******************************************************************************
610 Functionname:  FDKsbrEnc_UpdateHiRes
611 *******************************************************************************
612 Description:
613
614
615 Arguments:
616
617 Return:
618 *******************************************************************************/
619INT
620FDKsbrEnc_UpdateHiRes(
621        UCHAR   *h_hires,
622        INT     *num_hires,
623        UCHAR   *v_k_master,
624        INT      num_master,
625        INT     *xover_band
626        )
627{
628  INT i;
629  INT max1,max2;
630
631  if( (v_k_master[*xover_band] > 32 ) || /* v_k_master[*xover_band] > noQMFChannels(dualRate)/divider */
632      ( *xover_band > num_master ) )  {
633      /* xover_band error, too big for this startFreq. Will be clipped */
634
635    /* Calculate maximum value for xover_band */
636    max1=0;
637    max2=num_master;
638    while( (v_k_master[max1+1] < 32 ) && /* noQMFChannels(dualRate)/divider */
639           ( (max1+1) < max2) )
640      {
641        max1++;
642      }
643
644    *xover_band=max1;
645  }
646
647  *num_hires = num_master - *xover_band;
648  for(i = *xover_band; i <= num_master; i++)
649    {
650      h_hires[i - *xover_band] = v_k_master[i];
651    }
652
653  return (0);
654}/* End FDKsbrEnc_UpdateHiRes */
655
656
657/*******************************************************************************
658 Functionname:  FDKsbrEnc_UpdateLoRes
659 *******************************************************************************
660 Description:
661
662 Arguments:
663
664 Return:
665 *******************************************************************************/
666void
667FDKsbrEnc_UpdateLoRes(UCHAR * h_lores, INT *num_lores, UCHAR * h_hires, INT num_hires)
668{
669  INT i;
670
671  if(num_hires%2 == 0) /* if even number of hires bands */
672    {
673      *num_lores=num_hires/2;
674      /* Use every second lores=hires[0,2,4...] */
675      for(i=0;i<=*num_lores;i++)
676        h_lores[i]=h_hires[i*2];
677
678    }
679  else            /* odd number of hires which means xover is odd */
680    {
681      *num_lores=(num_hires+1)/2;
682
683      /* Use lores=hires[0,1,3,5 ...] */
684      h_lores[0]=h_hires[0];
685      for(i=1;i<=*num_lores;i++)
686        {
687          h_lores[i]=h_hires[i*2-1];
688        }
689    }
690
691}/* End FDKsbrEnc_UpdateLoRes */
692