xref: /aosp_15_r20/external/aac/libPCMutils/src/limiter.cpp (revision e54365361535b070c2db7374cec45c159c7d0e7a)
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 - 2020 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 /**************************** PCM utility library ******************************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):   Matthias Neusinger
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description: Hard limiter for clipping prevention
100*e5436536SAndroid Build Coastguard Worker 
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker 
103*e5436536SAndroid Build Coastguard Worker #include "limiter.h"
104*e5436536SAndroid Build Coastguard Worker #include "FDK_core.h"
105*e5436536SAndroid Build Coastguard Worker 
106*e5436536SAndroid Build Coastguard Worker /* library version */
107*e5436536SAndroid Build Coastguard Worker #include "version.h"
108*e5436536SAndroid Build Coastguard Worker /* library title */
109*e5436536SAndroid Build Coastguard Worker #define TDLIMIT_LIB_TITLE "TD Limiter Lib"
110*e5436536SAndroid Build Coastguard Worker 
111*e5436536SAndroid Build Coastguard Worker /* create limiter */
pcmLimiter_Create(unsigned int maxAttackMs,unsigned int releaseMs,FIXP_DBL threshold,unsigned int maxChannels,UINT maxSampleRate)112*e5436536SAndroid Build Coastguard Worker TDLimiterPtr pcmLimiter_Create(unsigned int maxAttackMs, unsigned int releaseMs,
113*e5436536SAndroid Build Coastguard Worker                                FIXP_DBL threshold, unsigned int maxChannels,
114*e5436536SAndroid Build Coastguard Worker                                UINT maxSampleRate) {
115*e5436536SAndroid Build Coastguard Worker   TDLimiterPtr limiter = NULL;
116*e5436536SAndroid Build Coastguard Worker   unsigned int attack, release;
117*e5436536SAndroid Build Coastguard Worker   FIXP_DBL attackConst, releaseConst, exponent;
118*e5436536SAndroid Build Coastguard Worker   INT e_ans;
119*e5436536SAndroid Build Coastguard Worker 
120*e5436536SAndroid Build Coastguard Worker   /* calc attack and release time in samples */
121*e5436536SAndroid Build Coastguard Worker   attack = (unsigned int)(maxAttackMs * maxSampleRate / 1000);
122*e5436536SAndroid Build Coastguard Worker   release = (unsigned int)(releaseMs * maxSampleRate / 1000);
123*e5436536SAndroid Build Coastguard Worker 
124*e5436536SAndroid Build Coastguard Worker   /* alloc limiter struct */
125*e5436536SAndroid Build Coastguard Worker   limiter = (TDLimiterPtr)FDKcalloc(1, sizeof(struct TDLimiter));
126*e5436536SAndroid Build Coastguard Worker   if (!limiter) return NULL;
127*e5436536SAndroid Build Coastguard Worker 
128*e5436536SAndroid Build Coastguard Worker   /* alloc max and delay buffers */
129*e5436536SAndroid Build Coastguard Worker   limiter->maxBuf = (FIXP_DBL*)FDKcalloc(attack + 1, sizeof(FIXP_DBL));
130*e5436536SAndroid Build Coastguard Worker   limiter->delayBuf =
131*e5436536SAndroid Build Coastguard Worker       (FIXP_DBL*)FDKcalloc(attack * maxChannels, sizeof(FIXP_DBL));
132*e5436536SAndroid Build Coastguard Worker 
133*e5436536SAndroid Build Coastguard Worker   if (!limiter->maxBuf || !limiter->delayBuf) {
134*e5436536SAndroid Build Coastguard Worker     pcmLimiter_Destroy(limiter);
135*e5436536SAndroid Build Coastguard Worker     return NULL;
136*e5436536SAndroid Build Coastguard Worker   }
137*e5436536SAndroid Build Coastguard Worker 
138*e5436536SAndroid Build Coastguard Worker   /* attackConst = pow(0.1, 1.0 / (attack + 1)) */
139*e5436536SAndroid Build Coastguard Worker   exponent = invFixp(attack + 1);
140*e5436536SAndroid Build Coastguard Worker   attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
141*e5436536SAndroid Build Coastguard Worker   attackConst = scaleValue(attackConst, e_ans);
142*e5436536SAndroid Build Coastguard Worker 
143*e5436536SAndroid Build Coastguard Worker   /* releaseConst  = (float)pow(0.1, 1.0 / (release + 1)) */
144*e5436536SAndroid Build Coastguard Worker   exponent = invFixp(release + 1);
145*e5436536SAndroid Build Coastguard Worker   releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
146*e5436536SAndroid Build Coastguard Worker   releaseConst = scaleValue(releaseConst, e_ans);
147*e5436536SAndroid Build Coastguard Worker 
148*e5436536SAndroid Build Coastguard Worker   /* init parameters */
149*e5436536SAndroid Build Coastguard Worker   limiter->attackMs = maxAttackMs;
150*e5436536SAndroid Build Coastguard Worker   limiter->maxAttackMs = maxAttackMs;
151*e5436536SAndroid Build Coastguard Worker   limiter->releaseMs = releaseMs;
152*e5436536SAndroid Build Coastguard Worker   limiter->attack = attack;
153*e5436536SAndroid Build Coastguard Worker   limiter->attackConst = attackConst;
154*e5436536SAndroid Build Coastguard Worker   limiter->releaseConst = releaseConst;
155*e5436536SAndroid Build Coastguard Worker   limiter->threshold = threshold;
156*e5436536SAndroid Build Coastguard Worker   limiter->channels = maxChannels;
157*e5436536SAndroid Build Coastguard Worker   limiter->maxChannels = maxChannels;
158*e5436536SAndroid Build Coastguard Worker   limiter->sampleRate = maxSampleRate;
159*e5436536SAndroid Build Coastguard Worker   limiter->maxSampleRate = maxSampleRate;
160*e5436536SAndroid Build Coastguard Worker 
161*e5436536SAndroid Build Coastguard Worker   pcmLimiter_Reset(limiter);
162*e5436536SAndroid Build Coastguard Worker 
163*e5436536SAndroid Build Coastguard Worker   return limiter;
164*e5436536SAndroid Build Coastguard Worker }
165*e5436536SAndroid Build Coastguard Worker 
166*e5436536SAndroid Build Coastguard Worker /* apply limiter */
pcmLimiter_Apply(TDLimiterPtr limiter,PCM_LIM * samplesIn,INT_PCM * samplesOut,FIXP_DBL * pGainPerSample,const INT scaling,const UINT nSamples)167*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_Apply(TDLimiterPtr limiter, PCM_LIM* samplesIn,
168*e5436536SAndroid Build Coastguard Worker                                  INT_PCM* samplesOut, FIXP_DBL* pGainPerSample,
169*e5436536SAndroid Build Coastguard Worker                                  const INT scaling, const UINT nSamples) {
170*e5436536SAndroid Build Coastguard Worker   unsigned int i, j;
171*e5436536SAndroid Build Coastguard Worker   FIXP_DBL tmp2;
172*e5436536SAndroid Build Coastguard Worker   FIXP_DBL tmp, old, gain, additionalGain = 0;
173*e5436536SAndroid Build Coastguard Worker   FIXP_DBL minGain = FL2FXCONST_DBL(1.0f / (1 << 1));
174*e5436536SAndroid Build Coastguard Worker   UINT additionalGainAvailable = 1;
175*e5436536SAndroid Build Coastguard Worker 
176*e5436536SAndroid Build Coastguard Worker   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
177*e5436536SAndroid Build Coastguard Worker 
178*e5436536SAndroid Build Coastguard Worker   {
179*e5436536SAndroid Build Coastguard Worker     unsigned int channels = limiter->channels;
180*e5436536SAndroid Build Coastguard Worker     unsigned int attack = limiter->attack;
181*e5436536SAndroid Build Coastguard Worker     FIXP_DBL attackConst = limiter->attackConst;
182*e5436536SAndroid Build Coastguard Worker     FIXP_DBL releaseConst = limiter->releaseConst;
183*e5436536SAndroid Build Coastguard Worker     FIXP_DBL threshold = limiter->threshold >> scaling;
184*e5436536SAndroid Build Coastguard Worker 
185*e5436536SAndroid Build Coastguard Worker     FIXP_DBL max = limiter->max;
186*e5436536SAndroid Build Coastguard Worker     FIXP_DBL* maxBuf = limiter->maxBuf;
187*e5436536SAndroid Build Coastguard Worker     unsigned int maxBufIdx = limiter->maxBufIdx;
188*e5436536SAndroid Build Coastguard Worker     FIXP_DBL cor = limiter->cor;
189*e5436536SAndroid Build Coastguard Worker     FIXP_DBL* delayBuf = limiter->delayBuf;
190*e5436536SAndroid Build Coastguard Worker     unsigned int delayBufIdx = limiter->delayBufIdx;
191*e5436536SAndroid Build Coastguard Worker 
192*e5436536SAndroid Build Coastguard Worker     FIXP_DBL smoothState0 = limiter->smoothState0;
193*e5436536SAndroid Build Coastguard Worker 
194*e5436536SAndroid Build Coastguard Worker     if (limiter->scaling != scaling) {
195*e5436536SAndroid Build Coastguard Worker       scaleValuesSaturate(delayBuf, attack * channels,
196*e5436536SAndroid Build Coastguard Worker                           limiter->scaling - scaling);
197*e5436536SAndroid Build Coastguard Worker       scaleValuesSaturate(maxBuf, attack + 1, limiter->scaling - scaling);
198*e5436536SAndroid Build Coastguard Worker       max = scaleValueSaturate(max, limiter->scaling - scaling);
199*e5436536SAndroid Build Coastguard Worker       limiter->scaling = scaling;
200*e5436536SAndroid Build Coastguard Worker     }
201*e5436536SAndroid Build Coastguard Worker 
202*e5436536SAndroid Build Coastguard Worker     if (pGainPerSample == NULL) {
203*e5436536SAndroid Build Coastguard Worker       additionalGainAvailable = 0;
204*e5436536SAndroid Build Coastguard Worker     }
205*e5436536SAndroid Build Coastguard Worker 
206*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < nSamples; i++) {
207*e5436536SAndroid Build Coastguard Worker       /* get maximum absolute sample value of all channels, including the
208*e5436536SAndroid Build Coastguard Worker        * additional gain. */
209*e5436536SAndroid Build Coastguard Worker       tmp = (FIXP_DBL)0;
210*e5436536SAndroid Build Coastguard Worker       for (j = 0; j < channels; j++) {
211*e5436536SAndroid Build Coastguard Worker         tmp2 = PCM_LIM2FIXP_DBL(samplesIn[j]);
212*e5436536SAndroid Build Coastguard Worker         tmp2 =
213*e5436536SAndroid Build Coastguard Worker             (tmp2 == (FIXP_DBL)MINVAL_DBL) ? (FIXP_DBL)MAXVAL_DBL : fAbs(tmp2);
214*e5436536SAndroid Build Coastguard Worker         tmp = fMax(tmp, tmp2);
215*e5436536SAndroid Build Coastguard Worker       }
216*e5436536SAndroid Build Coastguard Worker 
217*e5436536SAndroid Build Coastguard Worker       if (additionalGainAvailable) {
218*e5436536SAndroid Build Coastguard Worker         additionalGain = pGainPerSample[i];
219*e5436536SAndroid Build Coastguard Worker         tmp = fMult(tmp, additionalGain);
220*e5436536SAndroid Build Coastguard Worker       }
221*e5436536SAndroid Build Coastguard Worker 
222*e5436536SAndroid Build Coastguard Worker       /* set threshold as lower border to save calculations in running maximum
223*e5436536SAndroid Build Coastguard Worker        * algorithm */
224*e5436536SAndroid Build Coastguard Worker       tmp = fMax(tmp, threshold);
225*e5436536SAndroid Build Coastguard Worker 
226*e5436536SAndroid Build Coastguard Worker       /* running maximum */
227*e5436536SAndroid Build Coastguard Worker       old = maxBuf[maxBufIdx];
228*e5436536SAndroid Build Coastguard Worker       maxBuf[maxBufIdx] = tmp;
229*e5436536SAndroid Build Coastguard Worker 
230*e5436536SAndroid Build Coastguard Worker       if (tmp >= max) {
231*e5436536SAndroid Build Coastguard Worker         /* new sample is greater than old maximum, so it is the new maximum */
232*e5436536SAndroid Build Coastguard Worker         max = tmp;
233*e5436536SAndroid Build Coastguard Worker       } else if (old < max) {
234*e5436536SAndroid Build Coastguard Worker         /* maximum does not change, as the sample, which has left the window was
235*e5436536SAndroid Build Coastguard Worker            not the maximum */
236*e5436536SAndroid Build Coastguard Worker       } else {
237*e5436536SAndroid Build Coastguard Worker         /* the old maximum has left the window, we have to search the complete
238*e5436536SAndroid Build Coastguard Worker            buffer for the new max */
239*e5436536SAndroid Build Coastguard Worker         max = maxBuf[0];
240*e5436536SAndroid Build Coastguard Worker         for (j = 1; j <= attack; j++) {
241*e5436536SAndroid Build Coastguard Worker           max = fMax(max, maxBuf[j]);
242*e5436536SAndroid Build Coastguard Worker         }
243*e5436536SAndroid Build Coastguard Worker       }
244*e5436536SAndroid Build Coastguard Worker       maxBufIdx++;
245*e5436536SAndroid Build Coastguard Worker       if (maxBufIdx >= attack + 1) maxBufIdx = 0;
246*e5436536SAndroid Build Coastguard Worker 
247*e5436536SAndroid Build Coastguard Worker       /* calc gain */
248*e5436536SAndroid Build Coastguard Worker       /* gain is downscaled by one, so that gain = 1.0 can be represented */
249*e5436536SAndroid Build Coastguard Worker       if (max > threshold) {
250*e5436536SAndroid Build Coastguard Worker         gain = fDivNorm(threshold, max) >> 1;
251*e5436536SAndroid Build Coastguard Worker       } else {
252*e5436536SAndroid Build Coastguard Worker         gain = FL2FXCONST_DBL(1.0f / (1 << 1));
253*e5436536SAndroid Build Coastguard Worker       }
254*e5436536SAndroid Build Coastguard Worker 
255*e5436536SAndroid Build Coastguard Worker       /* gain smoothing, method: TDL_EXPONENTIAL */
256*e5436536SAndroid Build Coastguard Worker       /* first order IIR filter with attack correction to avoid overshoots */
257*e5436536SAndroid Build Coastguard Worker 
258*e5436536SAndroid Build Coastguard Worker       /* correct the 'aiming' value of the exponential attack to avoid the
259*e5436536SAndroid Build Coastguard Worker        * remaining overshoot */
260*e5436536SAndroid Build Coastguard Worker       if (gain < smoothState0) {
261*e5436536SAndroid Build Coastguard Worker         cor = fMin(cor,
262*e5436536SAndroid Build Coastguard Worker                    fMultDiv2((gain - fMultDiv2(FL2FXCONST_SGL(0.1f * (1 << 1)),
263*e5436536SAndroid Build Coastguard Worker                                                smoothState0)),
264*e5436536SAndroid Build Coastguard Worker                              FL2FXCONST_SGL(1.11111111f / (1 << 1)))
265*e5436536SAndroid Build Coastguard Worker                        << 2);
266*e5436536SAndroid Build Coastguard Worker       } else {
267*e5436536SAndroid Build Coastguard Worker         cor = gain;
268*e5436536SAndroid Build Coastguard Worker       }
269*e5436536SAndroid Build Coastguard Worker 
270*e5436536SAndroid Build Coastguard Worker       /* smoothing filter */
271*e5436536SAndroid Build Coastguard Worker       if (cor < smoothState0) {
272*e5436536SAndroid Build Coastguard Worker         smoothState0 =
273*e5436536SAndroid Build Coastguard Worker             fMult(attackConst, (smoothState0 - cor)) + cor; /* attack */
274*e5436536SAndroid Build Coastguard Worker         smoothState0 = fMax(smoothState0, gain); /* avoid overshooting target */
275*e5436536SAndroid Build Coastguard Worker       } else {
276*e5436536SAndroid Build Coastguard Worker         /* sign inversion twice to round towards +infinity,
277*e5436536SAndroid Build Coastguard Worker            so that gain can converge to 1.0 again,
278*e5436536SAndroid Build Coastguard Worker            for bit-identical output when limiter is not active */
279*e5436536SAndroid Build Coastguard Worker         smoothState0 =
280*e5436536SAndroid Build Coastguard Worker             -fMult(releaseConst, -(smoothState0 - cor)) + cor; /* release */
281*e5436536SAndroid Build Coastguard Worker       }
282*e5436536SAndroid Build Coastguard Worker 
283*e5436536SAndroid Build Coastguard Worker       gain = smoothState0;
284*e5436536SAndroid Build Coastguard Worker 
285*e5436536SAndroid Build Coastguard Worker       FIXP_DBL* p_delayBuf = &delayBuf[delayBufIdx * channels + 0];
286*e5436536SAndroid Build Coastguard Worker       if (gain < FL2FXCONST_DBL(1.0f / (1 << 1))) {
287*e5436536SAndroid Build Coastguard Worker         gain <<= 1;
288*e5436536SAndroid Build Coastguard Worker         /* lookahead delay, apply gain */
289*e5436536SAndroid Build Coastguard Worker         for (j = 0; j < channels; j++) {
290*e5436536SAndroid Build Coastguard Worker           tmp = p_delayBuf[j];
291*e5436536SAndroid Build Coastguard Worker 
292*e5436536SAndroid Build Coastguard Worker           if (additionalGainAvailable) {
293*e5436536SAndroid Build Coastguard Worker             p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
294*e5436536SAndroid Build Coastguard Worker           } else {
295*e5436536SAndroid Build Coastguard Worker             p_delayBuf[j] = PCM_LIM2FIXP_DBL(samplesIn[j]);
296*e5436536SAndroid Build Coastguard Worker           }
297*e5436536SAndroid Build Coastguard Worker 
298*e5436536SAndroid Build Coastguard Worker           /* Apply gain to delayed signal */
299*e5436536SAndroid Build Coastguard Worker           tmp = fMultDiv2(tmp, gain);
300*e5436536SAndroid Build Coastguard Worker #if (SAMPLE_BITS == DFRACT_BITS)
301*e5436536SAndroid Build Coastguard Worker           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM(
302*e5436536SAndroid Build Coastguard Worker               (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling + 1, DFRACT_BITS));
303*e5436536SAndroid Build Coastguard Worker #else
304*e5436536SAndroid Build Coastguard Worker           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
305*e5436536SAndroid Build Coastguard Worker               tmp + ((FIXP_DBL)0x8000 >> (scaling + 1)), scaling + 1,
306*e5436536SAndroid Build Coastguard Worker               DFRACT_BITS));
307*e5436536SAndroid Build Coastguard Worker #endif
308*e5436536SAndroid Build Coastguard Worker         }
309*e5436536SAndroid Build Coastguard Worker         gain >>= 1;
310*e5436536SAndroid Build Coastguard Worker       } else {
311*e5436536SAndroid Build Coastguard Worker         /* lookahead delay, apply gain=1.0f */
312*e5436536SAndroid Build Coastguard Worker         for (j = 0; j < channels; j++) {
313*e5436536SAndroid Build Coastguard Worker           tmp = p_delayBuf[j];
314*e5436536SAndroid Build Coastguard Worker           if (additionalGainAvailable) {
315*e5436536SAndroid Build Coastguard Worker             p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
316*e5436536SAndroid Build Coastguard Worker           } else {
317*e5436536SAndroid Build Coastguard Worker             p_delayBuf[j] = PCM_LIM2FIXP_DBL(samplesIn[j]);
318*e5436536SAndroid Build Coastguard Worker           }
319*e5436536SAndroid Build Coastguard Worker 
320*e5436536SAndroid Build Coastguard Worker #if (SAMPLE_BITS == DFRACT_BITS)
321*e5436536SAndroid Build Coastguard Worker           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM(
322*e5436536SAndroid Build Coastguard Worker               (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling, DFRACT_BITS));
323*e5436536SAndroid Build Coastguard Worker #else
324*e5436536SAndroid Build Coastguard Worker           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
325*e5436536SAndroid Build Coastguard Worker               (tmp >> 1) + ((FIXP_DBL)0x8000 >> (scaling + 1)), scaling + 1,
326*e5436536SAndroid Build Coastguard Worker               DFRACT_BITS));
327*e5436536SAndroid Build Coastguard Worker #endif
328*e5436536SAndroid Build Coastguard Worker         }
329*e5436536SAndroid Build Coastguard Worker       }
330*e5436536SAndroid Build Coastguard Worker 
331*e5436536SAndroid Build Coastguard Worker       delayBufIdx++;
332*e5436536SAndroid Build Coastguard Worker       if (delayBufIdx >= attack) {
333*e5436536SAndroid Build Coastguard Worker         delayBufIdx = 0;
334*e5436536SAndroid Build Coastguard Worker       }
335*e5436536SAndroid Build Coastguard Worker 
336*e5436536SAndroid Build Coastguard Worker       /* save minimum gain factor */
337*e5436536SAndroid Build Coastguard Worker       if (gain < minGain) {
338*e5436536SAndroid Build Coastguard Worker         minGain = gain;
339*e5436536SAndroid Build Coastguard Worker       }
340*e5436536SAndroid Build Coastguard Worker 
341*e5436536SAndroid Build Coastguard Worker       /* advance sample pointer by <channel> samples */
342*e5436536SAndroid Build Coastguard Worker       samplesIn += channels;
343*e5436536SAndroid Build Coastguard Worker       samplesOut += channels;
344*e5436536SAndroid Build Coastguard Worker     }
345*e5436536SAndroid Build Coastguard Worker 
346*e5436536SAndroid Build Coastguard Worker     limiter->max = max;
347*e5436536SAndroid Build Coastguard Worker     limiter->maxBufIdx = maxBufIdx;
348*e5436536SAndroid Build Coastguard Worker     limiter->cor = cor;
349*e5436536SAndroid Build Coastguard Worker     limiter->delayBufIdx = delayBufIdx;
350*e5436536SAndroid Build Coastguard Worker 
351*e5436536SAndroid Build Coastguard Worker     limiter->smoothState0 = smoothState0;
352*e5436536SAndroid Build Coastguard Worker 
353*e5436536SAndroid Build Coastguard Worker     limiter->minGain = minGain;
354*e5436536SAndroid Build Coastguard Worker 
355*e5436536SAndroid Build Coastguard Worker     return TDLIMIT_OK;
356*e5436536SAndroid Build Coastguard Worker   }
357*e5436536SAndroid Build Coastguard Worker }
358*e5436536SAndroid Build Coastguard Worker 
359*e5436536SAndroid Build Coastguard Worker /* set limiter threshold */
pcmLimiter_SetThreshold(TDLimiterPtr limiter,FIXP_DBL threshold)360*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_SetThreshold(TDLimiterPtr limiter,
361*e5436536SAndroid Build Coastguard Worker                                         FIXP_DBL threshold) {
362*e5436536SAndroid Build Coastguard Worker   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
363*e5436536SAndroid Build Coastguard Worker 
364*e5436536SAndroid Build Coastguard Worker   limiter->threshold = threshold;
365*e5436536SAndroid Build Coastguard Worker 
366*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
367*e5436536SAndroid Build Coastguard Worker }
368*e5436536SAndroid Build Coastguard Worker 
369*e5436536SAndroid Build Coastguard Worker /* reset limiter */
pcmLimiter_Reset(TDLimiterPtr limiter)370*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_Reset(TDLimiterPtr limiter) {
371*e5436536SAndroid Build Coastguard Worker   if (limiter != NULL) {
372*e5436536SAndroid Build Coastguard Worker     limiter->maxBufIdx = 0;
373*e5436536SAndroid Build Coastguard Worker     limiter->delayBufIdx = 0;
374*e5436536SAndroid Build Coastguard Worker     limiter->max = (FIXP_DBL)0;
375*e5436536SAndroid Build Coastguard Worker     limiter->cor = FL2FXCONST_DBL(1.0f / (1 << 1));
376*e5436536SAndroid Build Coastguard Worker     limiter->smoothState0 = FL2FXCONST_DBL(1.0f / (1 << 1));
377*e5436536SAndroid Build Coastguard Worker     limiter->minGain = FL2FXCONST_DBL(1.0f / (1 << 1));
378*e5436536SAndroid Build Coastguard Worker     limiter->scaling = 0;
379*e5436536SAndroid Build Coastguard Worker 
380*e5436536SAndroid Build Coastguard Worker     FDKmemset(limiter->maxBuf, 0, (limiter->attack + 1) * sizeof(FIXP_DBL));
381*e5436536SAndroid Build Coastguard Worker     FDKmemset(limiter->delayBuf, 0,
382*e5436536SAndroid Build Coastguard Worker               limiter->attack * limiter->channels * sizeof(FIXP_DBL));
383*e5436536SAndroid Build Coastguard Worker   } else {
384*e5436536SAndroid Build Coastguard Worker     return TDLIMIT_INVALID_HANDLE;
385*e5436536SAndroid Build Coastguard Worker   }
386*e5436536SAndroid Build Coastguard Worker 
387*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
388*e5436536SAndroid Build Coastguard Worker }
389*e5436536SAndroid Build Coastguard Worker 
390*e5436536SAndroid Build Coastguard Worker /* destroy limiter */
pcmLimiter_Destroy(TDLimiterPtr limiter)391*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_Destroy(TDLimiterPtr limiter) {
392*e5436536SAndroid Build Coastguard Worker   if (limiter != NULL) {
393*e5436536SAndroid Build Coastguard Worker     FDKfree(limiter->maxBuf);
394*e5436536SAndroid Build Coastguard Worker     FDKfree(limiter->delayBuf);
395*e5436536SAndroid Build Coastguard Worker 
396*e5436536SAndroid Build Coastguard Worker     FDKfree(limiter);
397*e5436536SAndroid Build Coastguard Worker   } else {
398*e5436536SAndroid Build Coastguard Worker     return TDLIMIT_INVALID_HANDLE;
399*e5436536SAndroid Build Coastguard Worker   }
400*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
401*e5436536SAndroid Build Coastguard Worker }
402*e5436536SAndroid Build Coastguard Worker 
403*e5436536SAndroid Build Coastguard Worker /* get delay in samples */
pcmLimiter_GetDelay(TDLimiterPtr limiter)404*e5436536SAndroid Build Coastguard Worker unsigned int pcmLimiter_GetDelay(TDLimiterPtr limiter) {
405*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(limiter != NULL);
406*e5436536SAndroid Build Coastguard Worker   return limiter->attack;
407*e5436536SAndroid Build Coastguard Worker }
408*e5436536SAndroid Build Coastguard Worker 
409*e5436536SAndroid Build Coastguard Worker /* get maximum gain reduction of last processed block */
pcmLimiter_GetMaxGainReduction(TDLimiterPtr limiter)410*e5436536SAndroid Build Coastguard Worker INT pcmLimiter_GetMaxGainReduction(TDLimiterPtr limiter) {
411*e5436536SAndroid Build Coastguard Worker   /* maximum gain reduction in dB = -20 * log10(limiter->minGain)
412*e5436536SAndroid Build Coastguard Worker      = -20 * log2(limiter->minGain)/log2(10) = -6.0206*log2(limiter->minGain) */
413*e5436536SAndroid Build Coastguard Worker   int e_ans;
414*e5436536SAndroid Build Coastguard Worker   FIXP_DBL loggain, maxGainReduction;
415*e5436536SAndroid Build Coastguard Worker 
416*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(limiter != NULL);
417*e5436536SAndroid Build Coastguard Worker 
418*e5436536SAndroid Build Coastguard Worker   loggain = fLog2(limiter->minGain, 1, &e_ans);
419*e5436536SAndroid Build Coastguard Worker 
420*e5436536SAndroid Build Coastguard Worker   maxGainReduction = fMult(loggain, FL2FXCONST_DBL(-6.0206f / (1 << 3)));
421*e5436536SAndroid Build Coastguard Worker 
422*e5436536SAndroid Build Coastguard Worker   return fixp_roundToInt(maxGainReduction, (e_ans + 3));
423*e5436536SAndroid Build Coastguard Worker }
424*e5436536SAndroid Build Coastguard Worker 
425*e5436536SAndroid Build Coastguard Worker /* set number of channels */
pcmLimiter_SetNChannels(TDLimiterPtr limiter,unsigned int nChannels)426*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_SetNChannels(TDLimiterPtr limiter,
427*e5436536SAndroid Build Coastguard Worker                                         unsigned int nChannels) {
428*e5436536SAndroid Build Coastguard Worker   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
429*e5436536SAndroid Build Coastguard Worker 
430*e5436536SAndroid Build Coastguard Worker   if (nChannels > limiter->maxChannels) return TDLIMIT_INVALID_PARAMETER;
431*e5436536SAndroid Build Coastguard Worker 
432*e5436536SAndroid Build Coastguard Worker   limiter->channels = nChannels;
433*e5436536SAndroid Build Coastguard Worker   // pcmLimiter_Reset(limiter);
434*e5436536SAndroid Build Coastguard Worker 
435*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
436*e5436536SAndroid Build Coastguard Worker }
437*e5436536SAndroid Build Coastguard Worker 
438*e5436536SAndroid Build Coastguard Worker /* set sampling rate */
pcmLimiter_SetSampleRate(TDLimiterPtr limiter,UINT sampleRate)439*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_SetSampleRate(TDLimiterPtr limiter,
440*e5436536SAndroid Build Coastguard Worker                                          UINT sampleRate) {
441*e5436536SAndroid Build Coastguard Worker   unsigned int attack, release;
442*e5436536SAndroid Build Coastguard Worker   FIXP_DBL attackConst, releaseConst, exponent;
443*e5436536SAndroid Build Coastguard Worker   INT e_ans;
444*e5436536SAndroid Build Coastguard Worker 
445*e5436536SAndroid Build Coastguard Worker   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
446*e5436536SAndroid Build Coastguard Worker 
447*e5436536SAndroid Build Coastguard Worker   if (sampleRate > limiter->maxSampleRate) return TDLIMIT_INVALID_PARAMETER;
448*e5436536SAndroid Build Coastguard Worker 
449*e5436536SAndroid Build Coastguard Worker   /* update attack and release time in samples */
450*e5436536SAndroid Build Coastguard Worker   attack = (unsigned int)(limiter->attackMs * sampleRate / 1000);
451*e5436536SAndroid Build Coastguard Worker   release = (unsigned int)(limiter->releaseMs * sampleRate / 1000);
452*e5436536SAndroid Build Coastguard Worker 
453*e5436536SAndroid Build Coastguard Worker   /* attackConst = pow(0.1, 1.0 / (attack + 1)) */
454*e5436536SAndroid Build Coastguard Worker   exponent = invFixp(attack + 1);
455*e5436536SAndroid Build Coastguard Worker   attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
456*e5436536SAndroid Build Coastguard Worker   attackConst = scaleValue(attackConst, e_ans);
457*e5436536SAndroid Build Coastguard Worker 
458*e5436536SAndroid Build Coastguard Worker   /* releaseConst  = (float)pow(0.1, 1.0 / (release + 1)) */
459*e5436536SAndroid Build Coastguard Worker   exponent = invFixp(release + 1);
460*e5436536SAndroid Build Coastguard Worker   releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
461*e5436536SAndroid Build Coastguard Worker   releaseConst = scaleValue(releaseConst, e_ans);
462*e5436536SAndroid Build Coastguard Worker 
463*e5436536SAndroid Build Coastguard Worker   limiter->attack = attack;
464*e5436536SAndroid Build Coastguard Worker   limiter->attackConst = attackConst;
465*e5436536SAndroid Build Coastguard Worker   limiter->releaseConst = releaseConst;
466*e5436536SAndroid Build Coastguard Worker   limiter->sampleRate = sampleRate;
467*e5436536SAndroid Build Coastguard Worker 
468*e5436536SAndroid Build Coastguard Worker   /* reset */
469*e5436536SAndroid Build Coastguard Worker   // pcmLimiter_Reset(limiter);
470*e5436536SAndroid Build Coastguard Worker 
471*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
472*e5436536SAndroid Build Coastguard Worker }
473*e5436536SAndroid Build Coastguard Worker 
474*e5436536SAndroid Build Coastguard Worker /* set attack time */
pcmLimiter_SetAttack(TDLimiterPtr limiter,unsigned int attackMs)475*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_SetAttack(TDLimiterPtr limiter,
476*e5436536SAndroid Build Coastguard Worker                                      unsigned int attackMs) {
477*e5436536SAndroid Build Coastguard Worker   unsigned int attack;
478*e5436536SAndroid Build Coastguard Worker   FIXP_DBL attackConst, exponent;
479*e5436536SAndroid Build Coastguard Worker   INT e_ans;
480*e5436536SAndroid Build Coastguard Worker 
481*e5436536SAndroid Build Coastguard Worker   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
482*e5436536SAndroid Build Coastguard Worker 
483*e5436536SAndroid Build Coastguard Worker   if (attackMs > limiter->maxAttackMs) return TDLIMIT_INVALID_PARAMETER;
484*e5436536SAndroid Build Coastguard Worker 
485*e5436536SAndroid Build Coastguard Worker   /* calculate attack time in samples */
486*e5436536SAndroid Build Coastguard Worker   attack = (unsigned int)(attackMs * limiter->sampleRate / 1000);
487*e5436536SAndroid Build Coastguard Worker 
488*e5436536SAndroid Build Coastguard Worker   /* attackConst = pow(0.1, 1.0 / (attack + 1)) */
489*e5436536SAndroid Build Coastguard Worker   exponent = invFixp(attack + 1);
490*e5436536SAndroid Build Coastguard Worker   attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
491*e5436536SAndroid Build Coastguard Worker   attackConst = scaleValue(attackConst, e_ans);
492*e5436536SAndroid Build Coastguard Worker 
493*e5436536SAndroid Build Coastguard Worker   limiter->attack = attack;
494*e5436536SAndroid Build Coastguard Worker   limiter->attackConst = attackConst;
495*e5436536SAndroid Build Coastguard Worker   limiter->attackMs = attackMs;
496*e5436536SAndroid Build Coastguard Worker 
497*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
498*e5436536SAndroid Build Coastguard Worker }
499*e5436536SAndroid Build Coastguard Worker 
500*e5436536SAndroid Build Coastguard Worker /* set release time */
pcmLimiter_SetRelease(TDLimiterPtr limiter,unsigned int releaseMs)501*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_SetRelease(TDLimiterPtr limiter,
502*e5436536SAndroid Build Coastguard Worker                                       unsigned int releaseMs) {
503*e5436536SAndroid Build Coastguard Worker   unsigned int release;
504*e5436536SAndroid Build Coastguard Worker   FIXP_DBL releaseConst, exponent;
505*e5436536SAndroid Build Coastguard Worker   INT e_ans;
506*e5436536SAndroid Build Coastguard Worker 
507*e5436536SAndroid Build Coastguard Worker   if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
508*e5436536SAndroid Build Coastguard Worker 
509*e5436536SAndroid Build Coastguard Worker   /* calculate  release time in samples */
510*e5436536SAndroid Build Coastguard Worker   release = (unsigned int)(releaseMs * limiter->sampleRate / 1000);
511*e5436536SAndroid Build Coastguard Worker 
512*e5436536SAndroid Build Coastguard Worker   /* releaseConst  = (float)pow(0.1, 1.0 / (release + 1)) */
513*e5436536SAndroid Build Coastguard Worker   exponent = invFixp(release + 1);
514*e5436536SAndroid Build Coastguard Worker   releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
515*e5436536SAndroid Build Coastguard Worker   releaseConst = scaleValue(releaseConst, e_ans);
516*e5436536SAndroid Build Coastguard Worker 
517*e5436536SAndroid Build Coastguard Worker   limiter->releaseConst = releaseConst;
518*e5436536SAndroid Build Coastguard Worker   limiter->releaseMs = releaseMs;
519*e5436536SAndroid Build Coastguard Worker 
520*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
521*e5436536SAndroid Build Coastguard Worker }
522*e5436536SAndroid Build Coastguard Worker 
523*e5436536SAndroid Build Coastguard Worker /* Get library info for this module. */
pcmLimiter_GetLibInfo(LIB_INFO * info)524*e5436536SAndroid Build Coastguard Worker TDLIMITER_ERROR pcmLimiter_GetLibInfo(LIB_INFO* info) {
525*e5436536SAndroid Build Coastguard Worker   int i;
526*e5436536SAndroid Build Coastguard Worker 
527*e5436536SAndroid Build Coastguard Worker   if (info == NULL) {
528*e5436536SAndroid Build Coastguard Worker     return TDLIMIT_INVALID_PARAMETER;
529*e5436536SAndroid Build Coastguard Worker   }
530*e5436536SAndroid Build Coastguard Worker 
531*e5436536SAndroid Build Coastguard Worker   /* Search for next free tab */
532*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < FDK_MODULE_LAST; i++) {
533*e5436536SAndroid Build Coastguard Worker     if (info[i].module_id == FDK_NONE) break;
534*e5436536SAndroid Build Coastguard Worker   }
535*e5436536SAndroid Build Coastguard Worker   if (i == FDK_MODULE_LAST) {
536*e5436536SAndroid Build Coastguard Worker     return TDLIMIT_UNKNOWN;
537*e5436536SAndroid Build Coastguard Worker   }
538*e5436536SAndroid Build Coastguard Worker 
539*e5436536SAndroid Build Coastguard Worker   /* Add the library info */
540*e5436536SAndroid Build Coastguard Worker   info[i].module_id = FDK_TDLIMIT;
541*e5436536SAndroid Build Coastguard Worker   info[i].version =
542*e5436536SAndroid Build Coastguard Worker       LIB_VERSION(PCMUTIL_LIB_VL0, PCMUTIL_LIB_VL1, PCMUTIL_LIB_VL2);
543*e5436536SAndroid Build Coastguard Worker   LIB_VERSION_STRING(info + i);
544*e5436536SAndroid Build Coastguard Worker   info[i].build_date = PCMUTIL_LIB_BUILD_DATE;
545*e5436536SAndroid Build Coastguard Worker   info[i].build_time = PCMUTIL_LIB_BUILD_TIME;
546*e5436536SAndroid Build Coastguard Worker   info[i].title = TDLIMIT_LIB_TITLE;
547*e5436536SAndroid Build Coastguard Worker 
548*e5436536SAndroid Build Coastguard Worker   /* Set flags */
549*e5436536SAndroid Build Coastguard Worker   info[i].flags = CAPF_LIMITER;
550*e5436536SAndroid Build Coastguard Worker 
551*e5436536SAndroid Build Coastguard Worker   /* Add lib info for FDK tools (if not yet done). */
552*e5436536SAndroid Build Coastguard Worker   FDK_toolsGetLibInfo(info);
553*e5436536SAndroid Build Coastguard Worker 
554*e5436536SAndroid Build Coastguard Worker   return TDLIMIT_OK;
555*e5436536SAndroid Build Coastguard Worker }
556