diff options
| author | Michiel Van Der Kolk <not.valid@email.address> | 2005-07-11 15:42:37 +0000 |
|---|---|---|
| committer | Michiel Van Der Kolk <not.valid@email.address> | 2005-07-11 15:42:37 +0000 |
| commit | 9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e (patch) | |
| tree | 4c304cd4151020bd5494d279ee68a105ae3a5a3a /songdbj/com/jcraft/jorbis/StaticCodeBook.java | |
| parent | dfa8ecbe609ca8ea194d08560a44fb9a92e94b4b (diff) | |
| download | rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.zip rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.tar.gz rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.tar.bz2 rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.tar.xz | |
Songdb java version, source. only 1.5 compatible
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'songdbj/com/jcraft/jorbis/StaticCodeBook.java')
| -rw-r--r-- | songdbj/com/jcraft/jorbis/StaticCodeBook.java | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/songdbj/com/jcraft/jorbis/StaticCodeBook.java b/songdbj/com/jcraft/jorbis/StaticCodeBook.java new file mode 100644 index 0000000..7d9d6dc --- /dev/null +++ b/songdbj/com/jcraft/jorbis/StaticCodeBook.java @@ -0,0 +1,588 @@ +/* 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; + +import com.jcraft.jogg.*; + +class StaticCodeBook{ + int dim; // codebook dimensions (elements per vector) + int entries; // codebook entries + int[] lengthlist; // codeword lengths in bits + + // mapping + int maptype; // 0=none + // 1=implicitly populated values from map column + // 2=listed arbitrary values + + // The below does a linear, single monotonic sequence mapping. + int q_min; // packed 32 bit float; quant value 0 maps to minval + int q_delta; // packed 32 bit float; val 1 - val 0 == delta + int q_quant; // bits: 0 < quant <= 16 + int q_sequencep; // bitflag + + // additional information for log (dB) mapping; the linear mapping + // is assumed to actually be values in dB. encodebias is used to + // assign an error weight to 0 dB. We have two additional flags: + // zeroflag indicates if entry zero is to represent -Inf dB; negflag + // indicates if we're to represent negative linear values in a + // mirror of the positive mapping. + + int[] quantlist; // map == 1: (int)(entries/dim) element column map + // map == 2: list of dim*entries quantized entry vals + + // encode helpers + EncodeAuxNearestMatch nearest_tree; + EncodeAuxThreshMatch thresh_tree; + + StaticCodeBook(){} + StaticCodeBook(int dim, int entries, int[] lengthlist, + int maptype, int q_min, int q_delta, + int q_quant, int q_sequencep, int[] quantlist, + //EncodeAuxNearestmatch nearest_tree, + Object nearest_tree, + // EncodeAuxThreshmatch thresh_tree, + Object thresh_tree + ){ + this(); + this.dim=dim; this.entries=entries; this.lengthlist=lengthlist; + this.maptype=maptype; this.q_min=q_min; this.q_delta=q_delta; + this.q_quant=q_quant; this.q_sequencep=q_sequencep; + this.quantlist=quantlist; + } + + int pack(Buffer opb){ + int i; + boolean ordered=false; + + opb.write(0x564342,24); + opb.write(dim, 16); + opb.write(entries, 24); + + // pack the codewords. There are two packings; length ordered and + // length random. Decide between the two now. + + for(i=1;i<entries;i++){ + if(lengthlist[i]<lengthlist[i-1])break; + } + if(i==entries)ordered=true; + + if(ordered){ + // length ordered. We only need to say how many codewords of + // each length. The actual codewords are generated + // deterministically + + int count=0; + opb.write(1,1); // ordered + opb.write(lengthlist[0]-1,5); // 1 to 32 + + for(i=1;i<entries;i++){ + int _this=lengthlist[i]; + int _last=lengthlist[i-1]; + if(_this>_last){ + for(int j=_last;j<_this;j++){ + opb.write(i-count,ilog(entries-count)); + count=i; + } + } + } + opb.write(i-count,ilog(entries-count)); + } + else{ + // length random. Again, we don't code the codeword itself, just + // the length. This time, though, we have to encode each length + opb.write(0,1); // unordered + + // algortihmic mapping has use for 'unused entries', which we tag + // here. The algorithmic mapping happens as usual, but the unused + // entry has no codeword. + for(i=0;i<entries;i++){ + if(lengthlist[i]==0)break; + } + + if(i==entries){ + opb.write(0,1); // no unused entries + for(i=0;i<entries;i++){ + opb.write(lengthlist[i]-1,5); + } + } + else{ + opb.write(1,1); // we have unused entries; thus we tag + for(i=0;i<entries;i++){ + if(lengthlist[i]==0){ + opb.write(0,1); + } + else{ + opb.write(1,1); + opb.write(lengthlist[i]-1,5); + } + } + } + } + + // is the entry number the desired return value, or do we have a + // mapping? If we have a mapping, what type? + opb.write(maptype,4); + switch(maptype){ + case 0: + // no mapping + break; + case 1: + case 2: + // implicitly populated value mapping + // explicitly populated value mapping + if(quantlist==null){ + // no quantlist? error + return(-1); + } + + // values that define the dequantization + opb.write(q_min,32); + opb.write(q_delta,32); + opb.write(q_quant-1,4); + opb.write(q_sequencep,1); + + { + int quantvals=0; + switch(maptype){ + case 1: + // a single column of (c->entries/c->dim) quantized values for + // building a full value list algorithmically (square lattice) + quantvals=maptype1_quantvals(); + break; + case 2: + // every value (c->entries*c->dim total) specified explicitly + quantvals=entries*dim; + break; + } + + // quantized values + for(i=0;i<quantvals;i++){ + opb.write(Math.abs(quantlist[i]),q_quant); + } + } + break; + default: + // error case; we don't have any other map types now + return(-1); + } + return(0); + } +/* +*/ + + // unpacks a codebook from the packet buffer into the codebook struct, + // readies the codebook auxiliary structures for decode + int unpack(Buffer opb){ + int i; + //memset(s,0,sizeof(static_codebook)); + + // make sure alignment is correct + if(opb.read(24)!=0x564342){ +// goto _eofout; + clear(); + return(-1); + } + + // first the basic parameters + dim=opb.read(16); + entries=opb.read(24); + if(entries==-1){ +// goto _eofout; + clear(); + return(-1); + } + + // codeword ordering.... length ordered or unordered? + switch(opb.read(1)){ + case 0: + // unordered + lengthlist=new int[entries]; + + // allocated but unused entries? + if(opb.read(1)!=0){ + // yes, unused entries + + for(i=0;i<entries;i++){ + if(opb.read(1)!=0){ + int num=opb.read(5); + if(num==-1){ +// goto _eofout; + clear(); + return(-1); + } + lengthlist[i]=num+1; + } + else{ + lengthlist[i]=0; + } + } + } + else{ + // all entries used; no tagging + for(i=0;i<entries;i++){ + int num=opb.read(5); + if(num==-1){ +// goto _eofout; + clear(); + return(-1); + } + lengthlist[i]=num+1; + } + } + break; + case 1: + // ordered + { + int length=opb.read(5)+1; + lengthlist=new int[entries]; + + for(i=0;i<entries;){ + int num=opb.read(ilog(entries-i)); + if(num==-1){ +// goto _eofout; + clear(); + return(-1); + } + for(int j=0;j<num;j++,i++){ + lengthlist[i]=length; + } + length++; + } + } + break; + default: + // EOF + return(-1); + } + + // Do we have a mapping to unpack? + switch((maptype=opb.read(4))){ + case 0: + // no mapping + break; + case 1: + case 2: + // implicitly populated value mapping + // explicitly populated value mapping + q_min=opb.read(32); + q_delta=opb.read(32); + q_quant=opb.read(4)+1; + q_sequencep=opb.read(1); + + { + int quantvals=0; + switch(maptype){ + case 1: + quantvals=maptype1_quantvals(); + break; + case 2: + quantvals=entries*dim; + break; + } + + // quantized values + quantlist=new int[quantvals]; + for(i=0;i<quantvals;i++){ + quantlist[i]=opb.read(q_quant); + } + if(quantlist[quantvals-1]==-1){ +// goto _eofout; + clear(); + return(-1); + } + } + break; + default: +// goto _eofout; + clear(); + return(-1); + } + // all set + return(0); +// _errout: +// _eofout: +// vorbis_staticbook_clear(s); +// return(-1); + } + + // there might be a straightforward one-line way to do the below + // that's portable and totally safe against roundoff, but I haven't + // thought of it. Therefore, we opt on the side of caution + private int maptype1_quantvals(){ + int vals=(int)(Math.floor(Math.pow(entries,1./dim))); + + // the above *should* be reliable, but we'll not assume that FP is + // ever reliable when bitstream sync is at stake; verify via integer + // means that vals really is the greatest value of dim for which + // vals^b->bim <= b->entries + // treat the above as an initial guess + while(true){ + int acc=1; + int acc1=1; + for(int i=0;i<dim;i++){ + acc*=vals; + acc1*=vals+1; + } + if(acc<=entries && acc1>entries){ return(vals); } + else{ + if(acc>entries){ vals--; } + else{ vals++; } + } + } + } + + void clear(){ +// if(quantlist!=null)free(b->quantlist); +// if(lengthlist!=null)free(b->lengthlist); +// if(nearest_tree!=null){ +// free(b->nearest_tree->ptr0); +// free(b->nearest_tree->ptr1); +// free(b->nearest_tree->p); +// free(b->nearest_tree->q); +// memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch)); +// free(b->nearest_tree); +// } +// if(thresh_tree!=null){ +// free(b->thresh_tree->quantthresh); +// free(b->thresh_tree->quantmap); +// memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch)); +// free(b->thresh_tree); +// } +// memset(b,0,sizeof(static_codebook)); + } + + // unpack the quantized list of values for encode/decode + // we need to deal with two map types: in map type 1, the values are + // generated algorithmically (each column of the vector counts through + // the values in the quant vector). in map type 2, all the values came + // in in an explicit list. Both value lists must be unpacked + float[] unquantize(){ + + if(maptype==1 || maptype==2){ + int quantvals; + float mindel=float32_unpack(q_min); + float delta=float32_unpack(q_delta); + float[] r=new float[entries*dim]; + + //System.err.println("q_min="+q_min+", mindel="+mindel); + + // maptype 1 and 2 both use a quantized value vector, but + // different sizes + switch(maptype){ + case 1: + // most of the time, entries%dimensions == 0, but we need to be + // well defined. We define that the possible vales at each + // scalar is values == entries/dim. If entries%dim != 0, we'll + // have 'too few' values (values*dim<entries), which means that + // we'll have 'left over' entries; left over entries use zeroed + // values (and are wasted). So don't generate codebooks like that + quantvals=maptype1_quantvals(); + for(int j=0;j<entries;j++){ + float last=0.f; + int indexdiv=1; + for(int k=0;k<dim;k++){ + int index=(j/indexdiv)%quantvals; + float val=quantlist[index]; + val=Math.abs(val)*delta+mindel+last; + if(q_sequencep!=0)last=val; + r[j*dim+k]=val; + indexdiv*=quantvals; + } + } + break; + case 2: + for(int j=0;j<entries;j++){ + float last=0.f; + for(int k=0;k<dim;k++){ + float val=quantlist[j*dim+k]; +//if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");} + val=Math.abs(val)*delta+mindel+last; + if(q_sequencep!=0)last=val; + r[j*dim+k]=val; +//if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");} + } + } +//System.err.println("\nr[0]="+r[0]); + } + return(r); + } + return(null); + } + + private static int ilog(int v){ + int ret=0; + while(v!=0){ + ret++; + v>>>=1; + } + return(ret); + } + + // 32 bit float (not IEEE; nonnormalized mantissa + + // biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm + // Why not IEEE? It's just not that important here. + + static final int VQ_FEXP=10; + static final int VQ_FMAN=21; + static final int VQ_FEXP_BIAS=768; // bias toward values smaller than 1. + + // doesn't currently guard under/overflow + static long float32_pack(float val){ + int sign=0; + int exp; + int mant; + if(val<0){ + sign=0x80000000; + val= -val; + } + exp=(int)Math.floor(Math.log(val)/Math.log(2)); + mant=(int)Math.rint(Math.pow(val,(VQ_FMAN-1)-exp)); + exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN; + return(sign|exp|mant); + } + + static float float32_unpack(int val){ + float mant=val&0x1fffff; + float sign=val&0x80000000; + float exp =(val&0x7fe00000)>>>VQ_FMAN; +//System.err.println("mant="+mant+", sign="+sign+", exp="+exp); + //if(sign!=0.0)mant= -mant; + if((val&0x80000000)!=0)mant= -mant; +//System.err.println("mant="+mant); + return(ldexp(mant,((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS)); + } + + static float ldexp(float foo, int e){ + return (float)(foo*Math.pow(2, e)); + } + +/* + // TEST + // Unit tests of the dequantizer; this stuff will be OK + // cross-platform, I simply want to be sure that special mapping cases + // actually work properly; a bug could go unnoticed for a while + + // cases: + // + // no mapping + // full, explicit mapping + // algorithmic mapping + // + // nonsequential + // sequential + + static int[] full_quantlist1={0,1,2,3, 4,5,6,7, 8,3,6,1}; + static int[] partial_quantlist1={0,7,2}; + + // no mapping + static StaticCodeBook test1=new StaticCodeBook(4,16,null, + 0,0,0,0,0, + null,null,null); + static float[] test1_result=null; + + // linear, full mapping, nonsequential + static StaticCodeBook test2=new StaticCodeBook(4,3,null, + 2,-533200896,1611661312,4,0, + full_quantlist1, null, null); + static float[] test2_result={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2}; + + // linear, full mapping, sequential + static StaticCodeBook test3=new StaticCodeBook(4,3,null, + 2, -533200896,1611661312,4,1, + full_quantlist1,null, null); + static float[] test3_result={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6}; + + // linear, algorithmic mapping, nonsequential + static StaticCodeBook test4=new StaticCodeBook(3,27,null, + 1,-533200896,1611661312,4,0, + partial_quantlist1,null,null); + static float[] test4_result={-3,-3,-3, 4,-3,-3, -1,-3,-3, + -3, 4,-3, 4, 4,-3, -1, 4,-3, + -3,-1,-3, 4,-1,-3, -1,-1,-3, + -3,-3, 4, 4,-3, 4, -1,-3, 4, + -3, 4, 4, 4, 4, 4, -1, 4, 4, + -3,-1, 4, 4,-1, 4, -1,-1, 4, + -3,-3,-1, 4,-3,-1, -1,-3,-1, + -3, 4,-1, 4, 4,-1, -1, 4,-1, + -3,-1,-1, 4,-1,-1, -1,-1,-1}; + + // linear, algorithmic mapping, sequential + static StaticCodeBook test5=new StaticCodeBook(3,27,null, + 1,-533200896,1611661312,4,1, + partial_quantlist1,null,null); + static float[] test5_result={-3,-6,-9, 4, 1,-2, -1,-4,-7, + -3, 1,-2, 4, 8, 5, -1, 3, 0, + -3,-4,-7, 4, 3, 0, -1,-2,-5, + -3,-6,-2, 4, 1, 5, -1,-4, 0, + -3, 1, 5, 4, 8,12, -1, 3, 7, + -3,-4, 0, 4, 3, 7, -1,-2, 2, + -3,-6,-7, 4, 1, 0, -1,-4,-5, + -3, 1, 0, 4, 8, 7, -1, 3, 2, + -3,-4,-5, 4, 3, 2, -1,-2,-3}; + + void run_test(float[] comp){ + float[] out=unquantize(); + if(comp!=null){ + if(out==null){ + System.err.println("_book_unquantize incorrectly returned NULL"); + System.exit(1); + } + for(int i=0;i<entries*dim;i++){ + if(Math.abs(out[i]-comp[i])>.0001){ + System.err.println("disagreement in unquantized and reference data:\nposition "+i+": "+out[i]+" != "+comp[i]); + System.exit(1); + } + } + } + else{ + if(out!=null){ + System.err.println("_book_unquantize returned a value array:\n correct result should have been NULL"); + System.exit(1); + } + } + } + + public static void main(String[] arg){ + // run the nine dequant tests, and compare to the hand-rolled results + System.err.print("Dequant test 1... "); + test1.run_test(test1_result); + System.err.print("OK\nDequant test 2... "); + test2.run_test(test2_result); + System.err.print("OK\nDequant test 3... "); + test3.run_test(test3_result); + System.err.print("OK\nDequant test 4... "); + test4.run_test(test4_result); + System.err.print("OK\nDequant test 5... "); + test5.run_test(test5_result); + System.err.print("OK\n\n"); + } +*/ +} + + + + + |