1/* -----------------------------------------------------------------------------
2Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5Forschung e.V. All rights reserved.
6
7 1.    INTRODUCTION
8The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10scheme for digital audio. This FDK AAC Codec software is intended to be used on
11a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14general perceptual audio codecs. AAC-ELD is considered the best-performing
15full-bandwidth communications codec by independent studies and is widely
16deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17specifications.
18
19Patent licenses for necessary patent claims for the FDK AAC Codec (including
20those of Fraunhofer) may be obtained through Via Licensing
21(www.vialicensing.com) or through the respective patent owners individually for
22the purpose of encoding or decoding bit streams in products that are compliant
23with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24Android devices already license these patent claims through Via Licensing or
25directly from the patent owners, and therefore FDK AAC Codec software may
26already be covered under those patent licenses when it is used for those
27licensed purposes only.
28
29Commercially-licensed AAC software libraries, including floating-point versions
30with enhanced sound quality, are also available from Fraunhofer. Users are
31encouraged to check the Fraunhofer website for additional applications
32information and documentation.
33
342.    COPYRIGHT LICENSE
35
36Redistribution and use in source and binary forms, with or without modification,
37are permitted without payment of copyright license fees provided that you
38satisfy the following conditions:
39
40You must retain the complete text of this software license in redistributions of
41the FDK AAC Codec or your modifications thereto in source code form.
42
43You must retain the complete text of this software license in the documentation
44and/or other materials provided with redistributions of the FDK AAC Codec or
45your modifications thereto in binary form. You must make available free of
46charge copies of the complete source code of the FDK AAC Codec and your
47modifications thereto to recipients of copies in binary form.
48
49The name of Fraunhofer may not be used to endorse or promote products derived
50from this library without prior written permission.
51
52You may not charge copyright license fees for anyone to use, copy or distribute
53the FDK AAC Codec software or your modifications thereto.
54
55Your modified versions of the FDK AAC Codec must carry prominent notices stating
56that you changed the software and the date of any change. For modified versions
57of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59AAC Codec Library for Android."
60
613.    NO PATENT LICENSE
62
63NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65Fraunhofer provides no warranty of patent non-infringement with respect to this
66software.
67
68You may use this FDK AAC Codec software or modifications thereto only for
69purposes that are authorized by appropriate patent licenses.
70
714.    DISCLAIMER
72
73This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75including but not limited to the implied warranties of merchantability and
76fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78or consequential damages, including but not limited to procurement of substitute
79goods or services; loss of use, data, or profits, or business interruption,
80however caused and on any theory of liability, whether in contract, strict
81liability, or tort (including negligence), arising in any way out of the use of
82this software, even if advised of the possibility of such damage.
83
845.    CONTACT INFORMATION
85
86Fraunhofer Institute for Integrated Circuits IIS
87Attention: Audio and Multimedia Departments - FDK AAC LL
88Am Wolfsmantel 33
8991058 Erlangen, Germany
90
91www.iis.fraunhofer.de/amm
92amm-info@iis.fraunhofer.de
93----------------------------------------------------------------------------- */
94
95/**************************** SBR encoder library ******************************
96
97   Author(s):
98
99   Description:
100
101*******************************************************************************/
102
103/*!
104  \file
105  \brief  frequency scale $Revision: 95225 $
106*/
107
108#include "sbrenc_freq_sca.h"
109#include "sbr_misc.h"
110
111#include "genericStds.h"
112
113/*  StartFreq */
114static INT getStartFreq(INT fsCore, const INT start_freq);
115
116/* StopFreq */
117static INT getStopFreq(INT fsCore, const INT stop_freq);
118
119static INT numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor);
120static void CalcBands(INT *diff, INT start, INT stop, INT num_bands);
121static INT modifyBands(INT max_band, INT *diff, INT length);
122static void cumSum(INT start_value, INT *diff, INT length, UCHAR *start_adress);
123
124/*******************************************************************************
125 Functionname:  FDKsbrEnc_getSbrStartFreqRAW
126 *******************************************************************************
127 Description:
128
129 Arguments:
130
131 Return:
132 *******************************************************************************/
133
134INT FDKsbrEnc_getSbrStartFreqRAW(INT startFreq, INT fsCore) {
135  INT result;
136
137  if (startFreq < 0 || startFreq > 15) {
138    return -1;
139  }
140  /* Update startFreq struct */
141  result = getStartFreq(fsCore, startFreq);
142
143  result =
144      (result * (fsCore >> 5) + 1) >> 1; /* (result*fsSBR/QMFbands+1)>>1; */
145
146  return (result);
147
148} /* End FDKsbrEnc_getSbrStartFreqRAW */
149
150/*******************************************************************************
151 Functionname:  getSbrStopFreq
152 *******************************************************************************
153 Description:
154
155 Arguments:
156
157 Return:
158 *******************************************************************************/
159INT FDKsbrEnc_getSbrStopFreqRAW(INT stopFreq, INT fsCore) {
160  INT result;
161
162  if (stopFreq < 0 || stopFreq > 13) return -1;
163
164  /* Uppdate stopFreq struct */
165  result = getStopFreq(fsCore, stopFreq);
166  result =
167      (result * (fsCore >> 5) + 1) >> 1; /* (result*fsSBR/QMFbands+1)>>1; */
168
169  return (result);
170} /* End getSbrStopFreq */
171
172/*******************************************************************************
173 Functionname:  getStartFreq
174 *******************************************************************************
175 Description:
176
177 Arguments:  fsCore - core sampling rate
178
179
180 Return:
181 *******************************************************************************/
182static INT getStartFreq(INT fsCore, const INT start_freq) {
183  INT k0_min;
184
185  switch (fsCore) {
186    case 8000:
187      k0_min = 24; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */
188      break;
189    case 11025:
190      k0_min = 17; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */
191      break;
192    case 12000:
193      k0_min = 16; /* (3000 * nQmfChannels / fsSBR ) + 0.5 */
194      break;
195    case 16000:
196      k0_min = 16; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */
197      break;
198    case 22050:
199      k0_min = 12; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */
200      break;
201    case 24000:
202      k0_min = 11; /* (4000 * nQmfChannels / fsSBR ) + 0.5 */
203      break;
204    case 32000:
205      k0_min = 10; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
206      break;
207    case 44100:
208      k0_min = 7; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
209      break;
210    case 48000:
211      k0_min = 7; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
212      break;
213    case 96000:
214      k0_min = 3; /* (5000 * nQmfChannels / fsSBR ) + 0.5 */
215      break;
216    default:
217      k0_min = 11; /* illegal fs */
218  }
219
220  switch (fsCore) {
221    case 8000: {
222      INT v_offset[] = {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7};
223      return (k0_min + v_offset[start_freq]);
224    }
225    case 11025: {
226      INT v_offset[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13};
227      return (k0_min + v_offset[start_freq]);
228    }
229    case 12000: {
230      INT v_offset[] = {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16};
231      return (k0_min + v_offset[start_freq]);
232    }
233    case 16000: {
234      INT v_offset[] = {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16};
235      return (k0_min + v_offset[start_freq]);
236    }
237    case 22050:
238    case 24000:
239    case 32000: {
240      INT v_offset[] = {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20};
241      return (k0_min + v_offset[start_freq]);
242    }
243    case 44100:
244    case 48000:
245    case 96000: {
246      INT v_offset[] = {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24};
247      return (k0_min + v_offset[start_freq]);
248    }
249    default: {
250      INT v_offset[] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24, 28, 33};
251      return (k0_min + v_offset[start_freq]);
252    }
253  }
254} /* End getStartFreq */
255
256/*******************************************************************************
257 Functionname:  getStopFreq
258 *******************************************************************************
259 Description:
260
261 Arguments:
262
263 Return:
264 *******************************************************************************/
265static INT getStopFreq(INT fsCore, const INT stop_freq) {
266  INT result, i;
267  INT k1_min;
268  INT v_dstop[13];
269
270  INT *v_stop_freq = NULL;
271  INT v_stop_freq_16[14] = {48, 49, 50, 51, 52, 54, 55,
272                            56, 57, 59, 60, 61, 63, 64};
273  INT v_stop_freq_22[14] = {35, 37, 38, 40, 42, 44, 46,
274                            48, 51, 53, 56, 58, 61, 64};
275  INT v_stop_freq_24[14] = {32, 34, 36, 38, 40, 42, 44,
276                            46, 49, 52, 55, 58, 61, 64};
277  INT v_stop_freq_32[14] = {32, 34, 36, 38, 40, 42, 44,
278                            46, 49, 52, 55, 58, 61, 64};
279  INT v_stop_freq_44[14] = {23, 25, 27, 29, 32, 34, 37,
280                            40, 43, 47, 51, 55, 59, 64};
281  INT v_stop_freq_48[14] = {21, 23, 25, 27, 30, 32, 35,
282                            38, 42, 45, 49, 54, 59, 64};
283  INT v_stop_freq_64[14] = {20, 22, 24, 26, 29, 31, 34,
284                            37, 41, 45, 49, 54, 59, 64};
285  INT v_stop_freq_88[14] = {15, 17, 19, 21, 23, 26, 29,
286                            33, 37, 41, 46, 51, 57, 64};
287  INT v_stop_freq_96[14] = {13, 15, 17, 19, 21, 24, 27,
288                            31, 35, 39, 44, 50, 57, 64};
289  INT v_stop_freq_192[14] = {7,  8,  10, 12, 14, 16, 19,
290                             23, 27, 32, 38, 46, 54, 64};
291
292  switch (fsCore) {
293    case 8000:
294      k1_min = 48;
295      v_stop_freq = v_stop_freq_16;
296      break;
297    case 11025:
298      k1_min = 35;
299      v_stop_freq = v_stop_freq_22;
300      break;
301    case 12000:
302      k1_min = 32;
303      v_stop_freq = v_stop_freq_24;
304      break;
305    case 16000:
306      k1_min = 32;
307      v_stop_freq = v_stop_freq_32;
308      break;
309    case 22050:
310      k1_min = 23;
311      v_stop_freq = v_stop_freq_44;
312      break;
313    case 24000:
314      k1_min = 21;
315      v_stop_freq = v_stop_freq_48;
316      break;
317    case 32000:
318      k1_min = 20;
319      v_stop_freq = v_stop_freq_64;
320      break;
321    case 44100:
322      k1_min = 15;
323      v_stop_freq = v_stop_freq_88;
324      break;
325    case 48000:
326      k1_min = 13;
327      v_stop_freq = v_stop_freq_96;
328      break;
329    case 96000:
330      k1_min = 7;
331      v_stop_freq = v_stop_freq_192;
332      break;
333    default:
334      k1_min = 21; /* illegal fs  */
335  }
336
337  /* Ensure increasing bandwidth */
338  for (i = 0; i <= 12; i++) {
339    v_dstop[i] = v_stop_freq[i + 1] - v_stop_freq[i];
340  }
341
342  FDKsbrEnc_Shellsort_int(v_dstop, 13); /* Sort bandwidth changes */
343
344  result = k1_min;
345  for (i = 0; i < stop_freq; i++) {
346    result = result + v_dstop[i];
347  }
348
349  return (result);
350
351} /* End getStopFreq */
352
353/*******************************************************************************
354 Functionname:  FDKsbrEnc_FindStartAndStopBand
355 *******************************************************************************
356 Description:
357
358 Arguments:     srSbr            SBR sampling freqency
359                srCore           AAC core sampling freqency
360                noChannels       Number of QMF channels
361                startFreq        SBR start frequency in QMF bands
362                stopFreq         SBR start frequency in QMF bands
363
364               *k0               Output parameter
365               *k2               Output parameter
366
367 Return:       Error code (0 is OK)
368 *******************************************************************************/
369INT FDKsbrEnc_FindStartAndStopBand(const INT srSbr, const INT srCore,
370                                   const INT noChannels, const INT startFreq,
371                                   const INT stopFreq, INT *k0, INT *k2) {
372  /* Update startFreq struct */
373  *k0 = getStartFreq(srCore, startFreq);
374
375  /* Test if start freq is outside corecoder range */
376  if (srSbr * noChannels < *k0 * srCore) {
377    return (
378        1); /* raise the cross-over frequency and/or lower the number
379               of target bands per octave (or lower the sampling frequency) */
380  }
381
382  /*Update stopFreq struct */
383  if (stopFreq < 14) {
384    *k2 = getStopFreq(srCore, stopFreq);
385  } else if (stopFreq == 14) {
386    *k2 = 2 * *k0;
387  } else {
388    *k2 = 3 * *k0;
389  }
390
391  /* limit to Nyqvist */
392  if (*k2 > noChannels) {
393    *k2 = noChannels;
394  }
395
396  /* Test for invalid  k0 k2 combinations */
397  if ((srCore == 22050) && ((*k2 - *k0) > MAX_FREQ_COEFFS_FS44100))
398    return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for
399                   fs=44.1kHz */
400
401  if ((srCore >= 24000) && ((*k2 - *k0) > MAX_FREQ_COEFFS_FS48000))
402    return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for
403                   fs>=48kHz */
404
405  if ((*k2 - *k0) > MAX_FREQ_COEFFS)
406    return (1); /*Number of bands exceeds valid range of MAX_FREQ_COEFFS */
407
408  if ((*k2 - *k0) < 0) return (1); /* Number of bands is negative */
409
410  return (0);
411}
412
413/*******************************************************************************
414 Functionname:  FDKsbrEnc_UpdateFreqScale
415 *******************************************************************************
416 Description:
417
418 Arguments:
419
420 Return:
421 *******************************************************************************/
422INT FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, const INT k0,
423                              const INT k2, const INT freqScale,
424                              const INT alterScale)
425
426{
427  INT b_p_o = 0; /* bands_per_octave */
428  FIXP_DBL warp = FL2FXCONST_DBL(0.0f);
429  INT dk = 0;
430
431  /* Internal variables */
432  INT k1 = 0, i;
433  INT num_bands0;
434  INT num_bands1;
435  INT diff_tot[MAX_OCTAVE + MAX_SECOND_REGION];
436  INT *diff0 = diff_tot;
437  INT *diff1 = diff_tot + MAX_OCTAVE;
438  INT k2_achived;
439  INT k2_diff;
440  INT incr = 0;
441
442  /* Init */
443  if (freqScale == 1) b_p_o = 12;
444  if (freqScale == 2) b_p_o = 10;
445  if (freqScale == 3) b_p_o = 8;
446
447  if (freqScale > 0) /*Bark*/
448  {
449    if (alterScale == 0)
450      warp = FL2FXCONST_DBL(0.5f); /* 1.0/(1.0*2.0) */
451    else
452      warp = FL2FXCONST_DBL(1.0f / 2.6f); /* 1.0/(1.3*2.0); */
453
454    if (4 * k2 >= 9 * k0) /*two or more regions (how many times the basis band
455                             is copied)*/
456    {
457      k1 = 2 * k0;
458
459      num_bands0 = numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f));
460      num_bands1 = numberOfBands(b_p_o, k1, k2, warp);
461
462      CalcBands(diff0, k0, k1, num_bands0);       /*CalcBands1 => diff0 */
463      FDKsbrEnc_Shellsort_int(diff0, num_bands0); /*SortBands sort diff0 */
464
465      if (diff0[0] == 0) /* too wide FB bands for target tuning */
466      {
467        return (1); /* raise the cross-over frequency and/or lower the number
468                       of target bands per octave (or lower the sampling
469                       frequency */
470      }
471
472      cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */
473
474      CalcBands(diff1, k1, k2, num_bands1);       /* CalcBands2 => diff1 */
475      FDKsbrEnc_Shellsort_int(diff1, num_bands1); /* SortBands sort diff1 */
476      if (diff0[num_bands0 - 1] > diff1[0])       /* max(1) > min(2) */
477      {
478        if (modifyBands(diff0[num_bands0 - 1], diff1, num_bands1)) return (1);
479      }
480
481      /* Add 2'nd region */
482      cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]);
483      *h_num_bands = num_bands0 + num_bands1; /* Output nr of bands */
484
485    } else /* one region */
486    {
487      k1 = k2;
488
489      num_bands0 = numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f));
490      CalcBands(diff0, k0, k1, num_bands0);       /* CalcBands1 => diff0 */
491      FDKsbrEnc_Shellsort_int(diff0, num_bands0); /* SortBands sort diff0 */
492
493      if (diff0[0] == 0) /* too wide FB bands for target tuning */
494      {
495        return (1); /* raise the cross-over frequency and/or lower the number
496                       of target bands per octave (or lower the sampling
497                       frequency */
498      }
499
500      cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */
501      *h_num_bands = num_bands0;                 /* Output nr of bands */
502    }
503  } else /* Linear mode */
504  {
505    if (alterScale == 0) {
506      dk = 1;
507      num_bands0 = 2 * ((k2 - k0) / 2); /* FLOOR to get to few number of bands*/
508    } else {
509      dk = 2;
510      num_bands0 =
511          2 * (((k2 - k0) / dk + 1) / 2); /* ROUND to get closest fit */
512    }
513
514    k2_achived = k0 + num_bands0 * dk;
515    k2_diff = k2 - k2_achived;
516
517    for (i = 0; i < num_bands0; i++) diff_tot[i] = dk;
518
519    /* If linear scale wasn't achived */
520    /* and we got wide SBR are */
521    if (k2_diff < 0) {
522      incr = 1;
523      i = 0;
524    }
525
526    /* If linear scale wasn't achived */
527    /* and we got small SBR are */
528    if (k2_diff > 0) {
529      incr = -1;
530      i = num_bands0 - 1;
531    }
532
533    /* Adjust diff vector to get sepc. SBR range */
534    while (k2_diff != 0) {
535      diff_tot[i] = diff_tot[i] - incr;
536      i = i + incr;
537      k2_diff = k2_diff + incr;
538    }
539
540    cumSum(k0, diff_tot, num_bands0, v_k_master); /* cumsum */
541    *h_num_bands = num_bands0;                    /* Output nr of bands */
542  }
543
544  if (*h_num_bands < 1) return (1); /*To small sbr area */
545
546  return (0);
547} /* End FDKsbrEnc_UpdateFreqScale */
548
549static INT numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor) {
550  INT result = 0;
551  /* result = 2* (INT) ( (double)b_p_o *
552   * (double)(FDKlog((double)stop/(double)start)/FDKlog((double)2)) *
553   * (double)FX_DBL2FL(warp_factor) + 0.5); */
554  result = ((b_p_o * fMult((CalcLdInt(stop) - CalcLdInt(start)), warp_factor) +
555             (FL2FX_DBL(0.5f) >> LD_DATA_SHIFT)) >>
556            ((DFRACT_BITS - 1) - LD_DATA_SHIFT))
557           << 1; /* do not optimize anymore (rounding!!) */
558
559  return (result);
560}
561
562static void CalcBands(INT *diff, INT start, INT stop, INT num_bands) {
563  INT i, qb, qe, qtmp;
564  INT previous;
565  INT current;
566  FIXP_DBL base, exp, tmp;
567
568  previous = start;
569  for (i = 1; i <= num_bands; i++) {
570    base = fDivNorm((FIXP_DBL)stop, (FIXP_DBL)start, &qb);
571    exp = fDivNorm((FIXP_DBL)i, (FIXP_DBL)num_bands, &qe);
572    tmp = fPow(base, qb, exp, qe, &qtmp);
573    tmp = fMult(tmp, (FIXP_DBL)(start << 24));
574    current = (INT)scaleValue(tmp, qtmp - 23);
575    current = (current + 1) >> 1; /* rounding*/
576    diff[i - 1] = current - previous;
577    previous = current;
578  }
579
580} /* End CalcBands */
581
582static void cumSum(INT start_value, INT *diff, INT length,
583                   UCHAR *start_adress) {
584  INT i;
585  start_adress[0] = start_value;
586  for (i = 1; i <= length; i++)
587    start_adress[i] = start_adress[i - 1] + diff[i - 1];
588} /* End cumSum */
589
590static INT modifyBands(INT max_band_previous, INT *diff, INT length) {
591  INT change = max_band_previous - diff[0];
592
593  /* Limit the change so that the last band cannot get narrower than the first
594   * one */
595  if (change > (diff[length - 1] - diff[0]) / 2)
596    change = (diff[length - 1] - diff[0]) / 2;
597
598  diff[0] += change;
599  diff[length - 1] -= change;
600  FDKsbrEnc_Shellsort_int(diff, length);
601
602  return (0);
603} /* End modifyBands */
604
605/*******************************************************************************
606 Functionname:  FDKsbrEnc_UpdateHiRes
607 *******************************************************************************
608 Description:
609
610
611 Arguments:
612
613 Return:
614 *******************************************************************************/
615INT FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, INT *num_hires, UCHAR *v_k_master,
616                          INT num_master, INT *xover_band) {
617  INT i;
618  INT max1, max2;
619
620  if ((v_k_master[*xover_band] >
621       32) || /* v_k_master[*xover_band] > noQMFChannels(dualRate)/divider */
622      (*xover_band > num_master)) {
623    /* xover_band error, too big for this startFreq. Will be clipped */
624
625    /* Calculate maximum value for xover_band */
626    max1 = 0;
627    max2 = num_master;
628    while ((v_k_master[max1 + 1] < 32) && /* noQMFChannels(dualRate)/divider */
629           ((max1 + 1) < max2)) {
630      max1++;
631    }
632
633    *xover_band = max1;
634  }
635
636  *num_hires = num_master - *xover_band;
637  for (i = *xover_band; i <= num_master; i++) {
638    h_hires[i - *xover_band] = v_k_master[i];
639  }
640
641  return (0);
642} /* End FDKsbrEnc_UpdateHiRes */
643
644/*******************************************************************************
645 Functionname:  FDKsbrEnc_UpdateLoRes
646 *******************************************************************************
647 Description:
648
649 Arguments:
650
651 Return:
652 *******************************************************************************/
653void FDKsbrEnc_UpdateLoRes(UCHAR *h_lores, INT *num_lores, UCHAR *h_hires,
654                           INT num_hires) {
655  INT i;
656
657  if (num_hires % 2 == 0) /* if even number of hires bands */
658  {
659    *num_lores = num_hires / 2;
660    /* Use every second lores=hires[0,2,4...] */
661    for (i = 0; i <= *num_lores; i++) h_lores[i] = h_hires[i * 2];
662
663  } else /* odd number of hires which means xover is odd */
664  {
665    *num_lores = (num_hires + 1) / 2;
666
667    /* Use lores=hires[0,1,3,5 ...] */
668    h_lores[0] = h_hires[0];
669    for (i = 1; i <= *num_lores; i++) {
670      h_lores[i] = h_hires[i * 2 - 1];
671    }
672  }
673
674} /* End FDKsbrEnc_UpdateLoRes */
675