You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
7.6 KiB
C
283 lines
7.6 KiB
C
/*
|
|
* Musepack audio compression
|
|
* Copyright (c) 2005-2009, The Musepack Development Team
|
|
* Copyright (C) 1999-2004 Buschmann/Klemm/Piecha/Wolf
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "libmpcpsy.h"
|
|
#include <mpc/mpcmath.h>
|
|
|
|
#define CX0 -1.
|
|
#define CX1 0.5
|
|
|
|
#define SX1 -1.
|
|
#define SX2 (2./9/ 1)
|
|
#define SX3 (2./9/ 4)
|
|
#define SX4 (2./9/ 10)
|
|
#define SX5 (2./9/ 20)
|
|
#define SX6 (2./9/ 35)
|
|
#define SX7 (2./9/ 56)
|
|
#define SX8 (2./9/ 84)
|
|
#define SX9 (2./9/120)
|
|
#define SX10 (2./9/165)
|
|
|
|
|
|
#ifdef EXTRA_DECONV
|
|
# define DECONV \
|
|
{ \
|
|
tmp = (CX0*aix[0] + CX1*aix[2]) * (1./(CX0*CX0+CX1*CX1)); \
|
|
aix[ 0] -= CX0*tmp; \
|
|
aix[ 2] -= CX1*tmp; \
|
|
tmp = (SX1*aix[3] + SX2*aix[5] + SX3*aix[7] + SX4*aix[9] + SX5*aix[11]) * (1./(SX1*SX1+SX2*SX2+SX3*SX3+SX4*SX4+SX5*SX5)); \
|
|
aix[ 3] -= SX1*tmp; \
|
|
aix[ 5] -= SX2*tmp; \
|
|
aix[ 7] -= SX3*tmp; \
|
|
aix[ 9] -= SX4*tmp; \
|
|
aix[11] -= SX5*tmp; \
|
|
}
|
|
#elif 0
|
|
# define DECONV \
|
|
{ \
|
|
float A[20]; \
|
|
int i; \
|
|
memcpy (A, aix, 20*sizeof(aix)); \
|
|
tmp = (CX0*aix[0] + CX1*aix[2]) * (1./(CX0*CX0+CX1*CX1)); \
|
|
aix[ 0] -= CX0*tmp; \
|
|
aix[ 2] -= CX1*tmp; \
|
|
tmp = (SX1*aix[3] + SX2*aix[5] + SX3*aix[7] + SX4*aix[9] + SX5*aix[11]) * (1./(SX1*SX1+SX2*SX2+SX3*SX3+SX4*SX4+SX5*SX5)); \
|
|
aix[ 3] -= SX1*tmp; \
|
|
aix[ 5] -= SX2*tmp; \
|
|
aix[ 7] -= SX3*tmp; \
|
|
aix[ 9] -= SX4*tmp; \
|
|
aix[11] -= SX5*tmp; \
|
|
for ( i=0; i<10; i++) \
|
|
printf ("%u%9.0f%7.0f%9.0f%7.0f\n",i, A[i+i], A[i+i+1], aix[i+i], aix[i+i+1] ); \
|
|
}
|
|
#else
|
|
# define DECONV
|
|
#endif
|
|
|
|
|
|
/* V A R I A B L E S */
|
|
static int ip [4096]; // bitinverse for maximum 2048 FFT
|
|
static float w [4096]; // butterfly-coefficient for maximum 2048 FFT
|
|
static float a [4096]; // holds real input for FFT
|
|
static float Hann_256 [ 256];
|
|
static float Hann_1024 [1024];
|
|
static float Hann_1600 [1600];
|
|
|
|
void Generate_FFT_Tables ( const int, int*, float* );
|
|
void rdft ( const int, float*, int*, float* );
|
|
|
|
|
|
//////////////////////////////
|
|
//
|
|
// BesselI0 -- Regular Modified Cylindrical Bessel Function (Bessel I).
|
|
//
|
|
|
|
static double
|
|
Bessel_I_0 ( double x )
|
|
{
|
|
double denominator;
|
|
double numerator;
|
|
double z;
|
|
|
|
if (x == 0.)
|
|
return 1.;
|
|
|
|
z = x * x;
|
|
numerator = z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z*
|
|
0.210580722890567e-22 + 0.380715242345326e-19 ) +
|
|
0.479440257548300e-16) + 0.435125971262668e-13 ) +
|
|
0.300931127112960e-10) + 0.160224679395361e-07 ) +
|
|
0.654858370096785e-05) + 0.202591084143397e-02 ) +
|
|
0.463076284721000e+00) + 0.754337328948189e+02 ) +
|
|
0.830792541809429e+04) + 0.571661130563785e+06 ) +
|
|
0.216415572361227e+08) + 0.356644482244025e+09 ) +
|
|
0.144048298227235e+10;
|
|
|
|
denominator = z* (z* (z - 0.307646912682801e+04) + 0.347626332405882e+07) - 0.144048298227235e+10;
|
|
|
|
return - numerator / denominator;
|
|
}
|
|
|
|
static double
|
|
residual ( double x )
|
|
{
|
|
return sqrt ( 1. - x*x );
|
|
}
|
|
|
|
//////////////////////////////
|
|
//
|
|
// KBDWindow -- Kaiser Bessel Derived Window
|
|
// fills the input window array with size samples of the
|
|
// KBD window with the given tuning parameter alpha.
|
|
//
|
|
|
|
|
|
static void
|
|
KBDWindow ( float* window, unsigned int size, float alpha )
|
|
{
|
|
double sumvalue = 0.;
|
|
double scale;
|
|
int i;
|
|
|
|
scale = 0.25 / sqrt (size);
|
|
for ( i = 0; i < (int)size/2; i++ )
|
|
window [i] = sumvalue += Bessel_I_0 ( M_PI * alpha * residual (4.*i/size - 1.) );
|
|
|
|
// need to add one more value to the nomalization factor at size/2:
|
|
sumvalue += Bessel_I_0 ( M_PI * alpha * residual (4.*(size/2)/size-1.) );
|
|
|
|
// normalize the window and fill in the righthand side of the window:
|
|
for ( i = 0; i < (int)size/2; i++ )
|
|
window [size-1-i] = window [i] = /*sqrt*/ ( window [i] / sumvalue ) * scale;
|
|
}
|
|
|
|
static void
|
|
CosWindow ( float* window, unsigned int size )
|
|
{
|
|
double x;
|
|
double scale;
|
|
int i;
|
|
|
|
scale = 0.25 / sqrt (size);
|
|
for ( i = 0; i < (int)size/2; i++ ) {
|
|
x = cos ( (i+0.5) * (M_PI / size) );
|
|
window [size/2-1-i] = window [size/2+i] = scale * x * x;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Window ( float* window, unsigned int size, float alpha )
|
|
{
|
|
if ( alpha < 0. )
|
|
CosWindow ( window, size ) ;
|
|
else
|
|
KBDWindow ( window, size, alpha );
|
|
}
|
|
|
|
/* F U N C T I O N S */
|
|
// generates FFT lookup-tables
|
|
void
|
|
Init_FFT ( PsyModel* m )
|
|
{
|
|
int n;
|
|
double x;
|
|
double scale;
|
|
|
|
// normalized hann functions
|
|
Window ( Hann_256 , 256, m->KBD1 );
|
|
Window ( Hann_1024, 1024, m->KBD2 );
|
|
scale = 0.25 / sqrt (2048.);
|
|
for ( n = 0; n < 800; n++ )
|
|
x = cos ((n+0.5) * (M_PI/1600)), Hann_1600 [799-n] = Hann_1600 [800+n] = (float)(x * x * scale);
|
|
|
|
Generate_FFT_Tables ( 2048, ip, w );
|
|
}
|
|
|
|
// input : Signal *x
|
|
// output: energy spectrum *erg
|
|
void
|
|
PowSpec256 ( const float* x, float* erg )
|
|
{
|
|
int i;
|
|
// windowing
|
|
for( i = 0; i < 256; ++i )
|
|
a[i] = x[i] * Hann_256[i];
|
|
|
|
rdft(256, a, ip, w); // perform FFT
|
|
|
|
// calculate power
|
|
for( i = 0; i < 128; ++i)
|
|
erg[i] = a[i*2] * a[i*2] + a[i*2+1] * a[i*2+1];
|
|
}
|
|
|
|
// input : Signal *x
|
|
// output: energy spectrum *erg
|
|
void
|
|
PowSpec1024 ( const float* x, float* erg )
|
|
{
|
|
int i;
|
|
// windowing
|
|
for( i = 0; i < 1024; ++i )
|
|
a[i] = x[i] * Hann_1024[i];
|
|
|
|
rdft(1024, a, ip, w); // perform FFT
|
|
|
|
// calculate power
|
|
for( i = 0; i < 512; ++i)
|
|
erg[i] = a[i*2] * a[i*2] + a[i*2+1] * a[i*2+1];
|
|
}
|
|
|
|
// input : Signal *x
|
|
// output: energy spectrum *erg
|
|
void
|
|
PowSpec2048 ( const float* x, float* erg )
|
|
{
|
|
int i;
|
|
// windowing (only 1600 samples available -> centered in 2048!)
|
|
memset(a, 0, 224 * sizeof *a);
|
|
for( i = 0; i < 1600; ++i )
|
|
a[i+224] = x[i] * Hann_1600[i];
|
|
memset(a + 1824, 0, 224 * sizeof *a);
|
|
|
|
rdft(2048, a, ip, w); // perform FFT
|
|
|
|
// calculate power
|
|
for( i = 0; i < 1024; ++i)
|
|
erg[i] = a[i*2] * a[i*2] + a[i*2+1] * a[i*2+1];
|
|
}
|
|
|
|
// input : Signal *x
|
|
// output: energy spectrum *erg and phase spectrum *phs
|
|
void
|
|
PolarSpec1024 ( const float* x, float* erg, float* phs )
|
|
{
|
|
int i;
|
|
for( i = 0; i < 1024; i++ )
|
|
a[i] = x[i] * Hann_1024[i];
|
|
|
|
rdft( 1024, a, ip, w); // perform FFT
|
|
|
|
// calculate power and phase
|
|
for( i = 0; i < 512; ++i )
|
|
{
|
|
erg[i] = a[i*2] * a[i*2] + a[i*2+1] * a[i*2+1];
|
|
phs[i] = ATAN2F( a[i*2+1], a[i*2] );
|
|
}
|
|
}
|
|
|
|
// input : logarithmized energy spectrum *cep
|
|
// output: Cepstrum *cep (in-place)
|
|
void
|
|
Cepstrum2048 ( float* cep, const int MaxLine )
|
|
{
|
|
int i, j;
|
|
// generate real, even spectrum (symmetric around 1024, cep[2048-i] = cep[i])
|
|
for( i = 0, j = 1024; i < 1024; ++i, --j )
|
|
cep[1024 + j] = cep[i];
|
|
|
|
rdft(2048, cep, ip, w);
|
|
|
|
// only real part as outcome (all even indexes of cep[])
|
|
for( i = 0; i < MaxLine + 1; ++i )
|
|
cep[i] = cep[i*2] * (float) (0.9888 / 2048);
|
|
}
|