1603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
2603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* -----------------------------------------------------------------------------------------------------------
3603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviSoftware License for The Fraunhofer FDK AAC Codec Library for Android
4603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
5603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi� Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
6603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  All rights reserved.
7603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
8603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi 1.    INTRODUCTION
9603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviThe Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivithe MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviThis FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
13603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviAAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviaudio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviindependent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviof the MPEG specifications.
17603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
18603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviPatent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivimay be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviindividually for the purpose of encoding or decoding bit streams in products that are compliant with
21603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivithe ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivithese patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivisoftware may already be covered under those patent licenses when it is used for those licensed purposes only.
24603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
25603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviCommercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviare also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviapplications information and documentation.
28603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
29603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi2.    COPYRIGHT LICENSE
30603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
31603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviRedistribution and use in source and binary forms, with or without modification, are permitted without
32603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivipayment of copyright license fees provided that you satisfy the following conditions:
33603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
34603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviYou must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviyour modifications thereto in source code form.
36603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
37603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviYou must retain the complete text of this software license in the documentation and/or other materials
38603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviprovided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviYou must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivimodifications thereto to recipients of copies in binary form.
41603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
42603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviThe name of Fraunhofer may not be used to endorse or promote products derived from this library without
43603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviprior written permission.
44603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
45603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviYou may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivisoftware or your modifications thereto.
47603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
48603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviYour modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviand the date of any change. For modified versions of the FDK AAC Codec, the term
50603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
52603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
53603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi3.    NO PATENT LICENSE
54603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
55603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviNO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivirespect to this software.
58603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
59603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviYou may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviby appropriate patent licenses.
61603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
62603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi4.    DISCLAIMER
63603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
64603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviThis FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviof merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviCONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviincluding but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivior business interruption, however caused and on any theory of liability, whether in contract, strict
70603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviliability, or tort (including negligence), arising in any way out of the use of this software, even if
71603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviadvised of the possibility of such damage.
72603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
73603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi5.    CONTACT INFORMATION
74603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
75603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviFraunhofer Institute for Integrated Circuits IIS
76603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviAttention: Audio and Multimedia Departments - FDK AAC LL
77603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviAm Wolfsmantel 33
78603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi91058 Erlangen, Germany
79603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
80603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviwww.iis.fraunhofer.de/amm
81603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviamm-info@iis.fraunhofer.de
82603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi----------------------------------------------------------------------------------------------------------- */
83603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
84603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/************************  FDK PCM postprocessor module  *********************
85603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
86603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi   Author(s):   Matthias Neusinger
87603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi   Description: Hard limiter for clipping prevention
88603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
89603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi*******************************************************************************/
90603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
91603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi#include "limiter.h"
92603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
93603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
94603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivistruct TDLimiter {
95603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int  attack;
96603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      attackConst, releaseConst;
97603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int  attackMs, releaseMs, maxAttackMs;
98603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_PCM      threshold;
99603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int  channels, maxChannels;
100603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int  sampleRate, maxSampleRate;
101603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      cor, max;
102603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL*     maxBuf;
103603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL*     delayBuf;
104603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int  maxBufIdx, delayBufIdx;
105603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      smoothState0;
106603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      minGain;
107603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
108603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      additionalGainPrev;
109603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      additionalGainFilterState;
110603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL      additionalGainFilterState1;
111603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi};
112603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
113603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* create limiter */
114603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLimiterPtr createLimiter(
115603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                           unsigned int  maxAttackMs,
116603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                           unsigned int  releaseMs,
117603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                           INT_PCM       threshold,
118603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                           unsigned int  maxChannels,
119603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                           unsigned int  maxSampleRate
120603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                           )
121603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
122603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  TDLimiterPtr limiter = NULL;
123603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int attack, release;
124603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL attackConst, releaseConst, exponent;
125603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  INT e_ans;
126603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
127603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* calc attack and release time in samples */
128603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attack = (unsigned int)(maxAttackMs * maxSampleRate / 1000);
129603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  release = (unsigned int)(releaseMs * maxSampleRate / 1000);
130603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
131603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* alloc limiter struct */
132603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter = (TDLimiterPtr)FDKcalloc(1, sizeof(struct TDLimiter));
133603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (!limiter) return NULL;
134603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
135603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* alloc max and delay buffers */
136603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->maxBuf   = (FIXP_DBL*)FDKcalloc(attack + 1, sizeof(FIXP_DBL));
137603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->delayBuf = (FIXP_DBL*)FDKcalloc(attack * maxChannels, sizeof(FIXP_DBL));
138603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
139603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (!limiter->maxBuf || !limiter->delayBuf) {
140603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    destroyLimiter(limiter);
141603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    return NULL;
142603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  }
143603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
144603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* attackConst = pow(0.1, 1.0 / (attack + 1)) */
145603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  exponent = invFixp(attack+1);
146603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
147603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attackConst = scaleValue(attackConst, e_ans);
148603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
149603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* releaseConst  = (float)pow(0.1, 1.0 / (release + 1)) */
150603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  exponent = invFixp(release + 1);
151603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
152603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  releaseConst = scaleValue(releaseConst, e_ans);
153603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
154603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* init parameters */
155603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attackMs      = maxAttackMs;
156603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->maxAttackMs   = maxAttackMs;
157603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->releaseMs     = releaseMs;
158603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attack        = attack;
159603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attackConst   = attackConst;
160603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->releaseConst  = releaseConst;
161603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->threshold     = (FIXP_PCM)threshold;
162603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->channels      = maxChannels;
163603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->maxChannels   = maxChannels;
164603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->sampleRate    = maxSampleRate;
165603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->maxSampleRate = maxSampleRate;
166603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
167603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  resetLimiter(limiter);
168603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
169603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return limiter;
170603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
171603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
172603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
173603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* reset limiter */
174603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR resetLimiter(TDLimiterPtr limiter)
175603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
176603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (limiter != NULL) {
177603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
178603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->maxBufIdx = 0;
179603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->delayBufIdx = 0;
180603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->max = (FIXP_DBL)0;
181603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->cor = FL2FXCONST_DBL(1.0f/(1<<1));
182603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->smoothState0 = FL2FXCONST_DBL(1.0f/(1<<1));
183603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->minGain = FL2FXCONST_DBL(1.0f/(1<<1));
184603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
185603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->additionalGainPrev = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
186603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->additionalGainFilterState = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
187603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->additionalGainFilterState1 = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
188603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
189603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FDKmemset(limiter->maxBuf,   0, (limiter->attack + 1) * sizeof(FIXP_DBL) );
190603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FDKmemset(limiter->delayBuf, 0, limiter->attack * limiter->channels * sizeof(FIXP_DBL) );
191603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  }
192603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  else {
193603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    return TDLIMIT_INVALID_HANDLE;
194603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  }
195603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
196603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
197603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
198603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
199603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
200603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* destroy limiter */
201603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR destroyLimiter(TDLimiterPtr limiter)
202603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
203603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (limiter != NULL) {
204603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FDKfree(limiter->maxBuf);
205603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FDKfree(limiter->delayBuf);
206603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
207603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FDKfree(limiter);
208603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  }
209603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  else {
210603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    return TDLIMIT_INVALID_HANDLE;
211603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  }
212603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
213603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
214603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
215603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* apply limiter */
216603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR applyLimiter(TDLimiterPtr limiter,
217603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                 INT_PCM*    samples,
218603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                 FIXP_DBL*    pGain,
219603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                 const INT*   gain_scale,
220603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                 const UINT   gain_size,
221603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                 const UINT   gain_delay,
222603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi                 const UINT   nSamples)
223603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
224603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int i, j;
225603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_PCM tmp1, tmp2;
226603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL tmp, old, gain, additionalGain, additionalGainUnfiltered;
227603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL minGain = FL2FXCONST_DBL(1.0f/(1<<1));
228603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
229603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FDK_ASSERT(gain_size == 1);
230603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FDK_ASSERT(gain_delay <= nSamples);
231603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
232603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
233603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
234603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  {
235603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    unsigned int channels       = limiter->channels;
236603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    unsigned int attack         = limiter->attack;
237603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     attackConst    = limiter->attackConst;
238603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     releaseConst   = limiter->releaseConst;
239603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     threshold      = FX_PCM2FX_DBL(limiter->threshold)>>TDL_GAIN_SCALING;
240603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
241603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     max            = limiter->max;
242603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL*    maxBuf         = limiter->maxBuf;
243603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    unsigned int maxBufIdx      = limiter->maxBufIdx;
244603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     cor            = limiter->cor;
245603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL*    delayBuf       = limiter->delayBuf;
246603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    unsigned int delayBufIdx    = limiter->delayBufIdx;
247603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
248603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     smoothState0   = limiter->smoothState0;
249603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     additionalGainSmoothState = limiter->additionalGainFilterState;
250603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    FIXP_DBL     additionalGainSmoothState1 = limiter->additionalGainFilterState1;
251603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
252603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    for (i = 0; i < nSamples; i++) {
253603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
254603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (i < gain_delay) {
255603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        additionalGainUnfiltered = limiter->additionalGainPrev;
256603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      } else {
257603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        additionalGainUnfiltered = pGain[0];
258603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
259603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
260603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* Smooth additionalGain */
261603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* [b,a] = butter(1, 0.01) */
262603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      static const FIXP_SGL b[] = { FL2FXCONST_SGL(0.015466*2.0), FL2FXCONST_SGL( 0.015466*2.0) };
263603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      static const FIXP_SGL a[] = { FL2FXCONST_SGL(1.000000), FL2FXCONST_SGL(-0.96907) };
264603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* [b,a] = butter(1, 0.001) */
265603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      //static const FIXP_SGL b[] = { FL2FXCONST_SGL(0.0015683*2.0), FL2FXCONST_SGL( 0.0015683*2.0) };
266603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      //static const FIXP_SGL a[] = { FL2FXCONST_SGL(1.0000000), FL2FXCONST_SGL(-0.99686) };
267603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      additionalGain = - fMult(additionalGainSmoothState, a[1]) + fMultDiv2( additionalGainUnfiltered, b[0]) + fMultDiv2(additionalGainSmoothState1, b[1]);
268603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      additionalGainSmoothState1 = additionalGainUnfiltered;
269603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      additionalGainSmoothState = additionalGain;
270603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
271603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* Apply the additional scaling that has no delay and no smoothing */
272603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (gain_scale[0] > 0) {
273603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        additionalGain <<= gain_scale[0];
274603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      } else {
275603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        additionalGain >>= gain_scale[0];
276603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
277603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
278603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* get maximum absolute sample value of all channels, including the additional gain. */
279603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      tmp1 = (FIXP_PCM)0;
280603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      for (j = 0; j < channels; j++) {
281603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi          tmp2 = (FIXP_PCM)samples[i * channels + j];
282603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi          if (tmp2 == (FIXP_PCM)SAMPLE_MIN) /* protect fAbs from -1.0 value */
283603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi              tmp2 = (FIXP_PCM)(SAMPLE_MIN+1);
284603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        tmp1 = fMax(tmp1, fAbs(tmp2));
285603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
286603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      tmp = SATURATE_LEFT_SHIFT(fMultDiv2(tmp1, additionalGain), 1, DFRACT_BITS);
287603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
288603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* set threshold as lower border to save calculations in running maximum algorithm */
289603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      tmp = fMax(tmp, threshold);
290603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
291603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* running maximum */
292603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      old = maxBuf[maxBufIdx];
293603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      maxBuf[maxBufIdx] = tmp;
294603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
295603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (tmp >= max) {
296603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        /* new sample is greater than old maximum, so it is the new maximum */
297603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        max = tmp;
298603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
299603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      else if (old < max) {
300603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        /* maximum does not change, as the sample, which has left the window was
301603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi           not the maximum */
302603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
303603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      else {
304603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        /* the old maximum has left the window, we have to search the complete
305603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi           buffer for the new max */
306603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        max = maxBuf[0];
307603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        for (j = 1; j <= attack; j++) {
308603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi          if (maxBuf[j] > max) max = maxBuf[j];
309603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        }
310603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
311603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      maxBufIdx++;
312603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (maxBufIdx >= attack+1) maxBufIdx = 0;
313603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
314603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* calc gain */
315603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* gain is downscaled by one, so that gain = 1.0 can be represented */
316603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (max > threshold) {
317603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        gain = fDivNorm(threshold, max)>>1;
318603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
319603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      else {
320603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        gain = FL2FXCONST_DBL(1.0f/(1<<1));
321603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
322603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
323603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* gain smoothing, method: TDL_EXPONENTIAL */
324603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* first order IIR filter with attack correction to avoid overshoots */
325603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
326603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* correct the 'aiming' value of the exponential attack to avoid the remaining overshoot */
327603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (gain < smoothState0) {
328603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        cor = fMin(cor, fMultDiv2((gain - fMultDiv2(FL2FXCONST_SGL(0.1f*(1<<1)),smoothState0)), FL2FXCONST_SGL(1.11111111f/(1<<1)))<<2);
329603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
330603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      else {
331603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        cor = gain;
332603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
333603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
334603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* smoothing filter */
335603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (cor < smoothState0) {
336603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        smoothState0 = fMult(attackConst,(smoothState0 - cor)) + cor;  /* attack */
337603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        smoothState0 = fMax(smoothState0, gain); /* avoid overshooting target */
338603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
339603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      else {
340603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        /* sign inversion twice to round towards +infinity,
341603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi           so that gain can converge to 1.0 again,
342603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi           for bit-identical output when limiter is not active */
343603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        smoothState0 = -fMult(releaseConst,-(smoothState0 - cor)) + cor; /* release */
344603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
345603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
346603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      gain = smoothState0;
347603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
348603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* lookahead delay, apply gain */
349603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      for (j = 0; j < channels; j++) {
350603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
351603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        tmp = delayBuf[delayBufIdx * channels + j];
352603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        delayBuf[delayBufIdx * channels + j] = fMult((FIXP_PCM)samples[i * channels + j], additionalGain);
353603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
354603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        /* Apply gain to delayed signal */
355603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        if (gain < FL2FXCONST_DBL(1.0f/(1<<1)))
356603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi          tmp = fMult(tmp,gain<<1);
357603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
358603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi        samples[i * channels + j] = FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(tmp,TDL_GAIN_SCALING,DFRACT_BITS));
359603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      }
360603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      delayBufIdx++;
361603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (delayBufIdx >= attack) delayBufIdx = 0;
362603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
363603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      /* save minimum gain factor */
364603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi      if (gain < minGain) minGain = gain;
365603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    }
366603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
367603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
368603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->max = max;
369603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->maxBufIdx = maxBufIdx;
370603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->cor = cor;
371603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->delayBufIdx = delayBufIdx;
372603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
373603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->smoothState0 = smoothState0;
374603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->additionalGainFilterState = additionalGainSmoothState;
375603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->additionalGainFilterState1 = additionalGainSmoothState1;
376603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
377603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->minGain = minGain;
378603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
379603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    limiter->additionalGainPrev = pGain[0];
380603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
381603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi    return TDLIMIT_OK;
382603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  }
383603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
384603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
385603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* get delay in samples */
386603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Triviunsigned int getLimiterDelay(TDLimiterPtr limiter)
387603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
388603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FDK_ASSERT(limiter != NULL);
389603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return limiter->attack;
390603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
391603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
392603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* set number of channels */
393603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR setLimiterNChannels(TDLimiterPtr limiter, unsigned int nChannels)
394603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
395603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
396603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
397603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (nChannels > limiter->maxChannels) return TDLIMIT_INVALID_PARAMETER;
398603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
399603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->channels = nChannels;
400603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  //resetLimiter(limiter);
401603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
402603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
403603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
404603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
405603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* set sampling rate */
406603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR setLimiterSampleRate(TDLimiterPtr limiter, unsigned int sampleRate)
407603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
408603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int attack, release;
409603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL attackConst, releaseConst, exponent;
410603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  INT e_ans;
411603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
412603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
413603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
414603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (sampleRate > limiter->maxSampleRate) return TDLIMIT_INVALID_PARAMETER;
415603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
416603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* update attack and release time in samples */
417603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attack = (unsigned int)(limiter->attackMs * sampleRate / 1000);
418603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  release = (unsigned int)(limiter->releaseMs * sampleRate / 1000);
419603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
420603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* attackConst = pow(0.1, 1.0 / (attack + 1)) */
421603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  exponent = invFixp(attack+1);
422603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
423603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attackConst = scaleValue(attackConst, e_ans);
424603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
425603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* releaseConst  = (float)pow(0.1, 1.0 / (release + 1)) */
426603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  exponent = invFixp(release + 1);
427603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
428603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  releaseConst = scaleValue(releaseConst, e_ans);
429603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
430603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attack        = attack;
431603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attackConst   = attackConst;
432603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->releaseConst  = releaseConst;
433603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->sampleRate    = sampleRate;
434603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
435603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* reset */
436603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  //resetLimiter(limiter);
437603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
438603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
439603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
440603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
441603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* set attack time */
442603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR setLimiterAttack(TDLimiterPtr limiter, unsigned int attackMs)
443603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
444603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int attack;
445603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL attackConst, exponent;
446603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  INT e_ans;
447603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
448603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
449603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
450603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if (attackMs > limiter->maxAttackMs) return TDLIMIT_INVALID_PARAMETER;
451603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
452603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* calculate attack time in samples */
453603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attack = (unsigned int)(attackMs * limiter->sampleRate / 1000);
454603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
455603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* attackConst = pow(0.1, 1.0 / (attack + 1)) */
456603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  exponent = invFixp(attack+1);
457603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
458603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  attackConst = scaleValue(attackConst, e_ans);
459603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
460603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attack        = attack;
461603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attackConst   = attackConst;
462603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->attackMs      = attackMs;
463603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
464603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
465603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
466603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
467603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* set release time */
468603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR setLimiterRelease(TDLimiterPtr limiter, unsigned int releaseMs)
469603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
470603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  unsigned int release;
471603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  FIXP_DBL releaseConst, exponent;
472603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  INT e_ans;
473603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
474603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
475603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
476603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* calculate  release time in samples */
477603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  release = (unsigned int)(releaseMs * limiter->sampleRate / 1000);
478603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
479603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  /* releaseConst  = (float)pow(0.1, 1.0 / (release + 1)) */
480603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  exponent = invFixp(release + 1);
481603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
482603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  releaseConst = scaleValue(releaseConst, e_ans);
483603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
484603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->releaseConst  = releaseConst;
485603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->releaseMs     = releaseMs;
486603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
487603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
488603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
489603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
490603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi/* set limiter threshold */
491603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel TriviTDLIMITER_ERROR setLimiterThreshold(TDLimiterPtr limiter, INT_PCM threshold)
492603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi{
493603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
494603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
495603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  limiter->threshold = (FIXP_PCM)threshold;
496603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi
497603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi  return TDLIMIT_OK;
498603f48ab99ce76f552f4f6f85d06b8c5b94c698eJean-Michel Trivi}
499