/********************************************************************
* *
- * 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);
}