1*e5436536SAndroid Build Coastguard Worker /* -----------------------------------------------------------------------------
2*e5436536SAndroid Build Coastguard Worker Software License for The Fraunhofer FDK AAC Codec Library for Android
3*e5436536SAndroid Build Coastguard Worker
4*e5436536SAndroid Build Coastguard Worker © Copyright 1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
5*e5436536SAndroid Build Coastguard Worker Forschung e.V. All rights reserved.
6*e5436536SAndroid Build Coastguard Worker
7*e5436536SAndroid Build Coastguard Worker 1. INTRODUCTION
8*e5436536SAndroid Build Coastguard Worker The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9*e5436536SAndroid Build Coastguard Worker that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10*e5436536SAndroid Build Coastguard Worker scheme for digital audio. This FDK AAC Codec software is intended to be used on
11*e5436536SAndroid Build Coastguard Worker a wide variety of Android devices.
12*e5436536SAndroid Build Coastguard Worker
13*e5436536SAndroid Build Coastguard Worker AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14*e5436536SAndroid Build Coastguard Worker general perceptual audio codecs. AAC-ELD is considered the best-performing
15*e5436536SAndroid Build Coastguard Worker full-bandwidth communications codec by independent studies and is widely
16*e5436536SAndroid Build Coastguard Worker deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17*e5436536SAndroid Build Coastguard Worker specifications.
18*e5436536SAndroid Build Coastguard Worker
19*e5436536SAndroid Build Coastguard Worker Patent licenses for necessary patent claims for the FDK AAC Codec (including
20*e5436536SAndroid Build Coastguard Worker those of Fraunhofer) may be obtained through Via Licensing
21*e5436536SAndroid Build Coastguard Worker (www.vialicensing.com) or through the respective patent owners individually for
22*e5436536SAndroid Build Coastguard Worker the purpose of encoding or decoding bit streams in products that are compliant
23*e5436536SAndroid Build Coastguard Worker with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24*e5436536SAndroid Build Coastguard Worker Android devices already license these patent claims through Via Licensing or
25*e5436536SAndroid Build Coastguard Worker directly from the patent owners, and therefore FDK AAC Codec software may
26*e5436536SAndroid Build Coastguard Worker already be covered under those patent licenses when it is used for those
27*e5436536SAndroid Build Coastguard Worker licensed purposes only.
28*e5436536SAndroid Build Coastguard Worker
29*e5436536SAndroid Build Coastguard Worker Commercially-licensed AAC software libraries, including floating-point versions
30*e5436536SAndroid Build Coastguard Worker with enhanced sound quality, are also available from Fraunhofer. Users are
31*e5436536SAndroid Build Coastguard Worker encouraged to check the Fraunhofer website for additional applications
32*e5436536SAndroid Build Coastguard Worker information and documentation.
33*e5436536SAndroid Build Coastguard Worker
34*e5436536SAndroid Build Coastguard Worker 2. COPYRIGHT LICENSE
35*e5436536SAndroid Build Coastguard Worker
36*e5436536SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification,
37*e5436536SAndroid Build Coastguard Worker are permitted without payment of copyright license fees provided that you
38*e5436536SAndroid Build Coastguard Worker satisfy the following conditions:
39*e5436536SAndroid Build Coastguard Worker
40*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in redistributions of
41*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec or your modifications thereto in source code form.
42*e5436536SAndroid Build Coastguard Worker
43*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in the documentation
44*e5436536SAndroid Build Coastguard Worker and/or other materials provided with redistributions of the FDK AAC Codec or
45*e5436536SAndroid Build Coastguard Worker your modifications thereto in binary form. You must make available free of
46*e5436536SAndroid Build Coastguard Worker charge copies of the complete source code of the FDK AAC Codec and your
47*e5436536SAndroid Build Coastguard Worker modifications thereto to recipients of copies in binary form.
48*e5436536SAndroid Build Coastguard Worker
49*e5436536SAndroid Build Coastguard Worker The name of Fraunhofer may not be used to endorse or promote products derived
50*e5436536SAndroid Build Coastguard Worker from this library without prior written permission.
51*e5436536SAndroid Build Coastguard Worker
52*e5436536SAndroid Build Coastguard Worker You may not charge copyright license fees for anyone to use, copy or distribute
53*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec software or your modifications thereto.
54*e5436536SAndroid Build Coastguard Worker
55*e5436536SAndroid Build Coastguard Worker Your modified versions of the FDK AAC Codec must carry prominent notices stating
56*e5436536SAndroid Build Coastguard Worker that you changed the software and the date of any change. For modified versions
57*e5436536SAndroid Build Coastguard Worker of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58*e5436536SAndroid Build Coastguard Worker must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59*e5436536SAndroid Build Coastguard Worker AAC Codec Library for Android."
60*e5436536SAndroid Build Coastguard Worker
61*e5436536SAndroid Build Coastguard Worker 3. NO PATENT LICENSE
62*e5436536SAndroid Build Coastguard Worker
63*e5436536SAndroid Build Coastguard Worker NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64*e5436536SAndroid Build Coastguard Worker limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65*e5436536SAndroid Build Coastguard Worker Fraunhofer provides no warranty of patent non-infringement with respect to this
66*e5436536SAndroid Build Coastguard Worker software.
67*e5436536SAndroid Build Coastguard Worker
68*e5436536SAndroid Build Coastguard Worker You may use this FDK AAC Codec software or modifications thereto only for
69*e5436536SAndroid Build Coastguard Worker purposes that are authorized by appropriate patent licenses.
70*e5436536SAndroid Build Coastguard Worker
71*e5436536SAndroid Build Coastguard Worker 4. DISCLAIMER
72*e5436536SAndroid Build Coastguard Worker
73*e5436536SAndroid Build Coastguard Worker This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74*e5436536SAndroid Build Coastguard Worker holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75*e5436536SAndroid Build Coastguard Worker including but not limited to the implied warranties of merchantability and
76*e5436536SAndroid Build Coastguard Worker fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77*e5436536SAndroid Build Coastguard Worker CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78*e5436536SAndroid Build Coastguard Worker or consequential damages, including but not limited to procurement of substitute
79*e5436536SAndroid Build Coastguard Worker goods or services; loss of use, data, or profits, or business interruption,
80*e5436536SAndroid Build Coastguard Worker however caused and on any theory of liability, whether in contract, strict
81*e5436536SAndroid Build Coastguard Worker liability, or tort (including negligence), arising in any way out of the use of
82*e5436536SAndroid Build Coastguard Worker this software, even if advised of the possibility of such damage.
83*e5436536SAndroid Build Coastguard Worker
84*e5436536SAndroid Build Coastguard Worker 5. CONTACT INFORMATION
85*e5436536SAndroid Build Coastguard Worker
86*e5436536SAndroid Build Coastguard Worker Fraunhofer Institute for Integrated Circuits IIS
87*e5436536SAndroid Build Coastguard Worker Attention: Audio and Multimedia Departments - FDK AAC LL
88*e5436536SAndroid Build Coastguard Worker Am Wolfsmantel 33
89*e5436536SAndroid Build Coastguard Worker 91058 Erlangen, Germany
90*e5436536SAndroid Build Coastguard Worker
91*e5436536SAndroid Build Coastguard Worker www.iis.fraunhofer.de/amm
92*e5436536SAndroid Build Coastguard Worker [email protected]
93*e5436536SAndroid Build Coastguard Worker ----------------------------------------------------------------------------- */
94*e5436536SAndroid Build Coastguard Worker
95*e5436536SAndroid Build Coastguard Worker /**************************** SBR decoder library ******************************
96*e5436536SAndroid Build Coastguard Worker
97*e5436536SAndroid Build Coastguard Worker Author(s):
98*e5436536SAndroid Build Coastguard Worker
99*e5436536SAndroid Build Coastguard Worker Description:
100*e5436536SAndroid Build Coastguard Worker
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker
103*e5436536SAndroid Build Coastguard Worker /*!
104*e5436536SAndroid Build Coastguard Worker \file
105*e5436536SAndroid Build Coastguard Worker \brief Frequency scale calculation
106*e5436536SAndroid Build Coastguard Worker */
107*e5436536SAndroid Build Coastguard Worker
108*e5436536SAndroid Build Coastguard Worker #include "sbrdec_freq_sca.h"
109*e5436536SAndroid Build Coastguard Worker
110*e5436536SAndroid Build Coastguard Worker #include "transcendent.h"
111*e5436536SAndroid Build Coastguard Worker #include "sbr_rom.h"
112*e5436536SAndroid Build Coastguard Worker #include "env_extr.h"
113*e5436536SAndroid Build Coastguard Worker
114*e5436536SAndroid Build Coastguard Worker #include "genericStds.h" /* need log() for debug-code only */
115*e5436536SAndroid Build Coastguard Worker
116*e5436536SAndroid Build Coastguard Worker #define MAX_OCTAVE 29
117*e5436536SAndroid Build Coastguard Worker #define MAX_SECOND_REGION 50
118*e5436536SAndroid Build Coastguard Worker
119*e5436536SAndroid Build Coastguard Worker static int numberOfBands(FIXP_SGL bpo_div16, int start, int stop, int warpFlag);
120*e5436536SAndroid Build Coastguard Worker static void CalcBands(UCHAR *diff, UCHAR start, UCHAR stop, UCHAR num_bands);
121*e5436536SAndroid Build Coastguard Worker static SBR_ERROR modifyBands(UCHAR max_band, UCHAR *diff, UCHAR length);
122*e5436536SAndroid Build Coastguard Worker static void cumSum(UCHAR start_value, UCHAR *diff, UCHAR length,
123*e5436536SAndroid Build Coastguard Worker UCHAR *start_adress);
124*e5436536SAndroid Build Coastguard Worker
125*e5436536SAndroid Build Coastguard Worker /*!
126*e5436536SAndroid Build Coastguard Worker \brief Retrieve QMF-band where the SBR range starts
127*e5436536SAndroid Build Coastguard Worker
128*e5436536SAndroid Build Coastguard Worker Convert startFreq which was read from the bitstream into a
129*e5436536SAndroid Build Coastguard Worker QMF-channel number.
130*e5436536SAndroid Build Coastguard Worker
131*e5436536SAndroid Build Coastguard Worker \return Number of start band
132*e5436536SAndroid Build Coastguard Worker */
getStartBand(UINT fs,UCHAR startFreq,UINT headerDataFlags)133*e5436536SAndroid Build Coastguard Worker static UCHAR getStartBand(
134*e5436536SAndroid Build Coastguard Worker UINT fs, /*!< Output sampling frequency */
135*e5436536SAndroid Build Coastguard Worker UCHAR startFreq, /*!< Index to table of possible start bands */
136*e5436536SAndroid Build Coastguard Worker UINT headerDataFlags) /*!< Info to SBR mode */
137*e5436536SAndroid Build Coastguard Worker {
138*e5436536SAndroid Build Coastguard Worker INT band;
139*e5436536SAndroid Build Coastguard Worker UINT fsMapped = fs;
140*e5436536SAndroid Build Coastguard Worker SBR_RATE rate = DUAL;
141*e5436536SAndroid Build Coastguard Worker
142*e5436536SAndroid Build Coastguard Worker if (headerDataFlags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
143*e5436536SAndroid Build Coastguard Worker if (headerDataFlags & SBRDEC_QUAD_RATE) {
144*e5436536SAndroid Build Coastguard Worker rate = QUAD;
145*e5436536SAndroid Build Coastguard Worker }
146*e5436536SAndroid Build Coastguard Worker fsMapped = sbrdec_mapToStdSampleRate(fs, 1);
147*e5436536SAndroid Build Coastguard Worker }
148*e5436536SAndroid Build Coastguard Worker
149*e5436536SAndroid Build Coastguard Worker FDK_ASSERT(2 * (rate + 1) <= (4));
150*e5436536SAndroid Build Coastguard Worker
151*e5436536SAndroid Build Coastguard Worker switch (fsMapped) {
152*e5436536SAndroid Build Coastguard Worker case 192000:
153*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_192[startFreq];
154*e5436536SAndroid Build Coastguard Worker break;
155*e5436536SAndroid Build Coastguard Worker case 176400:
156*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_176[startFreq];
157*e5436536SAndroid Build Coastguard Worker break;
158*e5436536SAndroid Build Coastguard Worker case 128000:
159*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_128[startFreq];
160*e5436536SAndroid Build Coastguard Worker break;
161*e5436536SAndroid Build Coastguard Worker case 96000:
162*e5436536SAndroid Build Coastguard Worker case 88200:
163*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_88[rate][startFreq];
164*e5436536SAndroid Build Coastguard Worker break;
165*e5436536SAndroid Build Coastguard Worker case 64000:
166*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_64[rate][startFreq];
167*e5436536SAndroid Build Coastguard Worker break;
168*e5436536SAndroid Build Coastguard Worker case 48000:
169*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_48[rate][startFreq];
170*e5436536SAndroid Build Coastguard Worker break;
171*e5436536SAndroid Build Coastguard Worker case 44100:
172*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_44[rate][startFreq];
173*e5436536SAndroid Build Coastguard Worker break;
174*e5436536SAndroid Build Coastguard Worker case 40000:
175*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_40[rate][startFreq];
176*e5436536SAndroid Build Coastguard Worker break;
177*e5436536SAndroid Build Coastguard Worker case 32000:
178*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_32[rate][startFreq];
179*e5436536SAndroid Build Coastguard Worker break;
180*e5436536SAndroid Build Coastguard Worker case 24000:
181*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_24[rate][startFreq];
182*e5436536SAndroid Build Coastguard Worker break;
183*e5436536SAndroid Build Coastguard Worker case 22050:
184*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_22[rate][startFreq];
185*e5436536SAndroid Build Coastguard Worker break;
186*e5436536SAndroid Build Coastguard Worker case 16000:
187*e5436536SAndroid Build Coastguard Worker band = FDK_sbrDecoder_sbr_start_freq_16[rate][startFreq];
188*e5436536SAndroid Build Coastguard Worker break;
189*e5436536SAndroid Build Coastguard Worker default:
190*e5436536SAndroid Build Coastguard Worker band = 255;
191*e5436536SAndroid Build Coastguard Worker }
192*e5436536SAndroid Build Coastguard Worker
193*e5436536SAndroid Build Coastguard Worker return band;
194*e5436536SAndroid Build Coastguard Worker }
195*e5436536SAndroid Build Coastguard Worker
196*e5436536SAndroid Build Coastguard Worker /*!
197*e5436536SAndroid Build Coastguard Worker \brief Retrieve QMF-band where the SBR range starts
198*e5436536SAndroid Build Coastguard Worker
199*e5436536SAndroid Build Coastguard Worker Convert startFreq which was read from the bitstream into a
200*e5436536SAndroid Build Coastguard Worker QMF-channel number.
201*e5436536SAndroid Build Coastguard Worker
202*e5436536SAndroid Build Coastguard Worker \return Number of start band
203*e5436536SAndroid Build Coastguard Worker */
getStopBand(UINT fs,UCHAR stopFreq,UINT headerDataFlags,UCHAR k0)204*e5436536SAndroid Build Coastguard Worker static UCHAR getStopBand(
205*e5436536SAndroid Build Coastguard Worker UINT fs, /*!< Output sampling frequency */
206*e5436536SAndroid Build Coastguard Worker UCHAR stopFreq, /*!< Index to table of possible start bands */
207*e5436536SAndroid Build Coastguard Worker UINT headerDataFlags, /*!< Info to SBR mode */
208*e5436536SAndroid Build Coastguard Worker UCHAR k0) /*!< Start freq index */
209*e5436536SAndroid Build Coastguard Worker {
210*e5436536SAndroid Build Coastguard Worker UCHAR k2;
211*e5436536SAndroid Build Coastguard Worker
212*e5436536SAndroid Build Coastguard Worker if (stopFreq < 14) {
213*e5436536SAndroid Build Coastguard Worker INT stopMin;
214*e5436536SAndroid Build Coastguard Worker INT num = 2 * (64);
215*e5436536SAndroid Build Coastguard Worker UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION];
216*e5436536SAndroid Build Coastguard Worker UCHAR *diff0 = diff_tot;
217*e5436536SAndroid Build Coastguard Worker UCHAR *diff1 = diff_tot + MAX_OCTAVE;
218*e5436536SAndroid Build Coastguard Worker
219*e5436536SAndroid Build Coastguard Worker if (headerDataFlags & SBRDEC_QUAD_RATE) {
220*e5436536SAndroid Build Coastguard Worker num >>= 1;
221*e5436536SAndroid Build Coastguard Worker }
222*e5436536SAndroid Build Coastguard Worker
223*e5436536SAndroid Build Coastguard Worker if (fs < 32000) {
224*e5436536SAndroid Build Coastguard Worker stopMin = (((2 * 6000 * num) / fs) + 1) >> 1;
225*e5436536SAndroid Build Coastguard Worker } else {
226*e5436536SAndroid Build Coastguard Worker if (fs < 64000) {
227*e5436536SAndroid Build Coastguard Worker stopMin = (((2 * 8000 * num) / fs) + 1) >> 1;
228*e5436536SAndroid Build Coastguard Worker } else {
229*e5436536SAndroid Build Coastguard Worker stopMin = (((2 * 10000 * num) / fs) + 1) >> 1;
230*e5436536SAndroid Build Coastguard Worker }
231*e5436536SAndroid Build Coastguard Worker }
232*e5436536SAndroid Build Coastguard Worker
233*e5436536SAndroid Build Coastguard Worker stopMin = fMin(stopMin, 64);
234*e5436536SAndroid Build Coastguard Worker
235*e5436536SAndroid Build Coastguard Worker /*
236*e5436536SAndroid Build Coastguard Worker Choose a stop band between k1 and 64 depending on stopFreq (0..13),
237*e5436536SAndroid Build Coastguard Worker based on a logarithmic scale.
238*e5436536SAndroid Build Coastguard Worker The vectors diff0 and diff1 are used temporarily here.
239*e5436536SAndroid Build Coastguard Worker */
240*e5436536SAndroid Build Coastguard Worker CalcBands(diff0, stopMin, 64, 13);
241*e5436536SAndroid Build Coastguard Worker shellsort(diff0, 13);
242*e5436536SAndroid Build Coastguard Worker cumSum(stopMin, diff0, 13, diff1);
243*e5436536SAndroid Build Coastguard Worker k2 = diff1[stopFreq];
244*e5436536SAndroid Build Coastguard Worker } else if (stopFreq == 14)
245*e5436536SAndroid Build Coastguard Worker k2 = 2 * k0;
246*e5436536SAndroid Build Coastguard Worker else
247*e5436536SAndroid Build Coastguard Worker k2 = 3 * k0;
248*e5436536SAndroid Build Coastguard Worker
249*e5436536SAndroid Build Coastguard Worker /* Limit to Nyquist */
250*e5436536SAndroid Build Coastguard Worker if (k2 > (64)) k2 = (64);
251*e5436536SAndroid Build Coastguard Worker
252*e5436536SAndroid Build Coastguard Worker /* Range checks */
253*e5436536SAndroid Build Coastguard Worker /* 1 <= difference <= 48; 1 <= fs <= 96000 */
254*e5436536SAndroid Build Coastguard Worker {
255*e5436536SAndroid Build Coastguard Worker UCHAR max_freq_coeffs = (headerDataFlags & SBRDEC_QUAD_RATE)
256*e5436536SAndroid Build Coastguard Worker ? MAX_FREQ_COEFFS_QUAD_RATE
257*e5436536SAndroid Build Coastguard Worker : MAX_FREQ_COEFFS;
258*e5436536SAndroid Build Coastguard Worker if (((k2 - k0) > max_freq_coeffs) || (k2 <= k0)) {
259*e5436536SAndroid Build Coastguard Worker return 255;
260*e5436536SAndroid Build Coastguard Worker }
261*e5436536SAndroid Build Coastguard Worker }
262*e5436536SAndroid Build Coastguard Worker
263*e5436536SAndroid Build Coastguard Worker if (headerDataFlags & SBRDEC_QUAD_RATE) {
264*e5436536SAndroid Build Coastguard Worker return k2; /* skip other checks: (k2 - k0) must be <=
265*e5436536SAndroid Build Coastguard Worker MAX_FREQ_COEFFS_QUAD_RATE for all fs */
266*e5436536SAndroid Build Coastguard Worker }
267*e5436536SAndroid Build Coastguard Worker if (headerDataFlags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
268*e5436536SAndroid Build Coastguard Worker /* 1 <= difference <= 35; 42000 <= fs <= 96000 */
269*e5436536SAndroid Build Coastguard Worker if ((fs >= 42000) && ((k2 - k0) > MAX_FREQ_COEFFS_FS44100)) {
270*e5436536SAndroid Build Coastguard Worker return 255;
271*e5436536SAndroid Build Coastguard Worker }
272*e5436536SAndroid Build Coastguard Worker /* 1 <= difference <= 32; 46009 <= fs <= 96000 */
273*e5436536SAndroid Build Coastguard Worker if ((fs >= 46009) && ((k2 - k0) > MAX_FREQ_COEFFS_FS48000)) {
274*e5436536SAndroid Build Coastguard Worker return 255;
275*e5436536SAndroid Build Coastguard Worker }
276*e5436536SAndroid Build Coastguard Worker } else {
277*e5436536SAndroid Build Coastguard Worker /* 1 <= difference <= 35; fs == 44100 */
278*e5436536SAndroid Build Coastguard Worker if ((fs == 44100) && ((k2 - k0) > MAX_FREQ_COEFFS_FS44100)) {
279*e5436536SAndroid Build Coastguard Worker return 255;
280*e5436536SAndroid Build Coastguard Worker }
281*e5436536SAndroid Build Coastguard Worker /* 1 <= difference <= 32; 48000 <= fs <= 96000 */
282*e5436536SAndroid Build Coastguard Worker if ((fs >= 48000) && ((k2 - k0) > MAX_FREQ_COEFFS_FS48000)) {
283*e5436536SAndroid Build Coastguard Worker return 255;
284*e5436536SAndroid Build Coastguard Worker }
285*e5436536SAndroid Build Coastguard Worker }
286*e5436536SAndroid Build Coastguard Worker
287*e5436536SAndroid Build Coastguard Worker return k2;
288*e5436536SAndroid Build Coastguard Worker }
289*e5436536SAndroid Build Coastguard Worker
290*e5436536SAndroid Build Coastguard Worker /*!
291*e5436536SAndroid Build Coastguard Worker \brief Generates master frequency tables
292*e5436536SAndroid Build Coastguard Worker
293*e5436536SAndroid Build Coastguard Worker Frequency tables are calculated according to the selected domain
294*e5436536SAndroid Build Coastguard Worker (linear/logarithmic) and granularity.
295*e5436536SAndroid Build Coastguard Worker IEC 14496-3 4.6.18.3.2.1
296*e5436536SAndroid Build Coastguard Worker
297*e5436536SAndroid Build Coastguard Worker \return errorCode, 0 if successful
298*e5436536SAndroid Build Coastguard Worker */
299*e5436536SAndroid Build Coastguard Worker SBR_ERROR
sbrdecUpdateFreqScale(UCHAR * v_k_master,UCHAR * numMaster,UINT fs,HANDLE_SBR_HEADER_DATA hHeaderData,UINT flags)300*e5436536SAndroid Build Coastguard Worker sbrdecUpdateFreqScale(
301*e5436536SAndroid Build Coastguard Worker UCHAR *v_k_master, /*!< Master table to be created */
302*e5436536SAndroid Build Coastguard Worker UCHAR *numMaster, /*!< Number of entries in master table */
303*e5436536SAndroid Build Coastguard Worker UINT fs, /*!< SBR working sampling rate */
304*e5436536SAndroid Build Coastguard Worker HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Control data from bitstream */
305*e5436536SAndroid Build Coastguard Worker UINT flags) {
306*e5436536SAndroid Build Coastguard Worker FIXP_SGL bpo_div16; /* bands_per_octave divided by 16 */
307*e5436536SAndroid Build Coastguard Worker INT dk = 0;
308*e5436536SAndroid Build Coastguard Worker
309*e5436536SAndroid Build Coastguard Worker /* Internal variables */
310*e5436536SAndroid Build Coastguard Worker UCHAR k0, k2, i;
311*e5436536SAndroid Build Coastguard Worker UCHAR num_bands0 = 0;
312*e5436536SAndroid Build Coastguard Worker UCHAR num_bands1 = 0;
313*e5436536SAndroid Build Coastguard Worker UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION];
314*e5436536SAndroid Build Coastguard Worker UCHAR *diff0 = diff_tot;
315*e5436536SAndroid Build Coastguard Worker UCHAR *diff1 = diff_tot + MAX_OCTAVE;
316*e5436536SAndroid Build Coastguard Worker INT k2_achived;
317*e5436536SAndroid Build Coastguard Worker INT k2_diff;
318*e5436536SAndroid Build Coastguard Worker INT incr = 0;
319*e5436536SAndroid Build Coastguard Worker
320*e5436536SAndroid Build Coastguard Worker /*
321*e5436536SAndroid Build Coastguard Worker Determine start band
322*e5436536SAndroid Build Coastguard Worker */
323*e5436536SAndroid Build Coastguard Worker if (flags & SBRDEC_QUAD_RATE) {
324*e5436536SAndroid Build Coastguard Worker fs >>= 1;
325*e5436536SAndroid Build Coastguard Worker }
326*e5436536SAndroid Build Coastguard Worker
327*e5436536SAndroid Build Coastguard Worker k0 = getStartBand(fs, hHeaderData->bs_data.startFreq, flags);
328*e5436536SAndroid Build Coastguard Worker if (k0 == 255) {
329*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
330*e5436536SAndroid Build Coastguard Worker }
331*e5436536SAndroid Build Coastguard Worker
332*e5436536SAndroid Build Coastguard Worker /*
333*e5436536SAndroid Build Coastguard Worker Determine stop band
334*e5436536SAndroid Build Coastguard Worker */
335*e5436536SAndroid Build Coastguard Worker k2 = getStopBand(fs, hHeaderData->bs_data.stopFreq, flags, k0);
336*e5436536SAndroid Build Coastguard Worker if (k2 == 255) {
337*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
338*e5436536SAndroid Build Coastguard Worker }
339*e5436536SAndroid Build Coastguard Worker
340*e5436536SAndroid Build Coastguard Worker if (hHeaderData->bs_data.freqScale > 0) { /* Bark */
341*e5436536SAndroid Build Coastguard Worker INT k1;
342*e5436536SAndroid Build Coastguard Worker
343*e5436536SAndroid Build Coastguard Worker if (hHeaderData->bs_data.freqScale == 1) {
344*e5436536SAndroid Build Coastguard Worker bpo_div16 = FL2FXCONST_SGL(12.0f / 16.0f);
345*e5436536SAndroid Build Coastguard Worker } else if (hHeaderData->bs_data.freqScale == 2) {
346*e5436536SAndroid Build Coastguard Worker bpo_div16 = FL2FXCONST_SGL(10.0f / 16.0f);
347*e5436536SAndroid Build Coastguard Worker } else {
348*e5436536SAndroid Build Coastguard Worker bpo_div16 = FL2FXCONST_SGL(8.0f / 16.0f);
349*e5436536SAndroid Build Coastguard Worker }
350*e5436536SAndroid Build Coastguard Worker
351*e5436536SAndroid Build Coastguard Worker /* Ref: ISO/IEC 23003-3, Figure 12 - Flowchart calculation of fMaster for
352*e5436536SAndroid Build Coastguard Worker * 4:1 system when bs_freq_scale > 0 */
353*e5436536SAndroid Build Coastguard Worker if (flags & SBRDEC_QUAD_RATE) {
354*e5436536SAndroid Build Coastguard Worker if ((SHORT)k0 < (SHORT)(bpo_div16 >> ((FRACT_BITS - 1) - 4))) {
355*e5436536SAndroid Build Coastguard Worker bpo_div16 = (FIXP_SGL)(k0 & (UCHAR)0xfe)
356*e5436536SAndroid Build Coastguard Worker << ((FRACT_BITS - 1) - 4); /* bpo_div16 = floor(k0/2)*2 */
357*e5436536SAndroid Build Coastguard Worker }
358*e5436536SAndroid Build Coastguard Worker }
359*e5436536SAndroid Build Coastguard Worker
360*e5436536SAndroid Build Coastguard Worker if (1000 * k2 > 2245 * k0) { /* Two or more regions */
361*e5436536SAndroid Build Coastguard Worker k1 = 2 * k0;
362*e5436536SAndroid Build Coastguard Worker
363*e5436536SAndroid Build Coastguard Worker num_bands0 = numberOfBands(bpo_div16, k0, k1, 0);
364*e5436536SAndroid Build Coastguard Worker num_bands1 =
365*e5436536SAndroid Build Coastguard Worker numberOfBands(bpo_div16, k1, k2, hHeaderData->bs_data.alterScale);
366*e5436536SAndroid Build Coastguard Worker if (num_bands0 < 1) {
367*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
368*e5436536SAndroid Build Coastguard Worker }
369*e5436536SAndroid Build Coastguard Worker if (num_bands1 < 1) {
370*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
371*e5436536SAndroid Build Coastguard Worker }
372*e5436536SAndroid Build Coastguard Worker
373*e5436536SAndroid Build Coastguard Worker CalcBands(diff0, k0, k1, num_bands0);
374*e5436536SAndroid Build Coastguard Worker shellsort(diff0, num_bands0);
375*e5436536SAndroid Build Coastguard Worker if (diff0[0] == 0) {
376*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
377*e5436536SAndroid Build Coastguard Worker }
378*e5436536SAndroid Build Coastguard Worker
379*e5436536SAndroid Build Coastguard Worker cumSum(k0, diff0, num_bands0, v_k_master);
380*e5436536SAndroid Build Coastguard Worker
381*e5436536SAndroid Build Coastguard Worker CalcBands(diff1, k1, k2, num_bands1);
382*e5436536SAndroid Build Coastguard Worker shellsort(diff1, num_bands1);
383*e5436536SAndroid Build Coastguard Worker if (diff0[num_bands0 - 1] > diff1[0]) {
384*e5436536SAndroid Build Coastguard Worker SBR_ERROR err;
385*e5436536SAndroid Build Coastguard Worker
386*e5436536SAndroid Build Coastguard Worker err = modifyBands(diff0[num_bands0 - 1], diff1, num_bands1);
387*e5436536SAndroid Build Coastguard Worker if (err) return SBRDEC_UNSUPPORTED_CONFIG;
388*e5436536SAndroid Build Coastguard Worker }
389*e5436536SAndroid Build Coastguard Worker
390*e5436536SAndroid Build Coastguard Worker /* Add 2nd region */
391*e5436536SAndroid Build Coastguard Worker cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]);
392*e5436536SAndroid Build Coastguard Worker *numMaster = num_bands0 + num_bands1; /* Output nr of bands */
393*e5436536SAndroid Build Coastguard Worker
394*e5436536SAndroid Build Coastguard Worker } else { /* Only one region */
395*e5436536SAndroid Build Coastguard Worker k1 = k2;
396*e5436536SAndroid Build Coastguard Worker
397*e5436536SAndroid Build Coastguard Worker num_bands0 = numberOfBands(bpo_div16, k0, k1, 0);
398*e5436536SAndroid Build Coastguard Worker if (num_bands0 < 1) {
399*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
400*e5436536SAndroid Build Coastguard Worker }
401*e5436536SAndroid Build Coastguard Worker CalcBands(diff0, k0, k1, num_bands0);
402*e5436536SAndroid Build Coastguard Worker shellsort(diff0, num_bands0);
403*e5436536SAndroid Build Coastguard Worker if (diff0[0] == 0) {
404*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
405*e5436536SAndroid Build Coastguard Worker }
406*e5436536SAndroid Build Coastguard Worker
407*e5436536SAndroid Build Coastguard Worker cumSum(k0, diff0, num_bands0, v_k_master);
408*e5436536SAndroid Build Coastguard Worker *numMaster = num_bands0; /* Output nr of bands */
409*e5436536SAndroid Build Coastguard Worker }
410*e5436536SAndroid Build Coastguard Worker } else { /* Linear mode */
411*e5436536SAndroid Build Coastguard Worker if (hHeaderData->bs_data.alterScale == 0) {
412*e5436536SAndroid Build Coastguard Worker dk = 1;
413*e5436536SAndroid Build Coastguard Worker /* FLOOR to get to few number of bands (next lower even number) */
414*e5436536SAndroid Build Coastguard Worker num_bands0 = (k2 - k0) & 254;
415*e5436536SAndroid Build Coastguard Worker } else {
416*e5436536SAndroid Build Coastguard Worker dk = 2;
417*e5436536SAndroid Build Coastguard Worker num_bands0 = (((k2 - k0) >> 1) + 1) & 254; /* ROUND to the closest fit */
418*e5436536SAndroid Build Coastguard Worker }
419*e5436536SAndroid Build Coastguard Worker
420*e5436536SAndroid Build Coastguard Worker if (num_bands0 < 1) {
421*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
422*e5436536SAndroid Build Coastguard Worker /* We must return already here because 'i' can become negative below. */
423*e5436536SAndroid Build Coastguard Worker }
424*e5436536SAndroid Build Coastguard Worker
425*e5436536SAndroid Build Coastguard Worker k2_achived = k0 + num_bands0 * dk;
426*e5436536SAndroid Build Coastguard Worker k2_diff = k2 - k2_achived;
427*e5436536SAndroid Build Coastguard Worker
428*e5436536SAndroid Build Coastguard Worker for (i = 0; i < num_bands0; i++) diff_tot[i] = dk;
429*e5436536SAndroid Build Coastguard Worker
430*e5436536SAndroid Build Coastguard Worker /* If linear scale wasn't achieved */
431*e5436536SAndroid Build Coastguard Worker /* and we got too wide SBR area */
432*e5436536SAndroid Build Coastguard Worker if (k2_diff < 0) {
433*e5436536SAndroid Build Coastguard Worker incr = 1;
434*e5436536SAndroid Build Coastguard Worker i = 0;
435*e5436536SAndroid Build Coastguard Worker }
436*e5436536SAndroid Build Coastguard Worker
437*e5436536SAndroid Build Coastguard Worker /* If linear scale wasn't achieved */
438*e5436536SAndroid Build Coastguard Worker /* and we got too small SBR area */
439*e5436536SAndroid Build Coastguard Worker if (k2_diff > 0) {
440*e5436536SAndroid Build Coastguard Worker incr = -1;
441*e5436536SAndroid Build Coastguard Worker i = num_bands0 - 1;
442*e5436536SAndroid Build Coastguard Worker }
443*e5436536SAndroid Build Coastguard Worker
444*e5436536SAndroid Build Coastguard Worker /* Adjust diff vector to get sepc. SBR range */
445*e5436536SAndroid Build Coastguard Worker while (k2_diff != 0) {
446*e5436536SAndroid Build Coastguard Worker diff_tot[i] = diff_tot[i] - incr;
447*e5436536SAndroid Build Coastguard Worker i = i + incr;
448*e5436536SAndroid Build Coastguard Worker k2_diff = k2_diff + incr;
449*e5436536SAndroid Build Coastguard Worker }
450*e5436536SAndroid Build Coastguard Worker
451*e5436536SAndroid Build Coastguard Worker cumSum(k0, diff_tot, num_bands0, v_k_master); /* cumsum */
452*e5436536SAndroid Build Coastguard Worker *numMaster = num_bands0; /* Output nr of bands */
453*e5436536SAndroid Build Coastguard Worker }
454*e5436536SAndroid Build Coastguard Worker
455*e5436536SAndroid Build Coastguard Worker if (*numMaster < 1) {
456*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
457*e5436536SAndroid Build Coastguard Worker }
458*e5436536SAndroid Build Coastguard Worker
459*e5436536SAndroid Build Coastguard Worker /* Ref: ISO/IEC 23003-3 Cor.3, "In 7.5.5.2, add to the requirements:"*/
460*e5436536SAndroid Build Coastguard Worker if (flags & SBRDEC_QUAD_RATE) {
461*e5436536SAndroid Build Coastguard Worker int k;
462*e5436536SAndroid Build Coastguard Worker for (k = 1; k < *numMaster; k++) {
463*e5436536SAndroid Build Coastguard Worker if (!(v_k_master[k] - v_k_master[k - 1] <= k0 - 2)) {
464*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
465*e5436536SAndroid Build Coastguard Worker }
466*e5436536SAndroid Build Coastguard Worker }
467*e5436536SAndroid Build Coastguard Worker }
468*e5436536SAndroid Build Coastguard Worker
469*e5436536SAndroid Build Coastguard Worker /*
470*e5436536SAndroid Build Coastguard Worker Print out the calculated table
471*e5436536SAndroid Build Coastguard Worker */
472*e5436536SAndroid Build Coastguard Worker
473*e5436536SAndroid Build Coastguard Worker return SBRDEC_OK;
474*e5436536SAndroid Build Coastguard Worker }
475*e5436536SAndroid Build Coastguard Worker
476*e5436536SAndroid Build Coastguard Worker /*!
477*e5436536SAndroid Build Coastguard Worker \brief Calculate frequency ratio of one SBR band
478*e5436536SAndroid Build Coastguard Worker
479*e5436536SAndroid Build Coastguard Worker All SBR bands should span a constant frequency range in the logarithmic
480*e5436536SAndroid Build Coastguard Worker domain. This function calculates the ratio of any SBR band's upper and lower
481*e5436536SAndroid Build Coastguard Worker frequency.
482*e5436536SAndroid Build Coastguard Worker
483*e5436536SAndroid Build Coastguard Worker \return num_band-th root of k_start/k_stop
484*e5436536SAndroid Build Coastguard Worker */
calcFactorPerBand(int k_start,int k_stop,int num_bands)485*e5436536SAndroid Build Coastguard Worker static FIXP_SGL calcFactorPerBand(int k_start, int k_stop, int num_bands) {
486*e5436536SAndroid Build Coastguard Worker /* Scaled bandfactor and step 1 bit right to avoid overflow
487*e5436536SAndroid Build Coastguard Worker * use double data type */
488*e5436536SAndroid Build Coastguard Worker FIXP_DBL bandfactor = FL2FXCONST_DBL(0.25f); /* Start value */
489*e5436536SAndroid Build Coastguard Worker FIXP_DBL step = FL2FXCONST_DBL(0.125f); /* Initial increment for factor */
490*e5436536SAndroid Build Coastguard Worker
491*e5436536SAndroid Build Coastguard Worker int direction = 1;
492*e5436536SAndroid Build Coastguard Worker
493*e5436536SAndroid Build Coastguard Worker /* Because saturation can't be done in INT IIS,
494*e5436536SAndroid Build Coastguard Worker * changed start and stop data type from FIXP_SGL to FIXP_DBL */
495*e5436536SAndroid Build Coastguard Worker FIXP_DBL start = k_start << (DFRACT_BITS - 8);
496*e5436536SAndroid Build Coastguard Worker FIXP_DBL stop = k_stop << (DFRACT_BITS - 8);
497*e5436536SAndroid Build Coastguard Worker
498*e5436536SAndroid Build Coastguard Worker FIXP_DBL temp;
499*e5436536SAndroid Build Coastguard Worker
500*e5436536SAndroid Build Coastguard Worker int j, i = 0;
501*e5436536SAndroid Build Coastguard Worker
502*e5436536SAndroid Build Coastguard Worker while (step > FL2FXCONST_DBL(0.0f)) {
503*e5436536SAndroid Build Coastguard Worker i++;
504*e5436536SAndroid Build Coastguard Worker temp = stop;
505*e5436536SAndroid Build Coastguard Worker
506*e5436536SAndroid Build Coastguard Worker /* Calculate temp^num_bands: */
507*e5436536SAndroid Build Coastguard Worker for (j = 0; j < num_bands; j++)
508*e5436536SAndroid Build Coastguard Worker // temp = fMult(temp,bandfactor);
509*e5436536SAndroid Build Coastguard Worker temp = fMultDiv2(temp, bandfactor) << 2;
510*e5436536SAndroid Build Coastguard Worker
511*e5436536SAndroid Build Coastguard Worker if (temp < start) { /* Factor too strong, make it weaker */
512*e5436536SAndroid Build Coastguard Worker if (direction == 0)
513*e5436536SAndroid Build Coastguard Worker /* Halfen step. Right shift is not done as fract because otherwise the
514*e5436536SAndroid Build Coastguard Worker lowest bit cannot be cleared due to rounding */
515*e5436536SAndroid Build Coastguard Worker step = (FIXP_DBL)((LONG)step >> 1);
516*e5436536SAndroid Build Coastguard Worker direction = 1;
517*e5436536SAndroid Build Coastguard Worker bandfactor = bandfactor + step;
518*e5436536SAndroid Build Coastguard Worker } else { /* Factor is too weak: make it stronger */
519*e5436536SAndroid Build Coastguard Worker if (direction == 1) step = (FIXP_DBL)((LONG)step >> 1);
520*e5436536SAndroid Build Coastguard Worker direction = 0;
521*e5436536SAndroid Build Coastguard Worker bandfactor = bandfactor - step;
522*e5436536SAndroid Build Coastguard Worker }
523*e5436536SAndroid Build Coastguard Worker
524*e5436536SAndroid Build Coastguard Worker if (i > 100) {
525*e5436536SAndroid Build Coastguard Worker step = FL2FXCONST_DBL(0.0f);
526*e5436536SAndroid Build Coastguard Worker }
527*e5436536SAndroid Build Coastguard Worker }
528*e5436536SAndroid Build Coastguard Worker return (bandfactor >= FL2FXCONST_DBL(0.5)) ? (FIXP_SGL)MAXVAL_SGL
529*e5436536SAndroid Build Coastguard Worker : FX_DBL2FX_SGL(bandfactor << 1);
530*e5436536SAndroid Build Coastguard Worker }
531*e5436536SAndroid Build Coastguard Worker
532*e5436536SAndroid Build Coastguard Worker /*!
533*e5436536SAndroid Build Coastguard Worker \brief Calculate number of SBR bands between start and stop band
534*e5436536SAndroid Build Coastguard Worker
535*e5436536SAndroid Build Coastguard Worker Given the number of bands per octave, this function calculates how many
536*e5436536SAndroid Build Coastguard Worker bands fit in the given frequency range.
537*e5436536SAndroid Build Coastguard Worker When the warpFlag is set, the 'band density' is decreased by a factor
538*e5436536SAndroid Build Coastguard Worker of 1/1.3
539*e5436536SAndroid Build Coastguard Worker
540*e5436536SAndroid Build Coastguard Worker \return number of bands
541*e5436536SAndroid Build Coastguard Worker */
numberOfBands(FIXP_SGL bpo_div16,int start,int stop,int warpFlag)542*e5436536SAndroid Build Coastguard Worker static int numberOfBands(
543*e5436536SAndroid Build Coastguard Worker FIXP_SGL bpo_div16, /*!< Input: number of bands per octave divided by 16 */
544*e5436536SAndroid Build Coastguard Worker int start, /*!< First QMF band of SBR frequency range */
545*e5436536SAndroid Build Coastguard Worker int stop, /*!< Last QMF band of SBR frequency range + 1 */
546*e5436536SAndroid Build Coastguard Worker int warpFlag) /*!< Stretching flag */
547*e5436536SAndroid Build Coastguard Worker {
548*e5436536SAndroid Build Coastguard Worker FIXP_SGL num_bands_div128;
549*e5436536SAndroid Build Coastguard Worker int num_bands;
550*e5436536SAndroid Build Coastguard Worker
551*e5436536SAndroid Build Coastguard Worker num_bands_div128 =
552*e5436536SAndroid Build Coastguard Worker FX_DBL2FX_SGL(fMult(FDK_getNumOctavesDiv8(start, stop), bpo_div16));
553*e5436536SAndroid Build Coastguard Worker
554*e5436536SAndroid Build Coastguard Worker if (warpFlag) {
555*e5436536SAndroid Build Coastguard Worker /* Apply the warp factor of 1.3 to get wider bands. We use a value
556*e5436536SAndroid Build Coastguard Worker of 32768/25200 instead of the exact value to avoid critical cases
557*e5436536SAndroid Build Coastguard Worker of rounding.
558*e5436536SAndroid Build Coastguard Worker */
559*e5436536SAndroid Build Coastguard Worker num_bands_div128 = FX_DBL2FX_SGL(
560*e5436536SAndroid Build Coastguard Worker fMult(num_bands_div128, FL2FXCONST_SGL(25200.0 / 32768.0)));
561*e5436536SAndroid Build Coastguard Worker }
562*e5436536SAndroid Build Coastguard Worker
563*e5436536SAndroid Build Coastguard Worker /* add scaled 1 for rounding to even numbers: */
564*e5436536SAndroid Build Coastguard Worker num_bands_div128 = num_bands_div128 + FL2FXCONST_SGL(1.0f / 128.0f);
565*e5436536SAndroid Build Coastguard Worker /* scale back to right aligned integer and double the value: */
566*e5436536SAndroid Build Coastguard Worker num_bands = 2 * ((LONG)num_bands_div128 >> (FRACT_BITS - 7));
567*e5436536SAndroid Build Coastguard Worker
568*e5436536SAndroid Build Coastguard Worker return (num_bands);
569*e5436536SAndroid Build Coastguard Worker }
570*e5436536SAndroid Build Coastguard Worker
571*e5436536SAndroid Build Coastguard Worker /*!
572*e5436536SAndroid Build Coastguard Worker \brief Calculate width of SBR bands
573*e5436536SAndroid Build Coastguard Worker
574*e5436536SAndroid Build Coastguard Worker Given the desired number of bands within the SBR frequency range,
575*e5436536SAndroid Build Coastguard Worker this function calculates the width of each SBR band in QMF channels.
576*e5436536SAndroid Build Coastguard Worker The bands get wider from start to stop (bark scale).
577*e5436536SAndroid Build Coastguard Worker */
CalcBands(UCHAR * diff,UCHAR start,UCHAR stop,UCHAR num_bands)578*e5436536SAndroid Build Coastguard Worker static void CalcBands(UCHAR *diff, /*!< Vector of widths to be calculated */
579*e5436536SAndroid Build Coastguard Worker UCHAR start, /*!< Lower end of subband range */
580*e5436536SAndroid Build Coastguard Worker UCHAR stop, /*!< Upper end of subband range */
581*e5436536SAndroid Build Coastguard Worker UCHAR num_bands) /*!< Desired number of bands */
582*e5436536SAndroid Build Coastguard Worker {
583*e5436536SAndroid Build Coastguard Worker int i;
584*e5436536SAndroid Build Coastguard Worker int previous;
585*e5436536SAndroid Build Coastguard Worker int current;
586*e5436536SAndroid Build Coastguard Worker FIXP_SGL exact, temp;
587*e5436536SAndroid Build Coastguard Worker FIXP_SGL bandfactor = calcFactorPerBand(start, stop, num_bands);
588*e5436536SAndroid Build Coastguard Worker
589*e5436536SAndroid Build Coastguard Worker previous = stop; /* Start with highest QMF channel */
590*e5436536SAndroid Build Coastguard Worker exact = (FIXP_SGL)(
591*e5436536SAndroid Build Coastguard Worker stop << (FRACT_BITS - 8)); /* Shift left to gain some accuracy */
592*e5436536SAndroid Build Coastguard Worker
593*e5436536SAndroid Build Coastguard Worker for (i = num_bands - 1; i >= 0; i--) {
594*e5436536SAndroid Build Coastguard Worker /* Calculate border of next lower sbr band */
595*e5436536SAndroid Build Coastguard Worker exact = FX_DBL2FX_SGL(fMult(exact, bandfactor));
596*e5436536SAndroid Build Coastguard Worker
597*e5436536SAndroid Build Coastguard Worker /* Add scaled 0.5 for rounding:
598*e5436536SAndroid Build Coastguard Worker We use a value 128/256 instead of 0.5 to avoid some critical cases of
599*e5436536SAndroid Build Coastguard Worker rounding. */
600*e5436536SAndroid Build Coastguard Worker temp = exact + FL2FXCONST_SGL(128.0 / 32768.0);
601*e5436536SAndroid Build Coastguard Worker
602*e5436536SAndroid Build Coastguard Worker /* scale back to right alinged integer: */
603*e5436536SAndroid Build Coastguard Worker current = (LONG)temp >> (FRACT_BITS - 8);
604*e5436536SAndroid Build Coastguard Worker
605*e5436536SAndroid Build Coastguard Worker /* Save width of band i */
606*e5436536SAndroid Build Coastguard Worker diff[i] = previous - current;
607*e5436536SAndroid Build Coastguard Worker previous = current;
608*e5436536SAndroid Build Coastguard Worker }
609*e5436536SAndroid Build Coastguard Worker }
610*e5436536SAndroid Build Coastguard Worker
611*e5436536SAndroid Build Coastguard Worker /*!
612*e5436536SAndroid Build Coastguard Worker \brief Calculate cumulated sum vector from delta vector
613*e5436536SAndroid Build Coastguard Worker */
cumSum(UCHAR start_value,UCHAR * diff,UCHAR length,UCHAR * start_adress)614*e5436536SAndroid Build Coastguard Worker static void cumSum(UCHAR start_value, UCHAR *diff, UCHAR length,
615*e5436536SAndroid Build Coastguard Worker UCHAR *start_adress) {
616*e5436536SAndroid Build Coastguard Worker int i;
617*e5436536SAndroid Build Coastguard Worker start_adress[0] = start_value;
618*e5436536SAndroid Build Coastguard Worker for (i = 1; i <= length; i++)
619*e5436536SAndroid Build Coastguard Worker start_adress[i] = start_adress[i - 1] + diff[i - 1];
620*e5436536SAndroid Build Coastguard Worker }
621*e5436536SAndroid Build Coastguard Worker
622*e5436536SAndroid Build Coastguard Worker /*!
623*e5436536SAndroid Build Coastguard Worker \brief Adapt width of frequency bands in the second region
624*e5436536SAndroid Build Coastguard Worker
625*e5436536SAndroid Build Coastguard Worker If SBR spans more than 2 octaves, the upper part of a bark-frequency-scale
626*e5436536SAndroid Build Coastguard Worker is calculated separately. This function tries to avoid that the second region
627*e5436536SAndroid Build Coastguard Worker starts with a band smaller than the highest band of the first region.
628*e5436536SAndroid Build Coastguard Worker */
modifyBands(UCHAR max_band_previous,UCHAR * diff,UCHAR length)629*e5436536SAndroid Build Coastguard Worker static SBR_ERROR modifyBands(UCHAR max_band_previous, UCHAR *diff,
630*e5436536SAndroid Build Coastguard Worker UCHAR length) {
631*e5436536SAndroid Build Coastguard Worker int change = max_band_previous - diff[0];
632*e5436536SAndroid Build Coastguard Worker
633*e5436536SAndroid Build Coastguard Worker /* Limit the change so that the last band cannot get narrower than the first
634*e5436536SAndroid Build Coastguard Worker * one */
635*e5436536SAndroid Build Coastguard Worker if (change > (diff[length - 1] - diff[0]) >> 1)
636*e5436536SAndroid Build Coastguard Worker change = (diff[length - 1] - diff[0]) >> 1;
637*e5436536SAndroid Build Coastguard Worker
638*e5436536SAndroid Build Coastguard Worker diff[0] += change;
639*e5436536SAndroid Build Coastguard Worker diff[length - 1] -= change;
640*e5436536SAndroid Build Coastguard Worker shellsort(diff, length);
641*e5436536SAndroid Build Coastguard Worker
642*e5436536SAndroid Build Coastguard Worker return SBRDEC_OK;
643*e5436536SAndroid Build Coastguard Worker }
644*e5436536SAndroid Build Coastguard Worker
645*e5436536SAndroid Build Coastguard Worker /*!
646*e5436536SAndroid Build Coastguard Worker \brief Update high resolution frequency band table
647*e5436536SAndroid Build Coastguard Worker */
sbrdecUpdateHiRes(UCHAR * h_hires,UCHAR * num_hires,UCHAR * v_k_master,UCHAR num_bands,UCHAR xover_band)648*e5436536SAndroid Build Coastguard Worker static void sbrdecUpdateHiRes(UCHAR *h_hires, UCHAR *num_hires,
649*e5436536SAndroid Build Coastguard Worker UCHAR *v_k_master, UCHAR num_bands,
650*e5436536SAndroid Build Coastguard Worker UCHAR xover_band) {
651*e5436536SAndroid Build Coastguard Worker UCHAR i;
652*e5436536SAndroid Build Coastguard Worker
653*e5436536SAndroid Build Coastguard Worker *num_hires = num_bands - xover_band;
654*e5436536SAndroid Build Coastguard Worker
655*e5436536SAndroid Build Coastguard Worker for (i = xover_band; i <= num_bands; i++) {
656*e5436536SAndroid Build Coastguard Worker h_hires[i - xover_band] = v_k_master[i];
657*e5436536SAndroid Build Coastguard Worker }
658*e5436536SAndroid Build Coastguard Worker }
659*e5436536SAndroid Build Coastguard Worker
660*e5436536SAndroid Build Coastguard Worker /*!
661*e5436536SAndroid Build Coastguard Worker \brief Build low resolution table out of high resolution table
662*e5436536SAndroid Build Coastguard Worker */
sbrdecUpdateLoRes(UCHAR * h_lores,UCHAR * num_lores,UCHAR * h_hires,UCHAR num_hires)663*e5436536SAndroid Build Coastguard Worker static void sbrdecUpdateLoRes(UCHAR *h_lores, UCHAR *num_lores, UCHAR *h_hires,
664*e5436536SAndroid Build Coastguard Worker UCHAR num_hires) {
665*e5436536SAndroid Build Coastguard Worker UCHAR i;
666*e5436536SAndroid Build Coastguard Worker
667*e5436536SAndroid Build Coastguard Worker if ((num_hires & 1) == 0) {
668*e5436536SAndroid Build Coastguard Worker /* If even number of hires bands */
669*e5436536SAndroid Build Coastguard Worker *num_lores = num_hires >> 1;
670*e5436536SAndroid Build Coastguard Worker /* Use every second lores=hires[0,2,4...] */
671*e5436536SAndroid Build Coastguard Worker for (i = 0; i <= *num_lores; i++) h_lores[i] = h_hires[i * 2];
672*e5436536SAndroid Build Coastguard Worker } else {
673*e5436536SAndroid Build Coastguard Worker /* Odd number of hires, which means xover is odd */
674*e5436536SAndroid Build Coastguard Worker *num_lores = (num_hires + 1) >> 1;
675*e5436536SAndroid Build Coastguard Worker /* Use lores=hires[0,1,3,5 ...] */
676*e5436536SAndroid Build Coastguard Worker h_lores[0] = h_hires[0];
677*e5436536SAndroid Build Coastguard Worker for (i = 1; i <= *num_lores; i++) {
678*e5436536SAndroid Build Coastguard Worker h_lores[i] = h_hires[i * 2 - 1];
679*e5436536SAndroid Build Coastguard Worker }
680*e5436536SAndroid Build Coastguard Worker }
681*e5436536SAndroid Build Coastguard Worker }
682*e5436536SAndroid Build Coastguard Worker
683*e5436536SAndroid Build Coastguard Worker /*!
684*e5436536SAndroid Build Coastguard Worker \brief Derive a low-resolution frequency-table from the master frequency
685*e5436536SAndroid Build Coastguard Worker table
686*e5436536SAndroid Build Coastguard Worker */
sbrdecDownSampleLoRes(UCHAR * v_result,UCHAR num_result,UCHAR * freqBandTableRef,UCHAR num_Ref)687*e5436536SAndroid Build Coastguard Worker void sbrdecDownSampleLoRes(UCHAR *v_result, UCHAR num_result,
688*e5436536SAndroid Build Coastguard Worker UCHAR *freqBandTableRef, UCHAR num_Ref) {
689*e5436536SAndroid Build Coastguard Worker int step;
690*e5436536SAndroid Build Coastguard Worker int i, j;
691*e5436536SAndroid Build Coastguard Worker int org_length, result_length;
692*e5436536SAndroid Build Coastguard Worker int v_index[MAX_FREQ_COEFFS >> 1];
693*e5436536SAndroid Build Coastguard Worker
694*e5436536SAndroid Build Coastguard Worker /* init */
695*e5436536SAndroid Build Coastguard Worker org_length = num_Ref;
696*e5436536SAndroid Build Coastguard Worker result_length = num_result;
697*e5436536SAndroid Build Coastguard Worker
698*e5436536SAndroid Build Coastguard Worker v_index[0] = 0; /* Always use left border */
699*e5436536SAndroid Build Coastguard Worker i = 0;
700*e5436536SAndroid Build Coastguard Worker while (org_length > 0) {
701*e5436536SAndroid Build Coastguard Worker /* Create downsample vector */
702*e5436536SAndroid Build Coastguard Worker i++;
703*e5436536SAndroid Build Coastguard Worker step = org_length / result_length;
704*e5436536SAndroid Build Coastguard Worker org_length = org_length - step;
705*e5436536SAndroid Build Coastguard Worker result_length--;
706*e5436536SAndroid Build Coastguard Worker v_index[i] = v_index[i - 1] + step;
707*e5436536SAndroid Build Coastguard Worker }
708*e5436536SAndroid Build Coastguard Worker
709*e5436536SAndroid Build Coastguard Worker for (j = 0; j <= i; j++) {
710*e5436536SAndroid Build Coastguard Worker /* Use downsample vector to index LoResolution vector */
711*e5436536SAndroid Build Coastguard Worker v_result[j] = freqBandTableRef[v_index[j]];
712*e5436536SAndroid Build Coastguard Worker }
713*e5436536SAndroid Build Coastguard Worker }
714*e5436536SAndroid Build Coastguard Worker
715*e5436536SAndroid Build Coastguard Worker /*!
716*e5436536SAndroid Build Coastguard Worker \brief Sorting routine
717*e5436536SAndroid Build Coastguard Worker */
shellsort(UCHAR * in,UCHAR n)718*e5436536SAndroid Build Coastguard Worker void shellsort(UCHAR *in, UCHAR n) {
719*e5436536SAndroid Build Coastguard Worker int i, j, v, w;
720*e5436536SAndroid Build Coastguard Worker int inc = 1;
721*e5436536SAndroid Build Coastguard Worker
722*e5436536SAndroid Build Coastguard Worker do
723*e5436536SAndroid Build Coastguard Worker inc = 3 * inc + 1;
724*e5436536SAndroid Build Coastguard Worker while (inc <= n);
725*e5436536SAndroid Build Coastguard Worker
726*e5436536SAndroid Build Coastguard Worker do {
727*e5436536SAndroid Build Coastguard Worker inc = inc / 3;
728*e5436536SAndroid Build Coastguard Worker for (i = inc; i < n; i++) {
729*e5436536SAndroid Build Coastguard Worker v = in[i];
730*e5436536SAndroid Build Coastguard Worker j = i;
731*e5436536SAndroid Build Coastguard Worker while ((w = in[j - inc]) > v) {
732*e5436536SAndroid Build Coastguard Worker in[j] = w;
733*e5436536SAndroid Build Coastguard Worker j -= inc;
734*e5436536SAndroid Build Coastguard Worker if (j < inc) break;
735*e5436536SAndroid Build Coastguard Worker }
736*e5436536SAndroid Build Coastguard Worker in[j] = v;
737*e5436536SAndroid Build Coastguard Worker }
738*e5436536SAndroid Build Coastguard Worker } while (inc > 1);
739*e5436536SAndroid Build Coastguard Worker }
740*e5436536SAndroid Build Coastguard Worker
741*e5436536SAndroid Build Coastguard Worker /*!
742*e5436536SAndroid Build Coastguard Worker \brief Reset frequency band tables
743*e5436536SAndroid Build Coastguard Worker \return errorCode, 0 if successful
744*e5436536SAndroid Build Coastguard Worker */
745*e5436536SAndroid Build Coastguard Worker SBR_ERROR
resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData,const UINT flags)746*e5436536SAndroid Build Coastguard Worker resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) {
747*e5436536SAndroid Build Coastguard Worker SBR_ERROR err = SBRDEC_OK;
748*e5436536SAndroid Build Coastguard Worker int k2, kx, lsb, usb;
749*e5436536SAndroid Build Coastguard Worker int intTemp;
750*e5436536SAndroid Build Coastguard Worker UCHAR nBandsLo, nBandsHi;
751*e5436536SAndroid Build Coastguard Worker HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
752*e5436536SAndroid Build Coastguard Worker
753*e5436536SAndroid Build Coastguard Worker /* Calculate master frequency function */
754*e5436536SAndroid Build Coastguard Worker err = sbrdecUpdateFreqScale(hFreq->v_k_master, &hFreq->numMaster,
755*e5436536SAndroid Build Coastguard Worker hHeaderData->sbrProcSmplRate, hHeaderData, flags);
756*e5436536SAndroid Build Coastguard Worker
757*e5436536SAndroid Build Coastguard Worker if (err || (hHeaderData->bs_info.xover_band > hFreq->numMaster)) {
758*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
759*e5436536SAndroid Build Coastguard Worker }
760*e5436536SAndroid Build Coastguard Worker
761*e5436536SAndroid Build Coastguard Worker /* Derive Hiresolution from master frequency function */
762*e5436536SAndroid Build Coastguard Worker sbrdecUpdateHiRes(hFreq->freqBandTable[1], &nBandsHi, hFreq->v_k_master,
763*e5436536SAndroid Build Coastguard Worker hFreq->numMaster, hHeaderData->bs_info.xover_band);
764*e5436536SAndroid Build Coastguard Worker /* Derive Loresolution from Hiresolution */
765*e5436536SAndroid Build Coastguard Worker sbrdecUpdateLoRes(hFreq->freqBandTable[0], &nBandsLo, hFreq->freqBandTable[1],
766*e5436536SAndroid Build Coastguard Worker nBandsHi);
767*e5436536SAndroid Build Coastguard Worker
768*e5436536SAndroid Build Coastguard Worker /* Check index to freqBandTable[0] */
769*e5436536SAndroid Build Coastguard Worker if (!(nBandsLo > 0) ||
770*e5436536SAndroid Build Coastguard Worker (nBandsLo > (((hHeaderData->numberOfAnalysisBands == 16)
771*e5436536SAndroid Build Coastguard Worker ? MAX_FREQ_COEFFS_QUAD_RATE
772*e5436536SAndroid Build Coastguard Worker : MAX_FREQ_COEFFS_DUAL_RATE) >>
773*e5436536SAndroid Build Coastguard Worker 1))) {
774*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
775*e5436536SAndroid Build Coastguard Worker }
776*e5436536SAndroid Build Coastguard Worker
777*e5436536SAndroid Build Coastguard Worker hFreq->nSfb[0] = nBandsLo;
778*e5436536SAndroid Build Coastguard Worker hFreq->nSfb[1] = nBandsHi;
779*e5436536SAndroid Build Coastguard Worker
780*e5436536SAndroid Build Coastguard Worker lsb = hFreq->freqBandTable[0][0];
781*e5436536SAndroid Build Coastguard Worker usb = hFreq->freqBandTable[0][nBandsLo];
782*e5436536SAndroid Build Coastguard Worker
783*e5436536SAndroid Build Coastguard Worker /* Check for start frequency border k_x:
784*e5436536SAndroid Build Coastguard Worker - ISO/IEC 14496-3 4.6.18.3.6 Requirements
785*e5436536SAndroid Build Coastguard Worker - ISO/IEC 23003-3 7.5.5.2 Modifications and additions to the MPEG-4 SBR
786*e5436536SAndroid Build Coastguard Worker tool
787*e5436536SAndroid Build Coastguard Worker */
788*e5436536SAndroid Build Coastguard Worker /* Note that lsb > as hHeaderData->numberOfAnalysisBands is a valid SBR config
789*e5436536SAndroid Build Coastguard Worker * for 24 band QMF analysis. */
790*e5436536SAndroid Build Coastguard Worker if ((lsb > ((flags & SBRDEC_QUAD_RATE) ? 16 : (32))) || (lsb >= usb)) {
791*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
792*e5436536SAndroid Build Coastguard Worker }
793*e5436536SAndroid Build Coastguard Worker
794*e5436536SAndroid Build Coastguard Worker /* Calculate number of noise bands */
795*e5436536SAndroid Build Coastguard Worker
796*e5436536SAndroid Build Coastguard Worker k2 = hFreq->freqBandTable[1][nBandsHi];
797*e5436536SAndroid Build Coastguard Worker kx = hFreq->freqBandTable[1][0];
798*e5436536SAndroid Build Coastguard Worker
799*e5436536SAndroid Build Coastguard Worker if (hHeaderData->bs_data.noise_bands == 0) {
800*e5436536SAndroid Build Coastguard Worker hFreq->nNfb = 1;
801*e5436536SAndroid Build Coastguard Worker } else /* Calculate no of noise bands 1,2 or 3 bands/octave */
802*e5436536SAndroid Build Coastguard Worker {
803*e5436536SAndroid Build Coastguard Worker /* Fetch number of octaves divided by 32 */
804*e5436536SAndroid Build Coastguard Worker intTemp = (LONG)FDK_getNumOctavesDiv8(kx, k2) >> 2;
805*e5436536SAndroid Build Coastguard Worker
806*e5436536SAndroid Build Coastguard Worker /* Integer-Multiplication with number of bands: */
807*e5436536SAndroid Build Coastguard Worker intTemp = intTemp * hHeaderData->bs_data.noise_bands;
808*e5436536SAndroid Build Coastguard Worker
809*e5436536SAndroid Build Coastguard Worker /* Add scaled 0.5 for rounding: */
810*e5436536SAndroid Build Coastguard Worker intTemp = intTemp + (LONG)FL2FXCONST_SGL(0.5f / 32.0f);
811*e5436536SAndroid Build Coastguard Worker
812*e5436536SAndroid Build Coastguard Worker /* Convert to right-aligned integer: */
813*e5436536SAndroid Build Coastguard Worker intTemp = intTemp >> (FRACT_BITS - 1 /*sign*/ - 5 /* rescale */);
814*e5436536SAndroid Build Coastguard Worker
815*e5436536SAndroid Build Coastguard Worker if (intTemp == 0) intTemp = 1;
816*e5436536SAndroid Build Coastguard Worker
817*e5436536SAndroid Build Coastguard Worker if (intTemp > MAX_NOISE_COEFFS) {
818*e5436536SAndroid Build Coastguard Worker return SBRDEC_UNSUPPORTED_CONFIG;
819*e5436536SAndroid Build Coastguard Worker }
820*e5436536SAndroid Build Coastguard Worker
821*e5436536SAndroid Build Coastguard Worker hFreq->nNfb = intTemp;
822*e5436536SAndroid Build Coastguard Worker }
823*e5436536SAndroid Build Coastguard Worker
824*e5436536SAndroid Build Coastguard Worker hFreq->nInvfBands = hFreq->nNfb;
825*e5436536SAndroid Build Coastguard Worker
826*e5436536SAndroid Build Coastguard Worker /* Get noise bands */
827*e5436536SAndroid Build Coastguard Worker sbrdecDownSampleLoRes(hFreq->freqBandTableNoise, hFreq->nNfb,
828*e5436536SAndroid Build Coastguard Worker hFreq->freqBandTable[0], nBandsLo);
829*e5436536SAndroid Build Coastguard Worker
830*e5436536SAndroid Build Coastguard Worker /* save old highband; required for overlap in usac
831*e5436536SAndroid Build Coastguard Worker when headerchange occurs at XVAR and VARX frame; */
832*e5436536SAndroid Build Coastguard Worker hFreq->ov_highSubband = hFreq->highSubband;
833*e5436536SAndroid Build Coastguard Worker
834*e5436536SAndroid Build Coastguard Worker hFreq->lowSubband = lsb;
835*e5436536SAndroid Build Coastguard Worker hFreq->highSubband = usb;
836*e5436536SAndroid Build Coastguard Worker
837*e5436536SAndroid Build Coastguard Worker return SBRDEC_OK;
838*e5436536SAndroid Build Coastguard Worker }
839