summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <xiphmont@xiph.org>2000-08-03 21:12:53 +0000
committerMonty <xiphmont@xiph.org>2000-08-03 21:12:53 +0000
commit12fa21918c0655b9b507d3195085e3c3991c07ec (patch)
treece033c5f234d78131f7b8513c355ddb3a624d8a0
parent45bb2f50b97db0f64f91c659f7b3a965cccb0fd6 (diff)
downloadlibvorbis-git-12fa21918c0655b9b507d3195085e3c3991c07ec.tar.gz
Incremental update
svn path=/branches/monty_branch_20000724/vorbis/; revision=541
-rw-r--r--vq/bookutil.c742
-rw-r--r--vq/latticehint.c398
2 files changed, 1140 insertions, 0 deletions
diff --git a/vq/bookutil.c b/vq/bookutil.c
new file mode 100644
index 00000000..8193d321
--- /dev/null
+++ b/vq/bookutil.c
@@ -0,0 +1,742 @@
+/********************************************************************
+ * *
+ * 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. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: utility functions for loading .vqh and .vqd files
+ last mod: $Id: bookutil.c,v 1.15.2.1 2000/08/03 21:12:53 xiphmont Exp $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include "vorbis/codebook.h"
+#include "../lib/sharedbook.h"
+#include "bookutil.h"
+
+/* A few little utils for reading files */
+/* read a line. Use global, persistent buffering */
+static char *linebuffer=NULL;
+static int lbufsize=0;
+char *get_line(FILE *in){
+ long sofar=0;
+ if(feof(in))return NULL;
+
+ while(1){
+ int gotline=0;
+
+ while(!gotline){
+ if(sofar+1>=lbufsize){
+ if(!lbufsize){
+ lbufsize=1024;
+ linebuffer=malloc(lbufsize);
+ }else{
+ lbufsize*=2;
+ linebuffer=realloc(linebuffer,lbufsize);
+ }
+ }
+ {
+ long c=fgetc(in);
+ switch(c){
+ case EOF:
+ if(sofar==0)return(NULL);
+ /* fallthrough correct */
+ case '\n':
+ linebuffer[sofar]='\0';
+ gotline=1;
+ break;
+ default:
+ linebuffer[sofar++]=c;
+ linebuffer[sofar]='\0';
+ break;
+ }
+ }
+ }
+
+ if(linebuffer[0]=='#'){
+ sofar=0;
+ }else{
+ return(linebuffer);
+ }
+ }
+}
+
+/* read the next numerical value from the given file */
+static char *value_line_buff=NULL;
+
+int get_line_value(FILE *in,double *value){
+ char *next;
+
+ if(!value_line_buff)return(-1);
+
+ *value=strtod(value_line_buff, &next);
+ if(next==value_line_buff){
+ value_line_buff=NULL;
+ return(-1);
+ }else{
+ value_line_buff=next;
+ while(*value_line_buff>44)value_line_buff++;
+ if(*value_line_buff==44)value_line_buff++;
+ return(0);
+ }
+}
+
+int get_next_value(FILE *in,double *value){
+ while(1){
+ if(get_line_value(in,value)){
+ value_line_buff=get_line(in);
+ if(!value_line_buff)return(-1);
+ }else{
+ return(0);
+ }
+ }
+}
+
+int get_next_ivalue(FILE *in,long *ivalue){
+ double value;
+ int ret=get_next_value(in,&value);
+ *ivalue=value;
+ return(ret);
+}
+
+static double sequence_base=0.;
+static int v_sofar=0;
+void reset_next_value(void){
+ value_line_buff=NULL;
+ sequence_base=0.;
+ v_sofar=0;
+}
+
+char *setup_line(FILE *in){
+ reset_next_value();
+ value_line_buff=get_line(in);
+ return(value_line_buff);
+}
+
+
+int get_vector(codebook *b,FILE *in,int start, int n,double *a){
+ int i;
+ const static_codebook *c=b->c;
+
+ while(1){
+
+ if(v_sofar==n || get_line_value(in,a)){
+ reset_next_value();
+ if(get_next_value(in,a))
+ break;
+ for(i=0;i<start;i++){
+ sequence_base=*a;
+ get_line_value(in,a);
+ }
+ }
+
+ for(i=1;i<c->dim;i++)
+ if(get_line_value(in,a+i))
+ break;
+
+ if(i==c->dim){
+ double temp=a[c->dim-1];
+ for(i=0;i<c->dim;i++)a[i]-=sequence_base;
+ if(c->q_sequencep)sequence_base=temp;
+ v_sofar++;
+ return(0);
+ }
+ sequence_base=0.;
+ }
+
+ return(-1);
+}
+
+/* read lines fromt he beginning until we find one containing the
+ specified string */
+char *find_seek_to(FILE *in,char *s){
+ rewind(in);
+ while(1){
+ char *line=get_line(in);
+ if(line){
+ if(strstr(line,s))
+ return(line);
+ }else
+ return(NULL);
+ }
+}
+
+
+/* this reads the format as written by vqbuild/latticebuild; innocent
+ (legal) tweaking of the file that would not affect its valid
+ header-ness will break this routine */
+
+codebook *codebook_load(char *filename){
+ codebook *b=calloc(1,sizeof(codebook));
+ static_codebook *c=(static_codebook *)(b->c=calloc(1,sizeof(static_codebook)));
+ encode_aux_nearestmatch *a=NULL;
+ encode_aux_threshmatch *t=NULL;
+ encode_aux_pigeonhole *p=NULL;
+ int quant_to_read=0;
+ FILE *in=fopen(filename,"r");
+ char *line;
+ long i;
+
+ if(in==NULL){
+ fprintf(stderr,"Couldn't open codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* find the codebook struct */
+ find_seek_to(in,"static static_codebook _vq_book_");
+
+ /* get the major important values */
+ line=get_line(in);
+ if(sscanf(line,"%ld, %ld,",
+ &(c->dim),&(c->entries))!=2){
+ fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+ line=get_line(in);
+ line=get_line(in);
+ if(sscanf(line,"%d, %ld, %ld, %d, %d,",
+ &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant),
+ &(c->q_sequencep))!=5){
+ fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+
+ /* find the auxiliary encode struct[s] (if any) */
+ if(find_seek_to(in,"static encode_aux_nearestmatch _vq_aux")){
+ /* how big? */
+ c->nearest_tree=a=calloc(1,sizeof(encode_aux_nearestmatch));
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ if(sscanf(line,"%ld, %ld",&(a->aux),&(a->alloc))!=2){
+ fprintf(stderr,"2: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+
+ /* load ptr0 */
+ find_seek_to(in,"static long _vq_ptr0");
+ reset_next_value();
+ a->ptr0=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->ptr0+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* load ptr1 */
+ find_seek_to(in,"static long _vq_ptr1");
+ reset_next_value();
+ a->ptr1=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->ptr1+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+
+ /* load p */
+ find_seek_to(in,"static long _vq_p_");
+ reset_next_value();
+ a->p=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->p+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* load q */
+ find_seek_to(in,"static long _vq_q_");
+ reset_next_value();
+ a->q=malloc(sizeof(long)*a->aux);
+ for(i=0;i<a->aux;i++)
+ if(get_next_ivalue(in,a->q+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+ }
+
+ if(find_seek_to(in,"static encode_aux_threshmatch _vq_aux")){
+ /* how big? */
+ c->thresh_tree=t=calloc(1,sizeof(encode_aux_threshmatch));
+ line=get_line(in);
+ line=get_line(in);
+ line=get_line(in);
+ if(sscanf(line,"%d",&(t->quantvals))!=1){
+ fprintf(stderr,"3: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+ line=get_line(in);
+ if(sscanf(line,"%d",&(t->threshvals))!=1){
+ fprintf(stderr,"4: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+ /* load quantthresh */
+ find_seek_to(in,"static double _vq_quantthresh_");
+ reset_next_value();
+ t->quantthresh=malloc(sizeof(double)*t->threshvals);
+ for(i=0;i<t->threshvals-1;i++)
+ if(get_next_value(in,t->quantthresh+i)){
+ fprintf(stderr,"out of data 1 while reading codebook %s\n",filename);
+ exit(1);
+ }
+ /* load quantmap */
+ find_seek_to(in,"static long _vq_quantmap_");
+ reset_next_value();
+ t->quantmap=malloc(sizeof(long)*t->threshvals);
+ for(i=0;i<t->threshvals;i++)
+ if(get_next_ivalue(in,t->quantmap+i)){
+ fprintf(stderr,"out of data 2 while reading codebook %s\n",filename);
+ exit(1);
+ }
+ }
+
+ if(find_seek_to(in,"static encode_aux_pigeonhole _vq_aux")){
+ int pigeons=1,i;
+ /* how big? */
+ c->pigeon_tree=p=calloc(1,sizeof(encode_aux_pigeonhole));
+ line=get_line(in);
+ if(sscanf(line,"%lf, %lf, %d, %d",&(p->min),&(p->del),
+ &(p->mapentries),&(p->quantvals))!=4){
+ fprintf(stderr,"5: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+ line=get_line(in);
+ line=get_line(in);
+ if(sscanf(line,"%ld",&(p->fittotal))!=1){
+ fprintf(stderr,"6: syntax in %s in line:\t %s",filename,line);
+ exit(1);
+ }
+ /* load pigeonmap */
+ find_seek_to(in,"static long _vq_pigeonmap_");
+ reset_next_value();
+ p->pigeonmap=malloc(sizeof(long)*p->mapentries);
+ for(i=0;i<p->mapentries;i++)
+ if(get_next_ivalue(in,p->pigeonmap+i)){
+ fprintf(stderr,"out of data (pigeonmap) while reading codebook %s\n",filename);
+ exit(1);
+ }
+ /* load fitlist */
+ find_seek_to(in,"static long _vq_fitlist_");
+ reset_next_value();
+ p->fitlist=malloc(sizeof(long)*p->fittotal);
+ for(i=0;i<p->fittotal;i++)
+ if(get_next_ivalue(in,p->fitlist+i)){
+ fprintf(stderr,"out of data (fitlist) while reading codebook %s\n",filename);
+ exit(1);
+ }
+ /* load fitmap */
+ find_seek_to(in,"static long _vq_fitmap_");
+ reset_next_value();
+ for(i=0;i<c->dim;i++)pigeons*=p->quantvals;
+ p->fitmap=malloc(sizeof(long)*pigeons);
+ for(i=0;i<pigeons;i++)
+ if(get_next_ivalue(in,p->fitmap+i)){
+ fprintf(stderr,"out of data (fitmap) while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* load fitlength */
+ find_seek_to(in,"static long _vq_fitlength_");
+ reset_next_value();
+ p->fitlength=malloc(sizeof(long)*pigeons);
+ for(i=0;i<pigeons;i++)
+ if(get_next_ivalue(in,p->fitlength+i)){
+ fprintf(stderr,"out of data (fitlength) while reading codebook %s\n",filename);
+ exit(1);
+ }
+ }
+
+ switch(c->maptype){
+ case 0:
+ quant_to_read=0;
+ break;
+ case 1:
+ quant_to_read=_book_maptype1_quantvals(c);
+ break;
+ case 2:
+ quant_to_read=c->entries*c->dim;
+ break;
+ }
+
+ /* load the quantized entries */
+ find_seek_to(in,"static long _vq_quantlist_");
+ reset_next_value();
+ c->quantlist=malloc(sizeof(long)*quant_to_read);
+ for(i=0;i<quant_to_read;i++)
+ if(get_next_ivalue(in,c->quantlist+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* load the lengthlist */
+ find_seek_to(in,"static long _vq_lengthlist");
+ reset_next_value();
+ c->lengthlist=malloc(sizeof(long)*c->entries);
+ for(i=0;i<c->entries;i++)
+ if(get_next_ivalue(in,c->lengthlist+i)){
+ fprintf(stderr,"out of data while reading codebook %s\n",filename);
+ exit(1);
+ }
+
+ /* got it all */
+ fclose(in);
+
+ vorbis_book_init_encode(b,c);
+
+ return(b);
+}
+
+void spinnit(char *s,int n){
+ static int p=0;
+ static long lasttime=0;
+ long test;
+ struct timeval thistime;
+
+ gettimeofday(&thistime,NULL);
+ test=thistime.tv_sec*10+thistime.tv_usec/100000;
+ if(lasttime!=test){
+ lasttime=test;
+
+ fprintf(stderr,"%s%d ",s,n);
+
+ p++;if(p>3)p=0;
+ switch(p){
+ case 0:
+ fprintf(stderr,"| \r");
+ break;
+ case 1:
+ fprintf(stderr,"/ \r");
+ break;
+ case 2:
+ fprintf(stderr,"- \r");
+ break;
+ case 3:
+ fprintf(stderr,"\\ \r");
+ break;
+ }
+ fflush(stderr);
+ }
+}
+
+void build_tree_from_lengths(int vals, long *hist, long *lengths){
+ int i,j;
+ long *membership=malloc(vals*sizeof(long));
+ long *histsave=alloca(vals*sizeof(long));
+ memcpy(histsave,hist,vals*sizeof(long));
+
+ for(i=0;i<vals;i++)membership[i]=i;
+
+ /* find codeword lengths */
+ /* much more elegant means exist. Brute force n^2, minimum thought */
+ for(i=vals;i>1;i--){
+ int first=-1,second=-1;
+ long least=-1;
+
+ spinnit("building... ",i);
+
+ /* find the two nodes to join */
+ for(j=0;j<vals;j++)
+ if(least==-1 || hist[j]<least){
+ least=hist[j];
+ first=membership[j];
+ }
+ least=-1;
+ for(j=0;j<vals;j++)
+ if((least==-1 || hist[j]<least) && membership[j]!=first){
+ least=hist[j];
+ second=membership[j];
+ }
+ if(first==-1 || second==-1){
+ fprintf(stderr,"huffman fault; no free branch\n");
+ exit(1);
+ }
+
+ /* join them */
+ least=hist[first]+hist[second];
+ for(j=0;j<vals;j++)
+ if(membership[j]==first || membership[j]==second){
+ membership[j]=first;
+ hist[j]=least;
+ lengths[j]++;
+ }
+ }
+ for(i=0;i<vals-1;i++)
+ if(membership[i]!=membership[i+1]){
+ fprintf(stderr,"huffman fault; failed to build single tree\n");
+ exit(1);
+ }
+
+ /* for sanity check purposes: how many bits would it have taken to
+ encode the training set? */
+ {
+ long bitsum=0;
+ long samples=0;
+ for(i=0;i<vals;i++){
+ bitsum+=(histsave[i]-1)*lengths[i];
+ samples+=histsave[i]-1;
+ }
+
+ if(samples){
+ fprintf(stderr,"\rTotal samples in training set: %ld \n",samples);
+ fprintf(stderr,"\rTotal bits used to represent training set: %ld\n",
+ bitsum);
+ }
+ }
+
+ free(membership);
+}
+
+/* wrap build_tree_from_lengths to allow zero entries in the histogram */
+void build_tree_from_lengths0(int vals, long *hist, long *lengths){
+
+ /* pack the 'sparse' hit list into a dense list, then unpack
+ the lengths after the build */
+
+ int upper=0,i;
+ long *lengthlist=calloc(vals,sizeof(long));
+ long *newhist=alloca(vals*sizeof(long));
+
+ for(i=0;i<vals;i++)
+ if(hist[i]>0)
+ newhist[upper++]=hist[i];
+
+ if(upper != vals){
+ fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n",
+ vals-upper,upper);
+ }
+
+ build_tree_from_lengths(upper,newhist,lengthlist);
+
+ upper=0;
+ for(i=0;i<vals;i++)
+ if(hist[i]>0)
+ lengths[i]=lengthlist[upper++];
+ else
+ lengths[i]=0;
+
+ free(lengthlist);
+}
+
+void write_codebook(FILE *out,char *name,const static_codebook *c){
+ encode_aux_pigeonhole *p=c->pigeon_tree;
+ encode_aux_threshmatch *t=c->thresh_tree;
+ encode_aux_nearestmatch *n=c->nearest_tree;
+ int i,j,k;
+
+ /* save the book in C header form */
+ fprintf(out,
+ "/********************************************************************\n"
+ " * *\n"
+ " * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *\n"
+ " * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *\n"
+ " * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *\n"
+ " * PLEASE READ THESE TERMS DISTRIBUTING. *\n"
+ " * *\n"
+ " * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *\n"
+ " * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *\n"
+ " * http://www.xiph.org/ *\n"
+ " * *\n"
+ " ********************************************************************\n"
+ "\n"
+ " function: static codebook autogenerated by vq/somethingorother\n"
+ "\n"
+ " ********************************************************************/\n\n");
+
+ fprintf(out,"#ifndef _V_%s_VQH_\n#define _V_%s_VQH_\n",name,name);
+ fprintf(out,"#include \"vorbis/codebook.h\"\n\n");
+
+ /* first, the static vectors, then the book structure to tie it together. */
+ /* quantlist */
+ if(c->quantlist){
+ long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim);
+ fprintf(out,"static long _vq_quantlist_%s[] = {\n",name);
+ for(j=0;j<vals;j++){
+ fprintf(out,"\t%ld,\n",c->quantlist[j]);
+ }
+ fprintf(out,"};\n\n");
+ }
+
+ /* lengthlist */
+ fprintf(out,"static long _vq_lengthlist_%s[] = {\n",name);
+ for(j=0;j<c->entries;){
+ fprintf(out,"\t");
+ for(k=0;k<16 && j<c->entries;k++,j++)
+ fprintf(out,"%2ld,",c->lengthlist[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ if(t){
+ /* quantthresh */
+ fprintf(out,"static double _vq_quantthresh_%s[] = {\n",name);
+ for(j=0;j<t->threshvals-1;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<t->threshvals-1;k++,j++)
+ fprintf(out,"%.5g, ",t->quantthresh[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* quantmap */
+ fprintf(out,"static long _vq_quantmap_%s[] = {\n",name);
+ for(j=0;j<t->threshvals;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<t->threshvals;k++,j++)
+ fprintf(out,"%5ld,",t->quantmap[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ fprintf(out,"static encode_aux_threshmatch _vq_auxt_%s = {\n",name);
+ fprintf(out,"\t_vq_quantthresh_%s,\n",name);
+ fprintf(out,"\t_vq_quantmap_%s,\n",name);
+ fprintf(out,"\t%d,\n",t->quantvals);
+ fprintf(out,"\t%d\n};\n\n",t->threshvals);
+ }
+
+ if(p){
+ int pigeons=1;
+ for(i=0;i<c->dim;i++)pigeons*=p->quantvals;
+
+ /* pigeonmap */
+ fprintf(out,"static long _vq_pigeonmap_%s[] = {\n",name);
+ for(j=0;j<p->mapentries;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<p->mapentries;k++,j++)
+ fprintf(out,"%5ld, ",p->pigeonmap[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+ /* fitlist */
+ fprintf(out,"static long _vq_fitlist_%s[] = {\n",name);
+ for(j=0;j<p->fittotal;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<p->fittotal;k++,j++)
+ fprintf(out,"%5ld, ",p->fitlist[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+ /* fitmap */
+ fprintf(out,"static long _vq_fitmap_%s[] = {\n",name);
+ for(j=0;j<pigeons;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<pigeons;k++,j++)
+ fprintf(out,"%5ld, ",p->fitmap[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+ /* fitlength */
+ fprintf(out,"static long _vq_fitlength_%s[] = {\n",name);
+ for(j=0;j<pigeons;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<pigeons;k++,j++)
+ fprintf(out,"%5ld, ",p->fitlength[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ fprintf(out,"static encode_aux_pigeonhole _vq_auxp_%s = {\n",name);
+ fprintf(out,"\t%g, %g, %d, %d,\n",
+ p->min,p->del,p->mapentries,p->quantvals);
+
+ fprintf(out,"\t_vq_pigeonmap_%s,\n",name);
+
+ fprintf(out,"\t%ld,\n",p->fittotal);
+ fprintf(out,"\t_vq_fitlist_%s,\n",name);
+ fprintf(out,"\t_vq_fitmap_%s,\n",name);
+ fprintf(out,"\t_vq_fitlength_%s\n};\n\n",name);
+ }
+
+ if(n){
+
+ /* ptr0 */
+ fprintf(out,"static long _vq_ptr0_%s[] = {\n",name);
+ for(j=0;j<n->aux;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<n->aux;k++,j++)
+ fprintf(out,"%6ld,",n->ptr0[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* ptr1 */
+ fprintf(out,"static long _vq_ptr1_%s[] = {\n",name);
+ for(j=0;j<n->aux;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<n->aux;k++,j++)
+ fprintf(out,"%6ld,",n->ptr1[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* p */
+ fprintf(out,"static long _vq_p_%s[] = {\n",name);
+ for(j=0;j<n->aux;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<n->aux;k++,j++)
+ fprintf(out,"%6ld,",n->p[j]*c->dim);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* q */
+ fprintf(out,"static long _vq_q_%s[] = {\n",name);
+ for(j=0;j<n->aux;){
+ fprintf(out,"\t");
+ for(k=0;k<8 && j<n->aux;k++,j++)
+ fprintf(out,"%6ld,",n->q[j]*c->dim);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ fprintf(out,"static encode_aux_nearestmatch _vq_auxn_%s = {\n",name);
+ fprintf(out,"\t_vq_ptr0_%s,\n",name);
+ fprintf(out,"\t_vq_ptr1_%s,\n",name);
+ fprintf(out,"\t_vq_p_%s,\n",name);
+ fprintf(out,"\t_vq_q_%s,\n",name);
+ fprintf(out,"\t%ld, %ld\n};\n\n",n->aux,n->aux);
+ }
+
+ /* tie it all together */
+
+ fprintf(out,"static static_codebook _vq_book_%s = {\n",name);
+
+ fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries);
+ fprintf(out,"\t_vq_lengthlist_%s,\n",name);
+ fprintf(out,"\t%d, %ld, %ld, %d, %d,\n",
+ c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep);
+ if(c->quantlist)
+ fprintf(out,"\t_vq_quantlist_%s,\n",name);
+ else
+ fprintf(out,"\tNULL,\n");
+
+ if(n)
+ fprintf(out,"\t&_vq_auxn_%s,\n",name);
+ else
+ fprintf(out,"\tNULL,\n");
+ if(t)
+ fprintf(out,"\t&_vq_auxt_%s,\n",name);
+ else
+ fprintf(out,"\tNULL,\n");
+ if(p)
+ fprintf(out,"\t&_vq_auxp_%s,\n",name);
+ else
+ fprintf(out,"\tNULL,\n");
+
+ fprintf(out,"};\n\n");
+
+ fprintf(out,"\n#endif\n");
+}
diff --git a/vq/latticehint.c b/vq/latticehint.c
new file mode 100644
index 00000000..357fe0d8
--- /dev/null
+++ b/vq/latticehint.c
@@ -0,0 +1,398 @@
+/********************************************************************
+ * *
+ * 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. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: utility main for building thresh/pigeonhole encode hints
+ last mod: $Id: latticehint.c,v 1.1.2.1 2000/08/03 21:12:53 xiphmont Exp $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include "vorbis/codebook.h"
+#include "../lib/sharedbook.h"
+#include "bookutil.h"
+
+/* The purpose of this util is to build encode hints for lattice
+ codebooks so that brute forcing each codebook entry isn't needed.
+ Threshhold hints are for books in which each scalar in the vector
+ is independant (eg, residue) and pigeonhole lookups provide a
+ minimum error fit for words where the scalars are interdependant
+ (each affecting the fit of the next in sequence) as in an LSP
+ sequential book (or can be used along with a sparse threshhold map,
+ like a splitting tree that need not be trained)
+
+ If the input book is non-sequential, a threshhold hint is built.
+ If the input book is sequential, a pigeonholing hist is built.
+ If the book is sparse, a pigeonholing hint is built, possibly in addition
+ to the threshhold hint
+
+ command line:
+ latticehint book.vqh
+
+ latticehint produces book.vqh on stdout */
+
+static int longsort(const void *a, const void *b){
+ return(**((long **)a)-**((long **)b));
+}
+
+static int addtosearch(int entry,long **tempstack,long *tempcount,int add){
+ long *ptr=tempstack[entry];
+ long i=tempcount[entry];
+
+ if(ptr){
+ while(i--)
+ if(*ptr++==add)return(0);
+ tempstack[entry]=realloc(tempstack[entry],
+ (tempcount[entry]+1)*sizeof(long));
+ }else{
+ tempstack[entry]=malloc(sizeof(long));
+ }
+
+ tempstack[entry][tempcount[entry]++]=add;
+ return(1);
+}
+
+static void setvals(int dim,encode_aux_pigeonhole *p,
+ long *temptrack,double *tempmin,double *tempmax,
+ int seqp){
+ int i;
+ double last=0.;
+ for(i=0;i<dim;i++){
+ tempmin[i]=(temptrack[i])*p->del+p->min+last;
+ tempmax[i]=tempmin[i]+p->del;
+ if(seqp)last=tempmin[i];
+ }
+}
+
+/* note that things are currently set up such that input fits that
+ quantize outside the pigeonmap are dropped and brute-forced. So we
+ can ignore the <0 and >=n boundary cases in min/max error */
+
+static double minerror(int dim,double *a,encode_aux_pigeonhole *p,
+ long *temptrack,double *tempmin,double *tempmax){
+ int i;
+ double err=0.;
+ for(i=0;i<dim;i++){
+ double eval=0.;
+ if(a[i]<tempmin[i]){
+ eval=tempmin[i]-a[i];
+ }else if(a[i]>tempmax[i]){
+ eval=a[i]-tempmax[i];
+ }
+ err+=eval*eval;
+ }
+ return(err);
+}
+
+static double maxerror(int dim,double *a,encode_aux_pigeonhole *p,
+ long *temptrack,double *tempmin,double *tempmax){
+ int i;
+ double err=0.,eval;
+ for(i=0;i<dim;i++){
+ if(a[i]<tempmin[i]){
+ eval=tempmax[i]-a[i];
+ }else if(a[i]>tempmax[i]){
+ eval=a[i]-tempmin[i];
+ }else{
+ double t1=a[i]-tempmin[i];
+ eval=tempmax[i]-a[i];
+ if(t1>eval)eval=t1;
+ }
+ err+=eval*eval;
+ }
+ return(err);
+}
+
+int main(int argc,char *argv[]){
+ codebook *b;
+ static_codebook *c;
+ int entries=-1,dim=-1;
+ double min,del,cutoff=1.;
+ char *name;
+ long i,j;
+
+ if(argv[1]==NULL){
+ fprintf(stderr,"Need a lattice book on the command line.\n");
+ exit(1);
+ }
+
+ if(argv[2])cutoff=atof(argv[2]);
+
+ {
+ char *ptr;
+ char *filename=strdup(argv[1]);
+
+ b=codebook_load(filename);
+ c=(static_codebook *)(b->c);
+
+ ptr=strrchr(filename,'.');
+ if(ptr){
+ *ptr='\0';
+ name=strdup(filename);
+ }else{
+ name=strdup(filename);
+ }
+ }
+
+ if(c->maptype!=1){
+ fprintf(stderr,"Provided book is not a latticebook.\n");
+ exit(1);
+ }
+
+ entries=b->entries;
+ dim=b->dim;
+ min=_float32_unpack(c->q_min);
+ del=_float32_unpack(c->q_delta);
+
+ /* Do we want to gen a threshold hint? */
+ if(c->q_sequencep==0){
+ /* yes. Discard any preexisting threshhold hint */
+ long quantvals=_book_maptype1_quantvals(c);
+ long **quantsort=alloca(quantvals*sizeof(long *));
+ encode_aux_threshmatch *t=calloc(1,sizeof(encode_aux_threshmatch));
+ c->thresh_tree=t;
+
+ fprintf(stderr,"Adding threshold hint to %s...\n",name);
+
+ /* simplest possible threshold hint only */
+ t->quantthresh=calloc(quantvals-1,sizeof(double));
+ t->quantmap=calloc(quantvals,sizeof(int));
+ t->threshvals=quantvals;
+ t->quantvals=quantvals;
+
+ /* the quantvals may not be in order; sort em first */
+ for(i=0;i<quantvals;i++)quantsort[i]=c->quantlist+i;
+ qsort(quantsort,quantvals,sizeof(long *),longsort);
+
+ /* ok, gen the map and thresholds */
+ for(i=0;i<quantvals;i++)t->quantmap[i]=quantsort[i]-c->quantlist;
+ for(i=0;i<quantvals-1;i++)
+ t->quantthresh[i]=(*(quantsort[i])+*(quantsort[i+1]))*.5*del+min;
+ }
+
+ /* Do we want to gen a pigeonhole hint? */
+ for(i=0;i<entries;i++)if(c->lengthlist[i]==0)break;
+ if(c->q_sequencep || i<entries){
+ long **tempstack;
+ long *tempcount;
+ long *temptrack;
+ double *tempmin;
+ double *tempmax;
+ long totalstack=0;
+ long pigeons;
+ long subpigeons;
+ long quantvals=_book_maptype1_quantvals(c);
+ int changep=1;
+
+ encode_aux_pigeonhole *p=calloc(1,sizeof(encode_aux_pigeonhole));
+ c->pigeon_tree=p;
+
+ fprintf(stderr,"Adding pigeonhole hint to %s...\n",name);
+
+ /* the idea is that we quantize uniformly, even in a nonuniform
+ lattice, so that quantization of one scalar has a predictable
+ result on the next sequential scalar in a greedy matching
+ algorithm. We generate a lookup based on the quantization of
+ the vector (pigeonmap groups quantized entries together) and
+ list the entries that could possible be the best fit for any
+ given member of that pigeonhole. The encode process then has a
+ much smaller list to brute force */
+
+ /* find our pigeonhole-specific quantization values, fill in the
+ quant value->pigeonhole map */
+ p->del=del;
+ p->min=min-del*.5;
+ p->quantvals=(quantvals+1)/2;
+ {
+ int max=0;
+ for(i=0;i<quantvals;i++)if(max<c->quantlist[i])max=c->quantlist[i];
+ p->mapentries=max;
+ }
+ p->pigeonmap=malloc(p->mapentries*sizeof(long));
+
+ /* pigeonhole roughly on the boundaries of the quantvals; the
+ exact pigeonhole grouping is an optimization issue, not a
+ correctness issue */
+ for(i=0;i<p->mapentries;i++){
+ double thisval=del*(i+.5)+min; /* middle of the quant zone */
+ int quant=0;
+ double err=fabs(c->quantlist[0]*del+min-thisval);
+ for(j=1;j<quantvals;j++){
+ double thiserr=fabs(c->quantlist[j]*del+min-thisval);
+ if(thiserr<err){
+ quant=j/2;
+ err=thiserr;
+ }
+ }
+ p->pigeonmap[i]=quant;
+ }
+
+ /* pigeonmap complete. Now do the grungy business of finding the
+ entries that could possibly be the best fit for a value appearing
+ in the pigeonhole. The trick that allows the below to work is the
+ uniform quantization; even though the scalars may be 'sequential'
+ (each a delta from the last), the uniform quantization means that
+ the error variance is *not* dependant. Given a pigeonhole and an
+ entry, we can find the minimum and maximum possible errors
+ (relative to the entry) for any point that could appear in the
+ pigeonhole */
+
+ /* must iterate over both pigeonholes and entries */
+ /* temporarily (in order to avoid thinking hard), we grow each
+ pigeonhole seperately, the build a stack of 'em later */
+ pigeons=1;
+ subpigeons=1;
+ for(i=0;i<dim;i++)subpigeons*=p->mapentries;
+ for(i=0;i<dim;i++)pigeons*=p->quantvals;
+ temptrack=calloc(dim,sizeof(long));
+ tempmin=calloc(dim,sizeof(double));
+ tempmax=calloc(dim,sizeof(double));
+ tempstack=calloc(pigeons,sizeof(long *));
+ tempcount=calloc(pigeons,sizeof(long));
+
+ while(1){
+ double errorpost=-1;
+ char buffer[80];
+
+ /* map our current pigeonhole to a 'big pigeonhole' so we know
+ what list we're after */
+ int entry=0;
+ for(i=dim-1;i>=0;i--)entry=entry*p->quantvals+p->pigeonmap[temptrack[i]];
+ setvals(dim,p,temptrack,tempmin,tempmax,c->q_sequencep);
+ sprintf(buffer,"Building pigeonhole search list [%ld]...",totalstack);
+
+
+ /* Search all entries to find the one with the minimum possible
+ maximum error. Record that error */
+ for(i=0;i<entries;i++){
+ if(c->lengthlist[i]>0){
+ double this=maxerror(dim,b->valuelist+i*dim,p,
+ temptrack,tempmin,tempmax);
+ if(errorpost==-1 || this<errorpost)errorpost=this;
+ spinnit(buffer,subpigeons);
+ }
+ }
+
+ /* Our search list will contain all entries with a minimum
+ possible error <= our errorpost */
+ for(i=0;i<entries;i++)
+ if(c->lengthlist[i]>0){
+ spinnit(buffer,subpigeons);
+ if(minerror(dim,b->valuelist+i*dim,p,
+ temptrack,tempmin,tempmax)<errorpost)
+ totalstack+=addtosearch(entry,tempstack,tempcount,i);
+ }
+
+ for(i=0;i<dim;i++){
+ temptrack[i]++;
+ if(temptrack[i]<p->mapentries)break;
+ temptrack[i]=0;
+ }
+ if(i==dim)break;
+ subpigeons--;
+ }
+
+ fprintf(stderr,"\r "
+ "\rTotal search list size (all entries): %ld\n",totalstack);
+
+ /* pare the index of lists for improbable quantizations (where
+ improbable is determined by c->lengthlist; we assume that
+ pigeonholing is in sync with the codeword cells, which it is */
+ /*for(i=0;i<entries;i++){
+ double probability= 1./(1<<c->lengthlist[i]);
+ if(c->lengthlist[i]==0 || probability*entries<cutoff){
+ totalstack-=tempcount[i];
+ tempcount[i]=0;
+ }
+ }*/
+
+ /* pare the list of shortlists; merge contained and similar lists
+ together */
+ p->fitmap=malloc(pigeons*sizeof(long));
+ for(i=0;i<pigeons;i++)p->fitmap[i]=-1;
+ while(changep){
+ char buffer[80];
+ changep=0;
+
+ for(i=0;i<pigeons;i++){
+ if(p->fitmap[i]<0 && tempcount[i]){
+ for(j=i+1;j<pigeons;j++){
+ if(p->fitmap[j]<0 && tempcount[j]){
+ /* is one list a superset, or are they sufficiently similar? */
+ int amiss=0,bmiss=0,ii,jj;
+ for(ii=0;ii<tempcount[i];ii++){
+ for(jj=0;jj<tempcount[j];jj++)
+ if(tempstack[i][ii]==tempstack[j][jj])break;
+ if(jj==tempcount[j])amiss++;
+ }
+ for(jj=0;jj<tempcount[j];jj++){
+ for(ii=0;ii<tempcount[i];ii++)
+ if(tempstack[i][ii]==tempstack[j][jj])break;
+ if(ii==tempcount[i])bmiss++;
+ }
+ if(amiss==0 ||
+ bmiss==0 ||
+ (amiss*2<tempcount[i] && bmiss*2<tempcount[j] &&
+ tempcount[i]+bmiss<entries/30)){
+
+ /*superset/similar Add all of one to the other. */
+ for(jj=0;jj<tempcount[j];jj++)
+ totalstack+=addtosearch(i,tempstack,tempcount,
+ tempstack[j][jj]);
+ totalstack-=tempcount[j];
+ p->fitmap[j]=i;
+ changep=1;
+ }
+ }
+ }
+ sprintf(buffer,"Consolidating [%ld total, %s]... ",totalstack,
+ changep?"reit":"nochange");
+ spinnit(buffer,pigeons-i);
+ }
+ }
+ }
+
+ /* repack the temp stack in final form */
+
+ p->fittotal=totalstack;
+ p->fitlist=malloc((totalstack+1)*sizeof(long));
+ p->fitlength=malloc(pigeons*sizeof(long));
+ {
+ long usage=0;
+ for(i=0;i<pigeons;i++){
+ if(p->fitmap[i]==-1){
+ if(tempcount[i])
+ memcpy(p->fitlist+usage,tempstack[i],tempcount[i]*sizeof(long));
+ p->fitmap[i]=usage;
+ p->fitlength[i]=tempcount[i];
+ usage+=tempcount[i];
+ if(usage>totalstack){
+ fprintf(stderr,"Internal error; usage>totalstack\n");
+ exit(1);
+ }
+ }else{
+ p->fitlength[i]=p->fitlength[p->fitmap[i]];
+ p->fitmap[i]=p->fitmap[p->fitmap[i]];
+ }
+ }
+ }
+ }
+
+ write_codebook(stdout,name,c);
+ fprintf(stderr,"\r "
+ "\nDone.\n");
+ exit(0);
+}