9fee0ec4ca
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657
254 lines
5.9 KiB
Java
254 lines
5.9 KiB
Java
/* 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;
|
|
}
|
|
}
|
|
*/
|
|
}
|