summaryrefslogtreecommitdiff
path: root/songdbj/com/jcraft/jorbis/CodeBook.java
diff options
context:
space:
mode:
authorMichiel Van Der Kolk <not.valid@email.address>2005-07-11 15:42:37 +0000
committerMichiel Van Der Kolk <not.valid@email.address>2005-07-11 15:42:37 +0000
commit9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e (patch)
tree4c304cd4151020bd5494d279ee68a105ae3a5a3a /songdbj/com/jcraft/jorbis/CodeBook.java
parentdfa8ecbe609ca8ea194d08560a44fb9a92e94b4b (diff)
downloadrockbox-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/CodeBook.java')
-rw-r--r--songdbj/com/jcraft/jorbis/CodeBook.java742
1 files changed, 742 insertions, 0 deletions
diff --git a/songdbj/com/jcraft/jorbis/CodeBook.java b/songdbj/com/jcraft/jorbis/CodeBook.java
new file mode 100644
index 0000000..9708e06
--- /dev/null
+++ b/songdbj/com/jcraft/jorbis/CodeBook.java
@@ -0,0 +1,742 @@
+/* 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 CodeBook{
+ int dim; // codebook dimensions (elements per vector)
+ int entries; // codebook entries
+ StaticCodeBook c=new StaticCodeBook();
+
+ float[] valuelist; // list of dim*entries actual entry values
+ int[] codelist; // list of bitstream codewords for each entry
+ DecodeAux decode_tree;
+
+ // returns the number of bits
+ int encode(int a, Buffer b){
+ b.write(codelist[a], c.lengthlist[a]);
+ return(c.lengthlist[a]);
+ }
+
+ // One the encode side, our vector writers are each designed for a
+ // specific purpose, and the encoder is not flexible without modification:
+ //
+ // The LSP vector coder uses a single stage nearest-match with no
+ // interleave, so no step and no error return. This is specced by floor0
+ // and doesn't change.
+ //
+ // Residue0 encoding interleaves, uses multiple stages, and each stage
+ // peels of a specific amount of resolution from a lattice (thus we want
+ // to match by threshhold, not nearest match). Residue doesn't *have* to
+ // be encoded that way, but to change it, one will need to add more
+ // infrastructure on the encode side (decode side is specced and simpler)
+
+ // floor0 LSP (single stage, non interleaved, nearest match)
+ // returns entry number and *modifies a* to the quantization value
+ int errorv(float[] a){
+ int best=best(a,1);
+ for(int k=0;k<dim;k++){
+ a[k]=valuelist[best*dim+k];
+ }
+ return(best);
+ }
+
+ // returns the number of bits and *modifies a* to the quantization value
+ int encodev(int best, float[] a, Buffer b){
+ for(int k=0;k<dim;k++){
+ a[k]=valuelist[best*dim+k];
+ }
+ return(encode(best,b));
+ }
+
+ // res0 (multistage, interleave, lattice)
+ // returns the number of bits and *modifies a* to the remainder value
+ int encodevs(float[] a, Buffer b, int step,int addmul){
+ int best=besterror(a,step,addmul);
+ return(encode(best,b));
+ }
+
+ private int[] t=new int[15]; // decodevs_add is synchronized for re-using t.
+ synchronized int decodevs_add(float[]a, int offset, Buffer b, int n){
+ int step=n/dim;
+ int entry;
+ int i,j,o;
+
+ if(t.length<step){
+ t=new int[step];
+ }
+
+ for(i = 0; i < step; i++){
+ entry=decode(b);
+ if(entry==-1)return(-1);
+ t[i]=entry*dim;
+ }
+ for(i=0,o=0;i<dim;i++,o+=step){
+ for(j=0;j<step;j++){
+ a[offset+o+j]+=valuelist[t[j]+i];
+ }
+ }
+
+ return(0);
+ }
+
+ int decodev_add(float[]a, int offset, Buffer b,int n){
+ int i,j,entry;
+ int t;
+
+ if(dim>8){
+ for(i=0;i<n;){
+ entry = decode(b);
+ if(entry==-1)return(-1);
+ t=entry*dim;
+ for(j=0;j<dim;){
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ }
+ }
+ }
+ else{
+ for(i=0;i<n;){
+ entry=decode(b);
+ if(entry==-1)return(-1);
+ t=entry*dim;
+ j=0;
+ switch(dim){
+ case 8:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 7:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 6:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 5:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 4:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 3:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 2:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 1:
+ a[offset+(i++)]+=valuelist[t+(j++)];
+ case 0:
+ break;
+ }
+ }
+ }
+ return(0);
+ }
+
+ int decodev_set(float[] a,int offset, Buffer b, int n){
+ int i,j,entry;
+ int t;
+
+ for(i=0;i<n;){
+ entry = decode(b);
+ if(entry==-1)return(-1);
+ t=entry*dim;
+ for(j=0;j<dim;){
+ a[offset+i++]=valuelist[t+(j++)];
+ }
+ }
+ return(0);
+ }
+
+ int decodevv_add(float[][] a, int offset,int ch, Buffer b,int n){
+ int i,j,k,entry;
+ int chptr=0;
+ //System.out.println("decodevv_add: a="+a+",b="+b+",valuelist="+valuelist);
+
+ for(i=offset/ch;i<(offset+n)/ch;){
+ entry = decode(b);
+ if(entry==-1)return(-1);
+
+ int t = entry*dim;
+ for(j=0;j<dim;j++){
+ a[chptr++][i]+=valuelist[t+j];
+ if(chptr==ch){
+ chptr=0;
+ i++;
+ }
+ }
+ }
+ return(0);
+ }
+
+
+ // Decode side is specced and easier, because we don't need to find
+ // matches using different criteria; we simply read and map. There are
+ // two things we need to do 'depending':
+ //
+ // We may need to support interleave. We don't really, but it's
+ // convenient to do it here rather than rebuild the vector later.
+ //
+ // Cascades may be additive or multiplicitive; this is not inherent in
+ // the codebook, but set in the code using the codebook. Like
+ // interleaving, it's easiest to do it here.
+ // stage==0 -> declarative (set the value)
+ // stage==1 -> additive
+ // stage==2 -> multiplicitive
+
+ // returns the entry number or -1 on eof
+ int decode(Buffer b){
+ int ptr=0;
+ DecodeAux t=decode_tree;
+ int lok=b.look(t.tabn);
+ //System.err.println(this+" "+t+" lok="+lok+", tabn="+t.tabn);
+
+ if(lok>=0){
+ ptr=t.tab[lok];
+ b.adv(t.tabl[lok]);
+ if(ptr<=0){
+ return -ptr;
+ }
+ }
+ do{
+ switch(b.read1()){
+ case 0:
+ ptr=t.ptr0[ptr];
+ break;
+ case 1:
+ ptr=t.ptr1[ptr];
+ break;
+ case -1:
+ default:
+ return(-1);
+ }
+ }
+ while(ptr>0);
+ return(-ptr);
+ }
+
+ // returns the entry number or -1 on eof
+ int decodevs(float[] a, int index, Buffer b, int step,int addmul){
+ int entry=decode(b);
+ if(entry==-1)return(-1);
+ switch(addmul){
+ case -1:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[index+o]=valuelist[entry*dim+i];
+ break;
+ case 0:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[index+o]+=valuelist[entry*dim+i];
+ break;
+ case 1:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[index+o]*=valuelist[entry*dim+i];
+ break;
+ default:
+ //System.err.println("CodeBook.decodeves: addmul="+addmul);
+ }
+ return(entry);
+ }
+
+ int best(float[] a, int step){
+ EncodeAuxNearestMatch nt=c.nearest_tree;
+ EncodeAuxThreshMatch tt=c.thresh_tree;
+ int ptr=0;
+
+ // we assume for now that a thresh tree is the only other possibility
+ if(tt!=null){
+ int index=0;
+ // find the quant val of each scalar
+ for(int k=0,o=step*(dim-1);k<dim;k++,o-=step){
+ int i;
+ // linear search the quant list for now; it's small and although
+ // with > 8 entries, it would be faster to bisect, this would be
+ // a misplaced optimization for now
+ for(i=0;i<tt.threshvals-1;i++){
+ if(a[o]<tt.quantthresh[i]){
+ break;
+ }
+ }
+ index=(index*tt.quantvals)+tt.quantmap[i];
+ }
+ // regular lattices are easy :-)
+ if(c.lengthlist[index]>0){
+ // is this unused? If so, we'll
+ // use a decision tree after all
+ // and fall through
+ return(index);
+ }
+ }
+ if(nt!=null){
+ // optimized using the decision tree
+ while(true){
+ float c=0.f;
+ int p=nt.p[ptr];
+ int q=nt.q[ptr];
+ for(int k=0,o=0;k<dim;k++,o+=step){
+ c+=(valuelist[p+k]-valuelist[q+k])*
+ (a[o]-(valuelist[p+k]+valuelist[q+k])*.5);
+ }
+ if(c>0.){ // in A
+ ptr= -nt.ptr0[ptr];
+ }
+ else{ // in B
+ ptr= -nt.ptr1[ptr];
+ }
+ if(ptr<=0)break;
+ }
+ return(-ptr);
+ }
+
+ // brute force it!
+ {
+ int besti=-1;
+ float best=0.f;
+ int e=0;
+ for(int i=0;i<entries;i++){
+ if(c.lengthlist[i]>0){
+ float _this=dist(dim, valuelist, e, a, step);
+ if(besti==-1 || _this<best){
+ best=_this;
+ besti=i;
+ }
+ }
+ e+=dim;
+ }
+ return(besti);
+ }
+ }
+
+ // returns the entry number and *modifies a* to the remainder value
+ int besterror(float[] a, int step, int addmul){
+ int best=best(a,step);
+ switch(addmul){
+ case 0:
+ for(int i=0,o=0;i<dim;i++,o+=step)
+ a[o]-=valuelist[best*dim+i];
+ break;
+ case 1:
+ for(int i=0,o=0;i<dim;i++,o+=step){
+ float val=valuelist[best*dim+i];
+ if(val==0){
+ a[o]=0;
+ }else{
+ a[o]/=val;
+ }
+ }
+ break;
+ }
+ return(best);
+ }
+
+ void clear(){
+ // static book is not cleared; we're likely called on the lookup and
+ // the static codebook belongs to the info struct
+ //if(decode_tree!=null){
+ // free(b->decode_tree->ptr0);
+ // free(b->decode_tree->ptr1);
+ // memset(b->decode_tree,0,sizeof(decode_aux));
+ // free(b->decode_tree);
+ //}
+ //if(valuelist!=null)free(b->valuelist);
+ //if(codelist!=null)free(b->codelist);
+ //memset(b,0,sizeof(codebook));
+ }
+
+ private static float dist(int el, float[] ref, int index, float[] b, int step){
+ float acc=(float)0.;
+ for(int i=0; i<el; i++){
+ float val=(ref[index+i]-b[i*step]);
+ acc+=val*val;
+ }
+ return(acc);
+ }
+
+/*
+ int init_encode(StaticCodeBook s){
+ //memset(c,0,sizeof(codebook));
+ c=s;
+ entries=s.entries;
+ dim=s.dim;
+ codelist=make_words(s.lengthlist, s.entries);
+ valuelist=s.unquantize();
+ return(0);
+ }
+*/
+
+ int init_decode(StaticCodeBook s){
+ //memset(c,0,sizeof(codebook));
+ c=s;
+ entries=s.entries;
+ dim=s.dim;
+ valuelist=s.unquantize();
+
+ decode_tree=make_decode_tree();
+ if(decode_tree==null){
+ //goto err_out;
+ clear();
+ return(-1);
+ }
+ return(0);
+// err_out:
+// vorbis_book_clear(c);
+// return(-1);
+ }
+
+ // given a list of word lengths, generate a list of codewords. Works
+ // for length ordered or unordered, always assigns the lowest valued
+ // codewords first. Extended to handle unused entries (length 0)
+ static int[] make_words(int[] l, int n){
+ int[] marker=new int[33];
+ int[] r=new int[n];
+ //memset(marker,0,sizeof(marker));
+
+ for(int i=0;i<n;i++){
+ int length=l[i];
+ if(length>0){
+ int entry=marker[length];
+
+ // when we claim a node for an entry, we also claim the nodes
+ // below it (pruning off the imagined tree that may have dangled
+ // from it) as well as blocking the use of any nodes directly
+ // above for leaves
+
+ // update ourself
+ if(length<32 && (entry>>>length)!=0){
+ // error condition; the lengths must specify an overpopulated tree
+ //free(r);
+ return(null);
+ }
+ r[i]=entry;
+
+ // Look to see if the next shorter marker points to the node
+ // above. if so, update it and repeat.
+ {
+ for(int j=length;j>0;j--){
+ if((marker[j]&1)!=0){
+ // have to jump branches
+ if(j==1)marker[1]++;
+ else marker[j]=marker[j-1]<<1;
+ break; // invariant says next upper marker would already
+ // have been moved if it was on the same path
+ }
+ marker[j]++;
+ }
+ }
+
+ // prune the tree; the implicit invariant says all the longer
+ // markers were dangling from our just-taken node. Dangle them
+ // from our *new* node.
+ for(int j=length+1;j<33;j++){
+ if((marker[j]>>>1) == entry){
+ entry=marker[j];
+ marker[j]=marker[j-1]<<1;
+ }
+ else{
+ break;
+ }
+ }
+ }
+ }
+
+ // bitreverse the words because our bitwise packer/unpacker is LSb
+ // endian
+ for(int i=0;i<n;i++){
+ int temp=0;
+ for(int j=0;j<l[i];j++){
+ temp<<=1;
+ temp|=(r[i]>>>j)&1;
+ }
+ r[i]=temp;
+ }
+
+ return(r);
+ }
+
+ // build the decode helper tree from the codewords
+ DecodeAux make_decode_tree(){
+ int top=0;
+ DecodeAux t=new DecodeAux();
+ int[] ptr0=t.ptr0=new int[entries*2];
+ int[] ptr1=t.ptr1=new int[entries*2];
+ int[] codelist=make_words(c.lengthlist, c.entries);
+
+ if(codelist==null)return(null);
+ t.aux=entries*2;
+
+ for(int i=0;i<entries;i++){
+ if(c.lengthlist[i]>0){
+ int ptr=0;
+ int j;
+ for(j=0;j<c.lengthlist[i]-1;j++){
+ int bit=(codelist[i]>>>j)&1;
+ if(bit==0){
+ if(ptr0[ptr]==0){
+ ptr0[ptr]=++top;
+ }
+ ptr=ptr0[ptr];
+ }
+ else{
+ if(ptr1[ptr]==0){
+ ptr1[ptr]= ++top;
+ }
+ ptr=ptr1[ptr];
+ }
+ }
+
+ if(((codelist[i]>>>j)&1)==0){ ptr0[ptr]=-i; }
+ else{ ptr1[ptr]=-i; }
+
+ }
+ }
+ //free(codelist);
+
+ t.tabn = ilog(entries)-4;
+
+ if(t.tabn<5)t.tabn=5;
+ int n = 1<<t.tabn;
+ t.tab = new int[n];
+ t.tabl = new int[n];
+ for(int i = 0; i < n; i++){
+ int p = 0;
+ int j=0;
+ for(j = 0; j < t.tabn && (p > 0 || j == 0); j++){
+ if ((i&(1<<j))!=0){
+ p = ptr1[p];
+ }
+ else{
+ p = ptr0[p];
+ }
+ }
+ t.tab[i]=p; // -code
+ t.tabl[i]=j; // length
+ }
+
+ return(t);
+ }
+
+ private static int ilog(int v){
+ int ret=0;
+ while(v!=0){
+ ret++;
+ v>>>=1;
+ }
+ return(ret);
+ }
+
+/*
+ // TEST
+ // Simple enough; pack a few candidate codebooks, unpack them. Code a
+ // number of vectors through (keeping track of the quantized values),
+ // and decode using the unpacked book. quantized version of in should
+ // exactly equal out
+
+ //#include "vorbis/book/lsp20_0.vqh"
+ //#include "vorbis/book/lsp32_0.vqh"
+ //#include "vorbis/book/res0_1a.vqh"
+ static final int TESTSIZE=40;
+
+ static float[] test1={
+ 0.105939,
+ 0.215373,
+ 0.429117,
+ 0.587974,
+
+ 0.181173,
+ 0.296583,
+ 0.515707,
+ 0.715261,
+
+ 0.162327,
+ 0.263834,
+ 0.342876,
+ 0.406025,
+
+ 0.103571,
+ 0.223561,
+ 0.368513,
+ 0.540313,
+
+ 0.136672,
+ 0.395882,
+ 0.587183,
+ 0.652476,
+
+ 0.114338,
+ 0.417300,
+ 0.525486,
+ 0.698679,
+
+ 0.147492,
+ 0.324481,
+ 0.643089,
+ 0.757582,
+
+ 0.139556,
+ 0.215795,
+ 0.324559,
+ 0.399387,
+
+ 0.120236,
+ 0.267420,
+ 0.446940,
+ 0.608760,
+
+ 0.115587,
+ 0.287234,
+ 0.571081,
+ 0.708603,
+ };
+
+ static float[] test2={
+ 0.088654,
+ 0.165742,
+ 0.279013,
+ 0.395894,
+
+ 0.110812,
+ 0.218422,
+ 0.283423,
+ 0.371719,
+
+ 0.136985,
+ 0.186066,
+ 0.309814,
+ 0.381521,
+
+ 0.123925,
+ 0.211707,
+ 0.314771,
+ 0.433026,
+
+ 0.088619,
+ 0.192276,
+ 0.277568,
+ 0.343509,
+
+ 0.068400,
+ 0.132901,
+ 0.223999,
+ 0.302538,
+
+ 0.202159,
+ 0.306131,
+ 0.360362,
+ 0.416066,
+
+ 0.072591,
+ 0.178019,
+ 0.304315,
+ 0.376516,
+
+ 0.094336,
+ 0.188401,
+ 0.325119,
+ 0.390264,
+
+ 0.091636,
+ 0.223099,
+ 0.282899,
+ 0.375124,
+ };
+
+ static float[] test3={
+ 0,1,-2,3,4,-5,6,7,8,9,
+ 8,-2,7,-1,4,6,8,3,1,-9,
+ 10,11,12,13,14,15,26,17,18,19,
+ 30,-25,-30,-1,-5,-32,4,3,-2,0};
+
+// static_codebook *testlist[]={&_vq_book_lsp20_0,
+// &_vq_book_lsp32_0,
+// &_vq_book_res0_1a,NULL};
+ static[][] float testvec={test1,test2,test3};
+
+ static void main(String[] arg){
+ Buffer write=new Buffer();
+ Buffer read=new Buffer();
+ int ptr=0;
+ write.writeinit();
+
+ System.err.println("Testing codebook abstraction...:");
+
+ while(testlist[ptr]!=null){
+ CodeBook c=new CodeBook();
+ StaticCodeBook s=new StaticCodeBook();;
+ float *qv=alloca(sizeof(float)*TESTSIZE);
+ float *iv=alloca(sizeof(float)*TESTSIZE);
+ memcpy(qv,testvec[ptr],sizeof(float)*TESTSIZE);
+ memset(iv,0,sizeof(float)*TESTSIZE);
+
+ System.err.print("\tpacking/coding "+ptr+"... ");
+
+ // pack the codebook, write the testvector
+ write.reset();
+ vorbis_book_init_encode(&c,testlist[ptr]); // get it into memory
+ // we can write
+ vorbis_staticbook_pack(testlist[ptr],&write);
+ System.err.print("Codebook size "+write.bytes()+" bytes... ");
+ for(int i=0;i<TESTSIZE;i+=c.dim){
+ vorbis_book_encodev(&c,qv+i,&write);
+ }
+ c.clear();
+
+ System.err.print("OK.\n");
+ System.err.print("\tunpacking/decoding "+ptr+"... ");
+
+ // transfer the write data to a read buffer and unpack/read
+ _oggpack_readinit(&read,_oggpack_buffer(&write),_oggpack_bytes(&write));
+ if(s.unpack(read)){
+ System.err.print("Error unpacking codebook.\n");
+ System.exit(1);
+ }
+ if(vorbis_book_init_decode(&c,&s)){
+ System.err.print("Error initializing codebook.\n");
+ System.exit(1);
+ }
+ for(int i=0;i<TESTSIZE;i+=c.dim){
+ if(vorbis_book_decodevs(&c,iv+i,&read,1,-1)==-1){
+ System.err.print("Error reading codebook test data (EOP).\n");
+ System.exit(1);
+ }
+ }
+ for(int i=0;i<TESTSIZE;i++){
+ if(fabs(qv[i]-iv[i])>.000001){
+ System.err.print("read ("+iv[i]+") != written ("+qv[i]+") at position ("+i+")\n");
+ System.exit(1);
+ }
+ }
+
+ System.err.print("OK\n");
+ ptr++;
+ }
+ // The above is the trivial stuff;
+ // now try unquantizing a log scale codebook
+ }
+*/
+}
+
+class DecodeAux{
+ int[] tab;
+ int[] tabl;
+ int tabn;
+
+ int[] ptr0;
+ int[] ptr1;
+ int aux; // number of tree entries
+}