/* * $ProjectName$ * $ProjectRevision$ * ----------------------------------------------------------- * $Id: CodeBook.java,v 1.3 2003/04/10 19:49:04 jarnbjo Exp $ * ----------------------------------------------------------- * * $Author: jarnbjo $ * * Description: * * Copyright 2002-2003 Tor-Einar Jarnbjo * ----------------------------------------------------------- * * Change History * ----------------------------------------------------------- * $Log: CodeBook.java,v $ * Revision 1.3 2003/04/10 19:49:04 jarnbjo * no message * * Revision 1.2 2003/03/16 01:11:12 jarnbjo * no message * * */ package sound.jarnbjo.vorbis; import java.io.IOException; import java.util.Arrays; import sound.jarnbjo.util.io.BitInputStream; import sound.jarnbjo.util.io.HuffmanNode; public class CodeBook { private HuffmanNode huffmanRoot; private int dimensions, entries; private int[] entryLengths; private float[][] valueVector; protected CodeBook(BitInputStream source) throws VorbisFormatException, IOException { // check sync if(source.getInt(24)!=0x564342) { throw new VorbisFormatException("The code book sync pattern is not correct."); } dimensions=source.getInt(16); entries=source.getInt(24); entryLengths=new int[entries]; boolean ordered=source.getBit(); if(ordered) { int cl=source.getInt(5)+1; for(int i=0; i<entryLengths.length; ) { int num=source.getInt(Util.ilog(entryLengths.length-i)); if(i+num>entryLengths.length) { throw new VorbisFormatException("The codebook entry length list is longer than the actual number of entry lengths."); } Arrays.fill(entryLengths, i, i+num, cl); cl++; i+=num; } } else { // !ordered boolean sparse=source.getBit(); if(sparse) { for(int i=0; i<entryLengths.length; i++) { if(source.getBit()) { entryLengths[i]=source.getInt(5)+1; } else { entryLengths[i]=-1; } } } else { // !sparse for(int i=0; i<entryLengths.length; i++) { entryLengths[i]=source.getInt(5)+1; } } } if (!createHuffmanTree(entryLengths)) { throw new VorbisFormatException("An exception was thrown when building the codebook Huffman tree."); } int codeBookLookupType=source.getInt(4); switch(codeBookLookupType) { case 0: // codebook has no scalar vectors to be calculated break; case 1: case 2: float codeBookMinimumValue=Util.float32unpack(source.getInt(32)); float codeBookDeltaValue=Util.float32unpack(source.getInt(32)); int codeBookValueBits=source.getInt(4)+1; boolean codeBookSequenceP=source.getBit(); int codeBookLookupValues=0; if(codeBookLookupType==1) { codeBookLookupValues=Util.lookup1Values(entries, dimensions); } else { codeBookLookupValues=entries*dimensions; } int codeBookMultiplicands[]=new int[codeBookLookupValues]; for(int i=0; i<codeBookMultiplicands.length; i++) { codeBookMultiplicands[i]=source.getInt(codeBookValueBits); } valueVector=new float[entries][dimensions]; if(codeBookLookupType==1) { for(int i=0; i<entries; i++) { float last=0; int indexDivisor=1; for(int j=0; j<dimensions; j++) { int multiplicandOffset= (i/indexDivisor)%codeBookLookupValues; valueVector[i][j]= codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last; if(codeBookSequenceP) { last=valueVector[i][j]; } indexDivisor*=codeBookLookupValues; } } } else { throw new UnsupportedOperationException(); /** @todo implement */ } break; default: throw new VorbisFormatException("Unsupported codebook lookup type: "+codeBookLookupType); } } private static long totalTime=0; private boolean createHuffmanTree(int[] entryLengths) { huffmanRoot=new HuffmanNode(); for(int i=0; i<entryLengths.length; i++) { int el=entryLengths[i]; if(el>0) { if(!huffmanRoot.setNewValue(el, i)) { return false; } } } return true; } protected int getDimensions() { return dimensions; } protected int getEntries() { return entries; } protected HuffmanNode getHuffmanRoot() { return huffmanRoot; } //public float[] readVQ(ReadableBitChannel source) throws IOException { // return valueVector[readInt(source)]; //} protected int readInt(final BitInputStream source) throws IOException { return source.getInt(huffmanRoot); /* HuffmanNode node; for(node=huffmanRoot; node.value==null; node=source.getBit()?node.o1:node.o0); return node.value.intValue(); */ } protected void readVvAdd(float[][] a, BitInputStream source, int offset, int length) throws VorbisFormatException, IOException { int i,j;//k;//entry; int chptr=0; int ch=a.length; if(ch==0) { return; } int lim=(offset+length)/ch; for(i=offset/ch;i<lim;){ final float[] ve=valueVector[source.getInt(huffmanRoot)]; for(j=0;j<dimensions;j++){ a[chptr++][i]+=ve[j]; if(chptr==ch){ chptr=0; i++; } } } } /* public void readVAdd(double[] a, ReadableBitChannel source, int offset, int length) throws FormatException, IOException { int i,j,entry; int t; if(dimensions>8){ for(i=0;i<length;){ entry = readInt(source); //if(entry==-1)return(-1); //t=entry*dimensions; for(j=0;j<dimensions;){ a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; } } } else{ for(i=0;i<length;){ entry=readInt(source); //if(entry==-1)return(-1); //t=entry*dim; j=0; switch(dimensions){ case 8: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 7: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 6: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 5: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 4: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 3: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 2: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 1: a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)]; case 0: break; } } } } */ }