/*
* $ProjectName$
* $ProjectRevision$
* -----------------------------------------------------------
* $Id: Floor1.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $multip
* -----------------------------------------------------------
*
* $Author: jarnbjo $
*
* Description:
*
* Copyright 2002-2003 Tor-Einar Jarnbjo
* -----------------------------------------------------------
*
* Change History
* -----------------------------------------------------------
* $Log: Floor1.java,v $
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
* no message
*
*
*/
package sound.jarnbjo.vorbis;
import java.io.IOException;
import java.util.*;
import sound.jarnbjo.util.io.BitInputStream;
public class Floor1 extends Floor implements Cloneable {
private int[] partitionClassList;
private int maximumClass, multiplier, rangeBits;
private int[] classDimensions;
private int[] classSubclasses;
private int[] classMasterbooks;
private int[][] subclassBooks;
private int[] xList;
private int[] yList;
private int[] lowNeighbours, highNeighbours;
//private boolean[] step2Flags;
private static final int[] RANGES = {256, 128, 86, 64};
private Floor1() {
}
protected Floor1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
maximumClass=-1;
int partitions=source.getInt(5);
partitionClassList=new int[partitions];
for(int i=0; i<partitionClassList.length; i++) {
partitionClassList[i]=source.getInt(4);
if(partitionClassList[i]>maximumClass) {
maximumClass=partitionClassList[i];
}
}
classDimensions=new int[maximumClass+1];
classSubclasses=new int[maximumClass+1];
classMasterbooks=new int[maximumClass+1];
subclassBooks=new int[maximumClass+1][];
int xListLength=2;
for(int i=0; i<=maximumClass; i++) {
classDimensions[i]=source.getInt(3)+1;
xListLength+=classDimensions[i];
classSubclasses[i]=source.getInt(2);
if(classDimensions[i] > header.getCodeBooks().length ||
classSubclasses[i] > header.getCodeBooks().length) {
throw new VorbisFormatException("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");
}
if(classSubclasses[i]!=0) {
classMasterbooks[i]=source.getInt(8);
}
subclassBooks[i]=new int[1<<classSubclasses[i]];
for(int j=0; j<subclassBooks[i].length; j++) {
subclassBooks[i][j]=source.getInt(8)-1;
}
}
multiplier=source.getInt(2)+1;
rangeBits=source.getInt(4);
//System.out.println("multiplier: "+multiplier);
//System.out.println("rangeBits: "+rangeBits);
//System.out.println("xListLength: "+xListLength);
int floorValues=0;
ArrayList alXList=new ArrayList();
alXList.add(new Integer(0));
alXList.add(new Integer(1<<rangeBits));
//System.out.println("partitions: "+partitions);
//System.out.println("classDimensions.length: "+classDimensions.length);
for(int i=0; i<partitions; i++) {
for(int j=0; j<classDimensions[partitionClassList[i]]; j++) {
alXList.add(new Integer(source.getInt(rangeBits)));
}
}
xList=new int[alXList.size()];
lowNeighbours=new int[xList.length];
highNeighbours=new int[xList.length];
Iterator iter=alXList.iterator();
for(int i=0; i<xList.length; i++) {
xList[i]=((Integer)iter.next()).intValue();
}
for(int i=0; i<xList.length; i++) {
lowNeighbours[i]=Util.lowNeighbour(xList, i);
highNeighbours[i]=Util.highNeighbour(xList, i);
}
}
protected int getType() {
return 1;
}
protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
//System.out.println("decodeFloor");
if(!source.getBit()) {
//System.out.println("null");
return null;
}
Floor1 clone=(Floor1)clone();
clone.yList=new int[xList.length];
int range=RANGES[multiplier-1];
clone.yList[0]=source.getInt(Util.ilog(range-1));
clone.yList[1]=source.getInt(Util.ilog(range-1));
int offset=2;
for(int i=0; i<partitionClassList.length; i++) {
int cls=partitionClassList[i];
int cdim=classDimensions[cls];
int cbits=classSubclasses[cls];
int csub=(1<<cbits)-1;
int cval=0;
if(cbits>0) {
cval=source.getInt(vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].getHuffmanRoot());
//cval=vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].readInt(source);
//System.out.println("cval: "+cval);
}
//System.out.println("0: "+cls+" "+cdim+" "+cbits+" "+csub+" "+cval);
for(int j=0; j<cdim; j++) {
//System.out.println("a: "+cls+" "+cval+" "+csub);
int book=subclassBooks[cls][cval&csub];
cval>>>=cbits;
if(book>=0) {
clone.yList[j+offset]=source.getInt(vorbis.getSetupHeader().getCodeBooks()[book].getHuffmanRoot());
//clone.yList[j+offset]=vorbis.getSetupHeader().getCodeBooks()[book].readInt(source);
//System.out.println("b: "+(j+offset)+" "+book+" "+clone.yList[j+offset]);
//System.out.println("");
}
else {
clone.yList[j+offset]=0;
}
}
offset+=cdim;
}
//System.out.println("");
//for(int i=0; i<clone.xList.length; i++) {
// System.out.println(i+" = "+clone.xList[i]);
//}
//System.out.println("");
//for(int i=0; i<clone.yList.length; i++) {
// System.out.println(i+" = "+clone.yList[i]);
//}
//System.out.println("offset: "+offset);
//System.out.println("yList.length: "+clone.yList.length);
//System.exit(0);
return clone;
}
protected void computeFloor(final float[] vector) {
int n=vector.length;
final int values=xList.length;
final boolean[] step2Flags=new boolean[values];
final int range=RANGES[multiplier-1];
for(int i=2; i<values; i++) {
final int lowNeighbourOffset=lowNeighbours[i];//Util.lowNeighbour(xList, i);
final int highNeighbourOffset=highNeighbours[i];//Util.highNeighbour(xList, i);
final int predicted=Util.renderPoint(
xList[lowNeighbourOffset], xList[highNeighbourOffset],
yList[lowNeighbourOffset], yList[highNeighbourOffset],
xList[i]);
final int val=yList[i];
final int highRoom=range-predicted;
final int lowRoom=predicted;
final int room=highRoom<lowRoom?highRoom*2:lowRoom*2;
if(val!=0) {
step2Flags[lowNeighbourOffset]=true;
step2Flags[highNeighbourOffset]=true;
step2Flags[i]=true;
if(val>=room) {
yList[i]=highRoom>lowRoom?
val-lowRoom+predicted:
-val+highRoom+predicted-1;
}
else {
yList[i]=(val&1)==1?
predicted-((val+1)>>1):
predicted+(val>>1);
}
}
else {
step2Flags[i]=false;
yList[i]=predicted;
}
}
final int[] xList2=new int[values];
System.arraycopy(xList, 0, xList2, 0, values);
sort(xList2, yList, step2Flags);
int hx=0, hy=0, lx=0, ly=yList[0]*multiplier;
float[] vector2=new float[vector.length];
float[] vector3=new float[vector.length];
Arrays.fill(vector2, 1.0f);
System.arraycopy(vector, 0, vector3, 0, vector.length);
for(int i=1; i<values; i++) {
if(step2Flags[i]) {
hy=yList[i]*multiplier;
hx=xList2[i];
Util.renderLine(lx, ly, hx, hy, vector);
Util.renderLine(lx, ly, hx, hy, vector2);
lx=hx;
ly=hy;
}
}
final float r=DB_STATIC_TABLE[hy];
for(; hx<n/2; vector[hx++]=r);
}
public Object clone() {
Floor1 clone=new Floor1();
clone.classDimensions=classDimensions;
clone.classMasterbooks=classMasterbooks;
clone.classSubclasses=classSubclasses;
clone.maximumClass=maximumClass;
clone.multiplier=multiplier;
clone.partitionClassList=partitionClassList;
clone.rangeBits=rangeBits;
clone.subclassBooks=subclassBooks;
clone.xList=xList;
clone.yList=yList;
clone.lowNeighbours=lowNeighbours;
clone.highNeighbours=highNeighbours;
return clone;
}
private final static void sort(int x[], int y[], boolean b[]) {
int off=0;
int len=x.length;
int lim=len+off;
int itmp;
boolean btmp;
// Insertion sort on smallest arrays
for (int i=off; i<lim; i++) {
for (int j=i; j>off && x[j-1]>x[j]; j--) {
itmp=x[j];
x[j]=x[j-1];
x[j-1]=itmp;
itmp=y[j];
y[j]=y[j-1];
y[j-1]=itmp;
btmp=b[j];
b[j]=b[j-1];
b[j-1]=btmp;
//swap(x, j, j-1);
//swap(y, j, j-1);
//swap(b, j, j-1);
}
}
}
private final static void swap(int x[], int a, int b) {
int t = x[a];
x[a] = x[b];
x[b] = t;
}
private final static void swap(boolean x[], int a, int b) {
boolean t = x[a];
x[a] = x[b];
x[b] = t;
}
}