Update the VQ tools to pared down codebook abstraction.
[platform/upstream/libvorbis.git] / vq / build.c
index 0eac602..ac76bc8 100644 (file)
@@ -1,20 +1,17 @@
 /********************************************************************
  *                                                                  *
- * 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-1999             *
- * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company       *
- * http://www.xiph.org/                                             *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
  function: utility main for building codebooks from training sets
- author: Monty <xiphmont@mit.edu>
- modifications by: Monty
- last modification date: Dec 14 1999
+ last mod: $Id$
 
  ********************************************************************/
 
 #include <math.h>
 #include <string.h>
 #include <errno.h>
-#include <signal.h>
-#include "vqgen.h"
+#include "bookutil.h"
 
-static int rline(FILE *in,FILE *out,char *line,int max,int pass){
-  while(fgets(line,160,in)){
-    if(line[0]=='#'){
-      if(pass)fprintf(out,"%s",line);
+#include "vqgen.h"
+#include "vqsplit.h"
+
+static char *linebuffer=NULL;
+static int  lbufsize=0;
+static char *rline(FILE *in,FILE *out){
+  long sofar=0;
+  if(feof(in))return NULL;
+
+  while(1){
+    int gotline=0;
+
+    while(!gotline){
+      if(sofar>=lbufsize){
+        if(!lbufsize){        
+          lbufsize=1024;
+          linebuffer=_ogg_malloc(lbufsize);
+        }else{
+          lbufsize*=2;
+          linebuffer=_ogg_realloc(linebuffer,lbufsize);
+        }
+      }
+      {
+        long c=fgetc(in);
+        switch(c){
+        case '\n':
+        case EOF:
+          gotline=1;
+          break;
+        default:
+          linebuffer[sofar++]=c;
+          linebuffer[sofar]='\0';
+          break;
+        }
+      }
+    }
+    
+    if(linebuffer[0]=='#'){
+      sofar=0;
     }else{
-      return(1);
+      return(linebuffer);
     }
   }
-  return(0);
 }
 
 /* command line:
-   buildvq vq=file out=file quant=n
+   buildvq file
 */
 
-int exiting=0;
-void setexit(int dummy){
-  fprintf(stderr,"\nexiting... please wait to finish this iteration\n");
-  exiting=1;
-}
-
 int main(int argc,char *argv[]){
   vqgen v;
-  int entries=-1,dim=-1;
-  char line[1024];
+  static_codebook c;
+  codebook b;
+  quant_meta q;
+
+  long *quantlist=NULL;
+  int entries=-1,dim=-1,aux=-1;
+  FILE *out=NULL;
+  FILE *in=NULL;
+  char *line,*name;
   long i,j,k;
 
-  int init=0;
-  while(*argv){
+  b.c=&c;
 
-    /* load the trained data */
-    if(!strncmp(*argv,"vq=",3)){
-      FILE *in=NULL;
-      char filename[80],*ptr;
-      if(sscanf(*argv,"vq=%70s",filename)!=1){
-       fprintf(stderr,"Syntax error in argument '%s'\n",*argv);
-       exit(1);
-      }
+  if(argv[1]==NULL){
+    fprintf(stderr,"Need a trained data set on the command line.\n");
+    exit(1);
+  }
 
-      in=fopen(filename,"r");
-      ptr=strrchr(filename,'-');
-      if(ptr){
-       int num;
-       ptr++;
-       num=atoi(ptr);
-       sprintf(ptr,"%d.vqi",num+1);
-      }else
-       strcat(filename,"-0.vqi");
-      
-      out=fopen(filename,"w");
-      if(out==NULL){
-       fprintf(stderr,"Unable to open %s for writing\n",filename);
-       exit(1);
-      }
-      fprintf(out,"# OggVorbis VQ codebook trainer, intermediate file\n");
-
-      if(in){
-       /* we wish to suck in a preexisting book and continue to train it */
-       double a;
-           
-       rline(in,out,line,160,1);
-       if(sscanf(line,"%d %d %d",&entries,&dim,&met)!=3){
-         fprintf(stderr,"Syntax error reading book file\n");
-         exit(1);
-       }
-
-       metric=set_metric(met);
-       vqgen_init(&v,dim,entries,metric,0.);
-       init=1;
-
-       /* entries, bias, points */
-       i=0;
-       for(j=0;j<entries;j++){
-         for(k=0;k<dim;k++){
-           rline(in,out,line,160,0);
-           sscanf(line,"%lf",&a);
-           v.entrylist[i++]=a;
-         }
-       }
-
-       i=0;
-       for(j=0;j<entries;j++){
-         rline(in,out,line,160,0);
-         sscanf(line,"%lf",&a);
-         v.bias[i++]=a;
-       }
-
-       {
-         double b[80];
-         i=0;
-         v.entries=0; /* hack to avoid reseeding */
-         while(1){
-           for(k=0;k<dim && k<80;k++){
-             rline(in,out,line,160,0);
-             sscanf(line,"%lf",b+k);
-           }
-           if(feof(in))break;
-           vqgen_addpoint(&v,b);
-         }
-         v.entries=entries;
-       }
-
-       fclose(in);
-      }
-    }
+  {
+    char *ptr;
+    char *filename=strdup(argv[1]);
 
-    /* set parameters if we're not loading a pre book */
-    if(!strncmp(*argv,"entries=",8)){
-      sscanf(*argv,"entries=%d",&entries);
-    }
-    if(!strncmp(*argv,"desired=",8)){
-      sscanf(*argv,"desired=%lf",&desired);
+    in=fopen(filename,"r");
+    if(!in){
+      fprintf(stderr,"Could not open input file %s\n",filename);
+      exit(1);
     }
-    if(!strncmp(*argv,"dim=",4)){
-      sscanf(*argv,"dim=%d",&dim);
+    
+    ptr=strrchr(filename,'-');
+    if(ptr){
+      *ptr='\0';
+      name=strdup(filename);
+      sprintf(ptr,".vqh");
+    }else{
+      name=strdup(filename);
+      strcat(filename,".vqh");
     }
 
-    /* which error metric (0==euclidian distance default) */
-    if(!strncmp(*argv,"met=",4)){
-      sscanf(*argv,"met=%d",&met);
-      metric=set_metric(met);
+    out=fopen(filename,"w");
+    if(out==NULL){
+      fprintf(stderr,"Unable to open %s for writing\n",filename);
+      exit(1);
     }
-
-    if(!strncmp(*argv,"in=",3)){
-      int start;
-      char file[80];
-      FILE *in;
-
-      if(sscanf(*argv,"in=%79[^,],%d",file,&start)!=2)goto syner;
-      if(!out){
-       fprintf(stderr,"vq= must preceed in= arguments\n");
-       exit(1);
-      }
-      if(!init){
-       if(dim==-1 || entries==-1){
-         fprintf(stderr,"Must specify dimensionality and entries before"
-                 " first input file\n");
-         exit(1);
-       }
-       vqgen_init(&v,dim,entries,metric,0.);
-       init=1;
-      }
-
-      in=fopen(file,"r");
-      if(in==NULL){
-       fprintf(stderr,"Could not open input file %s\n",file);
-       exit(1);
-      }
-      fprintf(out,"# training file entry: %s\n",file);
-
-      while(rline(in,out,line,1024,1)){
-       double b[16];
-       int n=sscanf(line,"%lf %lf %lf %lf %lf %lf %lf %lf "
-                    "%lf %lf %lf %lf %lf %lf %lf %lf",
-                    b,b+1,b+2,b+3,b+4,b+5,b+6,b+7,b+8,b+9,b+10,b+11,b+12,b+13,
-                    b+14,b+15);
-       if(start+dim>n){
-         fprintf(stderr,"ran out of columns reading %s\n",file);
-         exit(1);
-       }
-       vqgen_addpoint(&v,b+start);
-      }
-
-      fclose(in);
-    }
-    argv++;
   }
 
-  /* train the book */
-  signal(SIGTERM,setexit);
-  signal(SIGINT,setexit);
+  /* suck in the trained book */
 
-  for(i=0;i<iter && !exiting;i++){
-    if(vqgen_iterate(&v)<desired)break;
+  /* read book type, but it doesn't matter */
+  line=rline(in,out);
+  
+  line=rline(in,out);
+  if(sscanf(line,"%d %d %d",&entries,&dim,&aux)!=3){
+    fprintf(stderr,"Syntax error reading book file\n");
+    exit(1);
+  }
+  
+  /* just use it to allocate mem */
+  vqgen_init(&v,dim,0,entries,0.f,NULL,NULL,0);
+  
+  /* quant */
+  line=rline(in,out);
+  if(sscanf(line,"%ld %ld %d %d",&q.min,&q.delta,
+            &q.quant,&q.sequencep)!=4){
+    fprintf(stderr,"Syntax error reading book file\n");
+    exit(1);
   }
-
-  /* save the book */
-
-  fprintf(out,"%d %d %d\n",entries,dim,met);
-
-  i=0;
-  for(j=0;j<entries;j++)
-    for(k=0;k<dim;k++)
-      fprintf(out,"%f\n",v.entrylist[i++]);
   
-  fprintf(out,"# biases---\n");
+  /* quantized entries */
+  /* save quant data; we don't want to requantize later as our method
+     is currently imperfect wrt repeated application */
   i=0;
-  for(j=0;j<entries;j++)
-    fprintf(out,"%f\n",v.bias[i++]);
+  quantlist=_ogg_malloc(sizeof(long)*v.elements*v.entries);
+  for(j=0;j<entries;j++){
+    float a;
+    for(k=0;k<dim;k++){
+      line=rline(in,out);
+      sscanf(line,"%f",&a);
+      v.entrylist[i]=a;
+      quantlist[i++]=rint(a);
+    }
+  }    
+  
+  /* ignore bias */
+  for(j=0;j<entries;j++)line=rline(in,out);
+  free(v.bias);
+  v.bias=NULL;
+  
+  /* training points */
+  {
+    float *b=alloca(sizeof(float)*(dim+aux));
+    i=0;
+    v.entries=0; /* hack to avoid reseeding */
+    while(1){
+      for(k=0;k<dim+aux;k++){
+        line=rline(in,out);
+        if(!line)break;
+        sscanf(line,"%f",b+k);
+      }
+      if(feof(in))break;
+      vqgen_addpoint(&v,b,NULL);
+    }
+    v.entries=entries;
+  }
+  
+  fclose(in);
+  vqgen_unquantize(&v,&q);
 
-  fprintf(out,"# points---\n");
-  i=0;
-  for(j=0;j<v.points;j++)
-    for(k=0;k<dim && k<80;k++)
-      fprintf(out,"%f\n",v.pointlist[i++]);
+  /* build the book */
+  vqsp_book(&v,&b,quantlist);
+  c.q_min=q.min;
+  c.q_delta=q.delta;
+  c.q_quant=q.quant;
+  c.q_sequencep=q.sequencep;
+
+  /* save the book in C header form */
+  write_codebook(out,name,b.c);
 
   fclose(out);
   exit(0);
-
-  syner:
-    fprintf(stderr,"Syntax error in argument '%s'\n",*argv);
-    exit(1);
 }