examples/SFExamples/oggvorbiscodec/src/libvorbis/lib/sharedbook.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
00004  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00005  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00006  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00007  *                                                                  *
00008  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
00009  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
00010  *                                                                  *
00011  ********************************************************************
00012 
00013  function: basic shared codebook operations
00014  last mod: $Id: sharedbook.c 7187 2004-07-20 07:24:27Z xiphmont $
00015 
00016  ********************************************************************/
00017 
00018 #include <stdlib.h>
00019 #include <math.h>
00020 #include <string.h>
00021 #include "ogg/ogg.h"
00022 #include "os.h"
00023 #include "misc.h"
00024 #include "vorbis/codec.h"
00025 #include "codebook.h"
00026 #include "scales.h"
00027 
00028 /**** pack/unpack helpers ******************************************/
00029 int _ilog(unsigned int v){
00030   int ret=0;
00031   while(v){
00032     ret++;
00033     v>>=1;
00034   }
00035   return(ret);
00036 }
00037 
00038 /* 32 bit float (not IEEE; nonnormalized mantissa +
00039    biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm 
00040    Why not IEEE?  It's just not that important here. */
00041 
00042 #define VQ_FEXP 10
00043 #define VQ_FMAN 21
00044 #define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
00045 
00046 /* doesn't currently guard under/overflow */
00047 long _float32_pack(float val){
00048   int sign=0;
00049   long exp;
00050   long mant;
00051   if(val<0){
00052     sign=0x80000000;
00053     val= -val;
00054   }
00055   exp= floor(log(val)/log(2.f));
00056   mant=rint(ldexp(val,(VQ_FMAN-1)-exp));
00057   exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
00058 
00059   return(sign|exp|mant);
00060 }
00061 
00062 float _float32_unpack(long val){
00063   double mant=val&0x1fffff;
00064   int    sign=val&0x80000000;
00065   long   exp =(val&0x7fe00000L)>>VQ_FMAN;
00066   if(sign)mant= -mant;
00067   return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS));
00068 }
00069 
00070 /* given a list of word lengths, generate a list of codewords.  Works
00071    for length ordered or unordered, always assigns the lowest valued
00072    codewords first.  Extended to handle unused entries (length 0) */
00073 ogg_uint32_t *_make_words(long *l,long n,long sparsecount){
00074   long i,j,count=0;
00075   ogg_uint32_t marker[33];
00076   ogg_uint32_t *r=(ogg_uint32_t*)_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
00077   memset(marker,0,sizeof(marker));
00078 
00079   for(i=0;i<n;i++){
00080     long length=l[i];
00081     if(length>0){
00082       ogg_uint32_t entry=marker[length];
00083       
00084       /* when we claim a node for an entry, we also claim the nodes
00085          below it (pruning off the imagined tree that may have dangled
00086          from it) as well as blocking the use of any nodes directly
00087          above for leaves */
00088       
00089       /* update ourself */
00090       if(length<32 && (entry>>length)){
00091         /* error condition; the lengths must specify an overpopulated tree */
00092         _ogg_free(r);
00093         return(NULL);
00094       }
00095       r[count++]=entry;
00096     
00097       /* Look to see if the next shorter marker points to the node
00098          above. if so, update it and repeat.  */
00099       {
00100         for(j=length;j>0;j--){
00101           
00102           if(marker[j]&1){
00103             /* have to jump branches */
00104             if(j==1)
00105               marker[1]++;
00106             else
00107               marker[j]=marker[j-1]<<1;
00108             break; /* invariant says next upper marker would already
00109                       have been moved if it was on the same path */
00110           }
00111           marker[j]++;
00112         }
00113       }
00114       
00115       /* prune the tree; the implicit invariant says all the longer
00116          markers were dangling from our just-taken node.  Dangle them
00117          from our *new* node. */
00118       for(j=length+1;j<33;j++)
00119         if((marker[j]>>1) == entry){
00120           entry=marker[j];
00121           marker[j]=marker[j-1]<<1;
00122         }else
00123           break;
00124     }else
00125       if(sparsecount==0)count++;
00126   }
00127     
00128   /* bitreverse the words because our bitwise packer/unpacker is LSb
00129      endian */
00130   for(i=0,count=0;i<n;i++){
00131     ogg_uint32_t temp=0;
00132     for(j=0;j<l[i];j++){
00133       temp<<=1;
00134       temp|=(r[count]>>j)&1;
00135     }
00136 
00137     if(sparsecount){
00138       if(l[i])
00139         r[count++]=temp;
00140     }else
00141       r[count++]=temp;
00142   }
00143 
00144   return(r);
00145 }
00146 
00147 /* there might be a straightforward one-line way to do the below
00148    that's portable and totally safe against roundoff, but I haven't
00149    thought of it.  Therefore, we opt on the side of caution */
00150 long _book_maptype1_quantvals(const static_codebook *b){
00151   long vals=floor(pow((float)b->entries,1.f/b->dim));
00152 
00153   /* the above *should* be reliable, but we'll not assume that FP is
00154      ever reliable when bitstream sync is at stake; verify via integer
00155      means that vals really is the greatest value of dim for which
00156      vals^b->bim <= b->entries */
00157   /* treat the above as an initial guess */
00158   while(1){
00159     long acc=1;
00160     long acc1=1;
00161     int i;
00162     for(i=0;i<b->dim;i++){
00163       acc*=vals;
00164       acc1*=vals+1;
00165     }
00166     if(acc<=b->entries && acc1>b->entries){
00167       return(vals);
00168     }else{
00169       if(acc>b->entries){
00170         vals--;
00171       }else{
00172         vals++;
00173       }
00174     }
00175   }
00176 }
00177 
00178 /* unpack the quantized list of values for encode/decode ***********/
00179 /* we need to deal with two map types: in map type 1, the values are
00180    generated algorithmically (each column of the vector counts through
00181    the values in the quant vector). in map type 2, all the values came
00182    in in an explicit list.  Both value lists must be unpacked */
00183 float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){
00184   long j,k,count=0;
00185   if(b->maptype==1 || b->maptype==2){
00186     int quantvals;
00187     float mindel=_float32_unpack(b->q_min);
00188     float delta=_float32_unpack(b->q_delta);
00189     float *r=(float*)_ogg_calloc(n*b->dim,sizeof(*r));
00190 
00191     /* maptype 1 and 2 both use a quantized value vector, but
00192        different sizes */
00193     switch(b->maptype){
00194     case 1:
00195       /* most of the time, entries%dimensions == 0, but we need to be
00196          well defined.  We define that the possible vales at each
00197          scalar is values == entries/dim.  If entries%dim != 0, we'll
00198          have 'too few' values (values*dim<entries), which means that
00199          we'll have 'left over' entries; left over entries use zeroed
00200          values (and are wasted).  So don't generate codebooks like
00201          that */
00202       quantvals=_book_maptype1_quantvals(b);
00203       for(j=0;j<b->entries;j++){
00204         if((sparsemap && b->lengthlist[j]) || !sparsemap){
00205           float last=0.f;
00206           int indexdiv=1;
00207           for(k=0;k<b->dim;k++){
00208             int index= (j/indexdiv)%quantvals;
00209             float val=b->quantlist[index];
00210             val=fabs(val)*delta+mindel+last;
00211             if(b->q_sequencep)last=val;   
00212             if(sparsemap)
00213               r[sparsemap[count]*b->dim+k]=val;
00214             else
00215               r[count*b->dim+k]=val;
00216             indexdiv*=quantvals;
00217           }
00218           count++;
00219         }
00220 
00221       }
00222       break;
00223     case 2:
00224       for(j=0;j<b->entries;j++){
00225         if((sparsemap && b->lengthlist[j]) || !sparsemap){
00226           float last=0.f;
00227           
00228           for(k=0;k<b->dim;k++){
00229             float val=b->quantlist[j*b->dim+k];
00230             val=fabs(val)*delta+mindel+last;
00231             if(b->q_sequencep)last=val;   
00232             if(sparsemap)
00233               r[sparsemap[count]*b->dim+k]=val;
00234             else
00235               r[count*b->dim+k]=val;
00236           }
00237           count++;
00238         }
00239       }
00240       break;
00241     }
00242 
00243     return(r);
00244   }
00245   return(NULL);
00246 }
00247 
00248 void vorbis_staticbook_clear(static_codebook *b){
00249   if(b->allocedp){
00250     if(b->quantlist)_ogg_free(b->quantlist);
00251     if(b->lengthlist)_ogg_free(b->lengthlist);
00252     if(b->nearest_tree){
00253       _ogg_free(b->nearest_tree->ptr0);
00254       _ogg_free(b->nearest_tree->ptr1);
00255       _ogg_free(b->nearest_tree->p);
00256       _ogg_free(b->nearest_tree->q);
00257       memset(b->nearest_tree,0,sizeof(*b->nearest_tree));
00258       _ogg_free(b->nearest_tree);
00259     }
00260     if(b->thresh_tree){
00261       _ogg_free(b->thresh_tree->quantthresh);
00262       _ogg_free(b->thresh_tree->quantmap);
00263       memset(b->thresh_tree,0,sizeof(*b->thresh_tree));
00264       _ogg_free(b->thresh_tree);
00265     }
00266 
00267     memset(b,0,sizeof(*b));
00268   }
00269 }
00270 
00271 void vorbis_staticbook_destroy(static_codebook *b){
00272   if(b->allocedp){
00273     vorbis_staticbook_clear(b);
00274     _ogg_free(b);
00275   }
00276 }
00277 
00278 void vorbis_book_clear(codebook *b){
00279   /* static book is not cleared; we're likely called on the lookup and
00280      the static codebook belongs to the info struct */
00281   if(b->valuelist)_ogg_free(b->valuelist);
00282   if(b->codelist)_ogg_free(b->codelist);
00283 
00284   if(b->dec_index)_ogg_free(b->dec_index);
00285   if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
00286   if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
00287 
00288   memset(b,0,sizeof(*b));
00289 }
00290 
00291 int vorbis_book_init_encode(codebook *c,const static_codebook *s){
00292 
00293   memset(c,0,sizeof(*c));
00294   c->c=s;
00295   c->entries=s->entries;
00296   c->used_entries=s->entries;
00297   c->dim=s->dim;
00298   c->codelist=_make_words(s->lengthlist,s->entries,0);
00299   c->valuelist=_book_unquantize(s,s->entries,NULL);
00300 
00301   return(0);
00302 }
00303 
00304 static ogg_uint32_t bitreverse(ogg_uint32_t x){
00305   x=    ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
00306   x=    ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
00307   x=    ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
00308   x=    ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
00309   return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
00310 }
00311 
00312 static int sort32a(const void *a,const void *b){
00313   return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)- 
00314     ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
00315 }
00316 
00317 /* decode codebook arrangement is more heavily optimized than encode */
00318 int vorbis_book_init_decode(codebook *c,const static_codebook *s){
00319   int i,j,n=0,tabn;
00320   int *sortindex;
00321   int *sortindex_cpy = NULL;
00322   memset(c,0,sizeof(*c));
00323   
00324   /* count actually used entries */
00325   for(i=0;i<s->entries;i++)
00326     if(s->lengthlist[i]>0)
00327       n++;
00328 
00329   c->entries=s->entries;
00330   c->used_entries=n;
00331   c->dim=s->dim;
00332 
00333   /* two different remappings go on here.  
00334 
00335      First, we collapse the likely sparse codebook down only to
00336      actually represented values/words.  This collapsing needs to be
00337      indexed as map-valueless books are used to encode original entry
00338      positions as integers.
00339 
00340      Second, we reorder all vectors, including the entry index above,
00341      by sorted bitreversed codeword to allow treeless decode. */
00342 
00343   {
00344     /* perform sort */
00345     ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
00346     ogg_uint32_t **codep= (ogg_uint32_t **)_ogg_malloc(sizeof(*codep)*n);//alloca(sizeof(*codep)*n); //patch
00347     ogg_uint32_t **codep_cpy = codep;
00348     
00349     if(codes==NULL)goto err_out;
00350 
00351     for(i=0;i<n;i++){
00352       codes[i]=bitreverse(codes[i]);
00353       codep[i]=codes+i;
00354     }
00355 
00356     qsort(codep,n,sizeof(*codep),sort32a);
00357 
00358     sortindex= (int*)_ogg_malloc(n*sizeof(*sortindex));//alloca(n*sizeof(*sortindex)); //patch
00359     sortindex_cpy =sortindex ;
00360     
00361     c->codelist=(ogg_uint32_t*)_ogg_malloc(n*sizeof(*c->codelist));
00362     /* the index is a reverse index */
00363     for(i=0;i<n;i++){
00364       int position=codep[i]-codes;
00365       sortindex[position]=i;
00366     }
00367 
00368     for(i=0;i<n;i++)
00369       c->codelist[sortindex[i]]=codes[i];
00370     _ogg_free(codes);
00371     
00372     free(codep_cpy);
00373   }
00374 
00375   c->valuelist=_book_unquantize(s,n,sortindex);
00376   c->dec_index=(int*)_ogg_malloc(n*sizeof(*c->dec_index));
00377 
00378   for(n=0,i=0;i<s->entries;i++)
00379     if(s->lengthlist[i]>0)
00380       c->dec_index[sortindex[n++]]=i;
00381   
00382   c->dec_codelengths=(char*)_ogg_malloc(n*sizeof(*c->dec_codelengths));
00383   for(n=0,i=0;i<s->entries;i++)
00384     if(s->lengthlist[i]>0)
00385       c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
00386 
00387   c->dec_firsttablen=_ilog(c->used_entries)-4; /* this is magic */
00388   if(c->dec_firsttablen<5)c->dec_firsttablen=5;
00389   if(c->dec_firsttablen>8)c->dec_firsttablen=8;
00390 
00391   tabn=1<<c->dec_firsttablen;
00392   c->dec_firsttable=(ogg_uint32_t*)_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
00393   c->dec_maxlength=0;
00394 
00395   for(i=0;i<n;i++){
00396     if(c->dec_maxlength<c->dec_codelengths[i])
00397       c->dec_maxlength=c->dec_codelengths[i];
00398     if(c->dec_codelengths[i]<=c->dec_firsttablen){
00399       ogg_uint32_t orig=bitreverse(c->codelist[i]);
00400       for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
00401         c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
00402     }
00403   }
00404 
00405   /* now fill in 'unused' entries in the firsttable with hi/lo search
00406      hints for the non-direct-hits */
00407   {
00408     ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
00409     long lo=0,hi=0;
00410 
00411     for(i=0;i<tabn;i++){
00412       ogg_uint32_t word=i<<(32-c->dec_firsttablen);
00413       if(c->dec_firsttable[bitreverse(word)]==0){
00414         while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
00415         while(    hi<n && word>=(c->codelist[hi]&mask))hi++;
00416         
00417         /* we only actually have 15 bits per hint to play with here.
00418            In order to overflow gracefully (nothing breaks, efficiency
00419            just drops), encode as the difference from the extremes. */
00420         {
00421           unsigned long loval=lo;
00422           unsigned long hival=n-hi;
00423 
00424           if(loval>0x7fff)loval=0x7fff;
00425           if(hival>0x7fff)hival=0x7fff;
00426           c->dec_firsttable[bitreverse(word)]=
00427             0x80000000UL | (loval<<15) | hival;
00428         }
00429       }
00430     }
00431   }
00432   
00433   free(sortindex_cpy);
00434   return(0);
00435  err_out:
00436   vorbis_book_clear(c);
00437   
00438   free(sortindex_cpy);
00439   return(-1);
00440 }
00441 
00442 static float _dist(int el,float *ref, float *b,int step){
00443   int i;
00444   float acc=0.f;
00445   for(i=0;i<el;i++){
00446     float val=(ref[i]-b[i*step]);
00447     acc+=val*val;
00448   }
00449   return(acc);
00450 }
00451 
00452 int _best(codebook *book, float *a, int step){
00453   encode_aux_threshmatch *tt=book->c->thresh_tree;
00454 
00455 #if 0
00456   encode_aux_nearestmatch *nt=book->c->nearest_tree;
00457   encode_aux_pigeonhole *pt=book->c->pigeon_tree;
00458 #endif
00459   int dim=book->dim;
00460   int k,o;
00461   /*int savebest=-1;
00462     float saverr;*/
00463 
00464   /* do we have a threshhold encode hint? */
00465   if(tt){
00466     int index=0,i;
00467     /* find the quant val of each scalar */
00468     for(k=0,o=step*(dim-1);k<dim;k++,o-=step){
00469 
00470       i=tt->threshvals>>1;
00471       if(a[o]<tt->quantthresh[i]){
00472 
00473         for(;i>0;i--)
00474           if(a[o]>=tt->quantthresh[i-1])
00475             break;
00476         
00477       }else{
00478 
00479         for(i++;i<tt->threshvals-1;i++)
00480           if(a[o]<tt->quantthresh[i])break;
00481 
00482       }
00483 
00484       index=(index*tt->quantvals)+tt->quantmap[i];
00485     }
00486     /* regular lattices are easy :-) */
00487     if(book->c->lengthlist[index]>0) /* is this unused?  If so, we'll
00488                                         use a decision tree after all
00489                                         and fall through*/
00490       return(index);
00491   }
00492 
00493 #if 0
00494   /* do we have a pigeonhole encode hint? */
00495   if(pt){
00496     const static_codebook *c=book->c;
00497     int i,besti=-1;
00498     float best=0.f;
00499     int entry=0;
00500 
00501     /* dealing with sequentialness is a pain in the ass */
00502     if(c->q_sequencep){
00503       int pv;
00504       long mul=1;
00505       float qlast=0;
00506       for(k=0,o=0;k<dim;k++,o+=step){
00507         pv=(int)((a[o]-qlast-pt->min)/pt->del);
00508         if(pv<0 || pv>=pt->mapentries)break;
00509         entry+=pt->pigeonmap[pv]*mul;
00510         mul*=pt->quantvals;
00511         qlast+=pv*pt->del+pt->min;
00512       }
00513     }else{
00514       for(k=0,o=step*(dim-1);k<dim;k++,o-=step){
00515         int pv=(int)((a[o]-pt->min)/pt->del);
00516         if(pv<0 || pv>=pt->mapentries)break;
00517         entry=entry*pt->quantvals+pt->pigeonmap[pv];
00518       }
00519     }
00520 
00521     /* must be within the pigeonholable range; if we quant outside (or
00522        in an entry that we define no list for), brute force it */
00523     if(k==dim && pt->fitlength[entry]){
00524       /* search the abbreviated list */
00525       long *list=pt->fitlist+pt->fitmap[entry];
00526       for(i=0;i<pt->fitlength[entry];i++){
00527         float this=_dist(dim,book->valuelist+list[i]*dim,a,step);
00528         if(besti==-1 || this<best){
00529           best=this;
00530           besti=list[i];
00531         }
00532       }
00533 
00534       return(besti); 
00535     }
00536   }
00537 
00538   if(nt){
00539     /* optimized using the decision tree */
00540     while(1){
00541       float c=0.f;
00542       float *p=book->valuelist+nt->p[ptr];
00543       float *q=book->valuelist+nt->q[ptr];
00544       
00545       for(k=0,o=0;k<dim;k++,o+=step)
00546         c+=(p[k]-q[k])*(a[o]-(p[k]+q[k])*.5);
00547       
00548       if(c>0.f) /* in A */
00549         ptr= -nt->ptr0[ptr];
00550       else     /* in B */
00551         ptr= -nt->ptr1[ptr];
00552       if(ptr<=0)break;
00553     }
00554     return(-ptr);
00555   }
00556 #endif 
00557 
00558   /* brute force it! */
00559   {
00560     const static_codebook *c=book->c;
00561     int i,besti=-1;
00562     float best=0.f;
00563     float *e=book->valuelist;
00564     for(i=0;i<book->entries;i++){
00565       if(c->lengthlist[i]>0){
00566         float temp=_dist(dim,e,a,step);
00567         if(besti==-1 || temp<best){
00568           best=temp;
00569           besti=i;
00570         }
00571       }
00572       e+=dim;
00573     }
00574 
00575     /*if(savebest!=-1 && savebest!=besti){
00576       fprintf(stderr,"brute force/pigeonhole disagreement:\n"
00577               "original:");
00578       for(i=0;i<dim*step;i+=step)fprintf(stderr,"%g,",a[i]);
00579       fprintf(stderr,"\n"
00580               "pigeonhole (entry %d, err %g):",savebest,saverr);
00581       for(i=0;i<dim;i++)fprintf(stderr,"%g,",
00582                                 (book->valuelist+savebest*dim)[i]);
00583       fprintf(stderr,"\n"
00584               "bruteforce (entry %d, err %g):",besti,best);
00585       for(i=0;i<dim;i++)fprintf(stderr,"%g,",
00586                                 (book->valuelist+besti*dim)[i]);
00587       fprintf(stderr,"\n");
00588       }*/
00589     return(besti);
00590   }
00591 }
00592 
00593 long vorbis_book_codeword(codebook *book,int entry){
00594   if(book->c) /* only use with encode; decode optimizations are
00595                  allowed to break this */
00596     return book->codelist[entry];
00597   return -1;
00598 }
00599 
00600 long vorbis_book_codelen(codebook *book,int entry){
00601   if(book->c) /* only use with encode; decode optimizations are
00602                  allowed to break this */
00603     return book->c->lengthlist[entry];
00604   return -1;
00605 }
00606 
00607 #ifdef _V_SELFTEST
00608 
00609 /* Unit tests of the dequantizer; this stuff will be OK
00610    cross-platform, I simply want to be sure that special mapping cases
00611    actually work properly; a bug could go unnoticed for a while */
00612 
00613 #include <stdio.h>
00614 
00615 /* cases:
00616 
00617    no mapping
00618    full, explicit mapping
00619    algorithmic mapping
00620 
00621    nonsequential
00622    sequential
00623 */
00624 
00625 static long full_quantlist1[]={0,1,2,3,    4,5,6,7, 8,3,6,1};
00626 static long partial_quantlist1[]={0,7,2};
00627 
00628 /* no mapping */
00629 static_codebook test1={
00630   4,16,
00631   NULL,
00632   0,
00633   0,0,0,0,
00634   NULL,
00635   NULL,NULL
00636 };
00637 static float *test1_result=NULL;
00638   
00639 /* linear, full mapping, nonsequential */
00640 static_codebook test2={
00641   4,3,
00642   NULL,
00643   2,
00644   -533200896,1611661312,4,0,
00645   full_quantlist1,
00646   NULL,NULL
00647 };
00648 static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
00649 
00650 /* linear, full mapping, sequential */
00651 static_codebook test3={
00652   4,3,
00653   NULL,
00654   2,
00655   -533200896,1611661312,4,1,
00656   full_quantlist1,
00657   NULL,NULL
00658 };
00659 static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
00660 
00661 /* linear, algorithmic mapping, nonsequential */
00662 static_codebook test4={
00663   3,27,
00664   NULL,
00665   1,
00666   -533200896,1611661312,4,0,
00667   partial_quantlist1,
00668   NULL,NULL
00669 };
00670 static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3,
00671                               -3, 4,-3, 4, 4,-3, -1, 4,-3,
00672                               -3,-1,-3, 4,-1,-3, -1,-1,-3, 
00673                               -3,-3, 4, 4,-3, 4, -1,-3, 4,
00674                               -3, 4, 4, 4, 4, 4, -1, 4, 4,
00675                               -3,-1, 4, 4,-1, 4, -1,-1, 4,
00676                               -3,-3,-1, 4,-3,-1, -1,-3,-1,
00677                               -3, 4,-1, 4, 4,-1, -1, 4,-1,
00678                               -3,-1,-1, 4,-1,-1, -1,-1,-1};
00679 
00680 /* linear, algorithmic mapping, sequential */
00681 static_codebook test5={
00682   3,27,
00683   NULL,
00684   1,
00685   -533200896,1611661312,4,1,
00686   partial_quantlist1,
00687   NULL,NULL
00688 };
00689 static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7,
00690                               -3, 1,-2, 4, 8, 5, -1, 3, 0,
00691                               -3,-4,-7, 4, 3, 0, -1,-2,-5, 
00692                               -3,-6,-2, 4, 1, 5, -1,-4, 0,
00693                               -3, 1, 5, 4, 8,12, -1, 3, 7,
00694                               -3,-4, 0, 4, 3, 7, -1,-2, 2,
00695                               -3,-6,-7, 4, 1, 0, -1,-4,-5,
00696                               -3, 1, 0, 4, 8, 7, -1, 3, 2,
00697                               -3,-4,-5, 4, 3, 2, -1,-2,-3};
00698 
00699 void run_test(static_codebook *b,float *comp){
00700   float *out=_book_unquantize(b,b->entries,NULL);
00701   int i;
00702 
00703   if(comp){
00704     if(!out){
00705       fprintf(stderr,"_book_unquantize incorrectly returned NULL\n");
00706       exit(1);
00707     }
00708 
00709     for(i=0;i<b->entries*b->dim;i++)
00710       if(fabs(out[i]-comp[i])>.0001){
00711         fprintf(stderr,"disagreement in unquantized and reference data:\n"
00712                 "position %d, %g != %g\n",i,out[i],comp[i]);
00713         exit(1);
00714       }
00715 
00716   }else{
00717     if(out){
00718       fprintf(stderr,"_book_unquantize returned a value array: \n"
00719               " correct result should have been NULL\n");
00720       exit(1);
00721     }
00722   }
00723 }
00724 
00725 int main(){
00726   /* run the nine dequant tests, and compare to the hand-rolled results */
00727   fprintf(stderr,"Dequant test 1... ");
00728   run_test(&test1,test1_result);
00729   fprintf(stderr,"OK\nDequant test 2... ");
00730   run_test(&test2,test2_result);
00731   fprintf(stderr,"OK\nDequant test 3... ");
00732   run_test(&test3,test3_result);
00733   fprintf(stderr,"OK\nDequant test 4... ");
00734   run_test(&test4,test4_result);
00735   fprintf(stderr,"OK\nDequant test 5... ");
00736   run_test(&test5,test5_result);
00737   fprintf(stderr,"OK\n\n");
00738   
00739   return(0);
00740 }
00741 
00742 #endif

Generated by  doxygen 1.6.2