limiter.c
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:12k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. /*
  36.  * Fixed-point lookahead peak-limiter
  37.  * by Ken Cooke
  38.  */
  39. #include "hlxclib/math.h"
  40. #include "hlxclib/stdlib.h"
  41. #include "limiter.h"
  42. #include "math64.h"
  43. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  44. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  45. #define INCMOD(a,b) ((a) = ((a) + (b)) & 0x1ff)
  46. #define LEFT 0
  47. #define RGHT 1
  48. #define MONO 0
  49. #define FIXSCALE 2147483648.0 /* convert to S.31 fixed-point */
  50. #define FLT_ONE 2147483647.0
  51. #define FIX_ONE 0x7fffffff
  52. static const double def_dbgain = 0.0;
  53. static const double def_outceil = -0.1;
  54. static const double def_release = 250.0;
  55. static const double def_rms_attack = 25.0;
  56. static const double def_rms_release = 250.0;
  57. static const double cicgain = (1 << 12) / (53.0 * 76.0);
  58. #define RAND16(r) (((r) = (r) * 69069U + 1U) >> 16)
  59. static unsigned char randseed[32] = { /* Flawfinder: ignore */
  60. 0x00, 0x0d, 0x0a, 0x50, 0x65, 0x61, 0x6b, 0x5f,
  61. 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x20,
  62. 0x62, 0x79, 0x20, 0x4b, 0x65, 0x6e, 0x20, 0x43,
  63. 0x6f, 0x6f, 0x6b, 0x65, 0x0d, 0x0a, 0x00, 0x00,
  64. };
  65. /*
  66.  * Utility functions
  67.  */
  68. double
  69. DbToGain(double db) {
  70. return pow(10.0, db / 20.0);
  71. }
  72. double
  73. GainToDb(double gain) {
  74. ASSERT(gain > 0.0);
  75. return (20.0 * log10(gain));
  76. }
  77. double
  78. MsToTc(double ms, double samprate) {
  79. ASSERT(ms > 0.0);
  80. ASSERT(samprate > 0.0);
  81. return exp(-1000.0 / (ms * samprate));
  82. }
  83. double
  84. TcToMs(double tc, double samprate) {
  85. ASSERT(tc > 0.0);
  86. ASSERT(samprate > 0.0);
  87. return (-1000.0 / (log(tc) * samprate));
  88. }
  89. double
  90. Log2(double x) {
  91. ASSERT(x > 0.0);
  92. return (log(x) / log(2.0));
  93. }
  94. void
  95. LimiterSetGain(double dbgain, LIMSTATE *lim)
  96. {
  97. double mkupgain;
  98. double outgain;
  99. lim->dbgain = dbgain;
  100. /* compute threshold */
  101. mkupgain = (1 << lim->headroom) * DbToGain(dbgain);
  102. lim->threshold = (int)(FLT_ONE / MAX(mkupgain, 1.0));
  103. /* compute output gain */
  104. outgain = DbToGain(def_outceil) * mkupgain * cicgain;
  105. /* normalize outgain into shift and fraction */
  106. lim->outshift = (int) (ceil(Log2(outgain)));
  107. lim->outshift = MAX(lim->outshift, 0);
  108. lim->outfract = (int) ((outgain / (1 << lim->outshift)) * FLT_ONE);
  109. ASSERT(lim->outfract >= 0); /* should never overflow */
  110. lim->outshift = 31 - lim->outshift;
  111. }
  112. void
  113. LimiterSetRelease(double release, LIMSTATE *lim)
  114. {
  115. double x, ms, tc;
  116. double peakval, rmsval;
  117. int n;
  118. /* compute time constants */
  119. lim->reltc = (int)(FIXSCALE * MsToTc(release, lim->samprate));
  120. lim->rmsatktc = (int)(FIXSCALE * MsToTc(def_rms_attack, lim->samprate));
  121. lim->rmsreltc = (int)(FIXSCALE * MsToTc(def_rms_release, lim->samprate));
  122. /* compute adaptive release tables */
  123. for (n = 0; n < 256; n++) {
  124. /* rms saturation curve */
  125. x = n * (1.0 / 256.0);
  126. x = x * x * x;
  127. x = 1.0 - x;
  128. x = x * x * x; /* cubic "S" curve */
  129. ms = x * release;
  130. ms = MAX(ms, 0.01); /* clamp small values */
  131. tc = MsToTc(ms, lim->samprate);
  132. /* peak-over-rms acceleration */
  133. peakval = pow(0.5, 1.0 / (n + 1));
  134. rmsval = tc / peakval;
  135. lim->peaktab[n] = (int)(FIXSCALE * peakval);
  136. lim->rmstab[n] = (int)(0.5 * FIXSCALE * rmsval); /* shifted >> 1 */
  137. }
  138. }
  139. int
  140. LimiterGetDelay(LIMSTATE *lim)
  141. {
  142. return 128;
  143. }
  144. double
  145. LimiterGetAtten(LIMSTATE *lim)
  146. {
  147. return -GainToDb(lim->peak_z / FLT_ONE); // fixme
  148. }
  149. LIMSTATE *
  150. LimiterInit(int samprate, int channels, int headroom)
  151. {
  152. LIMSTATE *lim;
  153. int i, n, dcinput;
  154. lim = (LIMSTATE *) calloc(1, sizeof(LIMSTATE));
  155. if (!lim)
  156. return NULL;
  157. ASSERT(headroom >= 0); /* required for abs(pcm) */
  158. lim->samprate = samprate;
  159. lim->channels = channels;
  160. lim->headroom = headroom;
  161. /* init history */
  162. lim->idx = 0;
  163. lim->peak_z = FIX_ONE;
  164. lim->rms_z = FIX_ONE;
  165. lim->randsave = randseed[19] | 0x1;
  166. i = 0;
  167. /* peak-hold lookahead */
  168. for (n = 0; n < 128; n++)
  169. lim->delay[i++] = FIX_ONE;
  170. /* CIC filter history */
  171. dcinput = FIX_ONE >> 6;
  172. lim->acc1 = 53 * dcinput;
  173. for (n = 52; n > 0; n--)
  174. lim->delay[i++] = n * dcinput;
  175. dcinput = (dcinput * 53) >> 6;
  176. lim->acc2 = 76 * dcinput;
  177. for (n = 75; n > 0; n--)
  178. lim->delay[i++] = n * dcinput;
  179. lim->delay[i++] = 0xbadf00d; /* unused tap */
  180. /* pcm delay */
  181. for (n = 0; n < 256; n++)
  182. lim->delay[i++] = 0;
  183. ASSERT(i == 512);
  184. /* default settings */
  185. LimiterSetGain(def_dbgain, lim);
  186. LimiterSetRelease(def_release, lim);
  187. return lim;
  188. }
  189. void
  190. LimiterFree(LIMSTATE *lim)
  191. {
  192. free(lim);
  193. }
  194. #ifdef HAVE_PLATFORM_MACROS
  195. void
  196. LimiterStereo(int *pcmbuf, int nsamples, LIMSTATE *lim)
  197. {
  198. int *pcmptr, *delay;
  199. int atten, rms, peak;
  200. int i, tc;
  201. // TICK();
  202. ASSERT(!(nsamples & 0x1)); /* must be even */
  203. delay = lim->delay;
  204. i = lim->idx;
  205. for (pcmptr = pcmbuf; pcmptr < pcmbuf + nsamples; pcmptr += 2) {
  206. unsigned int pcmleft  = abs(pcmptr[LEFT]) ;
  207. unsigned int pcmright = abs(pcmptr[RGHT]) ;
  208. /* peak detect */
  209. unsigned int pcmpeak  = MAX(pcmleft, pcmright) ;
  210. /* compute the required attenuation */
  211. if (pcmpeak == 0x80000000UL)
  212. atten = MulShift31(FIX_ONE, lim->threshold) ;
  213. else if ((signed)pcmpeak > lim->threshold)
  214. atten = MulDiv64(FIX_ONE, lim->threshold, pcmpeak);
  215. else
  216. atten = FIX_ONE;
  217. /* peak-hold lookahead */
  218. delay[i] = atten;
  219. INCMOD(i, 1);
  220. atten = MIN(atten, delay[i]);
  221. delay[i] = atten;
  222. INCMOD(i, 2);
  223. atten = MIN(atten, delay[i]);
  224. delay[i] = atten;
  225. INCMOD(i, 4);
  226. atten = MIN(atten, delay[i]);
  227. delay[i] = atten;
  228. INCMOD(i, 8);
  229. atten = MIN(atten, delay[i]);
  230. delay[i] = atten;
  231. INCMOD(i, 16);
  232. atten = MIN(atten, delay[i]);
  233. delay[i] = atten;
  234. INCMOD(i, 32);
  235. atten = MIN(atten, delay[i]);
  236. delay[i] = atten;
  237. INCMOD(i, 64);
  238. atten = MIN(atten, delay[i]);
  239. /* atten is now min value over lookahead */
  240. /* release filter */
  241. peak = atten;
  242. if (peak > lim->peak_z)
  243. peak -= MulShift31((peak - lim->peak_z), lim->reltc);
  244. lim->peak_z = peak;
  245. atten = peak;
  246. /* adapt release */
  247. rms = atten;
  248. tc = (rms < lim->rms_z ? lim->rmsatktc : lim->rmsreltc);
  249. rms -= MulShift31((rms - lim->rms_z), tc);
  250. lim->rms_z = rms;
  251. peak = MIN(peak, rms);
  252. lim->reltc = MulShiftN(lim->peaktab[peak>>23], lim->rmstab[rms>>23], 30);
  253. /*
  254.  * FIR attack/lowpass filter, via 2-stage CIC
  255.  *
  256.  * H(z) = 1 (1 - z^-53) (1 - z^-76)
  257.  *        - ---------- ----------
  258.  *    53*76 (1 - z^-1)  (1 - z^-1)
  259.  */
  260. delay[i] = lim->acc1;
  261. lim->acc1 += atten >> 6;
  262. INCMOD(i, 52);
  263. atten = lim->acc1 - delay[i];
  264. delay[i] = lim->acc2;
  265. lim->acc2 += atten >> 6;
  266. INCMOD(i, 75);
  267. atten = lim->acc2 - delay[i];
  268. atten = MulShift31(atten, lim->outfract);
  269. INCMOD(i, 1); /* skip unused taps */
  270. /* pcm delay */
  271. delay[i] = pcmptr[LEFT];
  272. INCMOD(i, 128);
  273. pcmptr[LEFT] = delay[i];
  274. delay[i] = pcmptr[RGHT];
  275. INCMOD(i, 128);
  276. pcmptr[RGHT] = delay[i];
  277. /* modulate pcm */
  278. pcmptr[LEFT] = MulShiftN(pcmptr[LEFT], atten, lim->outshift);
  279. pcmptr[RGHT] = MulShiftN(pcmptr[RGHT], atten, lim->outshift);
  280. }
  281. lim->idx = i;
  282. // TOCK();
  283. }
  284. void
  285. LimiterMono(int *pcmbuf, int nsamples, LIMSTATE *lim)
  286. {
  287. int *pcmptr, *delay;
  288. int atten, rms, peak;
  289. int i, tc;
  290. // TICK();
  291. delay = lim->delay;
  292. i = lim->idx;
  293. for (pcmptr = pcmbuf; pcmptr < pcmbuf + nsamples; pcmptr += 1) {
  294. /* peak detect */
  295. unsigned int pcmpeak = abs(pcmptr[MONO]);
  296. /* compute the required attenuation */
  297. if (pcmpeak == 0x80000000UL)
  298. atten = MulShift31(FIX_ONE, lim->threshold) ;
  299. else if ((signed)pcmpeak > lim->threshold)
  300. atten = MulDiv64(FIX_ONE, lim->threshold, pcmpeak);
  301. else
  302. atten = FIX_ONE;
  303. /* peak-hold lookahead */
  304. delay[i] = atten;
  305. INCMOD(i, 1);
  306. atten = MIN(atten, delay[i]);
  307. delay[i] = atten;
  308. INCMOD(i, 2);
  309. atten = MIN(atten, delay[i]);
  310. delay[i] = atten;
  311. INCMOD(i, 4);
  312. atten = MIN(atten, delay[i]);
  313. delay[i] = atten;
  314. INCMOD(i, 8);
  315. atten = MIN(atten, delay[i]);
  316. delay[i] = atten;
  317. INCMOD(i, 16);
  318. atten = MIN(atten, delay[i]);
  319. delay[i] = atten;
  320. INCMOD(i, 32);
  321. atten = MIN(atten, delay[i]);
  322. delay[i] = atten;
  323. INCMOD(i, 64);
  324. atten = MIN(atten, delay[i]);
  325. /* atten is now min value over lookahead */
  326. /* release filter */
  327. peak = atten;
  328. if (peak > lim->peak_z)
  329. peak -= MulShift31((peak - lim->peak_z), lim->reltc);
  330. lim->peak_z = peak;
  331. atten = peak;
  332. /* adapt release */
  333. rms = atten;
  334. tc = (rms < lim->rms_z ? lim->rmsatktc : lim->rmsreltc);
  335. rms -= MulShift31((rms - lim->rms_z), tc);
  336. lim->rms_z = rms;
  337. peak = MIN(peak, rms);
  338. lim->reltc = MulShiftN(lim->peaktab[peak>>23], lim->rmstab[rms>>23], 30);
  339. /*
  340.  * FIR attack/lowpass filter, via 2-stage CIC
  341.  *
  342.  * H(z) = 1 (1 - z^-53) (1 - z^-76)
  343.  *        - ---------- ----------
  344.  *    53*76 (1 - z^-1)  (1 - z^-1)
  345.  */
  346. delay[i] = lim->acc1;
  347. lim->acc1 += atten >> 6;
  348. INCMOD(i, 52);
  349. atten = lim->acc1 - delay[i];
  350. delay[i] = lim->acc2;
  351. lim->acc2 += atten >> 6;
  352. INCMOD(i, 75);
  353. atten = lim->acc2 - delay[i];
  354. atten = MulShift31(atten, lim->outfract);
  355. INCMOD(i, 129); /* skip unused taps */
  356. /* pcm delay */
  357. delay[i] = pcmptr[MONO];
  358. INCMOD(i, 128);
  359. pcmptr[MONO] = delay[i];
  360. /* modulate pcm */
  361. pcmptr[MONO] = MulShiftN(pcmptr[MONO], atten, lim->outshift);
  362. }
  363. lim->idx = i;
  364. // TOCK();
  365. }
  366. void
  367. LimiterProcess(int *pcmbuf, int nsamples, LIMSTATE *lim)
  368. {
  369. if (lim->channels == 1)
  370. LimiterMono(pcmbuf, nsamples, lim);
  371. else
  372. LimiterStereo(pcmbuf, nsamples, lim);
  373. }
  374. #endif
  375. void
  376. LimiterOutput16(int *pcmbuf, short *outbuf, int nsamples, LIMSTATE *lim)
  377. {
  378. unsigned int randsave;
  379. int i, r0, r1, dither;
  380. // TICK();
  381. ASSERT(def_outceil < -0.0004); /* guarantees no clipping */
  382. randsave = lim->randsave;
  383. for (i = 0; i < nsamples; i++) {
  384. r0 = RAND16(randsave);
  385. r1 = RAND16(randsave);
  386. dither = r0 - r1; /* flat TPDF dither */
  387. outbuf[i] = (short) ((pcmbuf[i] + dither + (1<<15)) >> 16);
  388. }
  389. lim->randsave = randsave;
  390. // TOCK();
  391. }