added ogg/vorbis source code for ease of building on msvc
[laserbrain_demo] / libs / vorbis / codebook.c
diff --git a/libs/vorbis/codebook.c b/libs/vorbis/codebook.c
new file mode 100644 (file)
index 0000000..3d68781
--- /dev/null
@@ -0,0 +1,484 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: basic codebook pack/unpack/code/decode operations
+ last mod: $Id: codebook.c 18183 2012-02-03 20:51:27Z xiphmont $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ogg/ogg.h>
+#include "vorbis/codec.h"
+#include "codebook.h"
+#include "scales.h"
+#include "misc.h"
+#include "os.h"
+
+/* packs the given codebook into the bitstream **************************/
+
+int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
+  long i,j;
+  int ordered=0;
+
+  /* first the basic parameters */
+  oggpack_write(opb,0x564342,24);
+  oggpack_write(opb,c->dim,16);
+  oggpack_write(opb,c->entries,24);
+
+  /* pack the codewords.  There are two packings; length ordered and
+     length random.  Decide between the two now. */
+
+  for(i=1;i<c->entries;i++)
+    if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break;
+  if(i==c->entries)ordered=1;
+
+  if(ordered){
+    /* length ordered.  We only need to say how many codewords of
+       each length.  The actual codewords are generated
+       deterministically */
+
+    long count=0;
+    oggpack_write(opb,1,1);  /* ordered */
+    oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */
+
+    for(i=1;i<c->entries;i++){
+      long this=c->lengthlist[i];
+      long last=c->lengthlist[i-1];
+      if(this>last){
+        for(j=last;j<this;j++){
+          oggpack_write(opb,i-count,_ilog(c->entries-count));
+          count=i;
+        }
+      }
+    }
+    oggpack_write(opb,i-count,_ilog(c->entries-count));
+
+  }else{
+    /* length random.  Again, we don't code the codeword itself, just
+       the length.  This time, though, we have to encode each length */
+    oggpack_write(opb,0,1);   /* unordered */
+
+    /* algortihmic mapping has use for 'unused entries', which we tag
+       here.  The algorithmic mapping happens as usual, but the unused
+       entry has no codeword. */
+    for(i=0;i<c->entries;i++)
+      if(c->lengthlist[i]==0)break;
+
+    if(i==c->entries){
+      oggpack_write(opb,0,1); /* no unused entries */
+      for(i=0;i<c->entries;i++)
+        oggpack_write(opb,c->lengthlist[i]-1,5);
+    }else{
+      oggpack_write(opb,1,1); /* we have unused entries; thus we tag */
+      for(i=0;i<c->entries;i++){
+        if(c->lengthlist[i]==0){
+          oggpack_write(opb,0,1);
+        }else{
+          oggpack_write(opb,1,1);
+          oggpack_write(opb,c->lengthlist[i]-1,5);
+        }
+      }
+    }
+  }
+
+  /* is the entry number the desired return value, or do we have a
+     mapping? If we have a mapping, what type? */
+  oggpack_write(opb,c->maptype,4);
+  switch(c->maptype){
+  case 0:
+    /* no mapping */
+    break;
+  case 1:case 2:
+    /* implicitly populated value mapping */
+    /* explicitly populated value mapping */
+
+    if(!c->quantlist){
+      /* no quantlist?  error */
+      return(-1);
+    }
+
+    /* values that define the dequantization */
+    oggpack_write(opb,c->q_min,32);
+    oggpack_write(opb,c->q_delta,32);
+    oggpack_write(opb,c->q_quant-1,4);
+    oggpack_write(opb,c->q_sequencep,1);
+
+    {
+      int quantvals;
+      switch(c->maptype){
+      case 1:
+        /* a single column of (c->entries/c->dim) quantized values for
+           building a full value list algorithmically (square lattice) */
+        quantvals=_book_maptype1_quantvals(c);
+        break;
+      case 2:
+        /* every value (c->entries*c->dim total) specified explicitly */
+        quantvals=c->entries*c->dim;
+        break;
+      default: /* NOT_REACHABLE */
+        quantvals=-1;
+      }
+
+      /* quantized values */
+      for(i=0;i<quantvals;i++)
+        oggpack_write(opb,labs(c->quantlist[i]),c->q_quant);
+
+    }
+    break;
+  default:
+    /* error case; we don't have any other map types now */
+    return(-1);
+  }
+
+  return(0);
+}
+
+/* unpacks a codebook from the packet buffer into the codebook struct,
+   readies the codebook auxiliary structures for decode *************/
+static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
+  long i,j;
+  static_codebook *s=_ogg_calloc(1,sizeof(*s));
+  s->allocedp=1;
+
+  /* make sure alignment is correct */
+  if(oggpack_read(opb,24)!=0x564342)goto _eofout;
+
+  /* first the basic parameters */
+  s->dim=oggpack_read(opb,16);
+  s->entries=oggpack_read(opb,24);
+  if(s->entries==-1)goto _eofout;
+
+  if(_ilog(s->dim)+_ilog(s->entries)>24)goto _eofout;
+
+  /* codeword ordering.... length ordered or unordered? */
+  switch((int)oggpack_read(opb,1)){
+  case 0:{
+    long unused;
+    /* allocated but unused entries? */
+    unused=oggpack_read(opb,1);
+    if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb))
+      goto _eofout;
+    /* unordered */
+    s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
+
+    /* allocated but unused entries? */
+    if(unused){
+      /* yes, unused entries */
+
+      for(i=0;i<s->entries;i++){
+        if(oggpack_read(opb,1)){
+          long num=oggpack_read(opb,5);
+          if(num==-1)goto _eofout;
+          s->lengthlist[i]=num+1;
+        }else
+          s->lengthlist[i]=0;
+      }
+    }else{
+      /* all entries used; no tagging */
+      for(i=0;i<s->entries;i++){
+        long num=oggpack_read(opb,5);
+        if(num==-1)goto _eofout;
+        s->lengthlist[i]=num+1;
+      }
+    }
+
+    break;
+  }
+  case 1:
+    /* ordered */
+    {
+      long length=oggpack_read(opb,5)+1;
+      if(length==0)goto _eofout;
+      s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
+
+      for(i=0;i<s->entries;){
+        long num=oggpack_read(opb,_ilog(s->entries-i));
+        if(num==-1)goto _eofout;
+        if(length>32 || num>s->entries-i ||
+           (num>0 && (num-1)>>(length-1)>1)){
+          goto _errout;
+        }
+        if(length>32)goto _errout;
+        for(j=0;j<num;j++,i++)
+          s->lengthlist[i]=length;
+        length++;
+      }
+    }
+    break;
+  default:
+    /* EOF */
+    goto _eofout;
+  }
+
+  /* Do we have a mapping to unpack? */
+  switch((s->maptype=oggpack_read(opb,4))){
+  case 0:
+    /* no mapping */
+    break;
+  case 1: case 2:
+    /* implicitly populated value mapping */
+    /* explicitly populated value mapping */
+
+    s->q_min=oggpack_read(opb,32);
+    s->q_delta=oggpack_read(opb,32);
+    s->q_quant=oggpack_read(opb,4)+1;
+    s->q_sequencep=oggpack_read(opb,1);
+    if(s->q_sequencep==-1)goto _eofout;
+
+    {
+      int quantvals=0;
+      switch(s->maptype){
+      case 1:
+        quantvals=(s->dim==0?0:_book_maptype1_quantvals(s));
+        break;
+      case 2:
+        quantvals=s->entries*s->dim;
+        break;
+      }
+
+      /* quantized values */
+      if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb))
+        goto _eofout;
+      s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals);
+      for(i=0;i<quantvals;i++)
+        s->quantlist[i]=oggpack_read(opb,s->q_quant);
+
+      if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout;
+    }
+    break;
+  default:
+    goto _errout;
+  }
+
+  /* all set */
+  return(s);
+
+ _errout:
+ _eofout:
+  vorbis_staticbook_destroy(s);
+  return(NULL);
+}
+
+/* returns the number of bits ************************************************/
+int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
+  if(a<0 || a>=book->c->entries)return(0);
+  oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
+  return(book->c->lengthlist[a]);
+}
+
+/* the 'eliminate the decode tree' optimization actually requires the
+   codewords to be MSb first, not LSb.  This is an annoying inelegancy
+   (and one of the first places where carefully thought out design
+   turned out to be wrong; Vorbis II and future Ogg codecs should go
+   to an MSb bitpacker), but not actually the huge hit it appears to
+   be.  The first-stage decode table catches most words so that
+   bitreverse is not in the main execution path. */
+
+static ogg_uint32_t bitreverse(ogg_uint32_t x){
+  x=    ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000);
+  x=    ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00);
+  x=    ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0);
+  x=    ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc);
+  return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa);
+}
+
+STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){
+  int  read=book->dec_maxlength;
+  long lo,hi;
+  long lok = oggpack_look(b,book->dec_firsttablen);
+
+  if (lok >= 0) {
+    long entry = book->dec_firsttable[lok];
+    if(entry&0x80000000UL){
+      lo=(entry>>15)&0x7fff;
+      hi=book->used_entries-(entry&0x7fff);
+    }else{
+      oggpack_adv(b, book->dec_codelengths[entry-1]);
+      return(entry-1);
+    }
+  }else{
+    lo=0;
+    hi=book->used_entries;
+  }
+
+  lok = oggpack_look(b, read);
+
+  while(lok<0 && read>1)
+    lok = oggpack_look(b, --read);
+  if(lok<0)return -1;
+
+  /* bisect search for the codeword in the ordered list */
+  {
+    ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok);
+
+    while(hi-lo>1){
+      long p=(hi-lo)>>1;
+      long test=book->codelist[lo+p]>testword;
+      lo+=p&(test-1);
+      hi-=p&(-test);
+      }
+
+    if(book->dec_codelengths[lo]<=read){
+      oggpack_adv(b, book->dec_codelengths[lo]);
+      return(lo);
+    }
+  }
+
+  oggpack_adv(b, read);
+
+  return(-1);
+}
+
+/* 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.
+   addmul==0 -> declarative (set the value)
+   addmul==1 -> additive
+   addmul==2 -> multiplicitive */
+
+/* returns the [original, not compacted] entry number or -1 on eof *********/
+long vorbis_book_decode(codebook *book, oggpack_buffer *b){
+  if(book->used_entries>0){
+    long packed_entry=decode_packed_entry_number(book,b);
+    if(packed_entry>=0)
+      return(book->dec_index[packed_entry]);
+  }
+
+  /* if there's no dec_index, the codebook unpacking isn't collapsed */
+  return(-1);
+}
+
+/* returns 0 on OK or -1 on eof *************************************/
+/* decode vector / dim granularity gaurding is done in the upper layer */
+long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){
+  if(book->used_entries>0){
+    int step=n/book->dim;
+    long *entry = alloca(sizeof(*entry)*step);
+    float **t = alloca(sizeof(*t)*step);
+    int i,j,o;
+
+    for (i = 0; i < step; i++) {
+      entry[i]=decode_packed_entry_number(book,b);
+      if(entry[i]==-1)return(-1);
+      t[i] = book->valuelist+entry[i]*book->dim;
+    }
+    for(i=0,o=0;i<book->dim;i++,o+=step)
+      for (j=0;j<step;j++)
+        a[o+j]+=t[j][i];
+  }
+  return(0);
+}
+
+/* decode vector / dim granularity gaurding is done in the upper layer */
+long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){
+  if(book->used_entries>0){
+    int i,j,entry;
+    float *t;
+
+    if(book->dim>8){
+      for(i=0;i<n;){
+        entry = decode_packed_entry_number(book,b);
+        if(entry==-1)return(-1);
+        t     = book->valuelist+entry*book->dim;
+        for (j=0;j<book->dim;)
+          a[i++]+=t[j++];
+      }
+    }else{
+      for(i=0;i<n;){
+        entry = decode_packed_entry_number(book,b);
+        if(entry==-1)return(-1);
+        t     = book->valuelist+entry*book->dim;
+        j=0;
+        switch((int)book->dim){
+        case 8:
+          a[i++]+=t[j++];
+        case 7:
+          a[i++]+=t[j++];
+        case 6:
+          a[i++]+=t[j++];
+        case 5:
+          a[i++]+=t[j++];
+        case 4:
+          a[i++]+=t[j++];
+        case 3:
+          a[i++]+=t[j++];
+        case 2:
+          a[i++]+=t[j++];
+        case 1:
+          a[i++]+=t[j++];
+        case 0:
+          break;
+        }
+      }
+    }
+  }
+  return(0);
+}
+
+/* unlike the others, we guard against n not being an integer number
+   of <dim> internally rather than in the upper layer (called only by
+   floor0) */
+long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){
+  if(book->used_entries>0){
+    int i,j,entry;
+    float *t;
+
+    for(i=0;i<n;){
+      entry = decode_packed_entry_number(book,b);
+      if(entry==-1)return(-1);
+      t     = book->valuelist+entry*book->dim;
+      for (j=0;i<n && j<book->dim;){
+        a[i++]=t[j++];
+      }
+    }
+  }else{
+    int i;
+
+    for(i=0;i<n;){
+      a[i++]=0.f;
+    }
+  }
+  return(0);
+}
+
+long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch,
+                              oggpack_buffer *b,int n){
+
+  long i,j,entry;
+  int chptr=0;
+  if(book->used_entries>0){
+    for(i=offset/ch;i<(offset+n)/ch;){
+      entry = decode_packed_entry_number(book,b);
+      if(entry==-1)return(-1);
+      {
+        const float *t = book->valuelist+entry*book->dim;
+        for (j=0;j<book->dim;j++){
+          a[chptr++][i]+=t[j];
+          if(chptr==ch){
+            chptr=0;
+            i++;
+          }
+        }
+      }
+    }
+  }
+  return(0);
+}