/********************************************************************
* *
- * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
- * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
- * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * 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 OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
- * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
- * http://www.xiph.org/ *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
function: basic codebook pack/unpack/code/decode operations
- last mod: $Id: codebook.c,v 1.11 2000/02/23 09:24:26 xiphmont Exp $
********************************************************************/
#include <stdlib.h>
+#include <string.h>
#include <math.h>
+#include <ogg/ogg.h>
#include "vorbis/codec.h"
-#include "vorbis/codebook.h"
-#include "bitwise.h"
-#include "bookinternal.h"
-
-/**** pack/unpack helpers ******************************************/
-static int ilog(unsigned int v){
- int ret=0;
- while(v){
- ret++;
- v>>=1;
- }
- return(ret);
-}
-
-/* code that packs the 24 bit float can be found in vq/bookutil.c */
-
-static double _float24_unpack(long val){
- double mant=val&0x3ffff;
- double sign=val&0x800000;
- double exp =(val&0x7c0000)>>18;
- if(sign)mant= -mant;
- return(ldexp(mant,exp-17-VQ_FEXP_BIAS));
-}
-
-/* given a list of word lengths, generate a list of codewords. Works
- for length ordered or unordered, always assigns the lowest valued
- codewords first */
-long *_make_words(long *l,long n){
- long i,j;
- long marker[33];
- long *r=malloc(n*sizeof(long));
- memset(marker,0,sizeof(marker));
-
- for(i=0;i<n;i++){
- long length=l[i];
- long 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)){
- /* 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(j=length;j>0;j--){
-
- if(marker[j]&1){
- /* 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(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(i=0;i<n;i++){
- long temp=0;
- for(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 */
-decode_aux *_make_decode_tree(codebook *c){
- const static_codebook *s=c->c;
- long top=0,i,j;
- decode_aux *t=malloc(sizeof(decode_aux));
- long *ptr0=t->ptr0=calloc(c->entries*2,sizeof(long));
- long *ptr1=t->ptr1=calloc(c->entries*2,sizeof(long));
- long *codelist=_make_words(s->lengthlist,s->entries);
-
- if(codelist==NULL)return(NULL);
- t->aux=c->entries*2;
-
- for(i=0;i<c->entries;i++){
- long ptr=0;
- for(j=0;j<s->lengthlist[i]-1;j++){
- int bit=(codelist[i]>>j)&1;
- if(!bit){
- if(!ptr0[ptr])
- ptr0[ptr]= ++top;
- ptr=ptr0[ptr];
- }else{
- if(!ptr1[ptr])
- ptr1[ptr]= ++top;
- ptr=ptr1[ptr];
- }
- }
- if(!((codelist[i]>>j)&1))
- ptr0[ptr]=-i;
- else
- ptr1[ptr]=-i;
- }
- free(codelist);
- return(t);
-}
-
-/* unpack the quantized list of values for encode/decode ***********/
-static double *_book_unquantize(const static_codebook *b){
- long j,k;
- if(b->quantlist){
- double mindel=_float24_unpack(b->q_min);
- double delta=_float24_unpack(b->q_delta);
- double *r=malloc(sizeof(double)*b->entries*b->dim);
-
- for(j=0;j<b->entries;j++){
- double last=0.;
- for(k=0;k<b->dim;k++){
- double val=b->quantlist[j*b->dim+k]*delta+last+mindel;
- r[j*b->dim+k]=val;
- if(b->q_sequencep)last=val;
- }
- }
- return(r);
- }else
- return(NULL);
-}
-
-void vorbis_staticbook_clear(static_codebook *b){
- if(b->quantlist)free(b->quantlist);
- if(b->lengthlist)free(b->lengthlist);
- if(b->encode_tree){
- free(b->encode_tree->ptr0);
- free(b->encode_tree->ptr1);
- free(b->encode_tree->p);
- free(b->encode_tree->q);
- memset(b->encode_tree,0,sizeof(encode_aux));
- free(b->encode_tree);
- }
- memset(b,0,sizeof(static_codebook));
-}
-
-void vorbis_book_clear(codebook *b){
- /* static book is not cleared; we're likely called on the lookup and
- the static codebook belongs to the info struct */
- if(b->decode_tree){
- free(b->decode_tree->ptr0);
- free(b->decode_tree->ptr1);
- memset(b->decode_tree,0,sizeof(decode_aux));
- free(b->decode_tree);
- }
- if(b->valuelist)free(b->valuelist);
- if(b->codelist)free(b->codelist);
- memset(b,0,sizeof(codebook));
-}
-
-int vorbis_book_init_encode(codebook *c,const static_codebook *s){
- memset(c,0,sizeof(codebook));
- c->c=s;
- c->entries=s->entries;
- c->dim=s->dim;
- c->codelist=_make_words(s->lengthlist,s->entries);
- c->valuelist=_book_unquantize(s);
- return(0);
-}
-
-int vorbis_book_init_decode(codebook *c,const static_codebook *s){
- memset(c,0,sizeof(codebook));
- c->c=s;
- c->entries=s->entries;
- c->dim=s->dim;
- c->valuelist=_book_unquantize(s);
- c->decode_tree=_make_decode_tree(c);
- if(c->decode_tree==NULL)goto err_out;
- return(0);
- err_out:
- vorbis_book_clear(c);
- return(-1);
-}
+#include "codebook.h"
+#include "scales.h"
+#include "misc.h"
+#include "os.h"
/* packs the given codebook into the bitstream **************************/
int ordered=0;
/* first the basic parameters */
- _oggpack_write(opb,0x564342,24);
- _oggpack_write(opb,c->dim,16);
- _oggpack_write(opb,c->entries,24);
+ 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]<c->lengthlist[i-1])break;
+ 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 */
+ 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];
+ char this=c->lengthlist[i];
+ char 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;
- }
+ for(j=last;j<this;j++){
+ oggpack_write(opb,i-count,ov_ilog(c->entries-count));
+ count=i;
+ }
}
}
- _oggpack_write(opb,i-count,ilog(c->entries-count));
+ oggpack_write(opb,i-count,ov_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 */
+ 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++)
- _oggpack_write(opb,c->lengthlist[i]-1,5);
+ 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(c->quantlist){
- /* we have a mapping. bundle it out. */
- _oggpack_write(opb,1,1);
+ 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,24);
- _oggpack_write(opb,c->q_delta,24);
- _oggpack_write(opb,c->q_quant-1,4);
- _oggpack_write(opb,c->q_sequencep,1);
+ 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);
- /* quantized values */
- for(i=0;i<c->entries*c->dim;i++)
- _oggpack_write(opb,c->quantlist[i],c->q_quant);
+ {
+ 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;
+ }
- }else{
- /* no mapping. */
- _oggpack_write(opb,0,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 *************/
-int vorbis_staticbook_unpack(oggpack_buffer *opb,static_codebook *s){
+static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
long i,j;
- memset(s,0,sizeof(static_codebook));
+ static_codebook *s=_ogg_calloc(1,sizeof(*s));
+ s->allocedp=1;
/* make sure alignment is correct */
- if(_oggpack_read(opb,24)!=0x564342)goto _eofout;
+ if(oggpack_read(opb,24)!=0x564342)goto _eofout;
/* first the basic parameters */
- s->dim=_oggpack_read(opb,16);
- s->entries=_oggpack_read(opb,24);
+ s->dim=oggpack_read(opb,16);
+ s->entries=oggpack_read(opb,24);
if(s->entries==-1)goto _eofout;
+ if(ov_ilog(s->dim)+ov_ilog(s->entries)>24)goto _eofout;
+
/* codeword ordering.... length ordered or unordered? */
- switch(_oggpack_read(opb,1)){
- case 0:
+ 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=malloc(sizeof(long)*s->entries);
- for(i=0;i<s->entries;i++){
- long num=_oggpack_read(opb,5);
- if(num==-1)goto _eofout;
- s->lengthlist[i]=num+1;
+ 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;
- s->lengthlist=malloc(sizeof(long)*s->entries);
-
+ 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;
- for(j=0;j<num;j++,i++)
- s->lengthlist[i]=length;
- length++;
+ long num=oggpack_read(opb,ov_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 */
- return(-1);
+ goto _eofout;
}
-
+
/* Do we have a mapping to unpack? */
- if(_oggpack_read(opb,1)){
+ switch((s->maptype=oggpack_read(opb,4))){
+ case 0:
+ /* no mapping */
+ break;
+ case 1: case 2:
+ /* implicitly populated value mapping */
+ /* explicitly populated value mapping */
- /* values that define the dequantization */
- s->q_min=_oggpack_read(opb,24);
- s->q_delta=_oggpack_read(opb,24);
- s->q_quant=_oggpack_read(opb,4)+1;
- s->q_sequencep=_oggpack_read(opb,1);
-
- /* quantized values */
- s->quantlist=malloc(sizeof(double)*s->entries*s->dim);
- for(i=0;i<s->entries*s->dim;i++)
- s->quantlist[i]=_oggpack_read(opb,s->q_quant);
- if(s->quantlist[i-1]==-1)goto _eofout;
+ 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(0);
+ return(s);
_errout:
_eofout:
- vorbis_staticbook_clear(s);
- return(-1);
+ vorbis_staticbook_destroy(s);
+ return(NULL);
}
-/* returns the number of bits ***************************************/
+/* returns the number of bits ************************************************/
int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
- _oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
+ if(a<0 || a>=book->c->entries)return(0);
+ oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
return(book->c->lengthlist[a]);
}
-static int _best(codebook *book, double *a){
- encode_aux *t=book->c->encode_tree;
- int dim=book->dim;
- int ptr=0,k;
- /* optimized, using the decision tree */
- while(1){
- double c=0.;
- double *p=book->valuelist+t->p[ptr];
- double *q=book->valuelist+t->q[ptr];
-
- for(k=0;k<dim;k++)
- c+=(p[k]-q[k])*(a[k]-(p[k]+q[k])*.5);
-
- if(c>0.) /* in A */
- ptr= -t->ptr0[ptr];
- else /* in B */
- ptr= -t->ptr1[ptr];
- if(ptr<=0)break;
- }
- return(-ptr);
+/* 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);
}
-/* returns the number of bits and *modifies a* to the quantization value *****/
-int vorbis_book_encodev(codebook *book, double *a, oggpack_buffer *b){
- int dim=book->dim;
- int best=_best(book,a);
- memcpy(a,book->valuelist+best*dim,dim*sizeof(double));
- return(vorbis_book_encode(book,best,b));}
-
-/* returns the number of bits and *modifies a* to the quantization error *****/
-int vorbis_book_encodevE(codebook *book, double *a, oggpack_buffer *b){
- int dim=book->dim,k;
- int best=_best(book,a);
- for(k=0;k<dim;k++)
- a[k]-=(book->valuelist+best*dim)[k];
- return(vorbis_book_encode(book,best,b));
-}
+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;
+ }
+
+ /* Single entry codebooks use a firsttablen of 1 and a
+ dec_maxlength of 1. If a single-entry codebook gets here (due to
+ failure to read one bit above), the next look attempt will also
+ fail and we'll correctly kick out instead of trying to walk the
+ underformed tree */
+
+ lok = oggpack_look(b, read);
-/* returns the total squared quantization error for best match and sets each
- element of a to local error ***************/
-double vorbis_book_vE(codebook *book, double *a){
- int dim=book->dim,k;
- int best=_best(book,a);
- double acc=0.;
- for(k=0;k<dim;k++){
- double val=(book->valuelist+best*dim)[k];
- a[k]-=val;
- acc+=a[k]*a[k];
+ 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);
+ }
}
- return(acc);
+
+ oggpack_adv(b, read);
+
+ return(-1);
}
-/* returns the entry number or -1 on eof *************************************/
+/* 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){
- long ptr=0;
- decode_aux *t=book->decode_tree;
- do{
- switch(_oggpack_read1(b)){
- case 0:
- ptr=t->ptr0[ptr];
- break;
- case 1:
- ptr=t->ptr1[ptr];
- break;
- case -1:
- return(-1);
+ 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;
}
- }while(ptr>0);
- return(-ptr);
+ for(i=0,o=0;i<book->dim;i++,o+=step)
+ for (j=0;o+j<n && j<step;j++)
+ a[o+j]+=t[j][i];
+ }
+ return(0);
}
-/* returns the entry number or -1 on eof *************************************/
-long vorbis_book_decodev(codebook *book, double *a, oggpack_buffer *b){
- long entry=vorbis_book_decode(book,b);
- int i;
- if(entry==-1)return(-1);
- for(i=0;i<book->dim;i++)a[i]+=(book->valuelist+entry*book->dim)[i];
- return(entry);
+/* 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;
+
+ 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++];
+ }
+ }
+ return(0);
}
-#ifdef _V_SELFTEST
-
-/* 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 <stdio.h>
-#include "vorbis/book/lsp20_0.vqh"
-#include "vorbis/book/lsp32_0.vqh"
-#define TESTSIZE 40
-#define TESTDIM 4
-
-double test1[40]={
- 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,
-};
-
-double test2[40]={
- 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_codebook *testlist[]={&_vq_book_lsp20_0,&_vq_book_lsp32_0,NULL};
-double *testvec[]={test1,test2};
-
-int main(){
- oggpack_buffer write;
- oggpack_buffer read;
- long ptr=0,i;
- _oggpack_writeinit(&write);
-
- fprintf(stderr,"Testing codebook abstraction...:\n");
-
- while(testlist[ptr]){
- codebook c;
- static_codebook s;
- double *qv=alloca(sizeof(double)*TESTSIZE);
- double *iv=alloca(sizeof(double)*TESTSIZE);
- memcpy(qv,testvec[ptr],sizeof(double)*TESTSIZE);
- memset(iv,0,sizeof(double)*TESTSIZE);
-
- fprintf(stderr,"\tpacking/coding %ld... ",ptr);
-
- /* pack the codebook, write the testvector */
- _oggpack_reset(&write);
- vorbis_book_init_encode(&c,testlist[ptr]); /* get it into memory
- we can write */
- vorbis_staticbook_pack(testlist[ptr],&write);
- fprintf(stderr,"Codebook size %ld bytes... ",_oggpack_bytes(&write));
- for(i=0;i<TESTSIZE;i+=TESTDIM)
- vorbis_book_encodev(&c,qv+i,&write);
- vorbis_book_clear(&c);
-
- fprintf(stderr,"OK.\n");
- fprintf(stderr,"\tunpacking/decoding %ld... ",ptr);
-
- /* transfer the write data to a read buffer and unpack/read */
- _oggpack_readinit(&read,_oggpack_buffer(&write),_oggpack_bytes(&write));
- if(vorbis_staticbook_unpack(&read,&s)){
- fprintf(stderr,"Error unpacking codebook.\n");
- exit(1);
+/* 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++];
+ }
}
- if(vorbis_book_init_decode(&c,&s)){
- fprintf(stderr,"Error initializing codebook.\n");
- exit(1);
+ }else{
+ int i;
+
+ for(i=0;i<n;){
+ a[i++]=0.f;
}
+ }
+ return(0);
+}
- for(i=0;i<TESTSIZE;i+=TESTDIM)
- if(vorbis_book_decodev(&c,iv+i,&read)==-1){
- fprintf(stderr,"Error reading codebook test data (EOP).\n");
- exit(1);
- }
- for(i=0;i<TESTSIZE;i++)
- if(fabs(qv[i]-iv[i])>.000001){
- fprintf(stderr,"input (%g) != output (%g) at position (%ld)\n",
- iv[i],testvec[ptr][i]-qv[i],i);
- exit(1);
+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){
+ int m=(offset+n)/ch;
+ for(i=offset/ch;i<m;){
+ entry = decode_packed_entry_number(book,b);
+ if(entry==-1)return(-1);
+ {
+ const float *t = book->valuelist+entry*book->dim;
+ for (j=0;i<m && j<book->dim;j++){
+ a[chptr++][i]+=t[j];
+ if(chptr==ch){
+ chptr=0;
+ i++;
+ }
+ }
}
-
- fprintf(stderr,"OK\n");
- ptr++;
+ }
}
- exit(0);
+ return(0);
}
-
-#endif