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; | |
public class DspState { | |
static final float M_PI = 3.1415926539f; | |
static final int VI_TRANSFORMB = 1; | |
static final int VI_WINDOWB = 1; | |
int analysisp; | |
Info vi; | |
int modebits; | |
float[][] pcm; | |
int pcm_storage; | |
int pcm_current; | |
int pcm_returned; | |
float[] multipliers; | |
int envelope_storage; | |
int envelope_current; | |
int eofflag; | |
int lW; | |
int W; | |
int nW; | |
int centerW; | |
long granulepos; | |
long sequence; | |
long glue_bits; | |
long time_bits; | |
long floor_bits; | |
long res_bits; | |
// local lookup storage | |
float[][][][][] window; // block, leadin, leadout, type | |
Object[][] transform; | |
CodeBook[] fullbooks; | |
// backend lookups are tied to the mode, not the backend or naked mapping | |
Object[] mode; | |
// local storage, only used on the encoding side. This way the | |
// application does not need to worry about freeing some packets' | |
// memory and not others'; packet storage is always tracked. | |
// Cleared next call to a _dsp_ function | |
byte[] header; | |
byte[] header1; | |
byte[] header2; | |
public DspState() { | |
transform = new Object[2][]; | |
window = new float[2][][][][]; | |
window[0] = new float[2][][][]; | |
window[0][0] = new float[2][][]; | |
window[0][1] = new float[2][][]; | |
window[0][0][0] = new float[2][]; | |
window[0][0][1] = new float[2][]; | |
window[0][1][0] = new float[2][]; | |
window[0][1][1] = new float[2][]; | |
window[1] = new float[2][][][]; | |
window[1][0] = new float[2][][]; | |
window[1][1] = new float[2][][]; | |
window[1][0][0] = new float[2][]; | |
window[1][0][1] = new float[2][]; | |
window[1][1][0] = new float[2][]; | |
window[1][1][1] = new float[2][]; | |
} | |
static float[] window(int type, int window, int left, int right) { | |
float[] ret = new float[window]; | |
switch (type) { | |
case 0: | |
// The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi) | |
{ | |
int leftbegin = window / 4 - left / 2; | |
int rightbegin = window - window / 4 - right / 2; | |
for (int i = 0; i < left; i++) { | |
float x = (float) ((i + .5) / left * M_PI / 2.); | |
x = (float) Math.sin(x); | |
x *= x; | |
x *= M_PI / 2.; | |
x = (float) Math.sin(x); | |
ret[i + leftbegin] = x; | |
} | |
for (int i = leftbegin + left; i < rightbegin; i++) { | |
ret[i] = 1.f; | |
} | |
for (int i = 0; i < right; i++) { | |
float x = (float) ((right - i - .5) / right * M_PI / 2.); | |
x = (float) Math.sin(x); | |
x *= x; | |
x *= M_PI / 2.; | |
x = (float) Math.sin(x); | |
ret[i + rightbegin] = x; | |
} | |
} | |
break; | |
default: | |
// free(ret); | |
return (null); | |
} | |
return (ret); | |
} | |
// Analysis side code, but directly related to blocking. Thus it's | |
// here and not in analysis.c (which is for analysis transforms only). | |
// The init is here because some of it is shared | |
int init(Info vi, boolean encp) { | |
this.vi = vi; | |
modebits = Util.ilog2(vi.modes); | |
transform[0] = new Object[VI_TRANSFORMB]; | |
transform[1] = new Object[VI_TRANSFORMB]; | |
// MDCT is tranform 0 | |
transform[0][0] = new Mdct(); | |
transform[1][0] = new Mdct(); | |
((Mdct) transform[0][0]).init(vi.blocksizes[0]); | |
((Mdct) transform[1][0]).init(vi.blocksizes[1]); | |
window[0][0][0] = new float[VI_WINDOWB][]; | |
window[0][0][1] = window[0][0][0]; | |
window[0][1][0] = window[0][0][0]; | |
window[0][1][1] = window[0][0][0]; | |
window[1][0][0] = new float[VI_WINDOWB][]; | |
window[1][0][1] = new float[VI_WINDOWB][]; | |
window[1][1][0] = new float[VI_WINDOWB][]; | |
window[1][1][1] = new float[VI_WINDOWB][]; | |
for (int i = 0; i < VI_WINDOWB; i++) { | |
window[0][0][0][i] = window(i, vi.blocksizes[0], vi.blocksizes[0] / 2, vi.blocksizes[0] / 2); | |
window[1][0][0][i] = window(i, vi.blocksizes[1], vi.blocksizes[0] / 2, vi.blocksizes[0] / 2); | |
window[1][0][1][i] = window(i, vi.blocksizes[1], vi.blocksizes[0] / 2, vi.blocksizes[1] / 2); | |
window[1][1][0][i] = window(i, vi.blocksizes[1], vi.blocksizes[1] / 2, vi.blocksizes[0] / 2); | |
window[1][1][1][i] = window(i, vi.blocksizes[1], vi.blocksizes[1] / 2, vi.blocksizes[1] / 2); | |
} | |
fullbooks = new CodeBook[vi.books]; | |
for (int i = 0; i < vi.books; i++) { | |
fullbooks[i] = new CodeBook(); | |
fullbooks[i].init_decode(vi.book_param[i]); | |
} | |
// initialize the storage vectors to a decent size greater than the | |
// minimum | |
pcm_storage = 8192; // we'll assume later that we have | |
// a minimum of twice the blocksize of | |
// accumulated samples in analysis | |
pcm = new float[vi.channels][]; | |
{ | |
for (int i = 0; i < vi.channels; i++) { | |
pcm[i] = new float[pcm_storage]; | |
} | |
} | |
// all 1 (large block) or 0 (small block) | |
// explicitly set for the sake of clarity | |
lW = 0; // previous window size | |
W = 0; // current window size | |
// all vector indexes; multiples of samples_per_envelope_step | |
centerW = vi.blocksizes[1] / 2; | |
pcm_current = centerW; | |
// initialize all the mapping/backend lookups | |
mode = new Object[vi.modes]; | |
for (int i = 0; i < vi.modes; i++) { | |
int mapnum = vi.mode_param[i].mapping; | |
int maptype = vi.map_type[mapnum]; | |
mode[i] = FuncMapping.mapping_P[maptype].look(this, vi.mode_param[i], vi.map_param[mapnum]); | |
} | |
return (0); | |
} | |
public int synthesis_init(Info vi) { | |
init(vi, false); | |
// Adjust centerW to allow an easier mechanism for determining output | |
pcm_returned = centerW; | |
centerW -= vi.blocksizes[W] / 4 + vi.blocksizes[lW] / 4; | |
granulepos = -1; | |
sequence = -1; | |
return (0); | |
} | |
DspState(Info vi) { | |
this(); | |
init(vi, false); | |
// Adjust centerW to allow an easier mechanism for determining output | |
pcm_returned = centerW; | |
centerW -= vi.blocksizes[W] / 4 + vi.blocksizes[lW] / 4; | |
granulepos = -1; | |
sequence = -1; | |
} | |
// Unike in analysis, the window is only partially applied for each | |
// block. The time domain envelope is not yet handled at the point of | |
// calling (as it relies on the previous block). | |
public int synthesis_blockin(Block vb) { | |
// Shift out any PCM/multipliers that we returned previously | |
// centerW is currently the center of the last block added | |
if (centerW > vi.blocksizes[1] / 2 && pcm_returned > 8192) { | |
// don't shift too much; we need to have a minimum PCM buffer of | |
// 1/2 long block | |
int shiftPCM = centerW - vi.blocksizes[1] / 2; | |
shiftPCM = (pcm_returned < shiftPCM ? pcm_returned : shiftPCM); | |
pcm_current -= shiftPCM; | |
centerW -= shiftPCM; | |
pcm_returned -= shiftPCM; | |
if (shiftPCM != 0) { | |
for (int i = 0; i < vi.channels; i++) { | |
System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current); | |
} | |
} | |
} | |
lW = W; | |
W = vb.W; | |
nW = -1; | |
glue_bits += vb.glue_bits; | |
time_bits += vb.time_bits; | |
floor_bits += vb.floor_bits; | |
res_bits += vb.res_bits; | |
if (sequence + 1 != vb.sequence) | |
granulepos = -1; // out of sequence; lose count | |
sequence = vb.sequence; | |
{ | |
int sizeW = vi.blocksizes[W]; | |
int _centerW = centerW + vi.blocksizes[lW] / 4 + sizeW / 4; | |
int beginW = _centerW - sizeW / 2; | |
int endW = beginW + sizeW; | |
int beginSl = 0; | |
int endSl = 0; | |
// Do we have enough PCM/mult storage for the block? | |
if (endW > pcm_storage) { | |
// expand the storage | |
pcm_storage = endW + vi.blocksizes[1]; | |
for (int i = 0; i < vi.channels; i++) { | |
float[] foo = new float[pcm_storage]; | |
System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length); | |
pcm[i] = foo; | |
} | |
} | |
// overlap/add PCM | |
switch (W) { | |
case 0: | |
beginSl = 0; | |
endSl = vi.blocksizes[0] / 2; | |
break; | |
case 1: | |
beginSl = vi.blocksizes[1] / 4 - vi.blocksizes[lW] / 4; | |
endSl = beginSl + vi.blocksizes[lW] / 2; | |
break; | |
} | |
for (int j = 0; j < vi.channels; j++) { | |
int _pcm = beginW; | |
// the overlap/add section | |
int i = 0; | |
for (i = beginSl; i < endSl; i++) { | |
pcm[j][_pcm + i] += vb.pcm[j][i]; | |
} | |
// the remaining section | |
for (; i < sizeW; i++) { | |
pcm[j][_pcm + i] = vb.pcm[j][i]; | |
} | |
} | |
// track the frame number... This is for convenience, but also | |
// making sure our last packet doesn't end with added padding. If | |
// the last packet is partial, the number of samples we'll have to | |
// return will be past the vb->granulepos. | |
// | |
// This is not foolproof! It will be confused if we begin | |
// decoding at the last page after a seek or hole. In that case, | |
// we don't have a starting point to judge where the last frame | |
// is. For this reason, vorbisfile will always try to make sure | |
// it reads the last two marked pages in proper sequence | |
if (granulepos == -1) { | |
granulepos = vb.granulepos; | |
} else { | |
granulepos += (_centerW - centerW); | |
if (vb.granulepos != -1 && granulepos != vb.granulepos) { | |
if (granulepos > vb.granulepos && vb.eofflag != 0) { | |
// partial last frame. Strip the padding off | |
_centerW -= (granulepos - vb.granulepos); | |
} // else{ Shouldn't happen *unless* the bitstream is out of | |
// spec. Either way, believe the bitstream } | |
granulepos = vb.granulepos; | |
} | |
} | |
// Update, cleanup | |
centerW = _centerW; | |
pcm_current = endW; | |
if (vb.eofflag != 0) | |
eofflag = 1; | |
} | |
return (0); | |
} | |
// pcm==NULL indicates we just want the pending samples, no more | |
public int synthesis_pcmout(float[][][] _pcm, int[] index) { | |
if (pcm_returned < centerW) { | |
if (_pcm != null) { | |
for (int i = 0; i < vi.channels; i++) { | |
index[i] = pcm_returned; | |
} | |
_pcm[0] = pcm; | |
} | |
return (centerW - pcm_returned); | |
} | |
return (0); | |
} | |
public int synthesis_read(int bytes) { | |
if (bytes != 0 && pcm_returned + bytes > centerW) | |
return (-1); | |
pcm_returned += bytes; | |
return (0); | |
} | |
public void clear() { | |
} | |
} | |