Blame lib/sharedbook.c

Packit 06404a
/********************************************************************
Packit 06404a
 *                                                                  *
Packit 06404a
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Packit 06404a
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
Packit 06404a
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Packit 06404a
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Packit 06404a
 *                                                                  *
Packit 06404a
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015             *
Packit 06404a
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
Packit 06404a
 *                                                                  *
Packit 06404a
 ********************************************************************
Packit 06404a
Packit 06404a
 function: basic shared codebook operations
Packit 06404a
 last mod: $Id: sharedbook.c 19457 2015-03-03 00:15:29Z giles $
Packit 06404a
Packit 06404a
 ********************************************************************/
Packit 06404a
Packit 06404a
#include <stdlib.h>
Packit 06404a
#include <math.h>
Packit 06404a
#include <string.h>
Packit 06404a
#include <ogg/ogg.h>
Packit 06404a
#include "os.h"
Packit 06404a
#include "misc.h"
Packit 06404a
#include "vorbis/codec.h"
Packit 06404a
#include "codebook.h"
Packit 06404a
#include "scales.h"
Packit 06404a
Packit 06404a
/**** pack/unpack helpers ******************************************/
Packit 06404a
Packit 06404a
int ov_ilog(ogg_uint32_t v){
Packit 06404a
  int ret;
Packit 06404a
  for(ret=0;v;ret++)v>>=1;
Packit 06404a
  return ret;
Packit 06404a
}
Packit 06404a
Packit 06404a
/* 32 bit float (not IEEE; nonnormalized mantissa +
Packit 06404a
   biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
Packit 06404a
   Why not IEEE?  It's just not that important here. */
Packit 06404a
Packit 06404a
#define VQ_FEXP 10
Packit 06404a
#define VQ_FMAN 21
Packit 06404a
#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
Packit 06404a
Packit 06404a
/* doesn't currently guard under/overflow */
Packit 06404a
long _float32_pack(float val){
Packit 06404a
  int sign=0;
Packit 06404a
  long exp;
Packit 06404a
  long mant;
Packit 06404a
  if(val<0){
Packit 06404a
    sign=0x80000000;
Packit 06404a
    val= -val;
Packit 06404a
  }
Packit 06404a
  exp= floor(log(val)/log(2.f)+.001); //+epsilon
Packit 06404a
  mant=rint(ldexp(val,(VQ_FMAN-1)-exp));
Packit 06404a
  exp=(exp+VQ_FEXP_BIAS)<
Packit 06404a
Packit 06404a
  return(sign|exp|mant);
Packit 06404a
}
Packit 06404a
Packit 06404a
float _float32_unpack(long val){
Packit 06404a
  double mant=val&0x1fffff;
Packit 06404a
  int    sign=val&0x80000000;
Packit 06404a
  long   exp =(val&0x7fe00000L)>>VQ_FMAN;
Packit 06404a
  if(sign)mant= -mant;
Packit 06404a
  return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS));
Packit 06404a
}
Packit 06404a
Packit 06404a
/* given a list of word lengths, generate a list of codewords.  Works
Packit 06404a
   for length ordered or unordered, always assigns the lowest valued
Packit 06404a
   codewords first.  Extended to handle unused entries (length 0) */
Packit 06404a
ogg_uint32_t *_make_words(char *l,long n,long sparsecount){
Packit 06404a
  long i,j,count=0;
Packit 06404a
  ogg_uint32_t marker[33];
Packit 06404a
  ogg_uint32_t *r=_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
Packit 06404a
  memset(marker,0,sizeof(marker));
Packit 06404a
Packit 06404a
  for(i=0;i
Packit 06404a
    long length=l[i];
Packit 06404a
    if(length>0){
Packit 06404a
      ogg_uint32_t entry=marker[length];
Packit 06404a
Packit 06404a
      /* when we claim a node for an entry, we also claim the nodes
Packit 06404a
         below it (pruning off the imagined tree that may have dangled
Packit 06404a
         from it) as well as blocking the use of any nodes directly
Packit 06404a
         above for leaves */
Packit 06404a
Packit 06404a
      /* update ourself */
Packit 06404a
      if(length<32 && (entry>>length)){
Packit 06404a
        /* error condition; the lengths must specify an overpopulated tree */
Packit 06404a
        _ogg_free(r);
Packit 06404a
        return(NULL);
Packit 06404a
      }
Packit 06404a
      r[count++]=entry;
Packit 06404a
Packit 06404a
      /* Look to see if the next shorter marker points to the node
Packit 06404a
         above. if so, update it and repeat.  */
Packit 06404a
      {
Packit 06404a
        for(j=length;j>0;j--){
Packit 06404a
Packit 06404a
          if(marker[j]&1){
Packit 06404a
            /* have to jump branches */
Packit 06404a
            if(j==1)
Packit 06404a
              marker[1]++;
Packit 06404a
            else
Packit 06404a
              marker[j]=marker[j-1]<<1;
Packit 06404a
            break; /* invariant says next upper marker would already
Packit 06404a
                      have been moved if it was on the same path */
Packit 06404a
          }
Packit 06404a
          marker[j]++;
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
Packit 06404a
      /* prune the tree; the implicit invariant says all the longer
Packit 06404a
         markers were dangling from our just-taken node.  Dangle them
Packit 06404a
         from our *new* node. */
Packit 06404a
      for(j=length+1;j<33;j++)
Packit 06404a
        if((marker[j]>>1) == entry){
Packit 06404a
          entry=marker[j];
Packit 06404a
          marker[j]=marker[j-1]<<1;
Packit 06404a
        }else
Packit 06404a
          break;
Packit 06404a
    }else
Packit 06404a
      if(sparsecount==0)count++;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* any underpopulated tree must be rejected. */
Packit 06404a
  /* Single-entry codebooks are a retconned extension to the spec.
Packit 06404a
     They have a single codeword '0' of length 1 that results in an
Packit 06404a
     underpopulated tree.  Shield that case from the underformed tree check. */
Packit 06404a
  if(!(count==1 && marker[2]==2)){
Packit 06404a
    for(i=1;i<33;i++)
Packit 06404a
      if(marker[i] & (0xffffffffUL>>(32-i))){
Packit 06404a
        _ogg_free(r);
Packit 06404a
        return(NULL);
Packit 06404a
      }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* bitreverse the words because our bitwise packer/unpacker is LSb
Packit 06404a
     endian */
Packit 06404a
  for(i=0,count=0;i
Packit 06404a
    ogg_uint32_t temp=0;
Packit 06404a
    for(j=0;j
Packit 06404a
      temp<<=1;
Packit 06404a
      temp|=(r[count]>>j)&1;
Packit 06404a
    }
Packit 06404a
Packit 06404a
    if(sparsecount){
Packit 06404a
      if(l[i])
Packit 06404a
        r[count++]=temp;
Packit 06404a
    }else
Packit 06404a
      r[count++]=temp;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return(r);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* there might be a straightforward one-line way to do the below
Packit 06404a
   that's portable and totally safe against roundoff, but I haven't
Packit 06404a
   thought of it.  Therefore, we opt on the side of caution */
Packit 06404a
long _book_maptype1_quantvals(const static_codebook *b){
Packit 06404a
  long vals=floor(pow((float)b->entries,1.f/b->dim));
Packit 06404a
Packit 06404a
  /* the above *should* be reliable, but we'll not assume that FP is
Packit 06404a
     ever reliable when bitstream sync is at stake; verify via integer
Packit 06404a
     means that vals really is the greatest value of dim for which
Packit 06404a
     vals^b->bim <= b->entries */
Packit 06404a
  /* treat the above as an initial guess */
Packit 06404a
  while(1){
Packit 06404a
    long acc=1;
Packit 06404a
    long acc1=1;
Packit 06404a
    int i;
Packit 06404a
    for(i=0;i<b->dim;i++){
Packit 06404a
      acc*=vals;
Packit 06404a
      acc1*=vals+1;
Packit 06404a
    }
Packit 06404a
    if(acc<=b->entries && acc1>b->entries){
Packit 06404a
      return(vals);
Packit 06404a
    }else{
Packit 06404a
      if(acc>b->entries){
Packit 06404a
        vals--;
Packit 06404a
      }else{
Packit 06404a
        vals++;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
/* unpack the quantized list of values for encode/decode ***********/
Packit 06404a
/* we need to deal with two map types: in map type 1, the values are
Packit 06404a
   generated algorithmically (each column of the vector counts through
Packit 06404a
   the values in the quant vector). in map type 2, all the values came
Packit 06404a
   in in an explicit list.  Both value lists must be unpacked */
Packit 06404a
float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){
Packit 06404a
  long j,k,count=0;
Packit 06404a
  if(b->maptype==1 || b->maptype==2){
Packit 06404a
    int quantvals;
Packit 06404a
    float mindel=_float32_unpack(b->q_min);
Packit 06404a
    float delta=_float32_unpack(b->q_delta);
Packit 06404a
    float *r=_ogg_calloc(n*b->dim,sizeof(*r));
Packit 06404a
Packit 06404a
    /* maptype 1 and 2 both use a quantized value vector, but
Packit 06404a
       different sizes */
Packit 06404a
    switch(b->maptype){
Packit 06404a
    case 1:
Packit 06404a
      /* most of the time, entries%dimensions == 0, but we need to be
Packit 06404a
         well defined.  We define that the possible vales at each
Packit 06404a
         scalar is values == entries/dim.  If entries%dim != 0, we'll
Packit 06404a
         have 'too few' values (values*dim
Packit 06404a
         we'll have 'left over' entries; left over entries use zeroed
Packit 06404a
         values (and are wasted).  So don't generate codebooks like
Packit 06404a
         that */
Packit 06404a
      quantvals=_book_maptype1_quantvals(b);
Packit 06404a
      for(j=0;j<b->entries;j++){
Packit 06404a
        if((sparsemap && b->lengthlist[j]) || !sparsemap){
Packit 06404a
          float last=0.f;
Packit 06404a
          int indexdiv=1;
Packit 06404a
          for(k=0;k<b->dim;k++){
Packit 06404a
            int index= (j/indexdiv)%quantvals;
Packit 06404a
            float val=b->quantlist[index];
Packit 06404a
            val=fabs(val)*delta+mindel+last;
Packit 06404a
            if(b->q_sequencep)last=val;
Packit 06404a
            if(sparsemap)
Packit 06404a
              r[sparsemap[count]*b->dim+k]=val;
Packit 06404a
            else
Packit 06404a
              r[count*b->dim+k]=val;
Packit 06404a
            indexdiv*=quantvals;
Packit 06404a
          }
Packit 06404a
          count++;
Packit 06404a
        }
Packit 06404a
Packit 06404a
      }
Packit 06404a
      break;
Packit 06404a
    case 2:
Packit 06404a
      for(j=0;j<b->entries;j++){
Packit 06404a
        if((sparsemap && b->lengthlist[j]) || !sparsemap){
Packit 06404a
          float last=0.f;
Packit 06404a
Packit 06404a
          for(k=0;k<b->dim;k++){
Packit 06404a
            float val=b->quantlist[j*b->dim+k];
Packit 06404a
            val=fabs(val)*delta+mindel+last;
Packit 06404a
            if(b->q_sequencep)last=val;
Packit 06404a
            if(sparsemap)
Packit 06404a
              r[sparsemap[count]*b->dim+k]=val;
Packit 06404a
            else
Packit 06404a
              r[count*b->dim+k]=val;
Packit 06404a
          }
Packit 06404a
          count++;
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
      break;
Packit 06404a
    }
Packit 06404a
Packit 06404a
    return(r);
Packit 06404a
  }
Packit 06404a
  return(NULL);
Packit 06404a
}
Packit 06404a
Packit 06404a
void vorbis_staticbook_destroy(static_codebook *b){
Packit 06404a
  if(b->allocedp){
Packit 06404a
    if(b->quantlist)_ogg_free(b->quantlist);
Packit 06404a
    if(b->lengthlist)_ogg_free(b->lengthlist);
Packit 06404a
    memset(b,0,sizeof(*b));
Packit 06404a
    _ogg_free(b);
Packit 06404a
  } /* otherwise, it is in static memory */
Packit 06404a
}
Packit 06404a
Packit 06404a
void vorbis_book_clear(codebook *b){
Packit 06404a
  /* static book is not cleared; we're likely called on the lookup and
Packit 06404a
     the static codebook belongs to the info struct */
Packit 06404a
  if(b->valuelist)_ogg_free(b->valuelist);
Packit 06404a
  if(b->codelist)_ogg_free(b->codelist);
Packit 06404a
Packit 06404a
  if(b->dec_index)_ogg_free(b->dec_index);
Packit 06404a
  if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
Packit 06404a
  if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
Packit 06404a
Packit 06404a
  memset(b,0,sizeof(*b));
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_book_init_encode(codebook *c,const static_codebook *s){
Packit 06404a
Packit 06404a
  memset(c,0,sizeof(*c));
Packit 06404a
  c->c=s;
Packit 06404a
  c->entries=s->entries;
Packit 06404a
  c->used_entries=s->entries;
Packit 06404a
  c->dim=s->dim;
Packit 06404a
  c->codelist=_make_words(s->lengthlist,s->entries,0);
Packit 06404a
  //c->valuelist=_book_unquantize(s,s->entries,NULL);
Packit 06404a
  c->quantvals=_book_maptype1_quantvals(s);
Packit 06404a
  c->minval=(int)rint(_float32_unpack(s->q_min));
Packit 06404a
  c->delta=(int)rint(_float32_unpack(s->q_delta));
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
static ogg_uint32_t bitreverse(ogg_uint32_t x){
Packit 06404a
  x=    ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
Packit 06404a
  x=    ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
Packit 06404a
  x=    ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
Packit 06404a
  x=    ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
Packit 06404a
  return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
Packit 06404a
}
Packit 06404a
Packit 06404a
static int sort32a(const void *a,const void *b){
Packit 06404a
  return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)-
Packit 06404a
    ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* decode codebook arrangement is more heavily optimized than encode */
Packit 06404a
int vorbis_book_init_decode(codebook *c,const static_codebook *s){
Packit 06404a
  int i,j,n=0,tabn;
Packit 06404a
  int *sortindex;
Packit 06404a
Packit 06404a
  memset(c,0,sizeof(*c));
Packit 06404a
Packit 06404a
  /* count actually used entries and find max length */
Packit 06404a
  for(i=0;i<s->entries;i++)
Packit 06404a
    if(s->lengthlist[i]>0)
Packit 06404a
      n++;
Packit 06404a
Packit 06404a
  c->entries=s->entries;
Packit 06404a
  c->used_entries=n;
Packit 06404a
  c->dim=s->dim;
Packit 06404a
Packit 06404a
  if(n>0){
Packit 06404a
    /* two different remappings go on here.
Packit 06404a
Packit 06404a
    First, we collapse the likely sparse codebook down only to
Packit 06404a
    actually represented values/words.  This collapsing needs to be
Packit 06404a
    indexed as map-valueless books are used to encode original entry
Packit 06404a
    positions as integers.
Packit 06404a
Packit 06404a
    Second, we reorder all vectors, including the entry index above,
Packit 06404a
    by sorted bitreversed codeword to allow treeless decode. */
Packit 06404a
Packit 06404a
    /* perform sort */
Packit 06404a
    ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
Packit 06404a
    ogg_uint32_t **codep=alloca(sizeof(*codep)*n);
Packit 06404a
Packit 06404a
    if(codes==NULL)goto err_out;
Packit 06404a
Packit 06404a
    for(i=0;i
Packit 06404a
      codes[i]=bitreverse(codes[i]);
Packit 06404a
      codep[i]=codes+i;
Packit 06404a
    }
Packit 06404a
Packit 06404a
    qsort(codep,n,sizeof(*codep),sort32a);
Packit 06404a
Packit 06404a
    sortindex=alloca(n*sizeof(*sortindex));
Packit 06404a
    c->codelist=_ogg_malloc(n*sizeof(*c->codelist));
Packit 06404a
    /* the index is a reverse index */
Packit 06404a
    for(i=0;i
Packit 06404a
      int position=codep[i]-codes;
Packit 06404a
      sortindex[position]=i;
Packit 06404a
    }
Packit 06404a
Packit 06404a
    for(i=0;i
Packit 06404a
      c->codelist[sortindex[i]]=codes[i];
Packit 06404a
    _ogg_free(codes);
Packit 06404a
Packit 06404a
    c->valuelist=_book_unquantize(s,n,sortindex);
Packit 06404a
    c->dec_index=_ogg_malloc(n*sizeof(*c->dec_index));
Packit 06404a
Packit 06404a
    for(n=0,i=0;i<s->entries;i++)
Packit 06404a
      if(s->lengthlist[i]>0)
Packit 06404a
        c->dec_index[sortindex[n++]]=i;
Packit 06404a
Packit 06404a
    c->dec_codelengths=_ogg_malloc(n*sizeof(*c->dec_codelengths));
Packit 06404a
    c->dec_maxlength=0;
Packit 06404a
    for(n=0,i=0;i<s->entries;i++)
Packit 06404a
      if(s->lengthlist[i]>0){
Packit 06404a
        c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
Packit 06404a
        if(s->lengthlist[i]>c->dec_maxlength)
Packit 06404a
          c->dec_maxlength=s->lengthlist[i];
Packit 06404a
      }
Packit 06404a
Packit 06404a
    if(n==1 && c->dec_maxlength==1){
Packit 06404a
      /* special case the 'single entry codebook' with a single bit
Packit 06404a
       fastpath table (that always returns entry 0 )in order to use
Packit 06404a
       unmodified decode paths. */
Packit 06404a
      c->dec_firsttablen=1;
Packit 06404a
      c->dec_firsttable=_ogg_calloc(2,sizeof(*c->dec_firsttable));
Packit 06404a
      c->dec_firsttable[0]=c->dec_firsttable[1]=1;
Packit 06404a
Packit 06404a
    }else{
Packit 06404a
      c->dec_firsttablen=ov_ilog(c->used_entries)-4; /* this is magic */
Packit 06404a
      if(c->dec_firsttablen<5)c->dec_firsttablen=5;
Packit 06404a
      if(c->dec_firsttablen>8)c->dec_firsttablen=8;
Packit 06404a
Packit 06404a
      tabn=1<<c->dec_firsttablen;
Packit 06404a
      c->dec_firsttable=_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
Packit 06404a
Packit 06404a
      for(i=0;i
Packit 06404a
        if(c->dec_codelengths[i]<=c->dec_firsttablen){
Packit 06404a
          ogg_uint32_t orig=bitreverse(c->codelist[i]);
Packit 06404a
          for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
Packit 06404a
            c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
Packit 06404a
      /* now fill in 'unused' entries in the firsttable with hi/lo search
Packit 06404a
         hints for the non-direct-hits */
Packit 06404a
      {
Packit 06404a
        ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
Packit 06404a
        long lo=0,hi=0;
Packit 06404a
Packit 06404a
        for(i=0;i
Packit 06404a
          ogg_uint32_t word=i<<(32-c->dec_firsttablen);
Packit 06404a
          if(c->dec_firsttable[bitreverse(word)]==0){
Packit 06404a
            while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
Packit 06404a
            while(    hi<n && word>=(c->codelist[hi]&mask))hi++;
Packit 06404a
Packit 06404a
            /* we only actually have 15 bits per hint to play with here.
Packit 06404a
               In order to overflow gracefully (nothing breaks, efficiency
Packit 06404a
               just drops), encode as the difference from the extremes. */
Packit 06404a
            {
Packit 06404a
              unsigned long loval=lo;
Packit 06404a
              unsigned long hival=n-hi;
Packit 06404a
Packit 06404a
              if(loval>0x7fff)loval=0x7fff;
Packit 06404a
              if(hival>0x7fff)hival=0x7fff;
Packit 06404a
              c->dec_firsttable[bitreverse(word)]=
Packit 06404a
                0x80000000UL | (loval<<15) | hival;
Packit 06404a
            }
Packit 06404a
          }
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
 err_out:
Packit 06404a
  vorbis_book_clear(c);
Packit 06404a
  return(-1);
Packit 06404a
}
Packit 06404a
Packit 06404a
long vorbis_book_codeword(codebook *book,int entry){
Packit 06404a
  if(book->c) /* only use with encode; decode optimizations are
Packit 06404a
                 allowed to break this */
Packit 06404a
    return book->codelist[entry];
Packit 06404a
  return -1;
Packit 06404a
}
Packit 06404a
Packit 06404a
long vorbis_book_codelen(codebook *book,int entry){
Packit 06404a
  if(book->c) /* only use with encode; decode optimizations are
Packit 06404a
                 allowed to break this */
Packit 06404a
    return book->c->lengthlist[entry];
Packit 06404a
  return -1;
Packit 06404a
}
Packit 06404a
Packit 06404a
#ifdef _V_SELFTEST
Packit 06404a
Packit 06404a
/* Unit tests of the dequantizer; this stuff will be OK
Packit 06404a
   cross-platform, I simply want to be sure that special mapping cases
Packit 06404a
   actually work properly; a bug could go unnoticed for a while */
Packit 06404a
Packit 06404a
#include <stdio.h>
Packit 06404a
Packit 06404a
/* cases:
Packit 06404a
Packit 06404a
   no mapping
Packit 06404a
   full, explicit mapping
Packit 06404a
   algorithmic mapping
Packit 06404a
Packit 06404a
   nonsequential
Packit 06404a
   sequential
Packit 06404a
*/
Packit 06404a
Packit 06404a
static long full_quantlist1[]={0,1,2,3,    4,5,6,7, 8,3,6,1};
Packit 06404a
static long partial_quantlist1[]={0,7,2};
Packit 06404a
Packit 06404a
/* no mapping */
Packit 06404a
static_codebook test1={
Packit 06404a
  4,16,
Packit 06404a
  NULL,
Packit 06404a
  0,
Packit 06404a
  0,0,0,0,
Packit 06404a
  NULL,
Packit 06404a
  0
Packit 06404a
};
Packit 06404a
static float *test1_result=NULL;
Packit 06404a
Packit 06404a
/* linear, full mapping, nonsequential */
Packit 06404a
static_codebook test2={
Packit 06404a
  4,3,
Packit 06404a
  NULL,
Packit 06404a
  2,
Packit 06404a
  -533200896,1611661312,4,0,
Packit 06404a
  full_quantlist1,
Packit 06404a
  0
Packit 06404a
};
Packit 06404a
static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
Packit 06404a
Packit 06404a
/* linear, full mapping, sequential */
Packit 06404a
static_codebook test3={
Packit 06404a
  4,3,
Packit 06404a
  NULL,
Packit 06404a
  2,
Packit 06404a
  -533200896,1611661312,4,1,
Packit 06404a
  full_quantlist1,
Packit 06404a
  0
Packit 06404a
};
Packit 06404a
static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
Packit 06404a
Packit 06404a
/* linear, algorithmic mapping, nonsequential */
Packit 06404a
static_codebook test4={
Packit 06404a
  3,27,
Packit 06404a
  NULL,
Packit 06404a
  1,
Packit 06404a
  -533200896,1611661312,4,0,
Packit 06404a
  partial_quantlist1,
Packit 06404a
  0
Packit 06404a
};
Packit 06404a
static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3,
Packit 06404a
                              -3, 4,-3, 4, 4,-3, -1, 4,-3,
Packit 06404a
                              -3,-1,-3, 4,-1,-3, -1,-1,-3,
Packit 06404a
                              -3,-3, 4, 4,-3, 4, -1,-3, 4,
Packit 06404a
                              -3, 4, 4, 4, 4, 4, -1, 4, 4,
Packit 06404a
                              -3,-1, 4, 4,-1, 4, -1,-1, 4,
Packit 06404a
                              -3,-3,-1, 4,-3,-1, -1,-3,-1,
Packit 06404a
                              -3, 4,-1, 4, 4,-1, -1, 4,-1,
Packit 06404a
                              -3,-1,-1, 4,-1,-1, -1,-1,-1};
Packit 06404a
Packit 06404a
/* linear, algorithmic mapping, sequential */
Packit 06404a
static_codebook test5={
Packit 06404a
  3,27,
Packit 06404a
  NULL,
Packit 06404a
  1,
Packit 06404a
  -533200896,1611661312,4,1,
Packit 06404a
  partial_quantlist1,
Packit 06404a
  0
Packit 06404a
};
Packit 06404a
static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7,
Packit 06404a
                              -3, 1,-2, 4, 8, 5, -1, 3, 0,
Packit 06404a
                              -3,-4,-7, 4, 3, 0, -1,-2,-5,
Packit 06404a
                              -3,-6,-2, 4, 1, 5, -1,-4, 0,
Packit 06404a
                              -3, 1, 5, 4, 8,12, -1, 3, 7,
Packit 06404a
                              -3,-4, 0, 4, 3, 7, -1,-2, 2,
Packit 06404a
                              -3,-6,-7, 4, 1, 0, -1,-4,-5,
Packit 06404a
                              -3, 1, 0, 4, 8, 7, -1, 3, 2,
Packit 06404a
                              -3,-4,-5, 4, 3, 2, -1,-2,-3};
Packit 06404a
Packit 06404a
void run_test(static_codebook *b,float *comp){
Packit 06404a
  float *out=_book_unquantize(b,b->entries,NULL);
Packit 06404a
  int i;
Packit 06404a
Packit 06404a
  if(comp){
Packit 06404a
    if(!out){
Packit 06404a
      fprintf(stderr,"_book_unquantize incorrectly returned NULL\n");
Packit 06404a
      exit(1);
Packit 06404a
    }
Packit 06404a
Packit 06404a
    for(i=0;i<b->entries*b->dim;i++)
Packit 06404a
      if(fabs(out[i]-comp[i])>.0001){
Packit 06404a
        fprintf(stderr,"disagreement in unquantized and reference data:\n"
Packit 06404a
                "position %d, %g != %g\n",i,out[i],comp[i]);
Packit 06404a
        exit(1);
Packit 06404a
      }
Packit 06404a
Packit 06404a
  }else{
Packit 06404a
    if(out){
Packit 06404a
      fprintf(stderr,"_book_unquantize returned a value array: \n"
Packit 06404a
              " correct result should have been NULL\n");
Packit 06404a
      exit(1);
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
int main(){
Packit 06404a
  /* run the nine dequant tests, and compare to the hand-rolled results */
Packit 06404a
  fprintf(stderr,"Dequant test 1... ");
Packit 06404a
  run_test(&test1,test1_result);
Packit 06404a
  fprintf(stderr,"OK\nDequant test 2... ");
Packit 06404a
  run_test(&test2,test2_result);
Packit 06404a
  fprintf(stderr,"OK\nDequant test 3... ");
Packit 06404a
  run_test(&test3,test3_result);
Packit 06404a
  fprintf(stderr,"OK\nDequant test 4... ");
Packit 06404a
  run_test(&test4,test4_result);
Packit 06404a
  fprintf(stderr,"OK\nDequant test 5... ");
Packit 06404a
  run_test(&test5,test5_result);
Packit 06404a
  fprintf(stderr,"OK\n\n");
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
#endif