vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

sharedbook.c (19720B)


      1 /********************************************************************
      2  *                                                                  *
      3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
      4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
      5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
      6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
      7  *                                                                  *
      8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
      9  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
     10  *                                                                  *
     11  ********************************************************************
     12 
     13  function: basic shared codebook operations
     14  last mod: $Id: sharedbook.c 1919 2005-07-24 14:18:04Z baford $
     15 
     16  ********************************************************************/
     17 
     18 #include <stdlib.h>
     19 #include <math.h>
     20 #include <string.h>
     21 #include <ogg/ogg.h>
     22 #include "os.h"
     23 #include "misc.h"
     24 #include "vorbis/codec.h"
     25 #include "codebook.h"
     26 #include "scales.h"
     27 
     28 /**** pack/unpack helpers ******************************************/
     29 int _ilog(unsigned int v){
     30   int ret=0;
     31   while(v){
     32     ret++;
     33     v>>=1;
     34   }
     35   return(ret);
     36 }
     37 
     38 /* 32 bit float (not IEEE; nonnormalized mantissa +
     39    biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm 
     40    Why not IEEE?  It's just not that important here. */
     41 
     42 #define VQ_FEXP 10
     43 #define VQ_FMAN 21
     44 #define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
     45 
     46 /* doesn't currently guard under/overflow */
     47 long _float32_pack(float val){
     48   int sign=0;
     49   long exp;
     50   long mant;
     51   if(val<0){
     52     sign=0x80000000;
     53     val= -val;
     54   }
     55   exp= floor(log(val)/log(2.f));
     56   mant=rint(ldexp(val,(VQ_FMAN-1)-exp));
     57   exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
     58 
     59   return(sign|exp|mant);
     60 }
     61 
     62 float _float32_unpack(long val){
     63   double mant=val&0x1fffff;
     64   int    sign=val&0x80000000;
     65   long   exp =(val&0x7fe00000L)>>VQ_FMAN;
     66   if(sign)mant= -mant;
     67   return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS));
     68 }
     69 
     70 /* given a list of word lengths, generate a list of codewords.  Works
     71    for length ordered or unordered, always assigns the lowest valued
     72    codewords first.  Extended to handle unused entries (length 0) */
     73 ogg_uint32_t *_make_words(long *l,long n,long sparsecount){
     74   long i,j,count=0;
     75   ogg_uint32_t marker[33];
     76   ogg_uint32_t *r=_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
     77   memset(marker,0,sizeof(marker));
     78 
     79   for(i=0;i<n;i++){
     80     long length=l[i];
     81     if(length>0){
     82       ogg_uint32_t entry=marker[length];
     83       
     84       /* when we claim a node for an entry, we also claim the nodes
     85 	 below it (pruning off the imagined tree that may have dangled
     86 	 from it) as well as blocking the use of any nodes directly
     87 	 above for leaves */
     88       
     89       /* update ourself */
     90       if(length<32 && (entry>>length)){
     91 	/* error condition; the lengths must specify an overpopulated tree */
     92 	_ogg_free(r);
     93 	return(NULL);
     94       }
     95       r[count++]=entry;
     96     
     97       /* Look to see if the next shorter marker points to the node
     98 	 above. if so, update it and repeat.  */
     99       {
    100 	for(j=length;j>0;j--){
    101 	  
    102 	  if(marker[j]&1){
    103 	    /* have to jump branches */
    104 	    if(j==1)
    105 	      marker[1]++;
    106 	    else
    107 	      marker[j]=marker[j-1]<<1;
    108 	    break; /* invariant says next upper marker would already
    109 		      have been moved if it was on the same path */
    110 	  }
    111 	  marker[j]++;
    112 	}
    113       }
    114       
    115       /* prune the tree; the implicit invariant says all the longer
    116 	 markers were dangling from our just-taken node.  Dangle them
    117 	 from our *new* node. */
    118       for(j=length+1;j<33;j++)
    119 	if((marker[j]>>1) == entry){
    120 	  entry=marker[j];
    121 	  marker[j]=marker[j-1]<<1;
    122 	}else
    123 	  break;
    124     }else
    125       if(sparsecount==0)count++;
    126   }
    127     
    128   /* bitreverse the words because our bitwise packer/unpacker is LSb
    129      endian */
    130   for(i=0,count=0;i<n;i++){
    131     ogg_uint32_t temp=0;
    132     for(j=0;j<l[i];j++){
    133       temp<<=1;
    134       temp|=(r[count]>>j)&1;
    135     }
    136 
    137     if(sparsecount){
    138       if(l[i])
    139 	r[count++]=temp;
    140     }else
    141       r[count++]=temp;
    142   }
    143 
    144   return(r);
    145 }
    146 
    147 /* there might be a straightforward one-line way to do the below
    148    that's portable and totally safe against roundoff, but I haven't
    149    thought of it.  Therefore, we opt on the side of caution */
    150 long _book_maptype1_quantvals(const static_codebook *b){
    151   long vals=floor(pow((float)b->entries,1.f/b->dim));
    152 
    153   /* the above *should* be reliable, but we'll not assume that FP is
    154      ever reliable when bitstream sync is at stake; verify via integer
    155      means that vals really is the greatest value of dim for which
    156      vals^b->bim <= b->entries */
    157   /* treat the above as an initial guess */
    158   while(1){
    159     long acc=1;
    160     long acc1=1;
    161     int i;
    162     for(i=0;i<b->dim;i++){
    163       acc*=vals;
    164       acc1*=vals+1;
    165     }
    166     if(acc<=b->entries && acc1>b->entries){
    167       return(vals);
    168     }else{
    169       if(acc>b->entries){
    170 	vals--;
    171       }else{
    172 	vals++;
    173       }
    174     }
    175   }
    176 }
    177 
    178 /* unpack the quantized list of values for encode/decode ***********/
    179 /* we need to deal with two map types: in map type 1, the values are
    180    generated algorithmically (each column of the vector counts through
    181    the values in the quant vector). in map type 2, all the values came
    182    in in an explicit list.  Both value lists must be unpacked */
    183 float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){
    184   long j,k,count=0;
    185   if(b->maptype==1 || b->maptype==2){
    186     int quantvals;
    187     float mindel=_float32_unpack(b->q_min);
    188     float delta=_float32_unpack(b->q_delta);
    189     float *r=_ogg_calloc(n*b->dim,sizeof(*r));
    190 
    191     /* maptype 1 and 2 both use a quantized value vector, but
    192        different sizes */
    193     switch(b->maptype){
    194     case 1:
    195       /* most of the time, entries%dimensions == 0, but we need to be
    196 	 well defined.  We define that the possible vales at each
    197 	 scalar is values == entries/dim.  If entries%dim != 0, we'll
    198 	 have 'too few' values (values*dim<entries), which means that
    199 	 we'll have 'left over' entries; left over entries use zeroed
    200 	 values (and are wasted).  So don't generate codebooks like
    201 	 that */
    202       quantvals=_book_maptype1_quantvals(b);
    203       for(j=0;j<b->entries;j++){
    204 	if((sparsemap && b->lengthlist[j]) || !sparsemap){
    205 	  float last=0.f;
    206 	  int indexdiv=1;
    207 	  for(k=0;k<b->dim;k++){
    208 	    int index= (j/indexdiv)%quantvals;
    209 	    float val=b->quantlist[index];
    210 	    val=fabs(val)*delta+mindel+last;
    211 	    if(b->q_sequencep)last=val;	  
    212 	    if(sparsemap)
    213 	      r[sparsemap[count]*b->dim+k]=val;
    214 	    else
    215 	      r[count*b->dim+k]=val;
    216 	    indexdiv*=quantvals;
    217 	  }
    218 	  count++;
    219 	}
    220 
    221       }
    222       break;
    223     case 2:
    224       for(j=0;j<b->entries;j++){
    225 	if((sparsemap && b->lengthlist[j]) || !sparsemap){
    226 	  float last=0.f;
    227 	  
    228 	  for(k=0;k<b->dim;k++){
    229 	    float val=b->quantlist[j*b->dim+k];
    230 	    val=fabs(val)*delta+mindel+last;
    231 	    if(b->q_sequencep)last=val;	  
    232 	    if(sparsemap)
    233 	      r[sparsemap[count]*b->dim+k]=val;
    234 	    else
    235 	      r[count*b->dim+k]=val;
    236 	  }
    237 	  count++;
    238 	}
    239       }
    240       break;
    241     }
    242 
    243     return(r);
    244   }
    245   return(NULL);
    246 }
    247 
    248 void vorbis_staticbook_clear(static_codebook *b){
    249   if(b->allocedp){
    250     if(b->quantlist)_ogg_free(b->quantlist);
    251     if(b->lengthlist)_ogg_free(b->lengthlist);
    252     if(b->nearest_tree){
    253       _ogg_free(b->nearest_tree->ptr0);
    254       _ogg_free(b->nearest_tree->ptr1);
    255       _ogg_free(b->nearest_tree->p);
    256       _ogg_free(b->nearest_tree->q);
    257       memset(b->nearest_tree,0,sizeof(*b->nearest_tree));
    258       _ogg_free(b->nearest_tree);
    259     }
    260     if(b->thresh_tree){
    261       _ogg_free(b->thresh_tree->quantthresh);
    262       _ogg_free(b->thresh_tree->quantmap);
    263       memset(b->thresh_tree,0,sizeof(*b->thresh_tree));
    264       _ogg_free(b->thresh_tree);
    265     }
    266 
    267     memset(b,0,sizeof(*b));
    268   }
    269 }
    270 
    271 void vorbis_staticbook_destroy(static_codebook *b){
    272   if(b->allocedp){
    273     vorbis_staticbook_clear(b);
    274     _ogg_free(b);
    275   }
    276 }
    277 
    278 void vorbis_book_clear(codebook *b){
    279   /* static book is not cleared; we're likely called on the lookup and
    280      the static codebook belongs to the info struct */
    281   if(b->valuelist)_ogg_free(b->valuelist);
    282   if(b->codelist)_ogg_free(b->codelist);
    283 
    284   if(b->dec_index)_ogg_free(b->dec_index);
    285   if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
    286   if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
    287 
    288   memset(b,0,sizeof(*b));
    289 }
    290 
    291 int vorbis_book_init_encode(codebook *c,const static_codebook *s){
    292 
    293   memset(c,0,sizeof(*c));
    294   c->c=s;
    295   c->entries=s->entries;
    296   c->used_entries=s->entries;
    297   c->dim=s->dim;
    298   c->codelist=_make_words(s->lengthlist,s->entries,0);
    299   c->valuelist=_book_unquantize(s,s->entries,NULL);
    300 
    301   return(0);
    302 }
    303 
    304 static ogg_uint32_t bitreverse(ogg_uint32_t x){
    305   x=    ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
    306   x=    ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
    307   x=    ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
    308   x=    ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
    309   return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
    310 }
    311 
    312 static int sort32a(const void *a,const void *b){
    313   return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)- 
    314     ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
    315 }
    316 
    317 /* decode codebook arrangement is more heavily optimized than encode */
    318 int vorbis_book_init_decode(codebook *c,const static_codebook *s){
    319   int i,j,n=0,tabn;
    320   int *sortindex;
    321   memset(c,0,sizeof(*c));
    322   
    323   /* count actually used entries */
    324   for(i=0;i<s->entries;i++)
    325     if(s->lengthlist[i]>0)
    326       n++;
    327 
    328   c->entries=s->entries;
    329   c->used_entries=n;
    330   c->dim=s->dim;
    331 
    332   /* two different remappings go on here.  
    333 
    334      First, we collapse the likely sparse codebook down only to
    335      actually represented values/words.  This collapsing needs to be
    336      indexed as map-valueless books are used to encode original entry
    337      positions as integers.
    338 
    339      Second, we reorder all vectors, including the entry index above,
    340      by sorted bitreversed codeword to allow treeless decode. */
    341 
    342   {
    343     /* perform sort */
    344     ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
    345     ogg_uint32_t **codep=alloca(sizeof(*codep)*n);
    346     
    347     if(codes==NULL)goto err_out;
    348 
    349     for(i=0;i<n;i++){
    350       codes[i]=bitreverse(codes[i]);
    351       codep[i]=codes+i;
    352     }
    353 
    354     qsort(codep,n,sizeof(*codep),sort32a);
    355 
    356     sortindex=alloca(n*sizeof(*sortindex));
    357     c->codelist=_ogg_malloc(n*sizeof(*c->codelist));
    358     /* the index is a reverse index */
    359     for(i=0;i<n;i++){
    360       int position=codep[i]-codes;
    361       sortindex[position]=i;
    362     }
    363 
    364     for(i=0;i<n;i++)
    365       c->codelist[sortindex[i]]=codes[i];
    366     _ogg_free(codes);
    367   }
    368 
    369   c->valuelist=_book_unquantize(s,n,sortindex);
    370   c->dec_index=_ogg_malloc(n*sizeof(*c->dec_index));
    371 
    372   for(n=0,i=0;i<s->entries;i++)
    373     if(s->lengthlist[i]>0)
    374       c->dec_index[sortindex[n++]]=i;
    375   
    376   c->dec_codelengths=_ogg_malloc(n*sizeof(*c->dec_codelengths));
    377   for(n=0,i=0;i<s->entries;i++)
    378     if(s->lengthlist[i]>0)
    379       c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
    380 
    381   c->dec_firsttablen=_ilog(c->used_entries)-4; /* this is magic */
    382   if(c->dec_firsttablen<5)c->dec_firsttablen=5;
    383   if(c->dec_firsttablen>8)c->dec_firsttablen=8;
    384 
    385   tabn=1<<c->dec_firsttablen;
    386   c->dec_firsttable=_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
    387   c->dec_maxlength=0;
    388 
    389   for(i=0;i<n;i++){
    390     if(c->dec_maxlength<c->dec_codelengths[i])
    391       c->dec_maxlength=c->dec_codelengths[i];
    392     if(c->dec_codelengths[i]<=c->dec_firsttablen){
    393       ogg_uint32_t orig=bitreverse(c->codelist[i]);
    394       for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
    395 	c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
    396     }
    397   }
    398 
    399   /* now fill in 'unused' entries in the firsttable with hi/lo search
    400      hints for the non-direct-hits */
    401   {
    402     ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
    403     long lo=0,hi=0;
    404 
    405     for(i=0;i<tabn;i++){
    406       ogg_uint32_t word=i<<(32-c->dec_firsttablen);
    407       if(c->dec_firsttable[bitreverse(word)]==0){
    408 	while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
    409 	while(    hi<n && word>=(c->codelist[hi]&mask))hi++;
    410 	
    411 	/* we only actually have 15 bits per hint to play with here.
    412            In order to overflow gracefully (nothing breaks, efficiency
    413            just drops), encode as the difference from the extremes. */
    414 	{
    415 	  unsigned long loval=lo;
    416 	  unsigned long hival=n-hi;
    417 
    418 	  if(loval>0x7fff)loval=0x7fff;
    419 	  if(hival>0x7fff)hival=0x7fff;
    420 	  c->dec_firsttable[bitreverse(word)]=
    421 	    0x80000000UL | (loval<<15) | hival;
    422 	}
    423       }
    424     }
    425   }
    426   
    427 
    428   return(0);
    429  err_out:
    430   vorbis_book_clear(c);
    431   return(-1);
    432 }
    433 
    434 static float _dist(int el,float *ref, float *b,int step){
    435   int i;
    436   float acc=0.f;
    437   for(i=0;i<el;i++){
    438     float val=(ref[i]-b[i*step]);
    439     acc+=val*val;
    440   }
    441   return(acc);
    442 }
    443 
    444 int _best(codebook *book, float *a, int step){
    445   encode_aux_threshmatch *tt=book->c->thresh_tree;
    446 
    447 #if 0
    448   encode_aux_nearestmatch *nt=book->c->nearest_tree;
    449   encode_aux_pigeonhole *pt=book->c->pigeon_tree;
    450 #endif
    451   int dim=book->dim;
    452   int k,o;
    453   /*int savebest=-1;
    454     float saverr;*/
    455 
    456   /* do we have a threshhold encode hint? */
    457   if(tt){
    458     int index=0,i;
    459     /* find the quant val of each scalar */
    460     for(k=0,o=step*(dim-1);k<dim;k++,o-=step){
    461 
    462       i=tt->threshvals>>1;
    463       if(a[o]<tt->quantthresh[i]){
    464 
    465 	for(;i>0;i--)
    466 	  if(a[o]>=tt->quantthresh[i-1])
    467 	    break;
    468 	
    469       }else{
    470 
    471 	for(i++;i<tt->threshvals-1;i++)
    472 	  if(a[o]<tt->quantthresh[i])break;
    473 
    474       }
    475 
    476       index=(index*tt->quantvals)+tt->quantmap[i];
    477     }
    478     /* regular lattices are easy :-) */
    479     if(book->c->lengthlist[index]>0) /* is this unused?  If so, we'll
    480 					use a decision tree after all
    481 					and fall through*/
    482       return(index);
    483   }
    484 
    485 #if 0
    486   /* do we have a pigeonhole encode hint? */
    487   if(pt){
    488     const static_codebook *c=book->c;
    489     int i,besti=-1;
    490     float best=0.f;
    491     int entry=0;
    492 
    493     /* dealing with sequentialness is a pain in the ass */
    494     if(c->q_sequencep){
    495       int pv;
    496       long mul=1;
    497       float qlast=0;
    498       for(k=0,o=0;k<dim;k++,o+=step){
    499 	pv=(int)((a[o]-qlast-pt->min)/pt->del);
    500 	if(pv<0 || pv>=pt->mapentries)break;
    501 	entry+=pt->pigeonmap[pv]*mul;
    502 	mul*=pt->quantvals;
    503 	qlast+=pv*pt->del+pt->min;
    504       }
    505     }else{
    506       for(k=0,o=step*(dim-1);k<dim;k++,o-=step){
    507 	int pv=(int)((a[o]-pt->min)/pt->del);
    508 	if(pv<0 || pv>=pt->mapentries)break;
    509 	entry=entry*pt->quantvals+pt->pigeonmap[pv];
    510       }
    511     }
    512 
    513     /* must be within the pigeonholable range; if we quant outside (or
    514        in an entry that we define no list for), brute force it */
    515     if(k==dim && pt->fitlength[entry]){
    516       /* search the abbreviated list */
    517       long *list=pt->fitlist+pt->fitmap[entry];
    518       for(i=0;i<pt->fitlength[entry];i++){
    519 	float this=_dist(dim,book->valuelist+list[i]*dim,a,step);
    520 	if(besti==-1 || this<best){
    521 	  best=this;
    522 	  besti=list[i];
    523 	}
    524       }
    525 
    526       return(besti); 
    527     }
    528   }
    529 
    530   if(nt){
    531     /* optimized using the decision tree */
    532     while(1){
    533       float c=0.f;
    534       float *p=book->valuelist+nt->p[ptr];
    535       float *q=book->valuelist+nt->q[ptr];
    536       
    537       for(k=0,o=0;k<dim;k++,o+=step)
    538 	c+=(p[k]-q[k])*(a[o]-(p[k]+q[k])*.5);
    539       
    540       if(c>0.f) /* in A */
    541 	ptr= -nt->ptr0[ptr];
    542       else     /* in B */
    543 	ptr= -nt->ptr1[ptr];
    544       if(ptr<=0)break;
    545     }
    546     return(-ptr);
    547   }
    548 #endif 
    549 
    550   /* brute force it! */
    551   {
    552     const static_codebook *c=book->c;
    553     int i,besti=-1;
    554     float best=0.f;
    555     float *e=book->valuelist;
    556     for(i=0;i<book->entries;i++){
    557       if(c->lengthlist[i]>0){
    558 	float this=_dist(dim,e,a,step);
    559 	if(besti==-1 || this<best){
    560 	  best=this;
    561 	  besti=i;
    562 	}
    563       }
    564       e+=dim;
    565     }
    566 
    567     /*if(savebest!=-1 && savebest!=besti){
    568       fprintf(stderr,"brute force/pigeonhole disagreement:\n"
    569 	      "original:");
    570       for(i=0;i<dim*step;i+=step)fprintf(stderr,"%g,",a[i]);
    571       fprintf(stderr,"\n"
    572 	      "pigeonhole (entry %d, err %g):",savebest,saverr);
    573       for(i=0;i<dim;i++)fprintf(stderr,"%g,",
    574 				(book->valuelist+savebest*dim)[i]);
    575       fprintf(stderr,"\n"
    576 	      "bruteforce (entry %d, err %g):",besti,best);
    577       for(i=0;i<dim;i++)fprintf(stderr,"%g,",
    578 				(book->valuelist+besti*dim)[i]);
    579       fprintf(stderr,"\n");
    580       }*/
    581     return(besti);
    582   }
    583 }
    584 
    585 long vorbis_book_codeword(codebook *book,int entry){
    586   if(book->c) /* only use with encode; decode optimizations are
    587                  allowed to break this */
    588     return book->codelist[entry];
    589   return -1;
    590 }
    591 
    592 long vorbis_book_codelen(codebook *book,int entry){
    593   if(book->c) /* only use with encode; decode optimizations are
    594                  allowed to break this */
    595     return book->c->lengthlist[entry];
    596   return -1;
    597 }
    598 
    599 #ifdef _V_SELFTEST
    600 
    601 /* Unit tests of the dequantizer; this stuff will be OK
    602    cross-platform, I simply want to be sure that special mapping cases
    603    actually work properly; a bug could go unnoticed for a while */
    604 
    605 #include <stdio.h>
    606 
    607 /* cases:
    608 
    609    no mapping
    610    full, explicit mapping
    611    algorithmic mapping
    612 
    613    nonsequential
    614    sequential
    615 */
    616 
    617 static long full_quantlist1[]={0,1,2,3,    4,5,6,7, 8,3,6,1};
    618 static long partial_quantlist1[]={0,7,2};
    619 
    620 /* no mapping */
    621 static_codebook test1={
    622   4,16,
    623   NULL,
    624   0,
    625   0,0,0,0,
    626   NULL,
    627   NULL,NULL
    628 };
    629 static float *test1_result=NULL;
    630   
    631 /* linear, full mapping, nonsequential */
    632 static_codebook test2={
    633   4,3,
    634   NULL,
    635   2,
    636   -533200896,1611661312,4,0,
    637   full_quantlist1,
    638   NULL,NULL
    639 };
    640 static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
    641 
    642 /* linear, full mapping, sequential */
    643 static_codebook test3={
    644   4,3,
    645   NULL,
    646   2,
    647   -533200896,1611661312,4,1,
    648   full_quantlist1,
    649   NULL,NULL
    650 };
    651 static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
    652 
    653 /* linear, algorithmic mapping, nonsequential */
    654 static_codebook test4={
    655   3,27,
    656   NULL,
    657   1,
    658   -533200896,1611661312,4,0,
    659   partial_quantlist1,
    660   NULL,NULL
    661 };
    662 static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3,
    663 			      -3, 4,-3, 4, 4,-3, -1, 4,-3,
    664 			      -3,-1,-3, 4,-1,-3, -1,-1,-3, 
    665 			      -3,-3, 4, 4,-3, 4, -1,-3, 4,
    666 			      -3, 4, 4, 4, 4, 4, -1, 4, 4,
    667 			      -3,-1, 4, 4,-1, 4, -1,-1, 4,
    668 			      -3,-3,-1, 4,-3,-1, -1,-3,-1,
    669 			      -3, 4,-1, 4, 4,-1, -1, 4,-1,
    670 			      -3,-1,-1, 4,-1,-1, -1,-1,-1};
    671 
    672 /* linear, algorithmic mapping, sequential */
    673 static_codebook test5={
    674   3,27,
    675   NULL,
    676   1,
    677   -533200896,1611661312,4,1,
    678   partial_quantlist1,
    679   NULL,NULL
    680 };
    681 static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7,
    682 			      -3, 1,-2, 4, 8, 5, -1, 3, 0,
    683 			      -3,-4,-7, 4, 3, 0, -1,-2,-5, 
    684 			      -3,-6,-2, 4, 1, 5, -1,-4, 0,
    685 			      -3, 1, 5, 4, 8,12, -1, 3, 7,
    686 			      -3,-4, 0, 4, 3, 7, -1,-2, 2,
    687 			      -3,-6,-7, 4, 1, 0, -1,-4,-5,
    688 			      -3, 1, 0, 4, 8, 7, -1, 3, 2,
    689 			      -3,-4,-5, 4, 3, 2, -1,-2,-3};
    690 
    691 void run_test(static_codebook *b,float *comp){
    692   float *out=_book_unquantize(b,b->entries,NULL);
    693   int i;
    694 
    695   if(comp){
    696     if(!out){
    697       fprintf(stderr,"_book_unquantize incorrectly returned NULL\n");
    698       exit(1);
    699     }
    700 
    701     for(i=0;i<b->entries*b->dim;i++)
    702       if(fabs(out[i]-comp[i])>.0001){
    703 	fprintf(stderr,"disagreement in unquantized and reference data:\n"
    704 		"position %d, %g != %g\n",i,out[i],comp[i]);
    705 	exit(1);
    706       }
    707 
    708   }else{
    709     if(out){
    710       fprintf(stderr,"_book_unquantize returned a value array: \n"
    711 	      " correct result should have been NULL\n");
    712       exit(1);
    713     }
    714   }
    715 }
    716 
    717 int main(){
    718   /* run the nine dequant tests, and compare to the hand-rolled results */
    719   fprintf(stderr,"Dequant test 1... ");
    720   run_test(&test1,test1_result);
    721   fprintf(stderr,"OK\nDequant test 2... ");
    722   run_test(&test2,test2_result);
    723   fprintf(stderr,"OK\nDequant test 3... ");
    724   run_test(&test3,test3_result);
    725   fprintf(stderr,"OK\nDequant test 4... ");
    726   run_test(&test4,test4_result);
    727   fprintf(stderr,"OK\nDequant test 5... ");
    728   run_test(&test5,test5_result);
    729   fprintf(stderr,"OK\n\n");
    730   
    731   return(0);
    732 }
    733 
    734 #endif