Mercurial > audlegacy-plugins
diff src/mpg123/paranoia.c @ 12:3da1b8942b8b trunk
[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 03:14:20 -0700 |
parents | src/Input/mpg123/paranoia.c@13389e613d67 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mpg123/paranoia.c Mon Sep 18 03:14:20 2006 -0700 @@ -0,0 +1,447 @@ +/* libmpgdec: An advanced MPEG layer 1/2/3 decoder. + * psycho.c: Psychoaccoustic modeling. + * + * Copyright (C) 2005-2006 William Pitcock <nenolod@nenolod.net> + * Portions copyright (C) 2001 Rafal Bosak <gyver@fanthom.irc.pl> + * Portions copyright (C) 1999 Michael Hipp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include "common.h" + +int bext_level; +int stereo_level; +int filter_level; +int harmonics_level; +int bext_sfactor; +int stereo_sfactor; +int harmonics_sfactor; +int enable_plugin = 1; +int lsine[65536]; +int rsine[65536]; + +/* + * Initialize and configure the psychoaccoustics engine. + */ +void psycho_init(void) +{ + int i, x; + double lsum; + double rsum; + + bext_level = 34; + stereo_level = stereo_sfactor = 16; + filter_level = 3; + harmonics_level = harmonics_sfactor = 43; + + bext_sfactor = (float)(((float)16384 * 10) / (float)(bext_level + 1)) + (float)(102 - bext_level) * 128; + +#define COND 0 + /* calculate sinetables */ + for (i = 0; i < 32768; ++i) + { + lsum = rsum = 0; + if (COND || i < 32768 )lsum+= ((cos((double)i * 3.141592535 / 32768/2 )) + 0) / 2; + if (COND || i < 16384 )rsum-= ((cos((double)i * 3.141592535 / 16384/2 )) + 0) / 4; + rsum = lsum; + + if (COND || i < 8192 ) lsum += ((cos((double)i * 3.141592535 / 8192/2 )) + 0) / 8; + if (COND || i < 5641 ) rsum += ((cos((double)i * 3.141592535 / 5641.333333/2)) + 0) / 8; + + lsine[32768 + i] = (double)(lsum - 0.5) * 32768 * 1.45; + lsine[32768 - i] = lsine[32768 + i]; + rsine[32768 + i] = (double)(rsum - 0.5) * 32768 * 1.45; + rsine[32768 - i] = rsine[32768 + i]; + + x = i; + } +} + +/* + * This routine computes a reverb for the track. + */ + +#define DELAY2 21000 +#define DELAY1 35000 +#define DELAY3 14000 +#define DELAY4 5 + +#define BUF_SIZE DELAY1+DELAY2+DELAY3+DELAY4 + +void echo3d(gint16 *data, int datasize) +{ + int x; + int left, right, dif, left0, right0, left1, right1, left2, right2, left3, right3, left4, right4, leftc, rightc, lsf, rsf; + static int left0p = 0, right0p = 0; + static int rangeErrorsUp = 0; + static int rangeErrorsDown = 0; + gint16 *dataptr; + static int l0, l1, l2, r0, r1, r2, ls, rs, ls1, rs1; + static int ll0, ll1, ll2, rr0, rr1, rr2; + static int lharmb = 0, rharmb = 0, lhfb = 0, rhfb = 0; + int lharm0, rharm0; + static gint16 buf[BUF_SIZE]; + static int bufPos1 = 1 + BUF_SIZE - DELAY1; + static int bufPos2 = 1 + BUF_SIZE - DELAY1 - DELAY2; + static int bufPos3 = 1 + BUF_SIZE - DELAY1 - DELAY2 - DELAY3; + static int bufPos4 = 1 + BUF_SIZE - DELAY1 - DELAY2 - DELAY3 - DELAY4; + dataptr = data; + + for (x = 0; x < datasize; x += 4) { + + // ************ load sample ********** + left0 = dataptr[0]; + right0 = dataptr[1]; + + // ************ slightly expand stereo for direct input ********** + ll0=left0;rr0=right0; + dif = (ll0+ll1+ll2 - rr0-rr1-rr2) * stereo_sfactor / 256; + left0 += dif; + right0 -= dif; + ll2= ll1; ll1= ll0; + rr2= rr1; rr1= rr0; + + // ************ echo from buffer - first echo ********** + // ************ ********** + left1 = buf[bufPos1++]; + if (bufPos1 == BUF_SIZE) + bufPos1 = 0; + right1 = buf[bufPos1++]; + if (bufPos1 == BUF_SIZE) + bufPos1 = 0; + + // ************ highly expand stereo for first echo ********** + dif = (left1 - right1); + left1 = left1 + dif; + right1 = right1 - dif; + + // ************ second echo ********** + left2 = buf[bufPos2++]; + if (bufPos2 == BUF_SIZE) + bufPos2 = 0; + right2 = buf[bufPos2++]; + if (bufPos2 == BUF_SIZE) + bufPos2 = 0; + + // ************ expand stereo for second echo ********** + dif = (left2 - right2); + left2 = left2 - dif; + right2 = right2 - dif; + + // ************ third echo ********** + left3 = buf[bufPos3++]; + if (bufPos3 == BUF_SIZE) + bufPos3 = 0; + right3 = buf[bufPos3++]; + if (bufPos3 == BUF_SIZE) + bufPos3 = 0; + + // ************ fourth echo ********** + left4 = buf[bufPos4++]; + if (bufPos4 == BUF_SIZE) + bufPos4 = 0; + right4 = buf[bufPos4++]; + if (bufPos4 == BUF_SIZE) + bufPos4 = 0; + + left3 = (left4+left3) / 2; + right3 = (right4+right3) / 2; + + // ************ expand stereo for second echo ********** + dif = (left4 - right4); + left3 = left3 - dif; + right3 = right3 - dif; + + // ************ a weighted sum taken from reverb buffer ********** + leftc = left1 / 9 + right2 /8 + left3 / 8; + rightc = right1 / 11 + left2 / 9 + right3 / 10; + + left = left0p; + right = right0p; + + l0 = leftc + left0 / 2; + r0 = rightc + right0 / 2; + + ls = l0 + l1 + l2; // do not reverb high frequencies (filter) + rs = r0 + r1 + r2; // + + // ************ add some extra even harmonics ********** + // ************ or rather specific nonlinearity + + lhfb = lhfb + (ls * 32768 - lhfb) / 32; + rhfb = rhfb + (rs * 32768 - rhfb) / 32; + + lsf = ls - lhfb / 32768; + rsf = rs - rhfb / 32768; + + lharm0 = 0 + + ((lsf + 10000) * ((((lsine[((lsf/4) + 32768 + 65536) % 65536] * harmonics_sfactor)) / 64))) / 32768 + - ((lsine[((lsf/4) + 32768 +65536) % 65536]) * harmonics_sfactor) / 128 + ; + + rharm0 = + + ((rsf + 10000) * ((((lsine[((rsf/4) + 32768 + 65536) % 65536] * harmonics_sfactor)) / 64))) / 32768 + - ((rsine[((rsf/4) + 32768 +65536) % 65536]) * harmonics_sfactor) / 128 + ; + + lharmb = lharmb + (lharm0 * 32768 - lharmb) / 16384; + rharmb = rharmb + (rharm0 * 32768 - rharmb) / 16384; + + // ************ for convolution filters ********** + l2= l1; r2= r1; + l1 = l0; r1 = r0; + ls1 = ls; rs1 = rs; + + left = 0 + lharm0 - lharmb / 32768 + left; + right = 0 + rharm0 - rharmb / 32768 + right; + + left0p = left0; + right0p = right0; + + + // ************ limiter ********** + if (left < -32768) { + left = -32768; // limit + rangeErrorsDown++; + } + else if (left > 32767) { + left = 32767; + rangeErrorsUp++; + } + if (right < -32768) { + right = -32768; + rangeErrorsDown++; + } + else if (right > 32767) { + right = 32767; + rangeErrorsUp++; + } + // ************ store sample ********** + dataptr[0] = left; + dataptr[1] = right; + dataptr += 2; + + } +} + +/* + * simple pith shifter, plays short fragments at 1.5 speed + */ +void pitchShifter(const int lin, const int rin, int *lout, int *rout) +{ +#define SH_BUF_SIZE 100 * 3 + static gint16 shBuf[SH_BUF_SIZE]; + static int shBufPos = SH_BUF_SIZE - 6; + static int shBufPos1 = SH_BUF_SIZE - 6; + static int cond; + + shBuf[shBufPos++] = lin; + shBuf[shBufPos++] = rin; + + if (shBufPos == SH_BUF_SIZE) shBufPos = 0; + + switch (cond){ + case 1: + *lout = (shBuf[shBufPos1 + 0] * 2 + shBuf[shBufPos1 + 2])/4; + *rout = (shBuf[shBufPos1 + 1] * 2 + shBuf[shBufPos1 + 3])/4; + break; + case 0: + *lout = (shBuf[shBufPos1 + 4] * 2 + shBuf[shBufPos1 + 2])/4; + *rout = (shBuf[shBufPos1 + 5] * 2 + shBuf[shBufPos1 + 3])/4; + cond = 2; + shBufPos1 += 6; + if (shBufPos1 == SH_BUF_SIZE) { + shBufPos1 = 0; + } + break; + } + cond--; +} + + +struct Interpolation{ + int acount; // counter + int lval, rval; // value + int sal, sar; // sum + int al, ar; + int a1l, a1r; +}; + +/* + * interpolation routine for ampliude and "energy" + */ +static inline void interpolate(struct Interpolation *s, int l, int r) +{ +#define AMPL_COUNT 64 + int a0l, a0r, dal = 0, dar = 0; + + if (l < 0) l = -l; + if (r < 0) r = -r; + + s->lval += l / 8; + s->rval += r / 8; + + s->lval = (s->lval * 120) / 128; + s->rval = (s->rval * 120) / 128; + + s->sal += s->lval; + s->sar += s->rval; + + s->acount++; + if (s->acount == AMPL_COUNT){ + s->acount = 0; + a0l = s->a1l; + a0r = s->a1r; + s->a1l = s->sal / AMPL_COUNT; + s->a1r = s->sar / AMPL_COUNT; + s->sal = 0; + s->sar = 0; + dal = s->a1l - a0l; + dar = s->a1r - a0r; + s->al = a0l * AMPL_COUNT; + s->ar = a0r * AMPL_COUNT; + } + + s->al += dal; + s->ar += dar; +} + +/* + * calculate scalefactor for mixer + */ +inline int calc_scalefactor(int a, int e) +{ + int x; + + if (a > 8192) a = 8192; + else if (a < 0) a = 0; + + if (e > 8192) e = 8192; + else if (e < 0) e = 0; + + x = ((e+500) * 4096 )/ (a + 300) + e; + + if (x > 16384) x = 16384; + else if (x < 0) x = 0; + return x; +} + +static struct Interpolation bandext_energy; +static struct Interpolation bandext_amplitude; + +/* + * exact bandwidth extender ("exciter") routine + */ +static void bandext(gint16 *data, const int datasize) +{ + + int x; + static int saw; // test stuff + int left, right; + gint16 *dataptr = data; + static int lprev0, rprev0, lprev1, rprev1, lprev2, rprev2; + int left0, right0, left1, right1, left2, right2, left3, right3; + static int lamplUp, lamplDown; + static int ramplUp, ramplDown; + int lampl, rampl; + int tmp; + + for (x = 0; x < datasize; x += 4) { + + // ************ load sample ********** + left0 = dataptr[0]; + right0 = dataptr[1]; + + // ************ highpass filter part 1 ********** + left1 = (left0 - lprev0) * 56880 / 65536; + right1 = (right0 - rprev0) * 56880 / 65536; + + left2 = (left1 - lprev1) * 56880 / 65536; + right2 = (right1 - rprev1) * 56880 / 65536; + + left3 = (left2 - lprev2) * 56880 / 65536; + right3 = (right2 - rprev2) * 56880 / 65536; + + switch (filter_level){ + case 1: + pitchShifter(left1, right1, &left, &right); + break; + case 2: + pitchShifter(left2, right2, &left, &right); + break; + case 3: + pitchShifter(left3, right3, &left, &right); + break; + } + + // ************ amplitude detector ************ + tmp = left1 + lprev1; + if (tmp * 16 > lamplUp ) lamplUp += (tmp - lamplUp ); + else if (tmp * 16 < lamplDown) lamplDown += (tmp - lamplDown); + lamplUp = (lamplUp * 1000) /1024; + lamplDown = (lamplDown * 1000) /1024; + lampl = lamplUp - lamplDown; + + tmp = right1 + rprev1; + if (tmp * 16 > ramplUp ) ramplUp += (tmp - ramplUp ); + else if (tmp * 16 < ramplDown) ramplDown += (tmp - ramplDown); + ramplUp = (ramplUp * 1000) /1024; + ramplDown = (ramplDown * 1000) /1024; + rampl = ramplUp - ramplDown; + + interpolate(&bandext_amplitude, lampl, rampl); + + // ************ "sound energy" detector (approx. spectrum complexity) *********** + interpolate(&bandext_energy, left0 - lprev0, right0 - rprev0); + + // ************ mixer *********** + left = left0 + left * calc_scalefactor(bandext_amplitude.lval, bandext_energy.lval) / bext_sfactor; + right = right0 + right * calc_scalefactor(bandext_amplitude.rval, bandext_energy.rval) / bext_sfactor; //16384 + + saw = (saw + 2048) & 0x7fff; + + lprev0 = left0; + rprev0 = right0; + lprev1 = left1; + rprev1 = right1; + lprev2 = left2; + rprev2 = right2; + + if (left < -32768) left = -32768; + else if (left > 32767) left = 32767; + if (right < -32768) right = -32768; + else if (right > 32767) right = 32767; + + dataptr[0] = left; + dataptr[1] = right; + dataptr += 2; + } +} + +int psycho_process(void *data, int length, int nch) +{ + if (nch != 2) + return length; /* XXX: we cant process mono yet */ + + echo3d((gint16 *)data, length); + bandext((gint16 *)data, length); + return length; +} +