rockbox/songdbj/com/jcraft/jorbis/Lpc.java

255 lines
5.9 KiB
Java
Raw Normal View History

/* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package com.jcraft.jorbis;
class Lpc{
// en/decode lookups
Drft fft=new Drft();;
int ln;
int m;
// Autocorrelation LPC coeff generation algorithm invented by
// N. Levinson in 1947, modified by J. Durbin in 1959.
// Input : n elements of time doamin data
// Output: m lpc coefficients, excitation energy
static float lpc_from_data(float[] data, float[] lpc,int n,int m){
float[] aut=new float[m+1];
float error;
int i,j;
// autocorrelation, p+1 lag coefficients
j=m+1;
while(j--!=0){
float d=0;
for(i=j;i<n;i++)d+=data[i]*data[i-j];
aut[j]=d;
}
// Generate lpc coefficients from autocorr values
error=aut[0];
/*
if(error==0){
for(int k=0; k<m; k++) lpc[k]=0.0f;
return 0;
}
*/
for(i=0;i<m;i++){
float r=-aut[i+1];
if(error==0){
for(int k=0; k<m; k++) lpc[k]=0.0f;
return 0;
}
// Sum up this iteration's reflection coefficient; note that in
// Vorbis we don't save it. If anyone wants to recycle this code
// and needs reflection coefficients, save the results of 'r' from
// each iteration.
for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
r/=error;
// Update LPC coefficients and total error
lpc[i]=r;
for(j=0;j<i/2;j++){
float tmp=lpc[j];
lpc[j]+=r*lpc[i-1-j];
lpc[i-1-j]+=r*tmp;
}
if(i%2!=0)lpc[j]+=lpc[j]*r;
error*=1.0-r*r;
}
// we need the error value to know how big an impulse to hit the
// filter with later
return error;
}
// Input : n element envelope spectral curve
// Output: m lpc coefficients, excitation energy
float lpc_from_curve(float[] curve, float[] lpc){
int n=ln;
float[] work=new float[n+n];
float fscale=(float)(.5/n);
int i,j;
// input is a real curve. make it complex-real
// This mixes phase, but the LPC generation doesn't care.
for(i=0;i<n;i++){
work[i*2]=curve[i]*fscale;
work[i*2+1]=0;
}
work[n*2-1]=curve[n-1]*fscale;
n*=2;
fft.backward(work);
// The autocorrelation will not be circular. Shift, else we lose
// most of the power in the edges.
for(i=0,j=n/2;i<n/2;){
float temp=work[i];
work[i++]=work[j];
work[j++]=temp;
}
return(lpc_from_data(work,lpc,n,m));
}
void init(int mapped, int m){
//memset(l,0,sizeof(lpc_lookup));
ln=mapped;
this.m=m;
// we cheat decoding the LPC spectrum via FFTs
fft.init(mapped*2);
}
void clear(){
fft.clear();
}
static float FAST_HYPOT(float a, float b){
return (float)Math.sqrt((a)*(a) + (b)*(b));
}
// One can do this the long way by generating the transfer function in
// the time domain and taking the forward FFT of the result. The
// results from direct calculation are cleaner and faster.
//
// This version does a linear curve generation and then later
// interpolates the log curve from the linear curve.
void lpc_to_curve(float[] curve, float[] lpc, float amp){
//memset(curve,0,sizeof(float)*l->ln*2);
for(int i=0; i<ln*2; i++)curve[i]=0.0f;
if(amp==0)return;
for(int i=0;i<m;i++){
curve[i*2+1]=lpc[i]/(4*amp);
curve[i*2+2]=-lpc[i]/(4*amp);
}
fft.backward(curve); // reappropriated ;-)
{
int l2=ln*2;
float unit=(float)(1./amp);
curve[0]=(float)(1./(curve[0]*2+unit));
for(int i=1;i<ln;i++){
float real=(curve[i]+curve[l2-i]);
float imag=(curve[i]-curve[l2-i]);
float a = real + unit;
curve[i] = (float)(1.0 / FAST_HYPOT(a, imag));
}
}
}
/*
// subtract or add an lpc filter to data. Vorbis doesn't actually use this.
static void lpc_residue(float[] coeff, float[] prime,int m,
float[] data, int n){
// in: coeff[0...m-1] LPC coefficients
// prime[0...m-1] initial values
// data[0...n-1] data samples
// out: data[0...n-1] residuals from LPC prediction
float[] work=new float[m+n];
float y;
if(prime==null){
for(int i=0;i<m;i++){
work[i]=0;
}
}
else{
for(int i=0;i<m;i++){
work[i]=prime[i];
}
}
for(int i=0;i<n;i++){
y=0;
for(int j=0;j<m;j++){
y-=work[i+j]*coeff[m-j-1];
}
work[i+m]=data[i];
data[i]-=y;
}
}
static void lpc_predict(float[] coeff, float[] prime,int m,
float[] data, int n){
// in: coeff[0...m-1] LPC coefficients
// prime[0...m-1] initial values (allocated size of n+m-1)
// data[0...n-1] residuals from LPC prediction
// out: data[0...n-1] data samples
int o,p;
float y;
float[] work=new float[m+n];
if(prime==null){
for(int i=0;i<m;i++){
work[i]=0.f;
}
}
else{
for(int i=0;i<m;i++){
work[i]=prime[i];
}
}
for(int i=0;i<n;i++){
y=data[i];
o=i;
p=m;
for(int j=0;j<m;j++){
y-=work[o++]*coeff[--p];
}
data[i]=work[o]=y;
}
}
*/
}