186 lines
4.6 KiB
Java
186 lines
4.6 KiB
Java
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
|
/* 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) {
|
|
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) {
|
|
|
|
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);
|
|
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
}
|