Spaces:
Build error
Build error
/* -*-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)); | |
} | |
} | |
} | |
} | |